Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/sun/util/calendar/zi/ZoneInfoOld.java
38855 views
/*1* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425import java.io.IOException;26import java.io.ObjectInputStream;27import java.lang.ref.SoftReference;28import java.time.ZoneOffset;29import java.time.LocalDateTime;30import java.util.Arrays;31import java.util.ArrayList;32import java.util.Date;33import java.util.List;34import java.util.Locale;35import java.util.Map;36import java.util.SimpleTimeZone;37import java.util.TimeZone;3839import sun.util.calendar.CalendarSystem;40import sun.util.calendar.CalendarDate;4142/**43* <code>ZoneInfoOld</code> is an implementation subclass of {@link44* java.util.TimeZone TimeZone} that represents GMT offsets and45* daylight saving time transitions of a time zone.46* <p>47* The daylight saving time transitions are described in the {@link48* #transitions transitions} table consisting of a chronological49* sequence of transitions of GMT offset and/or daylight saving time50* changes. Since all transitions are represented in UTC, in theory,51* <code>ZoneInfoOld</code> can be used with any calendar systems except52* for the {@link #getOffset(int,int,int,int,int,int) getOffset}53* method that takes Gregorian calendar date fields.54* <p>55* This table covers transitions from 1900 until 2037 (as of version56* 1.4), Before 1900, it assumes that there was no daylight saving57* time and the <code>getOffset</code> methods always return the58* {@link #getRawOffset} value. No Local Mean Time is supported. If a59* specified date is beyond the transition table and this time zone is60* supposed to observe daylight saving time in 2037, it delegates61* operations to a {@link java.util.SimpleTimeZone SimpleTimeZone}62* object created using the daylight saving time schedule as of 2037.63* <p>64* The date items, transitions, GMT offset(s), etc. are read from a database65* file. See {@link ZoneInfoFile} for details.66* @see java.util.SimpleTimeZone67* @since 1.468*/6970public class ZoneInfoOld extends TimeZone {7172// The constants assume no leap seconds support.73static final int SECOND_IN_MILLIS = 1000;74static final int MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;75static final int HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;76static final int DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;7778private static final int UTC_TIME = 0;79private static final int STANDARD_TIME = 1;80private static final int WALL_TIME = 2;8182private static final long OFFSET_MASK = 0x0fL;83private static final long DST_MASK = 0xf0L;84private static final int DST_NSHIFT = 4;85// this bit field is reserved for abbreviation support86private static final long ABBR_MASK = 0xf00L;87private static final int TRANSITION_NSHIFT = 12;8889// Flag for supporting JDK backward compatible IDs, such as "EST".90static final boolean USE_OLDMAPPING;91static {92String oldmapping = System.getProperty("sun.timezone.ids.oldmapping", "false").toLowerCase(Locale.ROOT);93USE_OLDMAPPING = (oldmapping.equals("yes") || oldmapping.equals("true"));94}9596// IDs having conflicting data between Olson and JDK 1.197static final String[] conflictingIDs = {98"EST", "MST", "HST"99};100101private static final CalendarSystem gcal = CalendarSystem.getGregorianCalendar();102103/**104* The raw GMT offset in milliseconds between this zone and GMT.105* Negative offsets are to the west of Greenwich. To obtain local106* <em>standard</em> time, add the offset to GMT time.107* @serial108*/109int rawOffset;110111/**112* Difference in milliseconds from the original GMT offset in case113* the raw offset value has been modified by calling {@link114* #setRawOffset}. The initial value is 0.115* @serial116*/117int rawOffsetDiff = 0;118119/**120* A CRC32 value of all pairs of transition time (in milliseconds121* in <code>long</code>) in local time and its GMT offset (in122* seconds in <code>int</code>) in the chronological order. Byte123* values of each <code>long</code> and <code>int</code> are taken124* in the big endian order (i.e., MSB to LSB).125* @serial126*/127int checksum;128129/**130* The amount of time in milliseconds saved during daylight saving131* time. If <code>useDaylight</code> is false, this value is 0.132* @serial133*/134int dstSavings;135136/**137* This array describes transitions of GMT offsets of this time138* zone, including both raw offset changes and daylight saving139* time changes.140* A long integer consists of four bit fields.141* <ul>142* <li>The most significant 52-bit field represents transition143* time in milliseconds from Gregorian January 1 1970, 00:00:00144* GMT.</li>145* <li>The next 4-bit field is reserved and must be 0.</li>146* <li>The next 4-bit field is an index value to {@link #offsets147* offsets[]} for the amount of daylight saving at the148* transition. If this value is zero, it means that no daylight149* saving, not the index value zero.</li>150* <li>The least significant 4-bit field is an index value to151* {@link #offsets offsets[]} for <em>total</em> GMT offset at the152* transition.</li>153* </ul>154* If this time zone doesn't observe daylight saving time and has155* never changed any GMT offsets in the past, this value is null.156* @serial157*/158long[] transitions;159160/**161* This array holds all unique offset values in162* milliseconds. Index values to this array are stored in the163* transitions array elements.164* @serial165*/166int[] offsets;167168/**169* SimpleTimeZone parameter values. It has to have either 8 for170* {@link java.util.SimpleTimeZone#SimpleTimeZone(int, String,171* int, int , int , int , int , int , int , int , int) the172* 11-argument SimpleTimeZone constructor} or 10 for {@link173* java.util.SimpleTimeZone#SimpleTimeZone(int, String, int, int,174* int , int , int , int , int , int , int, int, int) the175* 13-argument SimpleTimeZone constructor} parameters.176* @serial177*/178int[] simpleTimeZoneParams;179180/**181* True if the raw GMT offset value would change after the time182* zone data has been generated; false, otherwise. The default183* value is false.184* @serial185*/186boolean willGMTOffsetChange = false;187188/**189* True if the object has been modified after its instantiation.190*/191transient private boolean dirty = false;192193private static final long serialVersionUID = 2653134537216586139L;194195/**196* A constructor.197*/198public ZoneInfoOld() {199}200201/**202* A Constructor for CustomID.203*/204public ZoneInfoOld(String ID, int rawOffset) {205this(ID, rawOffset, 0, 0, null, null, null, false);206}207208/**209* Constructs a ZoneInfoOld instance.210*211* @param ID time zone name212* @param rawOffset GMT offset in milliseconds213* @param dstSavings daylight saving value in milliseconds or 0214* (zero) if this time zone doesn't observe Daylight Saving Time.215* @param checksum CRC32 value with all transitions table entry216* values217* @param transitions transition table218* @param offsets offset value table219* @param simpleTimeZoneParams parameter values for constructing220* SimpleTimeZone221* @param willGMTOffsetChange the value of willGMTOffsetChange222*/223ZoneInfoOld(String ID,224int rawOffset,225int dstSavings,226int checksum,227long[] transitions,228int[] offsets,229int[] simpleTimeZoneParams,230boolean willGMTOffsetChange) {231setID(ID);232this.rawOffset = rawOffset;233this.dstSavings = dstSavings;234this.checksum = checksum;235this.transitions = transitions;236this.offsets = offsets;237this.simpleTimeZoneParams = simpleTimeZoneParams;238this.willGMTOffsetChange = willGMTOffsetChange;239}240241/**242* Returns the difference in milliseconds between local time and UTC243* of given time, taking into account both the raw offset and the244* effect of daylight savings.245*246* @param date the milliseconds in UTC247* @return the milliseconds to add to UTC to get local wall time248*/249public int getOffset(long date) {250return getOffsets(date, null, UTC_TIME);251}252253public int getOffsets(long utc, int[] offsets) {254return getOffsets(utc, offsets, UTC_TIME);255}256257public int getOffsetsByStandard(long standard, int[] offsets) {258return getOffsets(standard, offsets, STANDARD_TIME);259}260261public int getOffsetsByWall(long wall, int[] offsets) {262return getOffsets(wall, offsets, WALL_TIME);263}264265private int getOffsets(long date, int[] offsets, int type) {266// if dst is never observed, there is no transition.267if (transitions == null) {268int offset = getLastRawOffset();269if (offsets != null) {270offsets[0] = offset;271offsets[1] = 0;272}273return offset;274}275276date -= rawOffsetDiff;277int index = getTransitionIndex(date, type);278279// prior to the transition table, returns the raw offset.280// FIXME: should support LMT.281if (index < 0) {282int offset = getLastRawOffset();283if (offsets != null) {284offsets[0] = offset;285offsets[1] = 0;286}287return offset;288}289290if (index < transitions.length) {291long val = transitions[index];292int offset = this.offsets[(int)(val & OFFSET_MASK)] + rawOffsetDiff;293if (offsets != null) {294int dst = (int)((val >>> DST_NSHIFT) & 0xfL);295int save = (dst == 0) ? 0 : this.offsets[dst];296offsets[0] = offset - save;297offsets[1] = save;298}299return offset;300}301302// beyond the transitions, delegate to SimpleTimeZone if there303// is a rule; otherwise, return rawOffset.304SimpleTimeZone tz = getLastRule();305if (tz != null) {306int rawoffset = tz.getRawOffset();307long msec = date;308if (type != UTC_TIME) {309msec -= rawOffset;310}311int dstoffset = tz.getOffset(msec) - rawOffset;312313// Check if it's in a standard-to-daylight transition.314if (dstoffset > 0 && tz.getOffset(msec - dstoffset) == rawoffset) {315dstoffset = 0;316}317318if (offsets != null) {319offsets[0] = rawoffset;320offsets[1] = dstoffset;321}322return rawoffset + dstoffset;323}324int offset = getLastRawOffset();325if (offsets != null) {326offsets[0] = offset;327offsets[1] = 0;328}329return offset;330}331332private int getTransitionIndex(long date, int type) {333int low = 0;334int high = transitions.length - 1;335336while (low <= high) {337int mid = (low + high) / 2;338long val = transitions[mid];339long midVal = val >> TRANSITION_NSHIFT; // sign extended340if (type != UTC_TIME) {341midVal += offsets[(int)(val & OFFSET_MASK)]; // wall time342}343if (type == STANDARD_TIME) {344int dstIndex = (int)((val >>> DST_NSHIFT) & 0xfL);345if (dstIndex != 0) {346midVal -= offsets[dstIndex]; // make it standard time347}348}349350if (midVal < date) {351low = mid + 1;352} else if (midVal > date) {353high = mid - 1;354} else {355return mid;356}357}358359// if beyond the transitions, returns that index.360if (low >= transitions.length) {361return low;362}363return low - 1;364}365366/**367* Returns the difference in milliseconds between local time and368* UTC, taking into account both the raw offset and the effect of369* daylight savings, for the specified date and time. This method370* assumes that the start and end month are distinct. This method371* assumes a Gregorian calendar for calculations.372* <p>373* <em>Note: In general, clients should use374* {@link Calendar#ZONE_OFFSET Calendar.get(ZONE_OFFSET)} +375* {@link Calendar#DST_OFFSET Calendar.get(DST_OFFSET)}376* instead of calling this method.</em>377*378* @param era The era of the given date. The value must be either379* GregorianCalendar.AD or GregorianCalendar.BC.380* @param year The year in the given date.381* @param month The month in the given date. Month is 0-based. e.g.,382* 0 for January.383* @param day The day-in-month of the given date.384* @param dayOfWeek The day-of-week of the given date.385* @param millis The milliseconds in day in <em>standard</em> local time.386* @return The milliseconds to add to UTC to get local time.387*/388public int getOffset(int era, int year, int month, int day,389int dayOfWeek, int milliseconds) {390if (milliseconds < 0 || milliseconds >= DAY_IN_MILLIS) {391throw new IllegalArgumentException();392}393394if (era == java.util.GregorianCalendar.BC) { // BC395year = 1 - year;396} else if (era != java.util.GregorianCalendar.AD) {397throw new IllegalArgumentException();398}399400CalendarDate date = gcal.newCalendarDate(null);401date.setDate(year, month + 1, day);402if (gcal.validate(date) == false) {403throw new IllegalArgumentException();404}405406// bug-for-bug compatible argument checking407if (dayOfWeek < java.util.GregorianCalendar.SUNDAY408|| dayOfWeek > java.util.GregorianCalendar.SATURDAY) {409throw new IllegalArgumentException();410}411412if (transitions == null) {413return getLastRawOffset();414}415416long dateInMillis = gcal.getTime(date) + milliseconds;417dateInMillis -= (long) rawOffset; // make it UTC418return getOffsets(dateInMillis, null, UTC_TIME);419}420421/**422* Sets the base time zone offset from GMT. This operation423* modifies all the transitions of this ZoneInfoOld object, including424* historical ones, if applicable.425*426* @param offsetMillis the base time zone offset to GMT.427* @see getRawOffset428*/429public synchronized void setRawOffset(int offsetMillis) {430if (offsetMillis == rawOffset + rawOffsetDiff) {431return;432}433rawOffsetDiff = offsetMillis - rawOffset;434if (lastRule != null) {435lastRule.setRawOffset(offsetMillis);436}437dirty = true;438}439440/**441* Returns the GMT offset of the current date. This GMT offset442* value is not modified during Daylight Saving Time.443*444* @return the GMT offset value in milliseconds to add to UTC time445* to get local standard time446*/447public int getRawOffset() {448if (!willGMTOffsetChange) {449return rawOffset + rawOffsetDiff;450}451452int[] offsets = new int[2];453getOffsets(System.currentTimeMillis(), offsets, UTC_TIME);454return offsets[0];455}456457public boolean isDirty() {458return dirty;459}460461int getLastRawOffset() {462return rawOffset + rawOffsetDiff;463}464465/**466* Queries if this time zone uses Daylight Saving Time in the last known rule.467*/468public boolean useDaylightTime() {469return (simpleTimeZoneParams != null);470}471472@Override473public boolean observesDaylightTime() {474if (simpleTimeZoneParams != null) {475return true;476}477if (transitions == null) {478return false;479}480481// Look up the transition table to see if it's in DST right482// now or if there's any standard-to-daylight transition at483// any future.484long utc = System.currentTimeMillis() - rawOffsetDiff;485int index = getTransitionIndex(utc, UTC_TIME);486487// before transitions in the transition table488if (index < 0) {489return false;490}491492// the time is in the table range.493for (int i = index; i < transitions.length; i++) {494if ((transitions[i] & DST_MASK) != 0) {495return true;496}497}498// No further DST is observed.499return false;500}501502/**503* Queries if the specified date is in Daylight Saving Time.504*/505public boolean inDaylightTime(Date date) {506if (date == null) {507throw new NullPointerException();508}509510if (transitions == null) {511return false;512}513514long utc = date.getTime() - rawOffsetDiff;515int index = getTransitionIndex(utc, UTC_TIME);516517// before transitions in the transition table518if (index < 0) {519return false;520}521522// the time is in the table range.523if (index < transitions.length) {524return (transitions[index] & DST_MASK) != 0;525}526527// beyond the transition table528SimpleTimeZone tz = getLastRule();529if (tz != null) {530return tz.inDaylightTime(date);531}532return false;533}534535/**536* Returns the amount of time in milliseconds that the clock is advanced537* during daylight saving time is in effect in its last daylight saving time rule.538*539* @return the number of milliseconds the time is advanced with respect to540* standard time when daylight saving time is in effect.541*/542public int getDSTSavings() {543return dstSavings;544}545546// /**547// * @return the last year in the transition table or -1 if this548// * time zone doesn't observe any daylight saving time.549// */550// public int getMaxTransitionYear() {551// if (transitions == null) {552// return -1;553// }554// long val = transitions[transitions.length - 1];555// int offset = this.offsets[(int)(val & OFFSET_MASK)] + rawOffsetDiff;556// val = (val >> TRANSITION_NSHIFT) + offset;557// CalendarDate lastDate = Gregorian.getCalendarDate(val);558// return lastDate.getYear();559// }560561/**562* Returns a string representation of this time zone.563* @return the string564*/565public String toString() {566return getClass().getName() +567"[id=\"" + getID() + "\"" +568",offset=" + getLastRawOffset() +569",dstSavings=" + dstSavings +570",useDaylight=" + useDaylightTime() +571",transitions=" + ((transitions != null) ? transitions.length : 0) +572",lastRule=" + (lastRule == null ? getLastRuleInstance() : lastRule) +573"]";574}575576/**577* Gets all available IDs supported in the Java run-time.578*579* @return an array of time zone IDs.580*/581public static String[] getAvailableIDs() {582List<String> idList = ZoneInfoFile.getZoneIDs();583List<String> excluded = ZoneInfoFile.getExcludedZones();584if (excluded != null) {585// List all zones from the idList and excluded lists586List<String> list = new ArrayList<>(idList.size() + excluded.size());587list.addAll(idList);588list.addAll(excluded);589idList = list;590}591String[] ids = new String[idList.size()];592return idList.toArray(ids);593}594595/**596* Gets all available IDs that have the same value as the597* specified raw GMT offset.598*599* @param rawOffset the GMT offset in milliseconds. This600* value should not include any daylight saving time.601*602* @return an array of time zone IDs.603*/604public static String[] getAvailableIDs(int rawOffset) {605String[] result;606List<String> matched = new ArrayList<>();607List<String> IDs = ZoneInfoFile.getZoneIDs();608int[] rawOffsets = ZoneInfoFile.getRawOffsets();609610loop:611for (int index = 0; index < rawOffsets.length; index++) {612if (rawOffsets[index] == rawOffset) {613byte[] indices = ZoneInfoFile.getRawOffsetIndices();614for (int i = 0; i < indices.length; i++) {615if (indices[i] == index) {616matched.add(IDs.get(i++));617while (i < indices.length && indices[i] == index) {618matched.add(IDs.get(i++));619}620break loop;621}622}623}624}625626// We need to add any zones from the excluded zone list that627// currently have the same GMT offset as the specified628// rawOffset. The zones returned by this method may not be629// correct as of return to the caller if any GMT offset630// transition is happening during this GMT offset checking...631List<String> excluded = ZoneInfoFile.getExcludedZones();632if (excluded != null) {633for (String id : excluded) {634TimeZone zi = getTimeZone(id);635if (zi != null && zi.getRawOffset() == rawOffset) {636matched.add(id);637}638}639}640641result = new String[matched.size()];642matched.toArray(result);643return result;644}645646/**647* Gets the ZoneInfoOld for the given ID.648*649* @param ID the ID for a ZoneInfoOld. See TimeZone for detail.650*651* @return the specified ZoneInfoOld object, or null if there is no652* time zone of the ID.653*/654public static TimeZone getTimeZone(String ID) {655String givenID = null;656657/*658* If old JDK compatibility is specified, get the old alias659* name.660*/661if (USE_OLDMAPPING) {662String compatibleID = TzIDOldMapping.MAP.get(ID);663if (compatibleID != null) {664givenID = ID;665ID = compatibleID;666}667}668669ZoneInfoOld zi = ZoneInfoFile.getZoneInfoOld(ID);670if (zi == null) {671// if we can't create an object for the ID, try aliases.672try {673Map<String, String> map = getAliasTable();674String alias = ID;675while ((alias = map.get(alias)) != null) {676zi = ZoneInfoFile.getZoneInfoOld(alias);677if (zi != null) {678zi.setID(ID);679zi = ZoneInfoFile.addToCache(ID, zi);680zi = (ZoneInfoOld) zi.clone();681break;682}683}684} catch (Exception e) {685// ignore exceptions686}687}688689if (givenID != null && zi != null) {690zi.setID(givenID);691}692return zi;693}694695private transient SimpleTimeZone lastRule;696697/**698* Returns a SimpleTimeZone object representing the last GMT699* offset and DST schedule or null if this time zone doesn't700* observe DST.701*/702synchronized SimpleTimeZone getLastRule() {703if (lastRule == null) {704lastRule = getLastRuleInstance();705}706return lastRule;707}708709/**710* Returns a SimpleTimeZone object that represents the last711* known daylight saving time rules.712*713* @return a SimpleTimeZone object or null if this time zone714* doesn't observe DST.715*/716public SimpleTimeZone getLastRuleInstance() {717if (simpleTimeZoneParams == null) {718return null;719}720if (simpleTimeZoneParams.length == 10) {721return new SimpleTimeZone(getLastRawOffset(), getID(),722simpleTimeZoneParams[0],723simpleTimeZoneParams[1],724simpleTimeZoneParams[2],725simpleTimeZoneParams[3],726simpleTimeZoneParams[4],727simpleTimeZoneParams[5],728simpleTimeZoneParams[6],729simpleTimeZoneParams[7],730simpleTimeZoneParams[8],731simpleTimeZoneParams[9],732dstSavings);733}734return new SimpleTimeZone(getLastRawOffset(), getID(),735simpleTimeZoneParams[0],736simpleTimeZoneParams[1],737simpleTimeZoneParams[2],738simpleTimeZoneParams[3],739simpleTimeZoneParams[4],740simpleTimeZoneParams[5],741simpleTimeZoneParams[6],742simpleTimeZoneParams[7],743dstSavings);744}745746/**747* Returns a copy of this <code>ZoneInfoOld</code>.748*/749public Object clone() {750ZoneInfoOld zi = (ZoneInfoOld) super.clone();751zi.lastRule = null;752return zi;753}754755/**756* Returns a hash code value calculated from the GMT offset and757* transitions.758* @return a hash code of this time zone759*/760public int hashCode() {761return getLastRawOffset() ^ checksum;762}763764/**765* Compares the equity of two ZoneInfoOld objects.766*767* @param obj the object to be compared with768* @return true if given object is same as this ZoneInfoOld object,769* false otherwise.770*/771public boolean equals(Object obj) {772if (this == obj) {773return true;774}775if (!(obj instanceof ZoneInfoOld)) {776return false;777}778ZoneInfoOld that = (ZoneInfoOld) obj;779return (getID().equals(that.getID())780&& (getLastRawOffset() == that.getLastRawOffset())781&& (checksum == that.checksum));782}783784/**785* Returns true if this zone has the same raw GMT offset value and786* transition table as another zone info. If the specified787* TimeZone object is not a ZoneInfoOld instance, this method returns788* true if the specified TimeZone object has the same raw GMT789* offset value with no daylight saving time.790*791* @param other the ZoneInfoOld object to be compared with792* @return true if the given <code>TimeZone</code> has the same793* GMT offset and transition information; false, otherwise.794*/795public boolean hasSameRules(TimeZone other) {796if (this == other) {797return true;798}799if (other == null) {800return false;801}802if (!(other instanceof ZoneInfoOld)) {803if (getRawOffset() != other.getRawOffset()) {804return false;805}806// if both have the same raw offset and neither observes807// DST, they have the same rule.808if ((transitions == null)809&& (useDaylightTime() == false)810&& (other.useDaylightTime() == false)) {811return true;812}813return false;814}815if (getLastRawOffset() != ((ZoneInfoOld)other).getLastRawOffset()) {816return false;817}818return (checksum == ((ZoneInfoOld)other).checksum);819}820821private static SoftReference<Map<String, String>> aliasTable;822823static Map<String, String> getCachedAliasTable() {824Map<String, String> aliases = null;825826SoftReference<Map<String, String>> cache = aliasTable;827if (cache != null) {828aliases = cache.get();829}830return aliases;831}832833/**834* Returns a Map from alias time zone IDs to their standard835* time zone IDs.836*837* @return the Map that holds the mappings from alias time zone IDs838* to their standard time zone IDs, or null if839* <code>ZoneInfoOldMappings</code> file is not available.840*/841public synchronized static Map<String, String> getAliasTable() {842Map<String, String> aliases = getCachedAliasTable();843if (aliases == null) {844aliases = ZoneInfoFile.getZoneAliases();845if (aliases != null) {846if (!USE_OLDMAPPING) {847// Remove the conflicting IDs from the alias table.848for (String key : conflictingIDs) {849aliases.remove(key);850}851}852aliasTable = new SoftReference<Map<String, String>>(aliases);853}854}855return aliases;856}857858private void readObject(ObjectInputStream stream)859throws IOException, ClassNotFoundException {860stream.defaultReadObject();861// We don't know how this object from 1.4.x or earlier has862// been mutated. So it should always be marked as `dirty'.863dirty = true;864}865866//////////////////////////////////////////////////////////////867public boolean equalsTo(ZoneInfoOld other) {868return (getID().equals(other.getID())869&& (getLastRawOffset() == other.getLastRawOffset())870&& (dstSavings == other.dstSavings)871&& (willGMTOffsetChange == other.willGMTOffsetChange)872&& (checksum == other.checksum)873&& equalsTransOffsets(other)874&& (Arrays.equals(simpleTimeZoneParams, other.simpleTimeZoneParams) ||875getLastRule().equals(other.getLastRule())));876}877878private boolean equalsTransOffsets(ZoneInfoOld other) {879if (transitions == null) {880return (other.transitions == null &&881Arrays.equals(offsets, other.offsets));882}883if (other.transitions == null ||884transitions.length != other.transitions.length) {885return false;886}887// if offsets and other.offsets have different order888// the last 4-bit in trans are different.889for (int i = 0; i < transitions.length; i++) {890long val = transitions[i];891int dst = (int)((val >>> DST_NSHIFT) & 0xfL);892int save = (dst == 0) ? 0 : offsets[dst] / 1000;893int off = offsets[(int)(val & OFFSET_MASK)]/1000;894long second = (val >> TRANSITION_NSHIFT)/1000;895896val = other.transitions[i];897int dstO = (int)((val >>> DST_NSHIFT) & 0xfL);898int saveO = (dstO == 0) ? 0 : other.offsets[dstO] / 1000;899int offO = other.offsets[(int)(val & OFFSET_MASK)]/1000;900long secondO = (val >> TRANSITION_NSHIFT)/1000;901if ((dst == 0) != (dstO == 0) || save != saveO || off != offO || second != secondO)902return false;903}904return true;905}906907private int transToString(long val, int off_old, int[] offsets, StringBuilder sb) {908int dst = (int)((val >>> DST_NSHIFT) & 0xfL);909int save = (dst == 0) ? 0 : offsets[dst] / 1000;910int off = offsets[(int)(val & OFFSET_MASK)]/1000;911long second = (val >> TRANSITION_NSHIFT)/1000;912ZoneOffset offset_old = ZoneOffset.ofTotalSeconds(off_old);913ZoneOffset offset = ZoneOffset.ofTotalSeconds(off);914sb.append(" " + LocalDateTime.ofEpochSecond(second, 0, offset_old));915916sb.append(" [utc=" + second +917" raw=" + Long.toHexString(val >> TRANSITION_NSHIFT) +918", offset=" + off + "/" + offset + ", saving=" + save + "]");919return off;920}921922public String diffsTo(ZoneInfoOld other) {923924int rawOffset0 = other.rawOffset;925int checksum0 = other.checksum;926int dstSavings0 = other.dstSavings;927long[] transitions0 = other.transitions;928int[] offsets0 = other.offsets;929int[] simpleTimeZoneParams0 = other.simpleTimeZoneParams;930boolean willGMTOffsetChange0 = other.willGMTOffsetChange;931932933//return getClass().getName() +934StringBuilder sb = new StringBuilder();935sb.append("******************************\n" +936getID() + " : " + other.getID());937// ROC is excluded by ZoneInfoOld938if ("ROC".equals(getID())) {939return sb.toString();940}941if (rawOffset != rawOffset0 ||942dstSavings != dstSavings0 ||943checksum != checksum0 ||944willGMTOffsetChange != willGMTOffsetChange0 ||945(simpleTimeZoneParams != null ) != (simpleTimeZoneParams0 != null) ||946(transitions != null && transitions0 != null &&947transitions.length != transitions0.length))948{949sb.append("\n offset=" + getLastRawOffset() +950",dstSavings=" + dstSavings +951",useDaylight=" + useDaylightTime() +952",transitions=" + ((transitions != null) ? transitions.length : 0) +953",offsets=" + ((offsets != null) ? offsets.length : 0) +954",checksum=" + checksum +955",gmtChanged=" + willGMTOffsetChange)956.append("\n[NG]offset=" + rawOffset0 +957",dstSavings=" + dstSavings0 +958",useDaylight=" + (simpleTimeZoneParams != null) +959",transitions=" + ((transitions0 != null) ? transitions0.length : 0) +960",offsets=" + ((offsets0 != null) ? offsets0.length : 0) +961",checksum=" + checksum0 +962",gmtChanged=" + willGMTOffsetChange0 +963"");964}965// offsets966if (!Arrays.equals(offsets, offsets0)) {967sb.append("\n offset.len=" + ((offsets != null)? offsets.length : "null") +968" " + ((offsets0 != null)? offsets0.length : "null"));969if (offsets != null && offsets0.length != 0) {970int len = Math.min(offsets.length, offsets0.length);971int i = 0;972for (i = 0; i < len; i++) {973sb.append("\n " +974ZoneOffset.ofTotalSeconds(offsets[i]/1000) + " " +975ZoneOffset.ofTotalSeconds(offsets0[i]/1000));976}977for (; i < offsets0.length; i++) {978sb.append("\n " + ZoneOffset.ofTotalSeconds(offsets0[i]/1000));979}980}981}982// trans983int offset = 0;984int offset0 = 0;985if (!equalsTransOffsets(other)) {986sb.append("\n -------------");987if ((transitions == null) != (transitions0 == null)) {988sb.append("\n (NG) Different trans(null) :" +989transitions + ", " + transitions0);990if (transitions != null) {991for (int i = 0; i < transitions.length; i++) {992sb.append("\n (NG)");993offset = transToString(transitions[i], offset, offsets, sb);994}995}996} else {997if (transitions.length != transitions0.length) {998sb.append("\n (NG) Different trans size :" +999transitions.length + ", " + transitions0.length);1000}1001int length = Math.min(transitions.length, transitions0.length);1002for (int i = 0; i < length; i++) {1003// sb.append("\n[" + i + "] ");1004// offset = transToString(transitions[i], offset, offsets, sb);1005long val = transitions[i];1006int dst = (int)((val >>> DST_NSHIFT) & 0xfL);1007int save = (dst == 0) ? 0 : offsets[dst] / 1000;1008int off = offsets[(int)(val & OFFSET_MASK)]/1000;1009long second = (val >> TRANSITION_NSHIFT)/1000;1010sb.append("\n ");1011offset = transToString(transitions[i], offset, offsets, sb);1012if (transitions0 == null || i >= transitions0.length) {1013sb.append("\n ");1014offset = transToString(transitions[i], offset, offsets, sb);1015sb.append("\n (NG) trans0 is null or < trans.length");1016} else {1017long val0 = transitions0[i];1018int dst0 = (int)((val0 >>> DST_NSHIFT) & 0xfL);1019int save0 = (dst0 == 0) ? 0 : offsets0[dst0] / 1000;1020int off0 = offsets0[(int)(val0 & OFFSET_MASK)]/1000;1021long second0 = (val0 >> TRANSITION_NSHIFT)/1000;1022if (save != save0 || off != off0 || second != second0) {1023sb.append("\n (NG)");1024} else {1025sb.append("\n (OK)");1026}1027offset0 = transToString(transitions0[i], offset0, offsets0, sb);1028sb.append("\n -----");1029}1030}1031}1032}1033SimpleTimeZone stz = getLastRuleInstance();1034if (stz != null) {1035SimpleTimeZone stz0 = other.getLastRule();1036if (!stz.hasSameRules(stz0)) {1037sb.append("\n -------------")1038.append("\n SimpleTimeZone (NG)")1039.append("\n stz=" + stz)1040.append("\n stz0=" + stz0);1041}1042}1043sb.append("\n -------------");1044return sb.toString();1045}1046}104710481049