Pseudo zones
As the class documentation explains briefly, the 3-4 letters commonly seen in mainstream media to indicate a time zone are not actually official time zones. These pseudo-zones are not standardized, and are not even unique! Many codes are re-used around the globe. For example, IST
is both India Standard Time and Irish Standard Time. And CST
is both China Standard Time and Central Standard Time (in North America).
Never use these pseudo-zones. Specify a proper time zone name in the format of continent/region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
.
Resolving ambiguity
If your input does have these pseudo zones, in the abbreviated format, you have to deal with the ambiguity. By default, the formatter builder will attempt to resolve the ambiguity by considering the Locale
of formatter. In the case of CST
if the Locale
is Locale.CHINA
, then perhaps the CST
means China Standard Time rather than Central Standard Time.
Unfortunately this is a crude approach. The issues of Locale
and time zone are orthogonal. You could have an Chinese-speaking user handling data for deliveries in Chicago in which case the Locale
may be China but the CST
found in the data means Central Standard Time. So in such cases, you can specify one or more time zones such as America/Chicago
and America/Winnipeg
to be considered by the formatter when trying to parse CST
to override the default of considering the Locale
.
Set< ZoneID > zones = new TreeSet<>() ;
zones.add( ZoneId.of( "America/Chicago" ) ;
zones.add( ZoneId.of( "America/Manitoba" ) ;
…
.appendZoneText( TextStyle.SHORT , zones )
…
Here is a full example, parsing CST
as Central Standard Time on my macOS MacBook set to default time zone of America/Los_Angeles
and default locale of Locale.US
. Notice that we pass only a single argument to appendZoneText
(no Set
passed).
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]
Let's pass the Set
of ZoneId
objects to override that behavior, hinting that CST
means China Standard Time
. Here we do pass a Set
of ZoneId
objects. We use the same input to get a very different output.
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]
Now, in your case, you have the full name of the pseudo-zone rather than the abbreviation. So there is likely no ambiguity. So you probably could get away with the overloaded method not taking a second argument.
.appendZoneText( TextStyle.FULL )
Example:
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]
Yet there is a usefulness to passing a Set
of ZoneId
objects here too. The Set
is used in assigning the time zone to the instantiated ZonedDateTime
object. Notice in output above that America/New_York
was assigned by default. But there are many other time zones that are also implied by the pseudo-zone “Eastern Standard Time”, such as the Bahamas, America/Nassau
, and Cancun in Mexico, and so on.
Which element in the set is chosen to be applied is a mystery to me however. I tried to use a SortedSet
thinking the first found in the natural order of the Set may be chosen. Alas, ZoneId
does not implement Comparable
interface so a SortedSet
such as TreeSet
cannot be used.
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]
toFormatter(Locale.US)
) because those zone names are locale-sensitive. In my JVM the default ispt_BR
(Brazilian Portuguese) and the parsing fails (it works only if the zone name isHorário de luz natural oriental
). The locale is also required due to month name (in pt_BR, they're all lowercase and it also fails for this case - I had to change the input tonov
). And in my JVM, the last example is resolved toAmerica/Nassau
. Maybe it just gets the first element returned by the set (which has no guaranteed order), who knows... – Balfour