编程语言
首页 > 编程语言> > 带有详细时区的Java DateTimeFormatterBuilder

带有详细时区的Java DateTimeFormatterBuilder

作者:互联网

假设我有一个日期,例如:

Nov 30, 2013 19:00:00.001930000 Eastern Standard Time

我正在尝试使用DateTimeFormatterBuilder解析输入,但是我无法弄清楚要为通用类型ZoneId设置的内容如下所示.

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();

解决方法:

伪区

正如class documentation简要解释的那样,主流媒体中常见的3-4个字母表示时区并不是官方时区.这些伪区域不是标准化的,甚至不是唯一的!许多代码在全球范围内重复使用.例如,IST是印度标准时间和爱尔兰标准时间. CST既是中国标准时间也是Central Standard Time(北美).

切勿使用这些伪区域.以continent / region格式指定proper time zone name,例如America/Montreal,Africa/Casablanca或Pacific / Auckland.

解决歧义

如果您的输入确实具有这些伪区域,则采用缩写格式,您必须处理歧义.默认情况下,格式化程序构建器将尝试通过考虑格式化程序的区域设置来解决歧义.对于CST,如果Locale是Locale.CHINA,那么CST可能意味着中国标准时间而不是中央标准时间.

不幸的是,这是一种粗暴的做法区域设置和时区的问题是正交的.您可以让一个讲中文的用户处理芝加哥的交货数据,在这种情况下,Locale可能是中国,但数据中的CST表示Central Standard Time.因此,在这种情况下,您可以指定一个或多个时区,例如America/ChicagoAmerica/Winnipeg在尝试解析CST以覆盖考虑Locale的默认值时由格式化程序考虑.

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 );

input: Nov 30, 2013 19:00:00.001930000 CST

zdt.toString(): 2013-11-30T19:00:00.001930-06:00[America/Chicago]

让我们通过SetId对象来覆盖该行为,暗示CST意味着中国标准时间.这里我们传递一组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 );

input: Nov 30, 2013 19:00:00.001930000 CST

zdt.toString(): 2013-11-30T19:00:00.001930+08:00[Asia/Shanghai]

现在,在您的情况下,您具有伪区域的全名而不是缩写.所以可能没有歧义.所以你可能会逃脱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 );

input: Nov 30, 2013 19:00:00.001930000 Eastern Standard Time

zdt.toString(): 2013-11-30T19:00:00.001930-05:00[America/New_York]

然而,在这里传递一组ZoneId对象也很有用. Set用于将时区分配给实例化的ZonedDateTime对象.请注意上面的输出中默认分配了America / New_York.但是还有许多其他时区也被伪区“东部标准时间”所暗示,例如巴哈马,美国/拿骚和墨西哥的坎昆,等等.

然而,选择应用集合中的哪个元素对我来说是一个谜.我尝试使用SortedSet思考可以选择在Set的自然顺序中找到的第一个.唉,ZoneId没有实现Comparable接口,因此无法使用诸如TreeSet之类的SortedSet.

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 );

input: Nov 30, 2013 19:00:00.001930000 Eastern Standard Time

zdt.toString(): 2013-11-30T19:00:00.001930-06:00[America/Cancun]

标签:java,timezone,java-8,java-time,datetime-parsing
来源: https://codeday.me/bug/20190527/1163114.html