【问题标题】:Joda LocalDateTime from LocalDate and string来自 LocalDate 和字符串的 Joda LocalDateTime
【发布时间】:2021-08-10 11:00:03
【问题描述】:

我有:

  • joda LocalDate,所以它没有时间信息,只有日期
  • 包含时间和区域信息的字符串,如"14:20 CEST"

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

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

【问题讨论】:

  • 如果缺少Option 之一应该是什么行为?没有LocalDateTime 我猜?
  • @jwvh,它是使用 joda 的遗留代码,所以我这里没有选择。
  • @GaëlJ,那么我们可以忽略整个信息的那一部分吗?如果没有时间,我可以约会。不确定如果缺少日期应该是什么行为,但我相信这不会发生。
  • 这是一个有趣且不切实际的输入(理解你可能无法改变它)。您可能会收到无效的输入,通常是如果日期不在一年中的夏季时间(CEST 表示中欧 夏季时间)。

标签: java scala jodatime


【解决方案1】:

要结合这两个选项,自然的方法是使用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,可能还有另一种更简单的方法

【讨论】:

    【解决方案2】:

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

    您已经得到了详细处理Option 的使用的答案。在这里,我想更详细地介绍使用 Joda-Time 将您的 LocalDate 和您的 String 组合成 LocalDateTime。我了解您正在从旧代码中获取 Joda-Time LocalDate,并且需要将 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。然后我们知道时间是在一年中的夏季时间,也就是在时钟倒转之前。您返回 2021-10-31T02:20:00.000,接收方将无法判断是将其理解为 2021-10-31T02:20:00.000+02:00(夏令时)还是 2021-10-31T02 :20:00.000+01:00(标准时间)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-30
      • 2011-02-12
      • 1970-01-01
      • 1970-01-01
      • 2011-04-12
      • 1970-01-01
      • 2016-03-31
      • 1970-01-01
      相关资源
      最近更新 更多