/** * Call on background thread to eagerly load all zones. Starts with loading * {@link ZoneId#systemDefault()} which is the one most likely to be used. */ @WorkerThread public static void cacheZones() { ZoneId.systemDefault().getRules(); for (String zoneId : ZoneRulesProvider.getAvailableZoneIds()) { ZoneRulesProvider.getRules(zoneId, true); } }
/** * Converts a {@code TimeZone} to a {@code ZoneId}. * * @param timeZone the time-zone, not null * @return the zone, not null */ public static ZoneId toZoneId(TimeZone timeZone) { return ZoneId.of(timeZone.getID(), ZoneId.SHORT_IDS); }
@Nonnull @Override public String convert(ZoneId source) { return source.toString(); } }
@Override public int parse(DateTimeParseContext context, CharSequence text, int position) { // this is a poor implementation that handles some but not all of the spec // JDK8 has a lot of extra information here Map<String, String> ids = new TreeMap<String, String>(LENGTH_COMPARATOR); for (String id : ZoneId.getAvailableZoneIds()) { ids.put(id, id); TimeZone tz = TimeZone.getTimeZone(id); int tzstyle = (textStyle.asNormal() == TextStyle.FULL ? TimeZone.LONG : TimeZone.SHORT); String textWinter = tz.getDisplayName(false, tzstyle, context.getLocale()); if (id.startsWith("Etc/") || (!textWinter.startsWith("GMT+") && !textWinter.startsWith("GMT+"))) { ids.put(textWinter, id); } String textSummer = tz.getDisplayName(true, tzstyle, context.getLocale()); if (id.startsWith("Etc/") || (!textSummer.startsWith("GMT+") && !textSummer.startsWith("GMT+"))) { ids.put(textSummer, id); } } for (Entry<String, String> entry : ids.entrySet()) { String name = entry.getKey(); if (context.subSequenceEquals(text, position, name, 0, name.length())) { context.setParsed(ZoneId.of(entry.getValue())); return position + name.length(); } } return ~position; }
/** * 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) { // ignore invalid objects } return this; }
/** * Obtains a clock that returns the current instant using the best available * system clock, converting to date and time using the default time-zone. * <p> * This clock is based on the best available system clock. * This may use {@link System#currentTimeMillis()}, or a higher resolution * clock if one is available. * <p> * Using this method hard codes a dependency to the default time-zone into your application. * It is recommended to avoid this and use a specific time-zone whenever possible. * The {@link #systemUTC() UTC clock} should be used when you need the current instant * without the date or time. * <p> * The returned implementation is immutable, thread-safe and {@code Serializable}. * It is equivalent to {@code system(ZoneId.systemDefault())}. * * @return a clock that uses the best available system clock in the default zone, not null * @see ZoneId#systemDefault() */ public static Clock systemDefaultZone() { return new SystemClock(ZoneId.systemDefault()); }
@Override public boolean print(DateTimePrintContext context, StringBuilder buf) { ZoneId zone = context.getValue(TemporalQueries.zoneId()); if (zone == null) { return false; } if (zone.normalized() instanceof ZoneOffset) { buf.append(zone.getId()); return true; } TemporalAccessor temporal = context.getTemporal(); boolean daylight = false; if (temporal.isSupported(INSTANT_SECONDS)) { Instant instant = Instant.ofEpochSecond(temporal.getLong(INSTANT_SECONDS)); daylight = zone.getRules().isDaylightSavings(instant); } TimeZone tz = TimeZone.getTimeZone(zone.getId()); int tzstyle = (textStyle.asNormal() == TextStyle.FULL ? TimeZone.LONG : TimeZone.SHORT); String text = tz.getDisplayName(daylight, tzstyle, context.getLocale()); buf.append(text); return true; }
@Override public boolean equals(Object obj) { if (obj instanceof SystemClock) { return zone.equals(((SystemClock) obj).zone); } return false; } @Override
ZoneId normalizedOffset = overrideZone.normalized(); ZoneOffset temporalOffset = temporal.query(TemporalQueries.offset()); if (normalizedOffset instanceof ZoneOffset && temporalOffset != null && normalizedOffset.equals(temporalOffset) == false) { throw new DateTimeException("Invalid override zone for temporal: " + overrideZone + " " + temporal);
/** * 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) { // ignore invalid objects } return this; }
/** * Obtains a clock that returns the current instant using the best available * system clock, converting to date and time using the default time-zone. * <p> * This clock is based on the best available system clock. * This may use {@link System#currentTimeMillis()}, or a higher resolution * clock if one is available. * <p> * Using this method hard codes a dependency to the default time-zone into your application. * It is recommended to avoid this and use a specific time-zone whenever possible. * The {@link #systemUTC() UTC clock} should be used when you need the current instant * without the date or time. * <p> * The returned implementation is immutable, thread-safe and {@code Serializable}. * It is equivalent to {@code system(ZoneId.systemDefault())}. * * @return a clock that uses the best available system clock in the default zone, not null * @see ZoneId#systemDefault() */ public static Clock systemDefaultZone() { return new SystemClock(ZoneId.systemDefault()); }
@Override public boolean print(DateTimePrintContext context, StringBuilder buf) { ZoneId zone = context.getValue(TemporalQueries.zoneId()); if (zone == null) { return false; } if (zone.normalized() instanceof ZoneOffset) { buf.append(zone.getId()); return true; } TemporalAccessor temporal = context.getTemporal(); boolean daylight = false; if (temporal.isSupported(INSTANT_SECONDS)) { Instant instant = Instant.ofEpochSecond(temporal.getLong(INSTANT_SECONDS)); daylight = zone.getRules().isDaylightSavings(instant); } TimeZone tz = TimeZone.getTimeZone(zone.getId()); int tzstyle = (textStyle.asNormal() == TextStyle.FULL ? TimeZone.LONG : TimeZone.SHORT); String text = tz.getDisplayName(daylight, tzstyle, context.getLocale()); buf.append(text); return true; }
@Override public int parse(DateTimeParseContext context, CharSequence text, int position) { // this is a poor implementation that handles some but not all of the spec // JDK8 has a lot of extra information here Map<String, String> ids = new TreeMap<String, String>(LENGTH_COMPARATOR); for (String id : ZoneId.getAvailableZoneIds()) { ids.put(id, id); TimeZone tz = TimeZone.getTimeZone(id); int tzstyle = (textStyle.asNormal() == TextStyle.FULL ? TimeZone.LONG : TimeZone.SHORT); String textWinter = tz.getDisplayName(false, tzstyle, context.getLocale()); if (id.startsWith("Etc/") || (!textWinter.startsWith("GMT+") && !textWinter.startsWith("GMT+"))) { ids.put(textWinter, id); } String textSummer = tz.getDisplayName(true, tzstyle, context.getLocale()); if (id.startsWith("Etc/") || (!textSummer.startsWith("GMT+") && !textSummer.startsWith("GMT+"))) { ids.put(textSummer, id); } } for (Entry<String, String> entry : ids.entrySet()) { String name = entry.getKey(); if (context.subSequenceEquals(text, position, name, 0, name.length())) { context.setParsed(ZoneId.of(entry.getValue())); return position + name.length(); } } return ~position; }
@Override public boolean equals(Object obj) { if (obj instanceof SystemClock) { return zone.equals(((SystemClock) obj).zone); } return false; } @Override
ZoneId normalizedOffset = overrideZone.normalized(); ZoneOffset temporalOffset = temporal.query(TemporalQueries.offset()); if (normalizedOffset instanceof ZoneOffset && temporalOffset != null && normalizedOffset.equals(temporalOffset) == false) { throw new DateTimeException("Invalid override zone for temporal: " + overrideZone + " " + temporal);
@Override public OffsetDateTime apply(OffsetDateTime d, ZoneId z) { return d.withOffsetSameInstant(z.getRules().getOffset(d.toLocalDateTime())); } }
@Nonnull @Override public LocalDateTime convert(Date source) { return ofInstant(toInstant(source), systemDefault()); } }
/** * Converts a {@code TimeZone} to a {@code ZoneId}. * * @param timeZone the time-zone, not null * @return the zone, not null */ public static ZoneId toZoneId(TimeZone timeZone) { return ZoneId.of(timeZone.getID(), ZoneId.SHORT_IDS); }
/** * Outputs this date-time as a {@code String}, such as * {@code 2007-12-23T10:15:30+01:00[Europe/Paris]}. * <p> * The format consists of the {@code LocalDateTime} followed by the {@code ZoneOffset}. * If the {@code ZoneId} is not the same as the offset, then the ID is output. * The output is compatible with ISO-8601 if the offset and ID are the same. * * @return a string representation of this date-time, not null */ @Override // override for Javadoc public String toString() { String str = dateTime.toString() + offset.toString(); if (offset != zone) { str += '[' + zone.toString() + ']'; } return str; }
@Override public Clock withZone(ZoneId zone) { if (zone.equals(this.zone)) { // intentional NPE return this; } return new SystemClock(zone); } @Override