diff options
| author | Andrew Haley <aph@redhat.com> | 2016-09-30 16:24:48 +0000 |
|---|---|---|
| committer | Andrew Haley <aph@gcc.gnu.org> | 2016-09-30 16:24:48 +0000 |
| commit | 07b78716af6a9d7c9fd1e94d9baf94a52c873947 (patch) | |
| tree | 3f22b3241c513ad168c8353805614ae1249410f4 /libjava/classpath/gnu/java/util/ZoneInfo.java | |
| parent | eae993948bae8b788c53772bcb9217c063716f93 (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.java | 1160 |
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; - } -} |
