来自 LocalDate 和字符串的 Joda LocalDateTime

Joda LocalDateTime from LocalDate and string

我有:

它们中的任何一个都可以不存在(Scala 的Option)。

我如何将这两者结合起来得到 joda LocalDateTime,即只代表日期和时间而不代表时区的实体?

要组合这两个选项,自然的方法是使用 flatMap 方法,如下所示:

val onlyDateOption: Option[LocalDate] = ???
val timeAndZoneOption: Option[String] = ???

val result: Option[LocalDateTime] = onlyDateOption.flatMap { onlyDate => 
  timeAndZoneOption.map { timeAndZone =>
    // Some logic here to build the LocalDateTime from onlyDate and timeAndZone
  }
}

也可以用for-comprehension写成更易读的方式:

val result: Option[LocalDateTime] =  for {
  onlyDate <- onlyDateOption
  timeAndZone <- timeAndZoneOption
} yield { 
  // Some logic here to build the LocalDateTime from onlyDate and timeAndZone
}

现在,如何使用 Joda 构建您期望的内容可能有多种不同的方式,其中一种可能是:

onlyDate
  .toLocalDateTime(LocalTime.MIDNIGHT)
  .withHourOfDay(...) // hour extracted from the string somehow
  .withMinuteOfHour(...) // minute extracted from the string somehow

我对 Joda 不熟悉API,可能还有另一种更简单的方法

如何使用 Joda-Time 组合 LocalDate 和 String

您已经得到了详细处理 Option 使用的答案。在这里,我想更详细地介绍如何使用 Joda-Time 将 LocalDateString 组合成 LocalDateTime。我了解到您正在从旧代码中获取 Joda-Time LocalDate,并且需要 return Joda-Time LocalDateTime 到旧代码。我假设您知道字符串中缩写的时区。我认为您应该验证该缩写,因为中欧时间在一年中的标准时间部分使用缩写 CET,在夏令时 (DST) 使用 CEST。请原谅我的 Java 代码。

    DateTimeUtils.setDefaultTimeZoneNames(createTimeZoneNamesMap());
    DateTimeFormatter timeFormatter = DateTimeFormat.forPattern("H:mm z");
    
    LocalDate date = new LocalDate(2021, 5, 22);
    String timeAndZoneString = "14:20 CEST";
    
    LocalTime time = LocalTime.parse(timeAndZoneString, timeFormatter);
    DateTime dateTime = date.toDateTime(time, ZONE);
    
    // Validate time zone abbreviation; take overlap at fall-back into account
    String earlierCorrectTimeString = dateTime.withEarlierOffsetAtOverlap()
            .toString(timeFormatter);
    if (! timeAndZoneString.equals(earlierCorrectTimeString)) {
        String laterCorrectTimeString = dateTime.withLaterOffsetAtOverlap()
                .toString(timeFormatter);
        if (! timeAndZoneString.equals(laterCorrectTimeString)) {
            throw new IllegalStateException("Incorrect time zone abbreviation for date");
        }
    }
    
    LocalDateTime ldt = dateTime.toLocalDateTime();
    
    System.out.println(ldt);

输出:

2021-05-22T14:20:00.000

我用过这两个辅助声明:

private static final DateTimeZone ZONE = DateTimeZone.forID("Europe/Paris");

private static Map<String, DateTimeZone> createTimeZoneNamesMap() {
    Map<String, DateTimeZone> names = new HashMap<>(4);
    names.put("CET", ZONE);
    names.put("CEST", ZONE);
    return names;
}

日期时间的有效性也被验证:date.toDateTime() 验证结果 DateTime 不会落在 spring-forward 的间隙中并抛出一个 IllegalInstantException: 如果可以的话。

如果您在字符串中收到的小时数总是两位数,则格式模式字符串需要对此进行指定,因此 HH:mm z.

请注意,您在极端情况下会丢失信息:如果时间落在回退时的重叠部分,时区缩写会消除歧义,但您生成的 LocalDateTime 会产生歧义。例如,日期是 2021-10-31,时间字符串是 2:20 CEST。然后我们知道时间是在一年中的夏令时部分,也就是在时钟拨回之前。你 return 2021-10-31T02:20:00.000,接收方将无法判断是将其理解为 2021-10-31T02:20:00.000+02:00(夏令时)还是 2021 -10-31T02:20:00.000+01:00(标准时间)。