6262import java .util .ResourceBundle ;
6363import java .util .Set ;
6464import java .util .TimeZone ;
65+ import java .util .TreeMap ;
6566
6667import org .threeten .bp .DateTimeException ;
6768import org .threeten .bp .Instant ;
@@ -3342,7 +3343,17 @@ public int parse(DateTimeParseContext context, CharSequence text, int position)
33423343 * Prints or parses a zone ID.
33433344 */
33443345 static final class ZoneTextPrinterParser implements DateTimePrinterParser {
3345- // TODO: remove this as it is incomplete
3346+ /** The text style to output. */
3347+ private static final Comparator <String > LENGTH_COMPARATOR = new Comparator <String >() {
3348+ @ Override
3349+ public int compare (String str1 , String str2 ) {
3350+ int cmp = str2 .length () - str1 .length ();
3351+ if (cmp == 0 ) {
3352+ cmp = str1 .compareTo (str2 );
3353+ }
3354+ return cmp ;
3355+ }
3356+ };
33463357 /** The text style to output. */
33473358 private final TextStyle textStyle ;
33483359
@@ -3378,7 +3389,24 @@ public boolean print(DateTimePrintContext context, StringBuilder buf) {
33783389
33793390 @ Override
33803391 public int parse (DateTimeParseContext context , CharSequence text , int position ) {
3381- throw new UnsupportedOperationException ();
3392+ // this is a poor implementation that handles some but not all of the spec
3393+ // JDK8 has a lot of extra information here
3394+ Map <String , String > ids = new TreeMap <>(LENGTH_COMPARATOR );
3395+ for (String id : ZoneId .getAvailableZoneIds ()) {
3396+ ids .put (id , id );
3397+ TimeZone tz = TimeZone .getTimeZone (id );
3398+ int tzstyle = (textStyle .asNormal () == TextStyle .FULL ? TimeZone .LONG : TimeZone .SHORT );
3399+ ids .put (tz .getDisplayName (false , tzstyle , context .getLocale ()), id );
3400+ ids .put (tz .getDisplayName (true , tzstyle , context .getLocale ()), id );
3401+ }
3402+ for (Entry <String , String > entry : ids .entrySet ()) {
3403+ String name = entry .getKey ();
3404+ if (context .subSequenceEquals (text , position , name , 0 , name .length ())) {
3405+ context .setParsed (ZoneId .of (entry .getValue ()));
3406+ return position + name .length ();
3407+ }
3408+ }
3409+ return ~position ;
33823410 }
33833411
33843412 @ Override
@@ -3429,7 +3457,6 @@ public boolean print(DateTimePrintContext context, StringBuilder buf) {
34293457 */
34303458 @ Override
34313459 public int parse (DateTimeParseContext context , CharSequence text , int position ) {
3432- // TODO case insensitive?
34333460 int length = text .length ();
34343461 if (position > length ) {
34353462 throw new IndexOutOfBoundsException ();
@@ -3489,20 +3516,36 @@ public int parse(DateTimeParseContext context, CharSequence text, int position)
34893516 break ;
34903517 }
34913518 parsedZoneId = text .subSequence (position , position + nodeLength ).toString ();
3492- tree = tree .get (parsedZoneId );
3519+ tree = tree .get (parsedZoneId , context . isCaseSensitive () );
34933520 }
3494-
3495- if (parsedZoneId == null || regionIds . contains ( parsedZoneId ) == false ) {
3521+ ZoneId zone = convertToZone ( regionIds , parsedZoneId , context . isCaseSensitive ());
3522+ if (zone == null ) {
34963523 if (context .charEquals (nextChar , 'Z' )) {
34973524 context .setParsed (ZoneOffset .UTC );
34983525 return position + 1 ;
34993526 }
35003527 return ~position ;
35013528 }
3502- context .setParsed (ZoneId . of ( parsedZoneId ) );
3529+ context .setParsed (zone );
35033530 return position + parsedZoneId .length ();
35043531 }
35053532
3533+ private ZoneId convertToZone (Set <String > regionIds , String parsedZoneId , boolean caseSensitive ) {
3534+ if (parsedZoneId == null ) {
3535+ return null ;
3536+ }
3537+ if (caseSensitive ) {
3538+ return (regionIds .contains (parsedZoneId ) ? ZoneId .of (parsedZoneId ) : null );
3539+ } else {
3540+ for (String regionId : regionIds ) {
3541+ if (regionId .equalsIgnoreCase (parsedZoneId )) {
3542+ return ZoneId .of (regionId );
3543+ }
3544+ }
3545+ return null ;
3546+ }
3547+ }
3548+
35063549 private int parsePrefixedOffset (DateTimeParseContext context , CharSequence text , int prefixPos , int position ) {
35073550 String prefix = text .subSequence (prefixPos , position ).toString ().toUpperCase ();
35083551 DateTimeParseContext newContext = context .copy ();
@@ -3553,6 +3596,10 @@ private static final class SubstringTree {
35533596 * Map of a substring to a set of substrings that contain the key.
35543597 */
35553598 private final Map <CharSequence , SubstringTree > substringMap = new HashMap <>();
3599+ /**
3600+ * Map of a substring to a set of substrings that contain the key.
3601+ */
3602+ private final Map <String , SubstringTree > substringMapCI = new HashMap <>();
35563603
35573604 /**
35583605 * Constructor.
@@ -3563,9 +3610,12 @@ private SubstringTree(int length) {
35633610 this .length = length ;
35643611 }
35653612
3566- private SubstringTree get (CharSequence substring2 ) {
3567- return substringMap .get (substring2 );
3568-
3613+ private SubstringTree get (CharSequence substring2 , boolean caseSensitive ) {
3614+ if (caseSensitive ) {
3615+ return substringMap .get (substring2 );
3616+ } else {
3617+ return substringMapCI .get (substring2 .toString ().toLowerCase (Locale .ENGLISH ));
3618+ }
35693619 }
35703620
35713621 /**
@@ -3577,12 +3627,14 @@ private void add(String newSubstring) {
35773627 int idLen = newSubstring .length ();
35783628 if (idLen == length ) {
35793629 substringMap .put (newSubstring , null );
3630+ substringMapCI .put (newSubstring .toLowerCase (Locale .ENGLISH ), null );
35803631 } else if (idLen > length ) {
35813632 String substring = newSubstring .substring (0 , length );
35823633 SubstringTree parserTree = substringMap .get (substring );
35833634 if (parserTree == null ) {
35843635 parserTree = new SubstringTree (idLen );
35853636 substringMap .put (substring , parserTree );
3637+ substringMapCI .put (substring .toLowerCase (Locale .ENGLISH ), parserTree );
35863638 }
35873639 parserTree .add (newSubstring );
35883640 }
0 commit comments