【问题标题】:migrate from Joda time library to Java time(Java 8)从 Joda 时间库迁移到 Java 时间(Java 8)
【发布时间】:2015-05-05 20:44:48
【问题描述】:

我正在尝试从 Joda 时间库迁移到 Java 时间 (Java 8)。 我在java.time 中找不到与ISODateTimeFormat.dateOptionalTimeParser() 等效的内容

Joda ISO 格式化程序有很好的解析器:

ISODateTimeFormat.dateTimeParser() : generic - 根据解析的字符串选择解析器。 相似地: ISODateTimeFormat.dateOptionalTimeParser().

我发现很难将 Joda 时间更改为 java.time。 有人可以指导我吗?

示例:

String dateTimeString = "2015-01-01T12:29:22+00:00"; 
String dateTimeString2 = "2015-01-01T12:29:22";

当我使用 joda time 解析这个字符串时

ISODateTimeFormat.dateTimeParser().withZone("EST")

可以毫无问题地处理这两个问题。在 java 时间里哪个等价于这个?

使用 java 8,带有 ISO_Zoned_date_time 的 ZonedDateTime 不能同时处理这两者。

【问题讨论】:

  • 请问您为什么要迁移? Joda-Time 中是否有您希望通过迁移解决的特殊问题?正如您在我的回答中看到的那样,迁移在实际实践中可能是一个挑战。如果您对 Joda-Time 没有任何特殊问题,并且只想迁移,因为 Java-8 更“现代”,那么这可能不值得付出所有努力。
  • 是的,你是对的。我们想使用 Java 8 的所有现代特性,这就是我们迁移到 Java 8 的原因。
  • @MenoHochschild 来自 joda-time 站点 从 Java SE 8 开始,要求用户迁移到 java.time (JSR-310)。 也来自该站点 请注意,Joda-Time 被认为是一个基本上“完成”的项目。没有计划进行重大改进。如果使用 Java SE 8,请迁移到 java.time (JSR-310)。 这些建议都出现在主页上。如果使用 Java8(或更高版本)进行迁移是明智的。
  • @BillTurner 我非常清楚这些使 Joda-Time 实际上过时的官方建议。尽管如此,在更大的基于 Joda 的软件上进行额外的迁移工作仍然是一个需要证明的决定,而不仅仅是“去一个更现代的库”。支持可能丢失的功能(例如间隔或持续时间/周期格式)和细节上的意外行为变化(请参阅我的回答)也是重要问题。

标签: java-8 jodatime


【解决方案1】:

您不能使用预定义的格式化程序,但您可以使用以下模式构建自己的格式化程序(并将其分配给静态常量):

static final DateTimeFormatter DATE_TIME_OPTIONAL_OFFSET =
    DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[xxx]");

注意:如果您解析的输入仅包含日期和时间但没有偏移量(并且没有任何偏移量/区域默认值),则结果只能是 LocalDateTime,而不是全局时间戳.

还请注意方法withZone(...) 的不同行为。

乔达时间

When parsing, this zone will be set on the parsed datetime.     
A null zone means of no-override. If both an override chronology
and an override zone are set, the override zone will take precedence
over the zone in the chronology.

Java-8 (JSR-310)

When parsing, there are two distinct cases to consider.
If a zone has been parsed directly from the text, perhaps because 
DateTimeFormatterBuilder.appendZoneId() was used, then this override Zone
has no effect. If no zone has been parsed, then this override zone will
be included in the result of the parse where it can be used to build
instants and date-times.

旁注:Joda-Time-method withOffsetParsed() 更接近 Java-8-behaviour。

更新:我现在已经完成了自己的测试。看看有时令人惊讶的结果。

System.out.println(System.getProperty("java.version")); // 1.8.0_31

// parsing s1 with offset = UTC
String s1 = "2015-01-01T12:29:22+00:00"; 

OffsetDateTime odt1 = DATE_TIME_OPTIONAL_OFFSET.parse(s1, OffsetDateTime::from);
System.out.println(odt1); // 2015-01-01T12:29:22Z --- OK

LocalDateTime ldt1 = DATE_TIME_OPTIONAL_OFFSET.parse(s1, LocalDateTime::from);
System.out.println(ldt1); // 2015-01-01T12:29:22 --- OK

