编程语言
首页 > 编程语言> > java – DateTimeFormatter不解析自定义日期格式

java – DateTimeFormatter不解析自定义日期格式

作者:互联网

我有java DataTimeFormmater的问题.
我觉得我错过了一些但却无法弄清楚到底是什么.

String format = "yyyy-MM-dd'T'HH:mm:ss[.S]'T'zxxx";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);

String date = "2017-07-05T12:28:36.4TGMT+03:00";

System.out.println(formatter.format(ZonedDateTime.now()));
System.out.println(formatter.parse(date));

上面的代码生成当前ZonedDateTime的字符串,并尝试使用相同的日期格式化程序解析日期时间字符串.
结果它成功生成2017-07-05T06:07:51.0TCDT-05:00但无法解析2017-07-05T12:28:36.4TGMT 03:00

我的目标是解析2017-07-05T12:28:36.4TGMT 03:00并提出适当的DateTimeFormatter.

解决方法:

您必须将格式更改为:

String format = "yyyy-MM-dd'T'HH:mm:ss[.S]'T'[zzz][xxx]";

[zzz]和[xxx]都在可选部分中,因为zzz可以解析整个GMT 03:00部分或仅解析区域短名称(例如CDT),xxx仅解析偏移部分(例如-05:00) – 如果找到GMT 03:00则不需要它.

只需提醒formatter.parse(date)返回TemporalAccessor对象.如果要创建特定类型,最好使用类的相应解析方法:

System.out.println(ZonedDateTime.parse(date, formatter)); // 2017-07-05T12:28:36.400+03:00[GMT+03:00]

PS:这个格式化程序的唯一问题是,在格式化时,它会打印所有可选部分.所以,如果你做这样的事情:

String date = "2017-07-05T12:28:36.4TGMT+03:00";
ZonedDateTime z  = ZonedDateTime.parse(date, formatter);
System.out.println(formatter.format(z));

输出将是:

2017-07-05T12:28:36.4TGMT+03:00+03:00

这是因为GMT 03:00是zzz的结果,第二个03:00是xxx的结果.如果您不想这样,我建议使用2个不同的DateTimeFormatter(一个用于解析,另一个用于格式化).

或者(一种“丑陋”的方法),使用2种不同的格式化程序:

DateTimeFormatter noGMT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.S]'T'zzzxxx");
DateTimeFormatter gmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.S]'TGMT'xxx");

然后,您尝试使用第一个进行解析 – 如果您遇到异常,请尝试使用第二个(或者检查您的输入是否包含GMT以了解要使用的GMT).

我个人不喜欢这个,因为GMT是区域名称的一部分,不应该被视为文字.但最后,你得到一个带有正确偏移量的ZonedDateTime,所以我不确定这种方法有多么错误.

时区缩写

请注意,您应避免(尽可能)使用3个字母的缩写(如CDT或PST),因为它们是ambiguous and not standard. CDT可以是中部夏令时(UTC-05:00),古巴夏令时(UTC-04) :00)甚至是中国夏令时(UTC 09:00).

如果可能,请更喜欢使用IANA timezones names(始终采用Continent / City格式,如America / Sao_Paulo或Europe / Berlin).根据该列表,有超过40个时区使用(或过去曾在某处使用过)CDT缩写.

CDT适用于这种情况,因为某些缩写配置了默认值,可能是由于复古兼容性原因,但您不应该依赖它们来处理所有情况.

要确保您的时区缩写始终有效(如果您无法避免使用它们),您可以创建一个使用一组首选区域的格式化程序.在这种情况下,我正在使用America / Chicago(因此,CST或CDT将被解析为芝加哥的时区):

Set<ZoneId> preferedZones = new HashSet<>();
preferedZones.add(ZoneId.of("America/Chicago"));
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    // append first part of pattern (before timezone)
    .appendPattern("yyyy-MM-dd'T'HH:mm:ss[.S]'T'")
    // append zone name, use prefered zones (optional)
    .optionalStart().appendZoneText(TextStyle.SHORT, preferedZones).optionalEnd()
    // offset (optional)
    .appendPattern("[xxx]")
    // create formatter
    .toFormatter();

对于您的输入(使用和不使用GMT),此格式化程序的工作方式与上述相同,并且当CDT位于输入中时,使用America / Chicago作为默认时区.根据您的使用情况,您可以在集合中添加所需的区域.

只是提醒这个格式化程序有关于输出的相同问题(它打印所有可选部分),如上所述.

标签:datetime-parsing,java,datetime,java-time
来源: https://codeday.me/bug/20190828/1751529.html