2015-05-05 45 views
5

我想从Joda时间库迁移到Java时间(Java 8)。 我无法在java.time从Joda时间库迁移到Java时间(Java 8)

乔达ISO格式找到等价的ISODateTimeFormat.dateOptionalTimeParser()具有良好的解析器:

ISODateTimeFormat.dateTimeParser():通用 - 选择基于分析的字符串解析器。 类似的: ISODateTimeFormat.dateOptionalTimeParser()

我发现很难将乔达时间更改为java.time。 有人能指导我吗?

例如:

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

当我使用约达时间解析这个字符串,然后

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

可以不作为问题处理两种。这在java时代相当于什么?

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

+0

我可以问你为什么要迁移吗? Joda-Time中存在一个特殊问题,您希望通过迁移来解决问题吗?正如您在我的回答中所看到的,迁移可能是实际操作中的挑战。如果您对Joda-Time没有任何特殊问题,并且只想迁移,因为Java-8更“现代”,那么这可能不值得所有的努力。 –

+0

是的,你是对的。我们想要使用Java 8的所有现代功能,这就是为什么我们要迁移到Java 8的原因。 – Shishir

+3

@MenoHochschild从Java SE 8开始,用户被要求迁移到java.time(JSR-310) 。_同样来自现场_注意Joda-Time被认为是一个大部分“完成”的项目。计划没有重大改进。如果使用Java SE 8,请迁移到java.time(JSR-310)._这些建议都出现在主页上。如果使用Java8(或更高版本),迁移是明智的。 –

回答

8

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

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. 

侧注释:约达-时间方法withOffsetParsed()是更接近于Java-8行为。

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

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”不是公认的时区标识(它在美国是一个本地时区名称缩写)。

更新 - 最终的解决方案

后额外的测试验证码似乎在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 
0

我与挣扎尝试将ISODateTimeFormat.dateTimeParser()。parseDateTime(“...”)转换为基于Java 8 java.time设施的等效项。 最后我失败了使用创建DateTimeFormatter重现乔达时间的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),但它在解析字符串时的宽松程度非常接近。