Skip to content

Instantly share code, notes, and snippets.

@jodastephen
Created February 11, 2013 20:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jodastephen/4757256 to your computer and use it in GitHub Desktop.
Save jodastephen/4757256 to your computer and use it in GitHub Desktop.
APPLIED: Patch for ThreeTen/threeten#262
diff -r 05525f23180e src/share/classes/java/time/ZoneId.java
--- a/src/share/classes/java/time/ZoneId.java Fri Feb 08 09:11:51 2013 -0800
+++ b/src/share/classes/java/time/ZoneId.java Mon Feb 11 20:14:51 2013 +0000
@@ -93,6 +93,8 @@
* the offset from UTC/Greenwich apply
* </ul><p>
* Most fixed offsets are represented by {@link ZoneOffset}.
+ * Calling {@link #normalized()} on any {@code ZoneId} will ensure that a
+ * fixed offset ID will be represented as a {@code ZoneOffset}.
* <p>
* The actual rules, describing when and how the offset changes, are defined by {@link ZoneRules}.
* This class is simply an ID used to obtain the underlying rules.
@@ -103,28 +105,29 @@
* the ID, whereas serializing the rules sends the entire data set.
* Similarly, a comparison of two IDs only examines the ID, whereas
* a comparison of two rules examines the entire data set.
- * <p>
- * The code supports loading a {@code ZoneId} on a JVM which does not have available rules
- * for that ID. This allows the date-time object, such as {@link ZonedDateTime},
- * to still be queried.
*
* <h3>Time-zone IDs</h3>
* The ID is unique within the system.
- * The formats for offset and region IDs differ.
+ * There are three types of ID.
* <p>
- * An ID is parsed as an offset ID if it starts with 'UTC', 'GMT', 'UT' '+' or '-', or
- * is a single letter. For example, 'Z', '+02:00', '-05:00', 'UTC+05', 'GMT-6' and
- * 'UT+01:00' are all valid offset IDs.
- * Note that some IDs, such as 'D' or '+ABC' meet the criteria to be parsed as offset IDs,
- * but have an invalid offset.
+ * The simplest type of ID is that from {@code ZoneOffset}.
+ * This consists of 'Z' and IDs starting with '+' or '-'.
* <p>
- * All other IDs are considered to be region IDs.
+ * The next type of ID are offset-style IDs with some form of prefix,
+ * such as 'GMT+2' or 'UTC+01:00'.
+ * The recognised prefixes are 'UTC', 'GMT' and 'UT'.
+ * The offset is the suffix and will be normalized during creation.
+ * These IDs can be normalized to a {@code ZoneOffset} using {@code normalized()}.
* <p>
- * Region IDs are defined by configuration, which can be thought of as a {@code Map}
- * from region ID to {@code ZoneRules}, see {@link ZoneRulesProvider}.
+ * The third type of ID are region-based IDs. A region-based ID must be of
+ * two or more characters, and not start with 'UTC', 'GMT', 'UT' '+' or '-'.
+ * Region-based IDs are defined by configuration, see {@link ZoneRulesProvider}.
+ * The configuration focuses on providing the lookup from the ID to the
+ * underlying {@code ZoneRules}.
* <p>
- * Time-zones are defined by governments and change frequently. There are a number of
- * organizations, known here as groups, that monitor time-zone changes and collate them.
+ * Time-zone rules are defined by governments and change frequently.
+ * There are a number of organizations, known here as groups, that monitor
+ * time-zone changes and collate them.
* The default group is the IANA Time Zone Database (TZDB).
* Other organizations include IATA (the airline industry body) and Microsoft.
* <p>
@@ -139,6 +142,20 @@
* The recommended format for region IDs from groups other than TZDB is 'group~region'.
* Thus if IATA data were defined, Utrecht airport would be 'IATA~UTC'.
*
+ * <h3>Serialization</h3>
+ * This class can be serialized and stores the string zone ID in the external form.
+ * The {@code ZoneOffset} subclass uses a dedicated format that only stores the
+ * offset from UTC/Greenwich.
+ * <p>
+ * A {@code ZoneId} can be deserialized in a JVM where the ID is unknown.
+ * For example, if a server-side JVM has been updated with a new zone ID, but
+ * the client-side JVM has not been updated. In this case, the {@code ZoneId}
+ * object will exist, and can be queried using {@code getId}, {@code equals},
+ * {@code hashCode}, {@code toString}, {@code getDisplayName} and {@code normalized}.
+ * However, any call to {@code getRules} will fail with {@code ZoneRulesException}.
+ * This approach is designed to allow a {@link ZonedDateTime} to be loaded and
+ * queried, but not modified, on a JVM with incomplete time-zone information.
+ *
* <h3>Specification for implementors</h3>
* This abstract class has two implementations, both of which are immutable and thread-safe.
* One implementation models region-based IDs, the other is {@code ZoneOffset} modelling
@@ -310,31 +327,36 @@
* Obtains an instance of {@code ZoneId} from an ID ensuring that the
* ID is valid and available for use.
* <p>
- * This method parses the ID, applies any appropriate normalization, and validates it
- * against the known set of IDs for which rules are available.
+ * This method parses the ID producing a {@code ZoneId} or {@code ZoneOffset}.
+ * A {@code ZoneOffset} is returned if the ID is 'Z', or starts with '+' or '-'.
+ * The result will always be a valid ID for which {@link ZoneRules} can be obtained.
* <p>
- * An ID is parsed as though it is an offset ID if it starts with 'UTC', 'GMT', 'UT', '+'
- * or '-', or if it has less then two letters.
- * The offset of {@linkplain ZoneOffset#UTC zero} may be represented in multiple ways,
- * including 'Z', 'UTC', 'GMT', 'UT', 'UTC0', 'GMT0', 'UT0', '+00:00', '-00:00' and 'UTC+00:00'.
- * <p>
- * Six forms of ID are recognized:
- * <p><ul>
- * <li><code>Z</code> - an offset of zero, which is {@code ZoneOffset.UTC}
- * <li><code>{offset}</code> - a {@code ZoneOffset} ID, such as '+02:00'
- * <li><code>{utcPrefix}</code> - a {@code ZoneOffset} ID equal to 'Z'
- * <li><code>{utcPrefix}0</code> - a {@code ZoneOffset} ID equal to 'Z'
- * <li><code>{utcPrefix}{offset}</code> - a {@code ZoneOffset} ID equal to '{offset}'
- * <li><code>{regionID}</code> - full region ID, loaded from configuration
- * </ul><p>
- * The {offset} is a valid format for {@link ZoneOffset#of(String)}, excluding 'Z'.
- * The {utcPrefix} is 'UTC', 'GMT' or 'UT'.
- * Region IDs must match the regular expression <code>[A-Za-z][A-Za-z0-9~/._+-]+</code>.
- * <p>
- * The detailed format of the region ID depends on the group supplying the data.
- * The default set of data is supplied by the IANA Time Zone Database (TZDB)
- * This has region IDs of the form '{area}/{city}', such as 'Europe/Paris' or 'America/New_York'.
- * This is compatible with most IDs from {@link java.util.TimeZone}.
+ * Parsing matches the zone ID step by step as follows.
+ * <ul>
+ * <li>If the zone ID equals 'Z', the result is {@code ZoneOffset.UTC}.
+ * <li>If the zone ID consists of a single letter, the zone ID is invalid
+ * and {@code DateTimeException} is thrown.
+ * <li>If the zone ID starts with '+' or '-', the ID is parsed as a
+ * {@code ZoneOffset} using {@link ZoneOffset#of(String)}.
+ * <li>If the zone ID equals 'GMT', 'UTC' or 'UT' then the result is a {@code ZoneId}
+ * with the same ID and rules equivalent to {@code ZoneOffset.UTC}.
+ * <li>If the zone ID starts with 'UTC+', 'UTC-', 'GMT+', 'GMT-', 'UT+' or 'UT-'
+ * then the ID is a prefixed offset-based ID. The ID is split in two, with
+ * a two or three letter prefix and a suffix starting with the sign.
+ * The suffix is parsed as a {@link ZoneOffset#of(String) ZoneOffset}.
+ * The result will be a {@code ZoneId} with the specified UTC/GMT/UT prefix
+ * and the normalized offset ID as per {@link ZoneOffset#getId()}.
+ * The rules of the returned {@code ZoneId} will be equivalent to the
+ * parsed {@code ZoneOffset}.
+ * <li>All other IDs are parsed as region-based zone IDs. Region IDs must
+ * match the regular expression <code>[A-Za-z][A-Za-z0-9~/._+-]+</code>
+ * otherwise a {@code DateTimeException} is thrown. If the zone ID is not
+ * in the configured set of IDs, {@code ZoneRulesException} is thrown.
+ * The detailed format of the region ID depends on the group supplying the data.
+ * The default set of data is supplied by the IANA Time Zone Database (TZDB)
+ * This has region IDs of the form '{area}/{city}', such as 'Europe/Paris' or 'America/New_York'.
+ * This is compatible with most IDs from {@link java.util.TimeZone}.
+ * </ul>
*
* @param zoneId the time-zone ID, not null
* @return the zone ID, not null
@@ -342,15 +364,29 @@
* @throws ZoneRulesException if the zone ID is a region ID that cannot be found
*/
public static ZoneId of(String zoneId) {
+ return of(zoneId, true);
+ }
+
+ /**
+ * Parses the ID, taking a flag to indicate whether {@code ZoneRulesException}
+ * should be thrown or not, used in deserialization.
+ *
+ * @param zoneId the time-zone ID, not null
+ * @param checkAvailable whether to check if the zone ID is available
+ * @return the zone ID, not null
+ * @throws DateTimeException if the ID format is invalid
+ * @throws ZoneRulesException if checking availability and the ID cannot be found
+ */
+ static ZoneId of(String zoneId, boolean checkAvailable) {
Objects.requireNonNull(zoneId, "zoneId");
if (zoneId.length() <= 1 || zoneId.startsWith("+") || zoneId.startsWith("-")) {
return ZoneOffset.of(zoneId);
} else if (zoneId.startsWith("UTC") || zoneId.startsWith("GMT")) {
- return ofWithPrefix(zoneId, 3);
+ return ofWithPrefix(zoneId, 3, checkAvailable);
} else if (zoneId.startsWith("UT")) {
- return ofWithPrefix(zoneId, 2);
+ return ofWithPrefix(zoneId, 2, checkAvailable);
}
- return ZoneRegion.ofId(zoneId, true);
+ return ZoneRegion.ofId(zoneId, checkAvailable);
}
/**
@@ -359,22 +395,25 @@
* @param zoneId the time-zone ID, not null
* @param prefixLength the length of the prefix, 2 or 3
* @return the zone ID, not null
- * @return the zone ID, not null
* @throws DateTimeException if the zone ID has an invalid format
*/
- private static ZoneId ofWithPrefix(String zoneId, int prefixLength) {
- if (zoneId.length() == prefixLength ||
- (zoneId.length() == prefixLength + 1 && zoneId.charAt(prefixLength) == '0')) {
- return ZoneOffset.UTC;
+ private static ZoneId ofWithPrefix(String zoneId, int prefixLength, boolean checkAvailable) {
+ String prefix = zoneId.substring(0, prefixLength);
+ if (zoneId.length() == prefixLength) {
+ return ZoneRegion.ofPrefixedOffset(prefix, ZoneOffset.UTC);
}
- if (zoneId.charAt(prefixLength) == '+' || zoneId.charAt(prefixLength) == '-') {
- try {
- return ZoneOffset.of(zoneId.substring(prefixLength));
- } catch (DateTimeException ex) {
- throw new DateTimeException("Invalid ID for offset-based ZoneId: " + zoneId, ex);
+ if (zoneId.charAt(prefixLength) != '+' && zoneId.charAt(prefixLength) != '-') {
+ return ZoneRegion.ofId(zoneId, checkAvailable); // drop through to ZoneRulesProvider
+ }
+ try {
+ ZoneOffset offset = ZoneOffset.of(zoneId.substring(prefixLength));
+ if (offset == ZoneOffset.UTC) {
+ return ZoneRegion.ofPrefixedOffset(prefix, offset);
}
+ return ZoneRegion.ofPrefixedOffset(prefix + offset.toString(), offset);
+ } catch (DateTimeException ex) {
+ throw new DateTimeException("Invalid ID for offset-based ZoneId: " + zoneId, ex);
}
- throw new DateTimeException("Invalid ID for offset-based ZoneId: " + zoneId);
}
//-----------------------------------------------------------------------
@@ -488,6 +527,32 @@
//-----------------------------------------------------------------------
/**
+ * Normalizes the time-zone ID, returning a {@code ZoneOffset} where possible.
+ * <p>
+ * The returns a normalized {@code ZoneId} that can be used in place of this ID.
+ * The result will have {@code ZoneRules} equivalent to those returned by this object,
+ * however the ID returned by {@code getId()} may be different.
+ * <p>
+ * The normalization checks if the rules of this {@code ZoneId} have a fixed offset.
+ * If they do, then the {@code ZoneOffset} equal to that offset is returned.
+ * Otherwise {@code this} is returned.
+ *
+ * @return the time-zone unique ID, not null
+ */
+ public ZoneId normalized() {
+ try {
+ ZoneRules rules = getRules();
+ if (rules.isFixedOffset()) {
+ return rules.getOffset(Instant.EPOCH);
+ }
+ } catch (ZoneRulesException ex) {
+ // invalid ZoneRegion is not important to this method
+ }
+ return this;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
* Checks if this time-zone ID is equal to another time-zone ID.
* <p>
* The comparison is based on the ID.
@@ -536,6 +601,10 @@
* out.writeByte(7); // identifies this as a ZoneId (not ZoneOffset)
* out.writeUTF(zoneId);
* </pre>
+ * <p>
+ * When read back in, the {@code ZoneId} will be created as though using
+ * {@link #of(String)}, but without any exception in the case where the
+ * ID has a valid format, but is not in the known set of region-based IDs.
*
* @return the instance of {@code Ser}, not null
*/
diff -r 05525f23180e src/share/classes/java/time/ZoneRegion.java
--- a/src/share/classes/java/time/ZoneRegion.java Fri Feb 08 09:11:51 2013 -0800
+++ b/src/share/classes/java/time/ZoneRegion.java Mon Feb 11 20:14:51 2013 +0000
@@ -109,26 +109,6 @@
private final transient ZoneRules rules;
/**
- * Obtains an instance of {@code ZoneRegion} from an identifier without checking
- * if the time-zone has available rules.
- * <p>
- * This method parses the ID and applies any appropriate normalization.
- * It does not validate the ID against the known set of IDs for which rules are available.
- * <p>
- * This method is intended for advanced use cases.
- * For example, consider a system that always retrieves time-zone rules from a remote server.
- * Using this factory would allow a {@code ZoneRegion}, and thus a {@code ZonedDateTime},
- * to be created without loading the rules from the remote server.
- *
- * @param zoneId the time-zone ID, not null
- * @return the zone ID, not null
- * @throws DateTimeException if the ID format is invalid
- */
- private static ZoneRegion ofLenient(String zoneId) {
- return ofId(zoneId, false);
- }
-
- /**
* Obtains an instance of {@code ZoneId} from an identifier.
*
* @param zoneId the time-zone ID, not null
@@ -139,10 +119,7 @@
*/
static ZoneRegion ofId(String zoneId, boolean checkAvailable) {
Objects.requireNonNull(zoneId, "zoneId");
- if (zoneId.length() < 2 ||
- zoneId.startsWith("UT") || // includes UTC
- zoneId.startsWith("GMT") ||
- (PATTERN.matcher(zoneId).matches() == false)) {
+ if (zoneId.length() < 2 || PATTERN.matcher(zoneId).matches() == false) {
throw new DateTimeException("Invalid ID for region-based ZoneId, invalid format: " + zoneId);
}
ZoneRules rules = null;
@@ -157,6 +134,19 @@
return new ZoneRegion(zoneId, rules);
}
+ /**
+ * Obtains an instance of {@code ZoneId} wrapping an offset.
+ * <p>
+ * For example, zone IDs like 'UTC', 'GMT', 'UT' and 'UTC+01:30' will be setup here.
+ *
+ * @param zoneId the time-zone ID, not null
+ * @param offset the offset, not null
+ * @return the zone ID, not null
+ */
+ static ZoneRegion ofPrefixedOffset(String zoneId, ZoneOffset offset) {
+ return new ZoneRegion(zoneId, offset.getRules());
+ }
+
//-------------------------------------------------------------------------
/**
* Constructor.
@@ -218,7 +208,7 @@
static ZoneId readExternal(DataInput in) throws IOException {
String id = in.readUTF();
- return ofLenient(id);
+ return ZoneId.of(id, false);
}
}
diff -r 05525f23180e test/java/time/tck/java/time/TCKZoneId.java
--- a/test/java/time/tck/java/time/TCKZoneId.java Fri Feb 08 09:11:51 2013 -0800
+++ b/test/java/time/tck/java/time/TCKZoneId.java Mon Feb 11 20:14:51 2013 +0000
@@ -64,22 +64,23 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
import java.io.DataOutputStream;
-import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamConstants;
import java.lang.reflect.Field;
import java.time.DateTimeException;
+import java.time.Instant;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
+import java.time.format.TextStyle;
import java.time.temporal.Queries;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.zone.ZoneRulesException;
import java.util.HashMap;
+import java.util.Locale;
import java.util.Map;
import org.testng.annotations.DataProvider;
@@ -114,9 +115,12 @@
// an ID can be loaded without validation during deserialization
String id = "QWERTYUIOPASDFGHJKLZXCVBNM~/._+-";
ZoneId deser = deserialize(id);
- // getting the ID and string are OK
+ // getId, equals, hashCode, toString and normalized are OK
assertEquals(deser.getId(), id);
assertEquals(deser.toString(), id);
+ assertEquals(deser, deser);
+ assertEquals(deser.hashCode(), deser.hashCode());
+ assertEquals(deser.normalized(), deser);
// getting the rules is not
try {
deser.getRules();
@@ -133,32 +137,32 @@
deserialize("|!?");
}
- @Test(dataProvider="offsetBasedValid", expectedExceptions=DateTimeException.class)
+ @Test(dataProvider="offsetBasedValid")
public void test_deserialization_lenient_offsetNotAllowed_noPrefix(String input, String resolvedId) throws Exception {
- // an ID can be loaded without validation during deserialization
- // but there is a check to ensure the ID format is valid
- deserialize(input);
+ ZoneId deserialized = deserialize(input);
+ assertEquals(deserialized, ZoneId.of(input));
+ assertEquals(deserialized, ZoneId.of(resolvedId));
}
- @Test(dataProvider="offsetBasedValid", expectedExceptions=DateTimeException.class)
- public void test_deserialization_lenient_offsetNotAllowed_prefixUTC(String input, String resolvedId) throws Exception {
- // an ID can be loaded without validation during deserialization
- // but there is a check to ensure the ID format is valid
- deserialize("UTC" + input);
+ @Test(dataProvider="offsetBasedValidPrefix")
+ public void test_deserialization_lenient_offsetNotAllowed_prefixUTC(String input, String resolvedId, String offsetId) throws Exception {
+ ZoneId deserialized = deserialize("UTC" + input);
+ assertEquals(deserialized, ZoneId.of("UTC" + input));
+ assertEquals(deserialized, ZoneId.of("UTC" + resolvedId));
}
- @Test(dataProvider="offsetBasedValid", expectedExceptions=DateTimeException.class)
- public void test_deserialization_lenient_offsetNotAllowed_prefixGMT(String input, String resolvedId) throws Exception {
- // an ID can be loaded without validation during deserialization
- // but there is a check to ensure the ID format is valid
- deserialize("GMT" + input);
+ @Test(dataProvider="offsetBasedValidPrefix")
+ public void test_deserialization_lenient_offsetNotAllowed_prefixGMT(String input, String resolvedId, String offsetId) throws Exception {
+ ZoneId deserialized = deserialize("GMT" + input);
+ assertEquals(deserialized, ZoneId.of("GMT" + input));
+ assertEquals(deserialized, ZoneId.of("GMT" + resolvedId));
}
- @Test(dataProvider="offsetBasedValid", expectedExceptions=DateTimeException.class)
- public void test_deserialization_lenient_offsetNotAllowed_prefixUT(String input, String resolvedId) throws Exception {
- // an ID can be loaded without validation during deserialization
- // but there is a check to ensure the ID format is valid
- deserialize("UT" + input);
+ @Test(dataProvider="offsetBasedValidPrefix")
+ public void test_deserialization_lenient_offsetNotAllowed_prefixUT(String input, String resolvedId, String offsetId) throws Exception {
+ ZoneId deserialized = deserialize("UT" + input);
+ assertEquals(deserialized, ZoneId.of("UT" + input));
+ assertEquals(deserialized, ZoneId.of("UT" + resolvedId));
}
private ZoneId deserialize(String id) throws Exception {
@@ -315,65 +319,41 @@
}
//-----------------------------------------------------------------------
- // regular factory
- //-----------------------------------------------------------------------
- @DataProvider(name="offsetBasedZero")
- Object[][] data_offsetBasedZero() {
- return new Object[][] {
- {""}, {"0"},
- {"+00"},{"+0000"},{"+00:00"},{"+000000"},{"+00:00:00"},
- {"-00"},{"-0000"},{"-00:00"},{"-000000"},{"-00:00:00"},
- };
- }
-
- @Test(dataProvider="offsetBasedZero")
- public void factory_of_String_offsetBasedZero_noPrefix(String id) {
- if (id.length() > 0 && id.equals("0") == false) {
- ZoneId test = ZoneId.of(id);
- assertEquals(test, ZoneOffset.UTC);
- }
- }
-
- @Test(dataProvider="offsetBasedZero")
- public void factory_of_String_offsetBasedZero_prefixUTC(String id) {
- ZoneId test = ZoneId.of("UTC" + id);
- assertEquals(test, ZoneOffset.UTC);
- }
-
- @Test(dataProvider="offsetBasedZero")
- public void factory_of_String_offsetBasedZero_prefixGMT(String id) {
- ZoneId test = ZoneId.of("GMT" + id);
- assertEquals(test, ZoneOffset.UTC);
- }
-
- @Test(dataProvider="offsetBasedZero")
- public void factory_of_String_offsetBasedZero_prefixUT(String id) {
- ZoneId test = ZoneId.of("UT" + id);
- assertEquals(test, ZoneOffset.UTC);
- }
-
- @Test
- public void factory_of_String_offsetBasedZero_z() {
- ZoneId test = ZoneId.of("Z");
- assertEquals(test, ZoneOffset.UTC);
- }
-
+ // regular factory and .normalized()
//-----------------------------------------------------------------------
@DataProvider(name="offsetBasedValid")
Object[][] data_offsetBasedValid() {
return new Object[][] {
+ {"Z", "Z"},
{"+0", "Z"},
+ {"-0", "Z"},
+ {"+00", "Z"},
+ {"+0000", "Z"},
+ {"+00:00", "Z"},
+ {"+000000", "Z"},
+ {"+00:00:00", "Z"},
+ {"-00", "Z"},
+ {"-0000", "Z"},
+ {"-00:00", "Z"},
+ {"-000000", "Z"},
+ {"-00:00:00", "Z"},
{"+5", "+05:00"},
{"+01", "+01:00"},
- {"+0100", "+01:00"},{"+01:00", "+01:00"},
- {"+010000", "+01:00"},{"+01:00:00", "+01:00"},
+ {"+0100", "+01:00"},
+ {"+01:00", "+01:00"},
+ {"+010000", "+01:00"},
+ {"+01:00:00", "+01:00"},
{"+12", "+12:00"},
- {"+1234", "+12:34"},{"+12:34", "+12:34"},
- {"+123456", "+12:34:56"},{"+12:34:56", "+12:34:56"},
+ {"+1234", "+12:34"},
+ {"+12:34", "+12:34"},
+ {"+123456", "+12:34:56"},
+ {"+12:34:56", "+12:34:56"},
{"-02", "-02:00"},
{"-5", "-05:00"},
- {"-0200", "-02:00"},{"-02:00", "-02:00"},
- {"-020000", "-02:00"},{"-02:00:00", "-02:00"},
+ {"-0200", "-02:00"},
+ {"-02:00", "-02:00"},
+ {"-020000", "-02:00"},
+ {"-02:00:00", "-02:00"},
};
}
@@ -382,27 +362,126 @@
ZoneId test = ZoneId.of(input);
assertEquals(test.getId(), id);
assertEquals(test, ZoneOffset.of(id));
+ assertEquals(test.normalized(), ZoneOffset.of(id));
+ assertEquals(test.getDisplayName(TextStyle.FULL, Locale.UK), id);
+ assertEquals(test.getRules().isFixedOffset(), true);
+ assertEquals(test.getRules().getOffset(Instant.EPOCH), ZoneOffset.of(id));
}
- @Test(dataProvider="offsetBasedValid")
- public void factory_of_String_offsetBasedValid_prefixUTC(String input, String id) {
- ZoneId test = ZoneId.of("UTC" + input);
- assertEquals(test.getId(), id);
- assertEquals(test, ZoneOffset.of(id));
+ //-----------------------------------------------------------------------
+ @DataProvider(name="offsetBasedValidPrefix")
+ Object[][] data_offsetBasedValidPrefix() {
+ return new Object[][] {
+ {"", "", "Z"},
+ {"+0", "", "Z"},
+ {"-0", "", "Z"},
+ {"+00", "", "Z"},
+ {"+0000", "", "Z"},
+ {"+00:00", "", "Z"},
+ {"+000000", "", "Z"},
+ {"+00:00:00", "", "Z"},
+ {"-00", "", "Z"},
+ {"-0000", "", "Z"},
+ {"-00:00", "", "Z"},
+ {"-000000", "", "Z"},
+ {"-00:00:00", "", "Z"},
+ {"+5", "+05:00", "+05:00"},
+ {"+01", "+01:00", "+01:00"},
+ {"+0100", "+01:00", "+01:00"},
+ {"+01:00", "+01:00", "+01:00"},
+ {"+010000", "+01:00", "+01:00"},
+ {"+01:00:00", "+01:00", "+01:00"},
+ {"+12", "+12:00", "+12:00"},
+ {"+1234", "+12:34", "+12:34"},
+ {"+12:34", "+12:34", "+12:34"},
+ {"+123456", "+12:34:56", "+12:34:56"},
+ {"+12:34:56", "+12:34:56", "+12:34:56"},
+ {"-02", "-02:00", "-02:00"},
+ {"-5", "-05:00", "-05:00"},
+ {"-0200", "-02:00", "-02:00"},
+ {"-02:00", "-02:00", "-02:00"},
+ {"-020000", "-02:00", "-02:00"},
+ {"-02:00:00", "-02:00", "-02:00"},
+ };
}
- @Test(dataProvider="offsetBasedValid")
- public void factory_of_String_offsetBasedValid_prefixGMT(String input, String id) {
- ZoneId test = ZoneId.of("GMT" + input);
- assertEquals(test.getId(), id);
- assertEquals(test, ZoneOffset.of(id));
+ @Test(dataProvider="offsetBasedValidPrefix")
+ public void factory_of_String_offsetBasedValid_prefixUTC(String input, String id, String offsetId) {
+ ZoneId test = ZoneId.of("UTC" + input);
+ assertEquals(test.getId(), "UTC" + id);
+ assertEquals(test.getRules(), ZoneOffset.of(offsetId).getRules());
+ assertEquals(test.normalized(), ZoneOffset.of(offsetId));
+ assertEquals(test.getDisplayName(TextStyle.FULL, Locale.UK), displayName("UTC" + id));
+ assertEquals(test.getRules().isFixedOffset(), true);
+ assertEquals(test.getRules().getOffset(Instant.EPOCH), ZoneOffset.of(offsetId));
}
- @Test(dataProvider="offsetBasedValid")
- public void factory_of_String_offsetBasedValid_prefixUT(String input, String id) {
+ @Test(dataProvider="offsetBasedValidPrefix")
+ public void factory_of_String_offsetBasedValid_prefixGMT(String input, String id, String offsetId) {
+ ZoneId test = ZoneId.of("GMT" + input);
+ assertEquals(test.getId(), "GMT" + id);
+ assertEquals(test.getRules(), ZoneOffset.of(offsetId).getRules());
+ assertEquals(test.normalized(), ZoneOffset.of(offsetId));
+ assertEquals(test.getDisplayName(TextStyle.FULL, Locale.UK), displayName("GMT" + id));
+ assertEquals(test.getRules().isFixedOffset(), true);
+ assertEquals(test.getRules().getOffset(Instant.EPOCH), ZoneOffset.of(offsetId));
+ }
+
+ @Test(dataProvider="offsetBasedValidPrefix")
+ public void factory_of_String_offsetBasedValid_prefixUT(String input, String id, String offsetId) {
ZoneId test = ZoneId.of("UT" + input);
- assertEquals(test.getId(), id);
- assertEquals(test, ZoneOffset.of(id));
+ assertEquals(test.getId(), "UT" + id);
+ assertEquals(test.getRules(), ZoneOffset.of(offsetId).getRules());
+ assertEquals(test.normalized(), ZoneOffset.of(offsetId));
+ assertEquals(test.getDisplayName(TextStyle.FULL, Locale.UK), displayName("UT" + id));
+ assertEquals(test.getRules().isFixedOffset(), true);
+ assertEquals(test.getRules().getOffset(Instant.EPOCH), ZoneOffset.of(offsetId));
+ }
+
+ private String displayName(String id) {
+ if (id.equals("GMT")) {
+ return "Greenwich Mean Time";
+ }
+ if (id.equals("GMT0")) {
+ return "Greenwich Mean Time";
+ }
+ if (id.equals("UTC")) {
+ return "Coordinated Universal Time";
+ }
+ return id;
+ }
+
+ //-----------------------------------------------------------------------
+ @DataProvider(name="offsetBasedValidOther")
+ Object[][] data_offsetBasedValidOther() {
+ return new Object[][] {
+ {"GMT", "Z"},
+ {"GMT0", "Z"},
+ {"UCT", "Z"},
+ {"Greenwich", "Z"},
+ {"Universal", "Z"},
+ {"Zulu", "Z"},
+ {"Etc/GMT", "Z"},
+ {"Etc/GMT+0", "Z"},
+ {"Etc/GMT+1", "-01:00"},
+ {"Etc/GMT-1", "+01:00"},
+ {"Etc/GMT+9", "-09:00"},
+ {"Etc/GMT-9", "+09:00"},
+ {"Etc/GMT0", "Z"},
+ {"Etc/UCT", "Z"},
+ {"Etc/UTC", "Z"},
+ {"Etc/Greenwich", "Z"},
+ {"Etc/Universal", "Z"},
+ {"Etc/Zulu", "Z"},
+ };
+ }
+
+ @Test(dataProvider="offsetBasedValidOther")
+ public void factory_of_String_offsetBasedValidOther(String input, String offsetId) {
+ ZoneId test = ZoneId.of(input);
+ assertEquals(test.getId(), input);
+ assertEquals(test.getRules(), ZoneOffset.of(offsetId).getRules());
+ assertEquals(test.normalized(), ZoneOffset.of(offsetId));
}
//-----------------------------------------------------------------------
@@ -422,6 +501,12 @@
{"-19"}, {"-19:00"}, {"-18:01"}, {"-18:00:01"}, {"-1801"}, {"-180001"},
{"-01_00"}, {"-01;00"}, {"-01@00"}, {"-01:AA"},
{"@01:00"},
+ {"0"},
+ {"UT0"},
+ {"UTZ"},
+ {"UTC0"},
+ {"UTCZ"},
+ {"GMTZ"}, // GMT0 is valid in ZoneRulesProvider
};
}
@@ -440,6 +525,9 @@
@Test(dataProvider="offsetBasedInvalid", expectedExceptions=DateTimeException.class)
public void factory_of_String_offsetBasedInvalid_prefixGMT(String id) {
+ if (id.equals("0")) {
+ throw new DateTimeException("Fake exception: GMT0 is valid, not invalid");
+ }
ZoneId.of("GMT" + id);
}
@@ -479,6 +567,7 @@
ZoneId test = ZoneId.of("Europe/London");
assertEquals(test.getId(), "Europe/London");
assertEquals(test.getRules().isFixedOffset(), false);
+ assertEquals(test.normalized(), test);
}
//-----------------------------------------------------------------------
@@ -578,8 +667,10 @@
{"Europe/London", "Europe/London"},
{"Europe/Paris", "Europe/Paris"},
{"Europe/Berlin", "Europe/Berlin"},
- {"UTC", "Z"},
- {"UTC+01:00", "+01:00"},
+ {"Z", "Z"},
+ {"+01:00", "+01:00"},
+ {"UTC", "UTC"},
+ {"UTC+01:00", "UTC+01:00"},
};
}
diff -r 05525f23180e test/java/time/test/java/time/TestZoneId.java
--- a/test/java/time/test/java/time/TestZoneId.java Fri Feb 08 09:11:51 2013 -0800
+++ b/test/java/time/test/java/time/TestZoneId.java Mon Feb 11 20:14:51 2013 +0000
@@ -62,7 +62,6 @@
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;
import java.lang.reflect.Field;
@@ -82,7 +81,6 @@
import java.util.SimpleTimeZone;
import java.util.TimeZone;
-import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
@@ -121,7 +119,6 @@
assertEquals(test.getRules().isFixedOffset(), true);
assertEquals(test.getRules().getOffset(Instant.ofEpochSecond(0L)), ZoneOffset.UTC);
checkOffset(test.getRules(), createLDT(2008, 6, 30), ZoneOffset.UTC, 1);
- assertSame(test, ZoneId.of("UTC+00"));
}
//-----------------------------------------------------------------------
@@ -129,9 +126,7 @@
//-----------------------------------------------------------------------
public void test_systemDefault() {
ZoneId test = ZoneId.systemDefault();
- assertEquals(test.getId(), TimeZone.getDefault()
- .getID()
- .replaceAll("GMT|UTC|UT", "Z"));
+ assertEquals(test.getId(), TimeZone.getDefault().getID());
}
@Test(expectedExceptions = DateTimeException.class)
@@ -157,58 +152,6 @@
}
//-----------------------------------------------------------------------
- @DataProvider(name="String_Fixed")
- Object[][] data_of_string_Fixed() {
- return new Object[][] {
- {"+0", "Z"},
- {"+5", "+05:00"},
- {"+01", "+01:00"},
- {"+0100", "+01:00"},{"+01:00", "+01:00"},
- {"+010000", "+01:00"},{"+01:00:00", "+01:00"},
- {"+12", "+12:00"},
- {"+1234", "+12:34"},{"+12:34", "+12:34"},
- {"+123456", "+12:34:56"},{"+12:34:56", "+12:34:56"},
- {"-02", "-02:00"},
- {"-5", "-05:00"},
- {"-0200", "-02:00"},{"-02:00", "-02:00"},
- {"-020000", "-02:00"},{"-02:00:00", "-02:00"},
- };
- }
-
- @Test(dataProvider="String_Fixed")
- public void test_of_string_offset(String input, String id) {
- ZoneId test = ZoneId.of(input);
- assertEquals(test.getId(), id);
- assertEquals(test.getDisplayName(TextStyle.FULL, Locale.UK), id);
- assertEquals(test.getRules().isFixedOffset(), true);
- ZoneOffset offset = ZoneOffset.of(id);
- assertEquals(test.getRules().getOffset(Instant.ofEpochSecond(0L)), offset);
- checkOffset(test.getRules(), createLDT(2008, 6, 30), offset, 1);
- }
-
- @Test(dataProvider="String_Fixed")
- public void test_of_string_FixedUTC(String input, String id) {
- ZoneId test = ZoneId.of("UTC" + input);
- assertEquals(test.getId(), id);
- assertEquals(test.getDisplayName(TextStyle.FULL, Locale.UK), id);
- assertEquals(test.getRules().isFixedOffset(), true);
- ZoneOffset offset = ZoneOffset.of(id);
- assertEquals(test.getRules().getOffset(Instant.ofEpochSecond(0L)), offset);
- checkOffset(test.getRules(), createLDT(2008, 6, 30), offset, 1);
- }
-
- @Test(dataProvider="String_Fixed")
- public void test_of_string_FixedGMT(String input, String id) {
- ZoneId test = ZoneId.of("GMT" + input);
- assertEquals(test.getId(), id);
- assertEquals(test.getDisplayName(TextStyle.FULL, Locale.UK), id);
- assertEquals(test.getRules().isFixedOffset(), true);
- ZoneOffset offset = ZoneOffset.of(id);
- assertEquals(test.getRules().getOffset(Instant.ofEpochSecond(0L)), offset);
- checkOffset(test.getRules(), createLDT(2008, 6, 30), offset, 1);
- }
-
- //-----------------------------------------------------------------------
// Europe/London
//-----------------------------------------------------------------------
public void test_London() {
diff -r 05525f23180e test/java/time/test/java/time/format/TestZoneTextPrinterParser.java
--- a/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java Fri Feb 08 09:11:51 2013 -0800
+++ b/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java Mon Feb 11 20:14:51 2013 +0000
@@ -41,6 +41,7 @@
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.time.zone.ZoneRulesProvider;
+import java.util.TreeSet;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@@ -49,7 +50,7 @@
/**
* Test ZoneTextPrinterParser
*/
-@Test(groups={"implementation"})
+@Test
public class TestZoneTextPrinterParser extends AbstractTestPrinterParser {
protected static DateTimeFormatter getFormatter(Locale locale, TextStyle style) {
@@ -70,26 +71,23 @@
zdt = zdt.withDayOfYear(r.nextInt(365) + 1)
.with(ChronoField.SECOND_OF_DAY, r.nextInt(86400));
for (String zid : zids) {
- if (zid.equals("ROC") ||
- zid.startsWith("UTC") ||
- zid.startsWith("GMT") || zid.startsWith("Etc/GMT")) {
- // UTC, GMT are treated as zone offset
+ if (zid.equals("ROC") || zid.startsWith("Etc/GMT")) {
continue; // TBD: match jdk behavior?
}
zdt = zdt.withZoneSameLocal(ZoneId.of(zid));
TimeZone tz = TimeZone.getTimeZone(zid);
boolean isDST = tz.inDaylightTime(new Date(zdt.toInstant().toEpochMilli()));
for (Locale locale : locales) {
- printText(locale, zdt, TextStyle.FULL,
- tz.getDisplayName(isDST, TimeZone.LONG, locale));
- printText(locale, zdt, TextStyle.SHORT,
- tz.getDisplayName(isDST, TimeZone.SHORT, locale));
+ printText(locale, zdt, TextStyle.FULL, tz,
+ tz.getDisplayName(isDST, TimeZone.LONG, locale));
+ printText(locale, zdt, TextStyle.SHORT, tz,
+ tz.getDisplayName(isDST, TimeZone.SHORT, locale));
}
}
}
}
- private void printText(Locale locale, ZonedDateTime zdt, TextStyle style, String expected) {
+ private void printText(Locale locale, ZonedDateTime zdt, TextStyle style, TimeZone zone, String expected) {
String result = getFormatter(locale, style).format(zdt);
if (!result.equals(expected)) {
if (result.equals("FooLocation")) { // from rules provider test if same vm
@@ -97,8 +95,8 @@
}
System.out.println("----------------");
System.out.printf("tdz[%s]%n", zdt.toString());
- System.out.printf("[%-4s, %5s] :[%s]%n", locale.toString(), style.toString(),result);
- System.out.printf("%4s, %5s :[%s]%n", "", "", expected);
+ System.out.printf("[%-5s, %5s] :[%s]%n", locale.toString(), style.toString(),result);
+ System.out.printf(" %5s, %5s :[%s] %s%n", "", "", expected, zone);
}
assertEquals(result, expected);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment