假设我有一个日期,例如:
2013年11月30日19:00:00.001930000东部标准时间
我尝试使用DateTimeFormatterBuilder
解析输入,但我无法弄清楚要为通用类型ZoneId
的Set
放置什么null
{1}}下面。
String basePattern = "MMM dd, yyyy HH:mm:ss";
new DateTimeFormatterBuilder()
.appendPattern(basePattern)
.appendFraction(ChronoField.NANO_OF_SECOND,0,9, true)
.appendZoneText(TextStyle.FULL, null)
.toFormatter();
答案 0 :(得分:6)
正如class documentation简要解释的那样,主流媒体中常见的3-4个字母表示时区并不是官方时区。这些伪区域不是标准化的,甚至不是唯一的!许多代码在全球范围内重复使用。例如,IST
是印度标准时间和爱尔兰标准时间。 CST
既是中国标准时间又是Central Standard Time(北美)。
切勿使用这些伪区域。以continent/region
格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。
如果您的输入确实有这些伪区域,则缩写格式,您必须处理歧义。默认情况下,格式化程序构建器将尝试通过考虑格式化程序的Locale
来解决歧义。对于CST
如果Locale
为Locale.CHINA
,则CST
可能意味着中国标准时间而非中央标准时间。
不幸的是,这是一种粗暴的做法。 Locale
和时区的问题是正交的。您可以让一个说汉语的用户处理芝加哥的交付数据,在这种情况下,Locale
可能是中国,但数据中的CST
表示Central Standard Time。因此,在这种情况下,您可以指定格式化程序在尝试解析CST
以覆盖考虑{Locale
的默认值时要考虑的一个或多个时区,例如America/Chicago
和America/Winnipeg
。 1}}。
Set< ZoneID > zones = new TreeSet<>() ;
zones.add( ZoneId.of( "America/Chicago" ) ;
zones.add( ZoneId.of( "America/Manitoba" ) ;
…
.appendZoneText( TextStyle.SHORT , zones )
…
以下是一个完整的示例,将我的macOS MacBook上的CST
解析为中央标准时间设置为默认时区America/Los_Angeles
和默认语言环境Locale.US
。请注意,我们只将一个参数传递给appendZoneText
(没有传递Set
。
String input = "Nov 30, 2013 19:00:00.001930000 CST";
String basePattern = "MMM dd, yyyy HH:mm:ss";
DateTimeFormatter f = new DateTimeFormatterBuilder( )
.appendPattern( basePattern )
.appendFraction( ChronoField.NANO_OF_SECOND , 0 , 9 , true )
.appendPattern( " " )
.appendZoneText( TextStyle.SHORT )
.toFormatter( );
ZonedDateTime zdt = ZonedDateTime.parse( input , f );
System.out.println( "input: " + input );
System.out.println( "zdt.toString(): " + zdt );
输入日期:2013年11月30日19:00:00.001930000 CST
zdt.toString():2013-11-30T19:00:00.001930-06:00 [美国/芝加哥]
让我们通过Set
个ZoneId
个对象来覆盖该行为,暗示CST
表示China Standard Time
。在这里,我们做传递Set
个ZoneId
个对象。我们使用相同的输入来获得非常不同的输出。
Set < ZoneId > zones = new HashSet <>( );
zones.add( ZoneId.of( "Asia/Shanghai" ) ) ;
String input = "Nov 30, 2013 19:00:00.001930000 CST";
String basePattern = "MMM dd, yyyy HH:mm:ss";
DateTimeFormatter f = new DateTimeFormatterBuilder( )
.appendPattern( basePattern )
.appendFraction( ChronoField.NANO_OF_SECOND , 0 , 9 , true )
.appendPattern( " " )
.appendZoneText( TextStyle.SHORT , zones )
.toFormatter( );
ZonedDateTime zdt = ZonedDateTime.parse( input , f );
System.out.println( "input: " + input );
System.out.println( "zdt.toString(): " + zdt );
输入日期:2013年11月30日19:00:00.001930000 CST
zdt.toString():2013-11-30T19:00:00.001930 + 08:00 [亚洲/上海]
现在,在您的情况下,您拥有伪区域的全名而不是缩写。所以可能没有歧义。所以你可能会逃脱overloaded method not taking a second argument。
.appendZoneText( TextStyle.FULL )
示例:
String input = "Nov 30, 2013 19:00:00.001930000 Eastern Standard Time";
String basePattern = "MMM dd, yyyy HH:mm:ss";
DateTimeFormatter f = new DateTimeFormatterBuilder( )
.appendPattern( basePattern )
.appendFraction( ChronoField.NANO_OF_SECOND , 0 , 9 , true )
.appendPattern( " " )
.appendZoneText( TextStyle.FULL )
.toFormatter( );
ZonedDateTime zdt = ZonedDateTime.parse( input , f );
System.out.println( "input: " + input );
System.out.println( "zdt.toString(): " + zdt );
输入日期:2013年11月30日19:00:00.001930000东部标准时间
zdt.toString():2013-11-30T19:00:00.001930-05:00 [America / New_York]
然而, 对于传递Set
个ZoneId
个对象也很有用。 Set
用于将时区分配给实例化的ZonedDateTime
对象。请注意,在上面的输出中默认分配了America/New_York
。但是,伪区“东部标准时间”也暗示了许多其他时区,例如巴哈马,America/Nassau
和墨西哥的坎昆,等等。
然而,选择应用集合中的哪个元素对我来说是一个谜。我尝试使用SortedSet
思考可以选择在Set的自然顺序中找到的第一个。唉,ZoneId
没有实现Comparable
界面,因此无法使用SortedSet
,例如TreeSet
。
Set < ZoneId > zones = new HashSet <>( );
zones.add( ZoneId.of( "America/Detroit" ) );
zones.add( ZoneId.of( "America/New_York" ) );
zones.add( ZoneId.of( "America/Nassau" ) );
zones.add( ZoneId.of( "America/Cancun" ) );
String input = "Nov 30, 2013 19:00:00.001930000 Eastern Standard Time";
String basePattern = "MMM dd, yyyy HH:mm:ss";
DateTimeFormatter f = new DateTimeFormatterBuilder( )
.appendPattern( basePattern )
.appendFraction( ChronoField.NANO_OF_SECOND , 0 , 9 , true )
.appendPattern( " " )
.appendZoneText( TextStyle.FULL , zones )
.toFormatter( );
ZonedDateTime zdt = ZonedDateTime.parse( input , f );
System.out.println( "input: " + input );
System.out.println( "zdt.toString(): " + zdt );
输入日期:2013年11月30日19:00:00.001930000东部标准时间
zdt.toString():2013-11-30T19:00:00.001930-06:00 [America / Cancun]