summaryrefslogtreecommitdiff
path: root/libjava/classpath/gnu/java/util/ZoneInfo.java
diff options
context:
space:
mode:
authorAndrew Haley <aph@redhat.com>2016-09-30 16:24:48 +0000
committerAndrew Haley <aph@gcc.gnu.org>2016-09-30 16:24:48 +0000
commit07b78716af6a9d7c9fd1e94d9baf94a52c873947 (patch)
tree3f22b3241c513ad168c8353805614ae1249410f4 /libjava/classpath/gnu/java/util/ZoneInfo.java
parenteae993948bae8b788c53772bcb9217c063716f93 (diff)
Makefile.def: Remove libjava.
2016-09-30 Andrew Haley <aph@redhat.com> * Makefile.def: Remove libjava. * Makefile.tpl: Likewise. * Makefile.in: Regenerate. * configure.ac: Likewise. * configure: Likewise. * gcc/java: Remove. * libjava: Likewise. From-SVN: r240662
Diffstat (limited to 'libjava/classpath/gnu/java/util/ZoneInfo.java')
-rw-r--r--libjava/classpath/gnu/java/util/ZoneInfo.java1160
1 files changed, 0 insertions, 1160 deletions
diff --git a/libjava/classpath/gnu/java/util/ZoneInfo.java b/libjava/classpath/gnu/java/util/ZoneInfo.java
deleted file mode 100644
index 117ef3cf25b..00000000000
--- a/libjava/classpath/gnu/java/util/ZoneInfo.java
+++ /dev/null
@@ -1,1160 +0,0 @@
-/* gnu.java.util.ZoneInfo
- Copyright (C) 2007 Free Software Foundation, Inc.
-
-This file is part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; see the file COPYING. If not, write to the
-Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301 USA.
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.java.util;
-
-import java.io.BufferedInputStream;
-import java.io.DataInputStream;
-import java.io.EOFException;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.SimpleTimeZone;
-import java.util.TimeZone;
-
-/**
- * This class represents more advanced variant of java.util.SimpleTimeZone.
- * It can handle zic(8) compiled transition dates plus uses a SimpleTimeZone
- * for years beyond last precomputed transition. Before first precomputed
- * transition it assumes no daylight saving was in effect.
- * Timezones that never used daylight saving time should use just
- * SimpleTimeZone instead of this class.
- *
- * This object is tightly bound to the Gregorian calendar. It assumes
- * a regular seven days week, and the month lengths are that of the
- * Gregorian Calendar.
- *
- * @see Calendar
- * @see GregorianCalendar
- * @see SimpleTimeZone
- * @author Jakub Jelinek
- */
-public class ZoneInfo extends TimeZone
-{
- private static final int SECS_SHIFT = 22;
- private static final long OFFSET_MASK = (1 << 21) - 1;
- private static final int OFFSET_SHIFT = 64 - 21;
- private static final long IS_DST = 1 << 21;
-
- /**
- * The raw time zone offset in milliseconds to GMT, ignoring
- * daylight savings.
- * @serial
- */
- private int rawOffset;
-
- /**
- * Cached DST savings for the last transition rule.
- */
- private int dstSavings;
-
- /**
- * Cached flag whether last transition rule uses DST saving.
- */
- private boolean useDaylight;
-
- /**
- * Array of encoded transitions.
- * Transition time in UTC seconds since epoch is in the most
- * significant 64 - SECS_SHIFT bits, then one bit flag
- * whether DST is active and the least significant bits
- * containing offset relative to rawOffset. Both the DST
- * flag and relative offset apply to time before the transition
- * and after or equal to previous transition if any.
- * The array must be sorted.
- */
- private long[] transitions;
-
- /**
- * SimpleTimeZone rule which applies on or after the latest
- * transition. If the DST changes are not expresible as a
- * SimpleTimeZone rule, then the rule should just contain
- * the standard time and no DST time.
- */
- private SimpleTimeZone lastRule;
-
- /**
- * Cached GMT SimpleTimeZone object for internal use in
- * getOffset method.
- */
- private static SimpleTimeZone gmtZone = null;
-
- static final long serialVersionUID = -3740626706860383657L;
-
- /**
- * Create a <code>ZoneInfo</code> with the given time offset
- * from GMT and with daylight savings.
- *
- * @param rawOffset The time offset from GMT in milliseconds.
- * @param id The identifier of this time zone.
- * @param transitions Array of transition times in UTC seconds since
- * Epoch in topmost 42 bits, below that 1 boolean bit whether the time
- * before that transition used daylight saving and in bottommost 21
- * bits relative daylight saving offset against rawOffset in seconds
- * that applies before this transition.
- * @param endRule SimpleTimeZone class describing the daylight saving
- * rules after the last transition.
- */
- public ZoneInfo(int rawOffset, String id, long[] transitions,
- SimpleTimeZone lastRule)
- {
- if (transitions == null || transitions.length < 1)
- throw new IllegalArgumentException("transitions must not be null");
- if (lastRule == null)
- throw new IllegalArgumentException("lastRule must not be null");
- this.rawOffset = rawOffset;
- this.transitions = transitions;
- this.lastRule = lastRule;
- setID(id);
- computeDSTSavings();
- }
-
- /**
- * Gets the time zone offset, for current date, modified in case of
- * daylight savings. This is the offset to add to UTC to get the local
- * time.
- *
- * The day must be a positive number and dayOfWeek must be a positive value
- * from Calendar. dayOfWeek is redundant, but must match the other values
- * or an inaccurate result may be returned.
- *
- * @param era the era of the given date
- * @param year the year of the given date
- * @param month the month of the given date, 0 for January.
- * @param day the day of month
- * @param dayOfWeek the day of week; this must match the other fields.
- * @param millis the millis in the day (in local standard time)
- * @return the time zone offset in milliseconds.
- * @throws IllegalArgumentException if arguments are incorrect.
- */
- public int getOffset(int era, int year, int month, int day, int dayOfWeek,
- int millis)
- {
- if (gmtZone == null)
- gmtZone = new SimpleTimeZone(0, "GMT");
-
- if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
- throw new IllegalArgumentException("dayOfWeek out of range");
- if (month < Calendar.JANUARY || month > Calendar.DECEMBER)
- throw new IllegalArgumentException("month out of range:" + month);
-
- if (era != GregorianCalendar.AD)
- return (int) (((transitions[0] << OFFSET_SHIFT) >> OFFSET_SHIFT) * 1000);
-
- GregorianCalendar cal = new GregorianCalendar((TimeZone) gmtZone);
- cal.set(year, month, day, 0, 0, 0);
- if (cal.get(Calendar.DAY_OF_MONTH) != day)
- throw new IllegalArgumentException("day out of range");
-
- return getOffset(cal.getTimeInMillis() - rawOffset + millis);
- }
-
- private long findTransition(long secs)
- {
- if (secs < (transitions[0] >> SECS_SHIFT))
- return transitions[0];
-
- if (secs >= (transitions[transitions.length-1] >> SECS_SHIFT))
- return Long.MAX_VALUE;
-
- long val = (secs + 1) << SECS_SHIFT;
- int lo = 1;
- int hi = transitions.length;
- int mid = 1;
- while (lo < hi)
- {
- mid = (lo + hi) / 2;
- // secs < (transitions[mid-1] >> SECS_SHIFT)
- if (val <= transitions[mid-1])
- hi = mid;
- // secs >= (transitions[mid] >> SECS_SHIFT)
- else if (val > transitions[mid])
- lo = mid + 1;
- else
- break;
- }
- return transitions[mid];
- }
-
- /**
- * Get the time zone offset for the specified date, modified in case of
- * daylight savings. This is the offset to add to UTC to get the local
- * time.
- * @param date the date represented in millisecends
- * since January 1, 1970 00:00:00 GMT.
- */
- public int getOffset(long date)
- {
- long d = (date >= 0 ? date / 1000 : (date + 1) / 1000 - 1);
- long transition = findTransition(d);
-
- // For times on or after last transition use lastRule.
- if (transition == Long.MAX_VALUE)
- return lastRule.getOffset(date);
-
- return (int) (((transition << OFFSET_SHIFT) >> OFFSET_SHIFT) * 1000);
- }
-
- /**
- * Returns the time zone offset to GMT in milliseconds, ignoring
- * day light savings.
- * @return the time zone offset.
- */
- public int getRawOffset()
- {
- return rawOffset;
- }
-
- /**
- * Sets the standard time zone offset to GMT.
- * @param rawOffset The time offset from GMT in milliseconds.
- */
- public void setRawOffset(int rawOffset)
- {
- this.rawOffset = rawOffset;
- lastRule.setRawOffset(rawOffset);
- }
-
- private void computeDSTSavings()
- {
- if (lastRule.useDaylightTime())
- {
- dstSavings = lastRule.getDSTSavings();
- useDaylight = true;
- }
- else
- {
- dstSavings = 0;
- useDaylight = false;
- // lastRule might say no DST is in effect simply because
- // the DST rules are too complex for SimpleTimeZone, say
- // for Asia/Jerusalem.
- // Look at the last DST offset if it is newer than current time.
- long currentSecs = System.currentTimeMillis() / 1000;
- int i;
- for (i = transitions.length - 1;
- i >= 0 && currentSecs < (transitions[i] >> SECS_SHIFT);
- i--)
- if ((transitions[i] & IS_DST) != 0)
- {
- dstSavings = (int) (((transitions[i] << OFFSET_SHIFT)
- >> OFFSET_SHIFT) * 1000)
- - rawOffset;
- useDaylight = true;
- break;
- }
- }
- }
-
- /**
- * Gets the daylight savings offset. This is a positive offset in
- * milliseconds with respect to standard time. Typically this
- * is one hour, but for some time zones this may be half an our.
- * @return the daylight savings offset in milliseconds.
- */
- public int getDSTSavings()
- {
- return dstSavings;
- }
-
- /**
- * Returns if this time zone uses daylight savings time.
- * @return true, if we use daylight savings time, false otherwise.
- */
- public boolean useDaylightTime()
- {
- return useDaylight;
- }
-
- /**
- * Determines if the given date is in daylight savings time.
- * @return true, if it is in daylight savings time, false otherwise.
- */
- public boolean inDaylightTime(Date date)
- {
- long d = date.getTime();
- d = (d >= 0 ? d / 1000 : (d + 1) / 1000 - 1);
- long transition = findTransition(d);
-
- // For times on or after last transition use lastRule.
- if (transition == Long.MAX_VALUE)
- return lastRule.inDaylightTime(date);
-
- return (transition & IS_DST) != 0;
- }
-
- /**
- * Generates the hashCode for the SimpleDateFormat object. It is
- * the rawOffset, possibly, if useDaylightSavings is true, xored
- * with startYear, startMonth, startDayOfWeekInMonth, ..., endTime.
- */
- public synchronized int hashCode()
- {
- int hash = lastRule.hashCode();
- // FIXME - hash transitions?
- return hash;
- }
-
- public synchronized boolean equals(Object o)
- {
- if (! hasSameRules((TimeZone) o))
- return false;
-
- ZoneInfo zone = (ZoneInfo) o;
- return getID().equals(zone.getID());
- }
-
- /**
- * Test if the other time zone uses the same rule and only
- * possibly differs in ID. This implementation for this particular
- * class will return true if the other object is a ZoneInfo,
- * the raw offsets and useDaylight are identical and if useDaylight
- * is true, also the start and end datas are identical.
- * @return true if this zone uses the same rule.
- */
- public boolean hasSameRules(TimeZone o)
- {
- if (this == o)
- return true;
- if (! (o instanceof ZoneInfo))
- return false;
- ZoneInfo zone = (ZoneInfo) o;
- if (zone.hashCode() != hashCode() || rawOffset != zone.rawOffset)
- return false;
- if (! lastRule.equals(zone.lastRule))
- return false;
- // FIXME - compare transitions?
- return true;
- }
-
- /**
- * Returns a string representation of this ZoneInfo object.
- * @return a string representation of this ZoneInfo object.
- */
- public String toString()
- {
- return getClass().getName() + "[" + "id=" + getID() + ",offset="
- + rawOffset + ",transitions=" + transitions.length
- + ",useDaylight=" + useDaylight
- + (useDaylight ? (",dstSavings=" + dstSavings) : "")
- + ",lastRule=" + lastRule.toString() + "]";
- }
-
- /**
- * Reads zic(8) compiled timezone data file from file
- * and returns a TimeZone class describing it, either
- * SimpleTimeZone or ZoneInfo depending on whether
- * it can be described by SimpleTimeZone rule or not.
- */
- public static TimeZone readTZFile(String id, String file)
- {
- DataInputStream dis = null;
- try
- {
- FileInputStream fis = new FileInputStream(file);
- BufferedInputStream bis = new BufferedInputStream(fis);
- dis = new DataInputStream(bis);
-
- // Make sure we are reading a tzfile.
- byte[] tzif = new byte[5];
- dis.readFully(tzif);
- int tzif2 = 4;
- if (tzif[0] == 'T' && tzif[1] == 'Z'
- && tzif[2] == 'i' && tzif[3] == 'f')
- {
- if (tzif[4] >= '2')
- tzif2 = 8;
- // Reserved bytes
- skipFully(dis, 16 - 1);
- }
- else
- // Darwin has tzdata files that don't start with the TZif marker
- skipFully(dis, 16 - 5);
-
- int ttisgmtcnt = dis.readInt();
- int ttisstdcnt = dis.readInt();
- int leapcnt = dis.readInt();
- int timecnt = dis.readInt();
- int typecnt = dis.readInt();
- int charcnt = dis.readInt();
- if (tzif2 == 8)
- {
- skipFully(dis, timecnt * (4 + 1) + typecnt * (4 + 1 + 1) + charcnt
- + leapcnt * (4 + 4) + ttisgmtcnt + ttisstdcnt);
-
- dis.readFully(tzif);
- if (tzif[0] != 'T' || tzif[1] != 'Z' || tzif[2] != 'i'
- || tzif[3] != 'f' || tzif[4] < '2')
- return null;
-
- // Reserved bytes
- skipFully(dis, 16 - 1);
- ttisgmtcnt = dis.readInt();
- ttisstdcnt = dis.readInt();
- leapcnt = dis.readInt();
- timecnt = dis.readInt();
- typecnt = dis.readInt();
- charcnt = dis.readInt();
- }
-
- // Sanity checks
- if (typecnt <= 0 || timecnt < 0 || charcnt < 0
- || leapcnt < 0 || ttisgmtcnt < 0 || ttisstdcnt < 0
- || ttisgmtcnt > typecnt || ttisstdcnt > typecnt)
- return null;
-
- // Transition times
- long[] times = new long[timecnt];
- for (int i = 0; i < timecnt; i++)
- if (tzif2 == 8)
- times[i] = dis.readLong();
- else
- times[i] = (long) dis.readInt();
-
- // Transition types
- int[] types = new int[timecnt];
- for (int i = 0; i < timecnt; i++)
- {
- types[i] = dis.readByte();
- if (types[i] < 0)
- types[i] += 256;
- if (types[i] >= typecnt)
- return null;
- }
-
- // Types
- int[] offsets = new int[typecnt];
- int[] typeflags = new int[typecnt];
- for (int i = 0; i < typecnt; i++)
- {
- offsets[i] = dis.readInt();
- if (offsets[i] >= IS_DST / 2 || offsets[i] <= -IS_DST / 2)
- return null;
- int dst = dis.readByte();
- int abbrind = dis.readByte();
- if (abbrind < 0)
- abbrind += 256;
- if (abbrind >= charcnt)
- return null;
- typeflags[i] = (dst != 0 ? (1 << 8) : 0) + abbrind;
- }
-
- // Abbrev names
- byte[] names = new byte[charcnt];
- dis.readFully(names);
-
- // Leap transitions, for now ignore
- skipFully(dis, leapcnt * (tzif2 + 4) + ttisstdcnt + ttisgmtcnt);
-
- // tzIf2 format has optional POSIX TZ env string
- String tzstr = null;
- if (tzif2 == 8 && dis.readByte() == '\n')
- {
- tzstr = dis.readLine();
- if (tzstr.length() <= 0)
- tzstr = null;
- }
-
- // Get std/dst_offset and dst/non-dst time zone names.
- int std_ind = -1;
- int dst_ind = -1;
- if (timecnt == 0)
- std_ind = 0;
- else
- for (int i = timecnt - 1; i >= 0; i--)
- {
- if (std_ind == -1 && (typeflags[types[i]] & (1 << 8)) == 0)
- std_ind = types[i];
- else if (dst_ind == -1 && (typeflags[types[i]] & (1 << 8)) != 0)
- dst_ind = types[i];
- if (dst_ind != -1 && std_ind != -1)
- break;
- }
-
- if (std_ind == -1)
- return null;
-
- int j = typeflags[std_ind] & 255;
- while (j < charcnt && names[j] != 0)
- j++;
- String std_zonename = new String(names, typeflags[std_ind] & 255,
- j - (typeflags[std_ind] & 255),
- "ASCII");
-
- String dst_zonename = "";
- if (dst_ind != -1)
- {
- j = typeflags[dst_ind] & 255;
- while (j < charcnt && names[j] != 0)
- j++;
- dst_zonename = new String(names, typeflags[dst_ind] & 255,
- j - (typeflags[dst_ind] & 255), "ASCII");
- }
-
- // Only use gmt offset when necessary.
- // Also special case GMT+/- timezones.
- String std_offset_string = "";
- String dst_offset_string = "";
- if (tzstr == null
- && (dst_ind != -1
- || (offsets[std_ind] != 0
- && !std_zonename.startsWith("GMT+")
- && !std_zonename.startsWith("GMT-"))))
- {
- std_offset_string = Integer.toString(-offsets[std_ind] / 3600);
- int seconds = -offsets[std_ind] % 3600;
- if (seconds != 0)
- {
- if (seconds < 0)
- seconds *= -1;
- if (seconds < 600)
- std_offset_string += ":0" + Integer.toString(seconds / 60);
- else
- std_offset_string += ":" + Integer.toString(seconds / 60);
- seconds = seconds % 60;
- if (seconds >= 10)
- std_offset_string += ":" + Integer.toString(seconds);
- else if (seconds > 0)
- std_offset_string += ":0" + Integer.toString(seconds);
- }
-
- if (dst_ind != -1 && offsets[dst_ind] != offsets[std_ind] + 3600)
- {
- dst_offset_string = Integer.toString(-offsets[dst_ind] / 3600);
- seconds = -offsets[dst_ind] % 3600;
- if (seconds != 0)
- {
- if (seconds < 0)
- seconds *= -1;
- if (seconds < 600)
- dst_offset_string
- += ":0" + Integer.toString(seconds / 60);
- else
- dst_offset_string
- += ":" + Integer.toString(seconds / 60);
- seconds = seconds % 60;
- if (seconds >= 10)
- dst_offset_string += ":" + Integer.toString(seconds);
- else if (seconds > 0)
- dst_offset_string += ":0" + Integer.toString(seconds);
- }
- }
- }
-
- /*
- * If no tzIf2 POSIX TZ string is available and the timezone
- * uses DST, try to guess the last rule by trying to make
- * sense from transitions at 5 years in the future and onwards.
- * tzdata actually uses only 3 forms of rules:
- * fixed date within a month, e.g. change on April, 5th
- * 1st weekday on or after Nth: change on Sun>=15 in April
- * last weekday in a month: change on lastSun in April
- */
- String[] change_spec = { null, null };
- if (tzstr == null && dst_ind != -1 && timecnt > 10)
- {
- long nowPlus5y = System.currentTimeMillis() / 1000
- + 5 * 365 * 86400;
- int first;
-
- for (first = timecnt - 1; first >= 0; first--)
- if (times[first] < nowPlus5y
- || (types[first] != std_ind && types[first] != dst_ind)
- || types[first] != types[timecnt - 2 + ((first ^ timecnt) & 1)])
- break;
- first++;
-
- if (timecnt - first >= 10 && types[timecnt - 1] != types[timecnt - 2])
- {
- GregorianCalendar cal
- = new GregorianCalendar(new SimpleTimeZone(0, "GMT"));
-
- int[] values = new int[2 * 11];
- int i;
- for (i = timecnt - 1; i >= first; i--)
- {
- int base = (i % 2) * 11;
- int offset = offsets[types[i > first ? i - 1 : i + 1]];
- cal.setTimeInMillis((times[i] + offset) * 1000);
- if (i >= timecnt - 2)
- {
- values[base + 0] = cal.get(Calendar.YEAR);
- values[base + 1] = cal.get(Calendar.MONTH);
- values[base + 2] = cal.get(Calendar.DAY_OF_MONTH);
- values[base + 3]
- = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
- values[base + 4] = cal.get(Calendar.DAY_OF_WEEK);
- values[base + 5] = cal.get(Calendar.HOUR_OF_DAY);
- values[base + 6] = cal.get(Calendar.MINUTE);
- values[base + 7] = cal.get(Calendar.SECOND);
- values[base + 8] = values[base + 2]; // Range start
- values[base + 9] = values[base + 2]; // Range end
- values[base + 10] = 0; // Determined type
- }
- else
- {
- int year = cal.get(Calendar.YEAR);
- int month = cal.get(Calendar.MONTH);
- int day_of_month = cal.get(Calendar.DAY_OF_MONTH);
- int month_days
- = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
- int day_of_week = cal.get(Calendar.DAY_OF_WEEK);
- int hour = cal.get(Calendar.HOUR_OF_DAY);
- int minute = cal.get(Calendar.MINUTE);
- int second = cal.get(Calendar.SECOND);
- if (year != values[base + 0] - 1
- || month != values[base + 1]
- || hour != values[base + 5]
- || minute != values[base + 6]
- || second != values[base + 7])
- break;
- if (day_of_week == values[base + 4])
- {
- // Either a Sun>=8 or lastSun rule.
- if (day_of_month < values[base + 8])
- values[base + 8] = day_of_month;
- if (day_of_month > values[base + 9])
- values[base + 9] = day_of_month;
- if (values[base + 10] < 0)
- break;
- if (values[base + 10] == 0)
- {
- values[base + 10] = 1;
- // If day of month > 28, this is
- // certainly lastSun rule.
- if (values[base + 2] > 28)
- values[base + 2] = 3;
- // If day of month isn't in the last
- // week, it can't be lastSun rule.
- else if (values[base + 2]
- <= values[base + 3] - 7)
- values[base + 3] = 2;
- }
- if (values[base + 10] == 1)
- {
- // If day of month is > 28, this is
- // certainly lastSun rule.
- if (day_of_month > 28)
- values[base + 10] = 3;
- // If day of month isn't in the last
- // week, it can't be lastSun rule.
- else if (day_of_month <= month_days - 7)
- values[base + 10] = 2;
- }
- else if ((values[base + 10] == 2
- && day_of_month > 28)
- || (values[base + 10] == 3
- && day_of_month <= month_days - 7))
- break;
- }
- else
- {
- // Must be fixed day in month rule.
- if (day_of_month != values[base + 2]
- || values[base + 10] > 0)
- break;
- values[base + 4] = day_of_week;
- values[base + 10] = -1;
- }
- values[base + 0] -= 1;
- }
- }
-
- if (i < first)
- {
- for (i = 0; i < 2; i++)
- {
- int base = 11 * i;
- if (values[base + 10] == 0)
- continue;
- if (values[base + 10] == -1)
- {
- int[] dayCount
- = { 0, 31, 59, 90, 120, 151,
- 181, 212, 243, 273, 304, 334 };
- int d = dayCount[values[base + 1]
- - Calendar.JANUARY];
- d += values[base + 2];
- change_spec[i] = ",J" + Integer.toString(d);
- }
- else if (values[base + 10] == 2)
- {
- // If we haven't seen all days of the week,
- // we can't be sure what the rule really is.
- if (values[base + 8] + 6 != values[base + 9])
- continue;
-
- int d;
- d = values[base + 1] - Calendar.JANUARY + 1;
- // E.g. Sun >= 5 is not representable in POSIX
- // TZ env string, use ",Am.n.d" extension
- // where m is month 1 .. 12, n is the date on
- // or after which it happens and d is day
- // of the week, 0 .. 6. So Sun >= 5 in April
- // is ",A4.5.0".
- if ((values[base + 8] % 7) == 1)
- {
- change_spec[i] = ",M" + Integer.toString(d);
- d = (values[base + 8] + 6) / 7;
- }
- else
- {
- change_spec[i] = ",A" + Integer.toString(d);
- d = values[base + 8];
- }
- change_spec[i] += "." + Integer.toString(d);
- d = values[base + 4] - Calendar.SUNDAY;
- change_spec[i] += "." + Integer.toString(d);
- }
- else
- {
- // If we don't know whether this is lastSun or
- // Sun >= 22 rule. That can be either because
- // there was insufficient number of
- // transitions, or February, where it is quite
- // probable we haven't seen any 29th dates.
- // For February, assume lastSun rule, otherwise
- // punt.
- if (values[base + 10] == 1
- && values[base + 1] != Calendar.FEBRUARY)
- continue;
-
- int d;
- d = values[base + 1] - Calendar.JANUARY + 1;
- change_spec[i] = ",M" + Integer.toString(d);
- d = values[base + 4] - Calendar.SUNDAY;
- change_spec[i] += ".5." + Integer.toString(d);
- }
-
- // Don't add time specification if time is
- // 02:00:00.
- if (values[base + 5] != 2
- || values[base + 6] != 0
- || values[base + 7] != 0)
- {
- int d = values[base + 5];
- change_spec[i] += "/" + Integer.toString(d);
- if (values[base + 6] != 0 || values[base + 7] != 0)
- {
- d = values[base + 6];
- if (d < 10)
- change_spec[i]
- += ":0" + Integer.toString(d);
- else
- change_spec[i] += ":" + Integer.toString(d);
- d = values[base + 7];
- if (d >= 10)
- change_spec[i]
- += ":" + Integer.toString(d);
- else if (d > 0)
- change_spec[i]
- += ":0" + Integer.toString(d);
- }
- }
- }
- if (types[(timecnt - 1) & -2] == std_ind)
- {
- String tmp = change_spec[0];
- change_spec[0] = change_spec[1];
- change_spec[1] = tmp;
- }
- }
- }
- }
-
- if (tzstr == null)
- {
- tzstr = std_zonename + std_offset_string;
- if (change_spec[0] != null && change_spec[1] != null)
- tzstr += dst_zonename + dst_offset_string
- + change_spec[0] + change_spec[1];
- }
-
- if (timecnt == 0)
- return new SimpleTimeZone(offsets[std_ind] * 1000,
- id != null ? id : tzstr);
-
- SimpleTimeZone endRule = createLastRule(tzstr);
- if (endRule == null)
- return null;
-
- /* Finally adjust the times array into the form the constructor
- * expects. times[0] is special, the offset and DST flag there
- * are for all times before that transition. Use the first non-DST
- * type. For all other transitions, the data file has the type
- * (<offset, isdst, zonename>) for the time interval starting
- */
- for (int i = 0; i < typecnt; i++)
- if ((typeflags[i] & (1 << 8)) == 0)
- {
- times[0] = (times[0] << SECS_SHIFT) | (offsets[i] & OFFSET_MASK);
- break;
- }
-
- for (int i = 1; i < timecnt; i++)
- times[i] = (times[i] << SECS_SHIFT)
- | (offsets[types[i - 1]] & OFFSET_MASK)
- | ((typeflags[types[i - 1]] & (1 << 8)) != 0 ? IS_DST : 0);
-
- return new ZoneInfo(offsets[std_ind] * 1000, id != null ? id : tzstr,
- times, endRule);
- }
- catch (IOException ioe)
- {
- // Parse error, not a proper tzfile.
- return null;
- }
- finally
- {
- try
- {
- if (dis != null)
- dis.close();
- }
- catch(IOException ioe)
- {
- // Error while close, nothing we can do.
- }
- }
- }
-
- /**
- * Skips the requested number of bytes in the given InputStream.
- * Throws EOFException if not enough bytes could be skipped.
- * Negative numbers of bytes to skip are ignored.
- */
- private static void skipFully(InputStream is, long l) throws IOException
- {
- while (l > 0)
- {
- long k = is.skip(l);
- if (k <= 0)
- throw new EOFException();
- l -= k;
- }
- }
-
- /**
- * Create a SimpleTimeZone from a POSIX TZ environment string,
- * see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html
- * for details.
- * It supports also an extension, where Am.n.d rule (m 1 .. 12, n 1 .. 25, d
- * 0 .. 6) describes day of week d on or after nth day of month m.
- * Say A4.5.0 is Sun>=5 in April.
- */
- private static SimpleTimeZone createLastRule(String tzstr)
- {
- String stdName = null;
- int stdOffs;
- int dstOffs;
- try
- {
- int idLength = tzstr.length();
-
- int index = 0;
- int prevIndex;
- char c;
-
- // get std
- do
- c = tzstr.charAt(index);
- while (c != '+' && c != '-' && c != ',' && c != ':'
- && ! Character.isDigit(c) && c != '\0' && ++index < idLength);
-
- if (index >= idLength)
- return new SimpleTimeZone(0, tzstr);
-
- stdName = tzstr.substring(0, index);
- prevIndex = index;
-
- // get the std offset
- do
- c = tzstr.charAt(index++);
- while ((c == '-' || c == '+' || c == ':' || Character.isDigit(c))
- && index < idLength);
- if (index < idLength)
- index--;
-
- { // convert the dst string to a millis number
- String offset = tzstr.substring(prevIndex, index);
- prevIndex = index;
-
- if (offset.charAt(0) == '+' || offset.charAt(0) == '-')
- stdOffs = parseTime(offset.substring(1));
- else
- stdOffs = parseTime(offset);
-
- if (offset.charAt(0) == '-')
- stdOffs = -stdOffs;
-
- // TZ timezone offsets are positive when WEST of the meridian.
- stdOffs = -stdOffs;
- }
-
- // Done yet? (Format: std offset)
- if (index >= idLength)
- return new SimpleTimeZone(stdOffs, stdName);
-
- // get dst
- do
- c = tzstr.charAt(index);
- while (c != '+' && c != '-' && c != ',' && c != ':'
- && ! Character.isDigit(c) && c != '\0' && ++index < idLength);
-
- // Done yet? (Format: std offset dst)
- if (index >= idLength)
- return new SimpleTimeZone(stdOffs, stdName);
-
- // get the dst offset
- prevIndex = index;
- do
- c = tzstr.charAt(index++);
- while ((c == '-' || c == '+' || c == ':' || Character.isDigit(c))
- && index < idLength);
- if (index < idLength)
- index--;
-
- if (index == prevIndex && (c == ',' || c == ';'))
- {
- // Missing dst offset defaults to one hour ahead of standard
- // time.
- dstOffs = stdOffs + 60 * 60 * 1000;
- }
- else
- { // convert the dst string to a millis number
- String offset = tzstr.substring(prevIndex, index);
- prevIndex = index;
-
- if (offset.charAt(0) == '+' || offset.charAt(0) == '-')
- dstOffs = parseTime(offset.substring(1));
- else
- dstOffs = parseTime(offset);
-
- if (offset.charAt(0) == '-')
- dstOffs = -dstOffs;
-
- // TZ timezone offsets are positive when WEST of the meridian.
- dstOffs = -dstOffs;
- }
-
- // Done yet? (Format: std offset dst offset)
- if (index >= idLength)
- return new SimpleTimeZone(stdOffs, stdName);
-
- // get the DST rule
- if (tzstr.charAt(index) == ','
- || tzstr.charAt(index) == ';')
- {
- index++;
- int offs = index;
- while (tzstr.charAt(index) != ','
- && tzstr.charAt(index) != ';')
- index++;
- String startTime = tzstr.substring(offs, index);
- index++;
- String endTime = tzstr.substring(index);
-
- index = startTime.indexOf('/');
- int startMillis;
- int endMillis;
- String startDate;
- String endDate;
- if (index != -1)
- {
- startDate = startTime.substring(0, index);
- startMillis = parseTime(startTime.substring(index + 1));
- }
- else
- {
- startDate = startTime;
- // if time isn't given, default to 2:00:00 AM.
- startMillis = 2 * 60 * 60 * 1000;
- }
- index = endTime.indexOf('/');
- if (index != -1)
- {
- endDate = endTime.substring(0, index);
- endMillis = parseTime(endTime.substring(index + 1));
- }
- else
- {
- endDate = endTime;
- // if time isn't given, default to 2:00:00 AM.
- endMillis = 2 * 60 * 60 * 1000;
- }
-
- int[] start = getDateParams(startDate);
- int[] end = getDateParams(endDate);
- return new SimpleTimeZone(stdOffs, tzstr, start[0], start[1],
- start[2], startMillis, end[0], end[1],
- end[2], endMillis, (dstOffs - stdOffs));
- }
- }
-
- catch (IndexOutOfBoundsException _)
- {
- }
- catch (NumberFormatException _)
- {
- }
-
- return null;
- }
-
- /**
- * Parses and returns the params for a POSIX TZ date field,
- * in the format int[]{ month, day, dayOfWeek }, following the
- * SimpleTimeZone constructor rules.
- */
- private static int[] getDateParams(String date)
- {
- int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
- int month;
- int type = 0;
-
- if (date.charAt(0) == 'M' || date.charAt(0) == 'm')
- type = 1;
- else if (date.charAt(0) == 'A' || date.charAt(0) == 'a')
- type = 2;
-
- if (type > 0)
- {
- int day;
-
- // Month, week of month, day of week
- // "Mm.w.d". d is between 0 (Sunday) and 6. Week w is
- // between 1 and 5; Week 1 is the first week in which day d
- // occurs and Week 5 specifies the last d day in the month.
- // Month m is between 1 and 12.
-
- // Month, day of month, day of week
- // ZoneInfo extension, not in POSIX
- // "Am.n.d". d is between 0 (Sunday) and 6. Day of month n is
- // between 1 and 25. Month m is between 1 and 12.
-
- month = Integer.parseInt(date.substring(1, date.indexOf('.')));
- int week = Integer.parseInt(date.substring(date.indexOf('.') + 1,
- date.lastIndexOf('.')));
- int dayOfWeek = Integer.parseInt(date.substring(date.lastIndexOf('.')
- + 1));
- dayOfWeek++; // Java day of week is one-based, Sunday is first day.
-
- if (type == 2)
- {
- day = week;
- dayOfWeek = -dayOfWeek;
- }
- else if (week == 5)
- day = -1; // last day of month is -1 in java, 5 in TZ
- else
- {
- // First day of week starting on or after. For example,
- // to specify the second Sunday of April, set month to
- // APRIL, day-of-month to 8, and day-of-week to -SUNDAY.
- day = (week - 1) * 7 + 1;
- dayOfWeek = -dayOfWeek;
- }
-
- month--; // Java month is zero-based.
- return new int[] { month, day, dayOfWeek };
- }
-
- // julian day, either zero-based 0<=n<=365 (incl feb 29)
- // or one-based 1<=n<=365 (no feb 29)
- int julianDay; // Julian day
-
- if (date.charAt(0) != 'J' || date.charAt(0) != 'j')
- {
- julianDay = Integer.parseInt(date.substring(1));
- julianDay++; // make 1-based
- // Adjust day count to include feb 29.
- dayCount = new int[]
- {
- 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335
- };
- }
- else
- // 1-based julian day
- julianDay = Integer.parseInt(date);
-
- int i = 11;
- while (i > 0)
- if (dayCount[i] < julianDay)
- break;
- else
- i--;
- julianDay -= dayCount[i];
- month = i;
- return new int[] { month, julianDay, 0 };
- }
-
- /**
- * Parses a time field hh[:mm[:ss]], returning the result
- * in milliseconds. No leading sign.
- */
- private static int parseTime(String time)
- {
- int millis = 0;
- int i = 0;
-
- while (i < time.length())
- if (time.charAt(i) == ':')
- break;
- else
- i++;
- millis = 60 * 60 * 1000 * Integer.parseInt(time.substring(0, i));
- if (i >= time.length())
- return millis;
-
- int iprev = ++i;
- while (i < time.length())
- if (time.charAt(i) == ':')
- break;
- else
- i++;
- millis += 60 * 1000 * Integer.parseInt(time.substring(iprev, i));
- if (i >= time.length())
- return millis;
-
- millis += 1000 * Integer.parseInt(time.substring(++i));
- return millis;
- }
-}