ZonedDateTime zdt1 = DATE_TIME_OPTIONAL_OFFSET.withZone(ZoneId.of("America/New_York")).parse(s1, ZonedDateTime::from);
System.out.println(zdt1); // 2015-01-01T12:29:22-05:00[America/New_York] --- seems to be a bug compared with the spec above, the parsed offset was overridden!!!

// now parsing s2 without offset
String s2 = "2015-01-01T12:29:22";

OffsetDateTime odt2 = DATE_TIME_OPTIONAL_OFFSET.parse(s2, OffsetDateTime::from);
System.out.println(odt2); // 2015-01-01T12:29:22Z --- questionable, the offset Z is invented/guessed here

LocalDateTime ldt2 = DATE_TIME_OPTIONAL_OFFSET.parse(s2, LocalDateTime::from);
System.out.println(ldt2); // 2015-01-01T12:29:22 --- OK

DATE_TIME_OPTIONAL_OFFSET.withZone(ZoneId.of("America/New_York")).parse(s2, ZonedDateTime::from);
// throws an exception --- seems to be a bug compared with the spec above, the zone set was not accepted

结论:

迁移时我会小心。细节决定成败。也许更新的 Java 版本 8u40 同时纠正了一些显示的问题(至少 withZone() 的行为可能已纠正 - 请参阅 JDK-issue 8033662,但对于 8u31,似乎缺少反向端口修复?!)。您还应该注意,在我的测试中,标记为“EST”的“时区”已被“America/New_York”替换,因为“EST”不是公认的时区 ID(它是美国本地化的时区名称缩写)。

更新 - 最终解决方案

经过额外测试,此代码似乎在 Java 8u31 中工作(假设 UTC 为默认值,以防输入中缺少偏移量):

static final DateTimeFormatter DATE_TIME_OPTIONAL_OFFSET =
    DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[xxx]");      
OffsetDateTime odt = 
  DATE_TIME_OPTIONAL_OFFSET.withZone(ZoneOffset.UTC).parse(input, OffsetDateTime::from);
ZonedDateTime zdt = odt.toZonedDateTime(); // containing a fixed offset

【讨论】:

    【解决方案2】:

    我在尝试将 ISODateTimeFormat.dateTimeParser().parseDateTime("...") 转换为基于 Java 8 java.time 设施的等价物时遇到了类似的问题。 最后,我未能使用 DateTimeFormatter 重现 Joda-Time 的 ISODateTimeFormat 的行为,而是选择了基于正则表达式的方法:

    private static final Pattern ISO_8601_PARSE = Pattern.compile(
            "(?<year>\\d{1,4})-(?<month>\\d{1,2})-(?<day>\\d{1,2})"
            + "(T((?<hour>\\d{1,2})(\\:(?<minute>\\d{1,2})(\\:(?<second>\\d{1,2})(\\.(?<millis>\\d{1,3}))?Z?)?)?)?)?");
    
    public static Date parseIso8601Date(String date) throws IllegalArgumentException {
        Matcher matcher = ISO_8601_PARSE.matcher(date);
        if (matcher.matches()) {
            try {
                String day = matcher.group("day");
                String month = matcher.group("month");
                String year = matcher.group("year");
                String hour = matcher.group("hour");
                String minute = matcher.group("minute");
                String second = matcher.group("second");
                String millis = matcher.group("millis");
                return Date.from(ZonedDateTime.of(
                        Integer.valueOf(year),
                        Integer.valueOf(month),
                        Integer.valueOf(day),
                        hasText(hour) ? Integer.valueOf(hour) : 0,
                        hasText(minute) ? Integer.valueOf(minute) : 0,
                        hasText(second) ? Integer.valueOf(second) : 0,
                        (hasText(millis) ? Integer.valueOf(millis) : 0) * 1000000, // nanoOfSecond
                        ZoneOffset.UTC).toInstant());
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Failed to parse [" + date + "]: " + e, e);
            }
        } else {
            throw new IllegalArgumentException("Failed to parse [" + date + "]; does not match pattern yyyy-MM-ddThh:mm:ss[.SSS]Z");
        }
    }
    

    这还不是 100% 等效的(即它不支持“+00:00”样式的时区偏移,而是假定 UTC),但是在解析字符串时它的宽松程度非常接近。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-26
      • 2016-01-24
      • 1970-01-01
      相关资源
      最近更新 更多