Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/sun/util/calendar/zi/Zoneinfo.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.BufferedReader;26import java.io.FileReader;27import java.io.FileNotFoundException;28import java.io.IOException;29import java.util.HashMap;30import java.util.List;31import java.util.Map;32import java.util.StringTokenizer;3334/**35* Zoneinfo provides javazic compiler front-end functionality.36* @since 1.437*/38class Zoneinfo {3940private static final int minYear = 1900;41private static final int maxYear = 2037;42private static final long minTime = Time.getLocalTime(minYear, Month.JANUARY, 1, 0);43private static int startYear = minYear;44private static int endYear = maxYear;4546/**47* True if javazic should generate a list of SimpleTimeZone48* instances for the SimpleTimeZone-based time zone support.49*/50static boolean isYearForTimeZoneDataSpecified = false;5152/**53* Zone name to Zone mappings54*/55private Map<String,Zone> zones;5657/**58* Rule name to Rule mappings59*/60private Map<String,Rule> rules;6162/**63* Alias name to real name mappings64*/65private Map<String,String> aliases;6667/**68* Constracts a Zoneinfo.69*/70Zoneinfo() {71zones = new HashMap<String,Zone>();72rules = new HashMap<String,Rule>();73aliases = new HashMap<String,String>();74}7576/**77* Adds the given zone to the list of Zones.78* @param zone Zone to be added to the list.79*/80void add(Zone zone) {81String name = zone.getName();82zones.put(name, zone);83}8485/**86* Adds the given rule to the list of Rules.87* @param rule Rule to be added to the list.88*/89void add(Rule rule) {90String name = rule.getName();91rules.put(name, rule);92}9394/**95* Puts the specifid name pair to the alias table.96* @param name1 an alias time zone name97* @param name2 the real time zone of the alias name98*/99void putAlias(String name1, String name2) {100aliases.put(name1, name2);101}102103/**104* Sets the given year for SimpleTimeZone list output.105* This method is called when the -S option is specified.106* @param year the year for which SimpleTimeZone list should be generated107*/108static void setYear(int year) {109setStartYear(year);110setEndYear(year);111isYearForTimeZoneDataSpecified = true;112}113114/**115* Sets the start year.116* @param year the start year value117* @throws IllegalArgumentException if the specified year value is118* smaller than the minimum year or greater than the end year.119*/120static void setStartYear(int year) {121if (year < minYear || year > endYear) {122throw new IllegalArgumentException("invalid start year specified: " + year);123}124startYear = year;125}126127/**128* @return the start year value129*/130static int getStartYear() {131return startYear;132}133134/**135* Sets the end year.136* @param year the end year value137* @throws IllegalArgumentException if the specified year value is138* smaller than the start year or greater than the maximum year.139*/140static void setEndYear(int year) {141if (year < startYear || year > maxYear) {142throw new IllegalArgumentException();143}144endYear = year;145}146147/**148* @return the end year value149*/150static int getEndYear() {151return endYear;152}153154/**155* @return the minimum year value156*/157static int getMinYear() {158return minYear;159}160161/**162* @return the maximum year value163*/164static int getMaxYear() {165return maxYear;166}167168/**169* @return the alias table170*/171Map<String,String> getAliases() {172return aliases;173}174175/**176* @return the Zone list177*/178Map<String,Zone> getZones() {179return zones;180}181182/**183* @return a Zone specified by name.184* @param name a zone name185*/186Zone getZone(String name) {187return zones.get(name);188}189190/**191* @return a Rule specified by name.192* @param name a rule name193*/194Rule getRule(String name) {195return rules.get(name);196}197198private static String line;199200private static int lineNum;201202/**203* Parses the specified time zone data file and creates a Zoneinfo204* that has all Rules, Zones and Links (aliases) information.205* @param fname the time zone data file name206* @return a Zoneinfo object207*/208static Zoneinfo parse(String fname) {209BufferedReader in = null;210try {211FileReader fr = new FileReader(fname);212in = new BufferedReader(fr);213} catch (FileNotFoundException e) {214panic("can't open file: "+fname);215}216Zoneinfo zi = new Zoneinfo();217boolean continued = false;218Zone zone = null;219String l;220lineNum = 0;221222try {223while ((line = in.readLine()) != null) {224lineNum++;225// skip blank and comment lines226if (line.length() == 0 || line.charAt(0) == '#') {227continue;228}229230// trim trailing comments231int rindex = line.lastIndexOf('#');232if (rindex != -1) {233// take the data part of the line234l = line.substring(0, rindex);235} else {236l = line;237}238239StringTokenizer tokens = new StringTokenizer(l);240if (!tokens.hasMoreTokens()) {241continue;242}243String token = tokens.nextToken();244245if (continued || "Zone".equals(token)) {246if (zone == null) {247if (!tokens.hasMoreTokens()) {248panic("syntax error: zone no more token");249}250token = tokens.nextToken();251// if the zone name is in "GMT+hh" or "GMT-hh"252// format, ignore it due to spec conflict.253if (token.startsWith("GMT+") || token.startsWith("GMT-")) {254continue;255}256zone = new Zone(token);257} else {258// no way to push the current token back...259tokens = new StringTokenizer(l);260}261262ZoneRec zrec = ZoneRec.parse(tokens);263zrec.setLine(line);264zone.add(zrec);265if ((continued = zrec.hasUntil()) == false) {266if (Zone.isTargetZone(zone.getName())) {267// zone.resolve(zi);268zi.add(zone);269}270zone = null;271}272} else if ("Rule".equals(token)) {273if (!tokens.hasMoreTokens()) {274panic("syntax error: rule no more token");275}276token = tokens.nextToken();277Rule rule = zi.getRule(token);278if (rule == null) {279rule = new Rule(token);280zi.add(rule);281}282RuleRec rrec = RuleRec.parse(tokens);283rrec.setLine(line);284rule.add(rrec);285} else if ("Link".equals(token)) {286// Link <newname> <oldname>287try {288String name1 = tokens.nextToken();289String name2 = tokens.nextToken();290291// if the zone name is in "GMT+hh" or "GMT-hh"292// format, ignore it due to spec conflict with293// custom time zones. Also, ignore "ROC" for294// PC-ness.295if (name2.startsWith("GMT+") || name2.startsWith("GMT-")296|| "ROC".equals(name2)) {297continue;298}299zi.putAlias(name2, name1);300} catch (Exception e) {301panic("syntax error: no more token for Link");302}303}304}305in.close();306} catch (IOException ex) {307panic("IO error: " + ex.getMessage());308}309310return zi;311}312313/**314* Interprets a zone and constructs a Timezone object that315* contains enough information on GMT offsets and DST schedules to316* generate a zone info database.317*318* @param zoneName the zone name for which a Timezone object is319* constructed.320*321* @return a Timezone object that contains all GMT offsets and DST322* rules information.323*/324Timezone phase2(String zoneName) {325Timezone tz = new Timezone(zoneName);326Zone zone = getZone(zoneName);327zone.resolve(this);328329// TODO: merge phase2's for the regular and SimpleTimeZone ones.330if (isYearForTimeZoneDataSpecified) {331ZoneRec zrec = zone.get(zone.size()-1);332tz.setLastZoneRec(zrec);333tz.setRawOffset(zrec.getGmtOffset());334if (zrec.hasRuleReference()) {335/*336* This part assumes that the specified year is covered by337* the rules referred to by the last zone record.338*/339List<RuleRec> rrecs = zrec.getRuleRef().getRules(startYear);340341if (rrecs.size() == 2) {342// make sure that one is a start rule and the other is343// an end rule.344RuleRec r0 = rrecs.get(0);345RuleRec r1 = rrecs.get(1);346if (r0.getSave() == 0 && r1.getSave() > 0) {347rrecs.set(0, r1);348rrecs.set(1, r0);349} else if (!(r0.getSave() > 0 && r1.getSave() == 0)) {350rrecs = null;351Main.error(zoneName + ": rules for " + startYear + " not found.");352}353} else {354rrecs = null;355}356if (rrecs != null) {357tz.setLastRules(rrecs);358}359}360return tz;361}362363int gmtOffset;364int year = minYear;365int fromYear = year;366long fromTime = Time.getLocalTime(startYear,367Month.JANUARY,3681, 0);369370// take the index 0 for the GMT offset of the last zone record371ZoneRec zrec = zone.get(zone.size()-1);372tz.getOffsetIndex(zrec.getGmtOffset());373374int lastGmtOffsetValue = -1;375ZoneRec prevzrec = null;376int currentSave = 0;377boolean usedZone;378for (int zindex = 0; zindex < zone.size(); zindex++) {379zrec = zone.get(zindex);380usedZone = false;381gmtOffset = zrec.getGmtOffset();382int stdOffset = zrec.getDirectSave();383384if (gmtOffset != lastGmtOffsetValue) {385tz.setRawOffset(gmtOffset, fromTime);386lastGmtOffsetValue = gmtOffset;387}388// If this is the last zone record, take the last rule info.389if (!zrec.hasUntil()) {390if (zrec.hasRuleReference()) {391tz.setLastRules(zrec.getRuleRef().getLastRules());392} else if (stdOffset != 0) {393// in case the last rule is all year round DST-only394// (Asia/Amman once announced this rule.)395tz.setLastDSTSaving(stdOffset);396}397}398if (!zrec.hasRuleReference()) {399if (!zrec.hasUntil() || zrec.getUntilTime(stdOffset) >= fromTime) {400tz.addTransition(fromTime,401tz.getOffsetIndex(gmtOffset+stdOffset),402tz.getDstOffsetIndex(stdOffset));403usedZone = true;404}405currentSave = stdOffset;406// optimization in case the last rule is fixed.407if (!zrec.hasUntil()) {408if (tz.getNTransitions() > 0) {409if (stdOffset == 0) {410tz.setDSTType(Timezone.X_DST);411} else {412tz.setDSTType(Timezone.LAST_DST);413}414long time = Time.getLocalTime(maxYear,415Month.JANUARY, 1, 0);416time -= zrec.getGmtOffset();417tz.addTransition(time,418tz.getOffsetIndex(gmtOffset+stdOffset),419tz.getDstOffsetIndex(stdOffset));420tz.addUsedRec(zrec);421} else {422tz.setDSTType(Timezone.NO_DST);423}424break;425}426} else {427Rule rule = zrec.getRuleRef();428boolean fromTimeUsed = false;429currentSave = 0;430year_loop:431for (year = getMinYear(); year <= endYear; year++) {432if (zrec.hasUntil() && year > zrec.getUntilYear()) {433break;434}435List<RuleRec> rules = rule.getRules(year);436if (rules.size() > 0) {437for (int i = 0; i < rules.size(); i++) {438RuleRec rrec = rules.get(i);439long transition = rrec.getTransitionTime(year,440gmtOffset,441currentSave);442if (zrec.hasUntil()) {443if (transition >= zrec.getUntilTime(currentSave)) {444// If the GMT offset changed from the previous one,445// record fromTime as a transition.446if (!fromTimeUsed && prevzrec != null447&& gmtOffset != prevzrec.getGmtOffset()) {448tz.addTransition(fromTime,449tz.getOffsetIndex(gmtOffset+currentSave),450tz.getDstOffsetIndex(currentSave));451fromTimeUsed = true; // for consistency452}453break year_loop;454}455}456457if (fromTimeUsed == false) {458if (fromTime <= transition) {459fromTimeUsed = true;460461if (fromTime != minTime) {462int prevsave;463464// See if until time in the previous465// ZoneRec is the same thing as the466// local time in the next rule.467// (examples are Asia/Ashkhabad in 1991,468// Europe/Riga in 1989)469470if (i > 0) {471prevsave = rules.get(i-1).getSave();472} else {473List<RuleRec> prevrules = rule.getRules(year-1);474475if (prevrules.size() > 0) {476prevsave = prevrules.get(prevrules.size()-1).getSave();477} else {478prevsave = 0;479}480}481482if (rrec.isSameTransition(prevzrec, prevsave, gmtOffset)) {483currentSave = rrec.getSave();484tz.addTransition(fromTime,485tz.getOffsetIndex(gmtOffset+currentSave),486tz.getDstOffsetIndex(currentSave));487tz.addUsedRec(rrec);488usedZone = true;489continue;490}491if (!prevzrec.hasRuleReference()492|| rule != prevzrec.getRuleRef()493|| (rule == prevzrec.getRuleRef()494&& gmtOffset != prevzrec.getGmtOffset())) {495int save = (fromTime == transition) ? rrec.getSave() : currentSave;496tz.addTransition(fromTime,497tz.getOffsetIndex(gmtOffset+save),498tz.getDstOffsetIndex(save));499tz.addUsedRec(rrec);500usedZone = true;501}502} else { // fromTime == minTime503int save = rrec.getSave();504tz.addTransition(minTime,505tz.getOffsetIndex(gmtOffset),506tz.getDstOffsetIndex(0));507508tz.addTransition(transition,509tz.getOffsetIndex(gmtOffset+save),510tz.getDstOffsetIndex(save));511512tz.addUsedRec(rrec);513usedZone = true;514}515} else if (year == fromYear && i == rules.size()-1) {516int save = rrec.getSave();517tz.addTransition(fromTime,518tz.getOffsetIndex(gmtOffset+save),519tz.getDstOffsetIndex(save));520}521}522523currentSave = rrec.getSave();524if (fromTime < transition) {525tz.addTransition(transition,526tz.getOffsetIndex(gmtOffset+currentSave),527tz.getDstOffsetIndex(currentSave));528tz.addUsedRec(rrec);529usedZone = true;530}531}532} else {533if (year == fromYear) {534tz.addTransition(fromTime,535tz.getOffsetIndex(gmtOffset+currentSave),536tz.getDstOffsetIndex(currentSave));537fromTimeUsed = true;538}539if (year == endYear && !zrec.hasUntil()) {540if (tz.getNTransitions() > 0) {541// Assume that this Zone stopped DST542tz.setDSTType(Timezone.X_DST);543long time = Time.getLocalTime(maxYear, Month.JANUARY,5441, 0);545time -= zrec.getGmtOffset();546tz.addTransition(time,547tz.getOffsetIndex(gmtOffset),548tz.getDstOffsetIndex(0));549usedZone = true;550} else {551tz.setDSTType(Timezone.NO_DST);552}553}554}555}556}557if (usedZone) {558tz.addUsedRec(zrec);559}560if (zrec.hasUntil() && zrec.getUntilTime(currentSave) > fromTime) {561fromTime = zrec.getUntilTime(currentSave);562fromYear = zrec.getUntilYear();563year = zrec.getUntilYear();564}565prevzrec = zrec;566}567568if (tz.getDSTType() == Timezone.UNDEF_DST) {569tz.setDSTType(Timezone.DST);570}571tz.optimize();572tz.checksum();573return tz;574}575576private static void panic(String msg) {577Main.panic(msg);578}579}580581582