从Joda Time库迁移到Java Time(Java 8)



我试图从Joda Time库迁移到Java Time(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时间解析此字符串时

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

可以没有问题的情况下处理两者。在Java时间中,哪个等效?

使用Java 8,ZonedDateTime与ISO_ZONED_DATE_TIME无法处理。

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

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

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

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

Joda Time

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-version 8U40同时纠正了某些问题(至少withZone()的行为可能已纠正 - 请参见JDK-ISSEUS 8033662,但有关8U31的Backport Fix似乎缺失了?!)。您还应该注意,在我的测试中,您标记为" 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

我在尝试转换Isodatementimeformat.dateTimeParser()的类似问题方面挣扎。parseDateTime(" ...")到基于Java 8 Java.Time设施的等价物。最后,我没有使用DateTimeFormatter重现Joda Time的IsodateTimeFormat的行为,而是选择了基于Regexp的方法:

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),但是在解析字符串时的宽大宽度非常接近。

相关内容

最新更新