Java DateTimeFormatter不';t解析自定义日期格式
我对javaJava DateTimeFormatter不';t解析自定义日期格式,java,datetime,java-time,datetime-parsing,Java,Datetime,Java Time,Datetime Parsing,我对javaDataTimeFormmater有问题。 我觉得我错过了一些东西,但却不知道到底是什么 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.
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
对象。如果要创建特定类型,最好使用类各自的parse
方法:
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
的结果。如果您不想这样做,我建议使用两个不同的DateTimeFormatter
(一个用于解析,另一个用于格式化)
或者(更丑陋的方法),使用两种不同的格式化程序:
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
是区域名称的一部分,不应被视为文字。但最终,您会得到一个具有正确偏移量的ZoneDateTime
,因此我不确定这种方法有多错误
时区缩写 请注意,您应该(尽可能)避免使用三个字母的缩写(如
CDT
或PST
),因为它们是CDT
既可以是中央夏时制
(UTC-05:00)、古巴夏时制
(UTC-04:00),也可以是中国夏时制
(UTC+09:00)
如果可能,更愿意使用(始终采用大陆/城市
格式,如美国/圣保罗
或欧洲/柏林
)。根据该列表,有40多个时区使用(或在过去某个地方使用过)CDT缩写
CDT
适用于这种情况,因为有些缩写配置了默认值,可能是由于追溯兼容性的原因,但您不应该在所有情况下都依赖它们
为了确保时区缩写始终有效(以防无法避免使用它们),您可以创建一个使用一组首选区域的格式化程序。在本例中,我使用的是America/Chicago
(因此,CST
或CDT
将被解析为芝加哥的时区):
Set preferedZones=new HashSet();
首选区域。添加(“美国/芝加哥”)区域ID;
DateTimeFormatter formatter=新的DateTimeFormatterBuilder()
//追加模式的第一部分(时区之前)
.appendPattern(“yyyy-MM-dd'T'HH:MM:ss[.S]'T'”)
//附加区域名称,使用首选区域(可选)
.optionalStart().appendZoneText(TextStyle.SHORT,PreferredZones)。optionalEnd()
//偏移量(可选)
.appendPattern(“[xxx]”)
//创建格式化程序
.toFormatter();
此格式化程序的工作方式与上述相同,适用于您的两种输入(带和不带GMT
),并在输入中包含CDT
时使用America/Chicago
作为默认时区。根据您的用例,您可以在集合中添加任意数量的区域
只是提醒一下,这个格式化程序在输出方面有相同的问题(它打印所有可选部分),如上所述。tl;博士
细节
您的格式很奇怪,比如对标准格式的奇怪误解或损坏
如果您的所有输入在最后一部分中都有“TGMT”,请将其去掉以符合ISO 8601
在解析/生成字符串时,java.time类默认使用标准格式,因此无需定义格式模式
OffsetDateTime odt = OffsetDateTime.parse( "2017-07-05T12:28:36.4TGMT+03:00".replace( "TGMT" , "" ) ) ;
不要使用3-4个字母的伪时区,如
CMT
、EST
和IST
。这些时区不是实际时区,也不是标准时区,甚至不是唯一的(!)。实时时区名称的格式为大陆/地区
,例如美国/蒙特利尔
或太平洋/奥克兰
,也可以使用ooooo
作为时区,但解析在Java 8中有缺陷,在Java 9中得到纠正:@CarlosHeuberger确实!我尝试过ooo
,但它只适用于格式化。它将d的使用是正确的,但代码是错误的fist+second lineint pos=position;int end=pos+text.length();
end大于字符串长度最终导致StringIndexOutOfBoundsException(位置是开始查找时区的位置),这是一种奇怪的格式。请尽可能使用标准格式。
OffsetDateTime.parse(
"2017-07-05T12:28:36.4TGMT+03:00".replace( "TGMT" , "" )
)
OffsetDateTime odt = OffsetDateTime.parse( "2017-07-05T12:28:36.4TGMT+03:00".replace( "TGMT" , "" ) ) ;