Skip to content

Commit 5b18a57

Browse files
committed
Improve time-zone parsing
1 parent e133d9d commit 5b18a57

File tree

2 files changed

+199
-137
lines changed

2 files changed

+199
-137
lines changed

src/main/java/org/threeten/bp/format/DateTimeFormatterBuilder.java

+62-10
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import java.util.ResourceBundle;
6363
import java.util.Set;
6464
import java.util.TimeZone;
65+
import java.util.TreeMap;
6566

6667
import org.threeten.bp.DateTimeException;
6768
import 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

Comments
 (0)