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