0
LocalDateTime formatOrderEndDateTime;
    try {
        DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
        formatOrderEndDateTime = LocalDateTime.parse("2019-12-03T10:00:01+01:00", formatter);
        System.out.println(formatOrderEndDateTime);
    } catch (Exception e) {
        throw new IllegalArgumentException();
    }

上面的代码按预期工作,但如果时区不可用,它就不能工作。

给定输入日期:2019-12-03T10:00:00-06:00 或 2019-12-03T10:00:00

预计开工日期:2019-12-03T10:00:00

我的代码应该适用于有时区和没有时区输入日期

4

3 回答 3

4

片刻

给定输入日期:2019-12-03T10:00:00-06:00 或 2019-12-03T10:00:00

这是两种截然不同的动物。

第一个代表一个时刻,时间线上的一个特定点。第二个没有。第二个是东京上午 10 点,图卢兹上午 10 点,托莱多上午 10 点——三个截然不同的时刻相隔几个小时。

第一个应该被解析为OffsetDateTime. 第二个应该被解析为LocalDateTime.

类型错误

对于诸如 的输入2019-12-03T10:00:00-06:00,解析为OffsetDateTime. 您使用了LocalDateTimewhich 无法处理该字符串末尾的 UTC 偏移量。

无需指定格式模式。您的输入符合默认使用的 ISO 8601 标准。

OffsetDateTime odt = OffsetDateTime.parse( "2019-12-03T10:00:00-06:00" )

错误的格式化程序

要生成省略偏移量的 ISO 8601 格式的文本,请使用DateTimeFormatter.ISO_LOCAL_DATE_TIME.

String output = odt.format( DateTimeFormatter.ISO_LOCAL_DATE_TIME ) ;

偏移量与时区

如果时区不工作

您的输入没有时区。它们与 UTC 有一个偏移量。偏移量只是几个小时-分钟-秒。

时区更多。时区是特定地区的人们使用的偏移量的过去、现在和未来变化的历史。时区的名称Continent/Region格式为Europe/Paris.

于 2020-01-21T09:19:46.413 回答
2

我认为您将不得不使用一对不同的格式化程序,如下面的代码所示。从以下文档DateTimeFormatter.ISO_DATE_TIME

类似 ISO 的日期时间格式化程序,它使用偏移量和区域(如果可用)格式化或解析日期时间,例如 '2011-12-03T10:15:30'、'2011-12-03T10:15:30+01: 00'或'2011-12-03T10:15:30+01:00[欧洲/巴黎]'。

然后,您将不得不使用不同的格式化程序将其转换为字符串,而不是使用LocalDateTime.toString().

LocalDateTime formatOrderEndDateTime;
try {
     DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
     formatOrderEndDateTime = LocalDateTime.parse(line.trim(), formatter);

     DateTimeFormatter f2 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
     System.out.println(formatOrderEndDateTime.format( f2 ));
} catch (Exception e) {
     System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}

因此,这允许以多种支持的格式提供输入,然后以我们想要的格式创建字符串。

于 2020-01-21T09:26:12.553 回答
1

你不应该想要 LocalDateTime

例如:两个字符串2019-12-03T10:00:01+09:002019-12-03T10:00:01-08:00表示相隔 17 小时的时间点,但将被解析为相等LocalDateTime的对象。我不认为你想要那个。

LocalDateTime可能不适合订单结束时间。它不知道任何时区或与 UTC 的偏移量,因此每个人和看到它的每一段代码都可以自由地解释为他们碰巧想到的时区,而不是预期的时区。这留下了意外结果的巨大风险。对于 20 种用途中的至少 19 种,使用 a Instant、 anOffsetDateTime或 a会更好ZonedDateTime

解析有无偏移:定义一个默认时区

您需要接受没有偏移量的字符串。然后,您还需要知道为此类字符串假定哪个时区——默认时区。然后你也可以解析它们。

例如:

    ZoneId defaultTimeZone = ZoneId.of("America/Guatemala");
    ZoneId resultTimeZone = ZoneId.of("Europe/Rome");
    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
            .appendPattern("[XXX]")
            .toFormatter();


    for (String input : new String[] {
            "2019-12-03T10:00:01+01:00",
            "2019-12-03T10:00:00-06:00",
            "2019-12-03T10:00:00"
    }) {
        TemporalAccessor parsed = formatter.parseBest(input,
                OffsetDateTime::from, LocalDateTime::from);
        ZonedDateTime dateTime;
        if (parsed instanceof OffsetDateTime) {
            dateTime = ((OffsetDateTime) parsed).atZoneSameInstant(resultTimeZone);
        } else {
            dateTime = ((LocalDateTime) parsed).atZone(defaultTimeZone)
                    .withZoneSameInstant(resultTimeZone);
        }
        System.out.format("%-25s is parsed into %s%n", input, dateTime);
    }

此片段的输出是:

2019-12-03T10:00:01+01:00 is parsed into 2019-12-03T10:00:01+01:00[Europe/Rome]
2019-12-03T10:00:00-06:00 is parsed into 2019-12-03T17:00+01:00[Europe/Rome]
2019-12-03T10:00:00       is parsed into 2019-12-03T17:00+01:00[Europe/Rome]

[XXX]在格式模式字符串中使用来表示可选的偏移量。如果可以的话,调用parseBest()解析为一个OffsetDateTime(偏移量存在),否则解析为LocalDateTime我随后转换的一个。最后,我将所有解析的日期和时间转换为一个时区,以便用户可以看到一致的结果。

于 2020-01-21T17:50:56.213 回答