8042369: Remove duplicated java.time classes in build.tools.tzdb
Summary: removed duplicated classes in builder
Reviewed-by: rriggs
--- a/jdk/make/src/classes/build/tools/tzdb/ChronoField.java Mon Jun 23 10:40:20 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,180 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of JSR-310 nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package build.tools.tzdb;
-
-/**
- * A standard set of date/time fields.
- *
- * @since 1.8
- */
-enum ChronoField {
-
- /**
- * The second-of-minute.
- * <p>
- * This counts the second within the minute, from 0 to 59.
- * This field has the same meaning for all calendar systems.
- */
- SECOND_OF_MINUTE("SecondOfMinute", 0, 59),
-
- /**
- * The second-of-day.
- * <p>
- * This counts the second within the day, from 0 to (24 * 60 * 60) - 1.
- * This field has the same meaning for all calendar systems.
- */
- SECOND_OF_DAY("SecondOfDay", 0, 86400 - 1),
-
- /**
- * The minute-of-hour.
- * <p>
- * This counts the minute within the hour, from 0 to 59.
- * This field has the same meaning for all calendar systems.
- */
- MINUTE_OF_HOUR("MinuteOfHour", 0, 59),
-
- /**
- * The hour-of-day.
- * <p>
- * This counts the hour within the day, from 0 to 23.
- * This is the hour that would be observed on a standard 24-hour digital clock.
- * This field has the same meaning for all calendar systems.
- */
- HOUR_OF_DAY("HourOfDay", 0, 23),
-
-
- /**
- * The day-of-month.
- * <p>
- * This represents the concept of the day within the month.
- * In the default ISO calendar system, this has values from 1 to 31 in most months.
- * April, June, September, November have days from 1 to 30, while February has days
- * from 1 to 28, or 29 in a leap year.
- * <p>
- * Non-ISO calendar systems should implement this field using the most recognized
- * day-of-month values for users of the calendar system.
- * Normally, this is a count of days from 1 to the length of the month.
- */
- DAY_OF_MONTH("DayOfMonth", 1, 31),
-
- /**
- * The month-of-year, such as March.
- * <p>
- * This represents the concept of the month within the year.
- * In the default ISO calendar system, this has values from January (1) to December (12).
- * <p>
- * Non-ISO calendar systems should implement this field using the most recognized
- * month-of-year values for users of the calendar system.
- * Normally, this is a count of months starting from 1.
- */
- MONTH_OF_YEAR("MonthOfYear", 1, 12),
-
- /**
- * The proleptic year, such as 2012.
- * <p>
- * This represents the concept of the year, counting sequentially and using negative numbers.
- * The proleptic year is not interpreted in terms of the era.
- * See {@link #YEAR_OF_ERA} for an example showing the mapping from proleptic year to year-of-era.
- * <p>
- * The standard mental model for a date is based on three concepts - year, month and day.
- * These map onto the {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
- * Note that there is no reference to eras.
- * The full model for a date requires four concepts - era, year, month and day. These map onto
- * the {@code ERA}, {@code YEAR_OF_ERA}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
- * Whether this field or {@code YEAR_OF_ERA} is used depends on which mental model is being used.
- * See {@link ChronoLocalDate} for more discussion on this topic.
- * <p>
- * Non-ISO calendar systems should implement this field as follows.
- * If the calendar system has only two eras, before and after a fixed date, then the
- * proleptic-year value must be the same as the year-of-era value for the later era,
- * and increasingly negative for the earlier era.
- * If the calendar system has more than two eras, then the proleptic-year value may be
- * defined with any appropriate value, although defining it to be the same as ISO may be
- * the best option.
- */
- YEAR("Year", -999_999_999, 999_999_999);
-
- private final String name;
- private final int min;
- private final int max;
-
- private ChronoField(String name, int min, int max) {
- this.name = name;
- this.min= min;
- this.max= max;
- }
-
- /**
- * Checks that the specified value is valid for this field.
- * <p>
- *
- * @param value the value to check
- * @return the value that was passed in
- */
- public int checkValidValue(int value) {
- if (value >= min && value <= max) {
- return value;
- }
- throw new DateTimeException("Invalid value for " + name + " value: " + value);
- }
-
- public String toString() {
- return name;
- }
-
-}
--- a/jdk/make/src/classes/build/tools/tzdb/DateTimeException.java Mon Jun 23 10:40:20 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of JSR-310 nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package build.tools.tzdb;
-
-/**
- * Exception used to indicate a problem while calculating a date-time.
- * <p>
- * This exception is used to indicate problems with creating, querying
- * and manipulating date-time objects.
- *
- * @since 1.8
- */
-class DateTimeException extends RuntimeException {
-
- /**
- * Serialization version.
- */
- private static final long serialVersionUID = -1632418723876261839L;
-
- /**
- * Constructs a new date-time exception with the specified message.
- *
- * @param message the message to use for this exception, may be null
- */
- public DateTimeException(String message) {
- super(message);
- }
-
- /**
- * Constructs a new date-time exception with the specified message and cause.
- *
- * @param message the message to use for this exception, may be null
- * @param cause the cause of the exception, may be null
- */
- public DateTimeException(String message, Throwable cause) {
- super(message, cause);
- }
-
-}
--- a/jdk/make/src/classes/build/tools/tzdb/LocalDate.java Mon Jun 23 10:40:20 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,363 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of JSR-310 nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package build.tools.tzdb;
-
-import static build.tools.tzdb.Utils.*;
-import static build.tools.tzdb.LocalTime.SECONDS_PER_DAY;
-import static build.tools.tzdb.ChronoField.DAY_OF_MONTH;
-import static build.tools.tzdb.ChronoField.MONTH_OF_YEAR;
-import static build.tools.tzdb.ChronoField.YEAR;
-
-import java.util.Objects;
-
-/**
- * A date without a time-zone in the ISO-8601 calendar system,
- * such as {@code 2007-12-03}.
- *
- * @since 1.8
- */
-final class LocalDate {
-
- /**
- * The minimum supported {@code LocalDate}, '-999999999-01-01'.
- * This could be used by an application as a "far past" date.
- */
- public static final LocalDate MIN = new LocalDate(YEAR_MIN_VALUE, 1, 1);
- /**
- * The maximum supported {@code LocalDate}, '+999999999-12-31'.
- * This could be used by an application as a "far future" date.
- */
- public static final LocalDate MAX = new LocalDate(YEAR_MAX_VALUE, 12, 31);
-
- /**
- * The number of days in a 400 year cycle.
- */
- private static final int DAYS_PER_CYCLE = 146097;
- /**
- * The number of days from year zero to year 1970.
- * There are five 400 year cycles from year zero to 2000.
- * There are 7 leap years from 1970 to 2000.
- */
- static final long DAYS_0000_TO_1970 = (DAYS_PER_CYCLE * 5L) - (30L * 365L + 7L);
-
- /**
- * The year.
- */
- private final int year;
- /**
- * The month-of-year.
- */
- private final short month;
- /**
- * The day-of-month.
- */
- private final short day;
-
- /**
- * Obtains an instance of {@code LocalDate} from a year, month and day.
- * <p>
- * The day must be valid for the year and month, otherwise an exception will be thrown.
- *
- * @param year the year to represent, from MIN_YEAR to MAX_YEAR
- * @param month the month-of-year to represent, from 1 (January) to 12 (December)
- * @param dayOfMonth the day-of-month to represent, from 1 to 31
- * @return the local date, not null
- * @throws DateTimeException if the value of any field is out of range
- * @throws DateTimeException if the day-of-month is invalid for the month-year
- */
- public static LocalDate of(int year, int month, int dayOfMonth) {
- YEAR.checkValidValue(year);
- MONTH_OF_YEAR.checkValidValue(month);
- DAY_OF_MONTH.checkValidValue(dayOfMonth);
- if (dayOfMonth > 28 && dayOfMonth > lengthOfMonth(month, isLeapYear(year))) {
- if (dayOfMonth == 29) {
- throw new DateTimeException("Invalid date 'February 29' as '" + year + "' is not a leap year");
- } else {
- throw new DateTimeException("Invalid date '" + month + " " + dayOfMonth + "'");
- }
- }
- return new LocalDate(year, month, dayOfMonth);
- }
-
- /**
- * Constructor, previously validated.
- *
- * @param year the year to represent, from MIN_YEAR to MAX_YEAR
- * @param month the month-of-year to represent, not null
- * @param dayOfMonth the day-of-month to represent, valid for year-month, from 1 to 31
- */
- private LocalDate(int year, int month, int dayOfMonth) {
- this.year = year;
- this.month = (short) month;
- this.day = (short) dayOfMonth;
- }
-
- /**
- * Gets the year field.
- * <p>
- * This method returns the primitive {@code int} value for the year.
- * <p>
- * The year returned by this method is proleptic as per {@code get(YEAR)}.
- * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}.
- *
- * @return the year, from MIN_YEAR to MAX_YEAR
- */
- public int getYear() {
- return year;
- }
-
- /**
- * Gets the month-of-year field as an int from 1 to 12.
- *
- * @return the month-of-year
- */
- public int getMonth() {
- return month;
- }
-
- /**
- * Gets the day-of-month field.
- * <p>
- * This method returns the primitive {@code int} value for the day-of-month.
- *
- * @return the day-of-month, from 1 to 31
- */
- public int getDayOfMonth() {
- return day;
- }
-
- /**
- * Gets the day-of-week field, which is an int from 1 to 7.
- *
- * @return the day-of-week
- */
- public int getDayOfWeek() {
- return (int)floorMod(toEpochDay() + 3, 7) + 1;
- }
-
- /**
- * Returns a copy of this {@code LocalDate} with the specified number of days added.
- * <p>
- * This method adds the specified amount to the days field incrementing the
- * month and year fields as necessary to ensure the result remains valid.
- * The result is only invalid if the maximum/minimum year is exceeded.
- * <p>
- * For example, 2008-12-31 plus one day would result in 2009-01-01.
- * <p>
- * This instance is immutable and unaffected by this method call.
- *
- * @param daysToAdd the days to add, may be negative
- * @return a {@code LocalDate} based on this date with the days added, not null
- * @throws DateTimeException if the result exceeds the supported date range
- */
- public LocalDate plusDays(long daysToAdd) {
- if (daysToAdd == 0) {
- return this;
- }
- long mjDay = addExact(toEpochDay(), daysToAdd);
- return LocalDate.ofEpochDay(mjDay);
- }
-
- /**
- * Returns a copy of this {@code LocalDate} with the specified number of days subtracted.
- * <p>
- * This method subtracts the specified amount from the days field decrementing the
- * month and year fields as necessary to ensure the result remains valid.
- * The result is only invalid if the maximum/minimum year is exceeded.
- * <p>
- * For example, 2009-01-01 minus one day would result in 2008-12-31.
- * <p>
- * This instance is immutable and unaffected by this method call.
- *
- * @param daysToSubtract the days to subtract, may be negative
- * @return a {@code LocalDate} based on this date with the days subtracted, not null
- * @throws DateTimeException if the result exceeds the supported date range
- */
- public LocalDate minusDays(long daysToSubtract) {
- return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract));
- }
-
- /**
- * Obtains an instance of {@code LocalDate} from the epoch day count.
- * <p>
- * The Epoch Day count is a simple incrementing count of days
- * where day 0 is 1970-01-01. Negative numbers represent earlier days.
- *
- * @param epochDay the Epoch Day to convert, based on the epoch 1970-01-01
- * @return the local date, not null
- * @throws DateTimeException if the epoch days exceeds the supported date range
- */
- public static LocalDate ofEpochDay(long epochDay) {
- long zeroDay = epochDay + DAYS_0000_TO_1970;
- // find the march-based year
- zeroDay -= 60; // adjust to 0000-03-01 so leap day is at end of four year cycle
- long adjust = 0;
- if (zeroDay < 0) {
- // adjust negative years to positive for calculation
- long adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1;
- adjust = adjustCycles * 400;
- zeroDay += -adjustCycles * DAYS_PER_CYCLE;
- }
- long yearEst = (400 * zeroDay + 591) / DAYS_PER_CYCLE;
- long doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
- if (doyEst < 0) {
- // fix estimate
- yearEst--;
- doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
- }
- yearEst += adjust; // reset any negative year
- int marchDoy0 = (int) doyEst;
-
- // convert march-based values back to january-based
- int marchMonth0 = (marchDoy0 * 5 + 2) / 153;
- int month = (marchMonth0 + 2) % 12 + 1;
- int dom = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1;
- yearEst += marchMonth0 / 10;
-
- // check year now we are certain it is correct
- int year = YEAR.checkValidValue((int)yearEst);
- return new LocalDate(year, month, dom);
- }
-
- public long toEpochDay() {
- long y = year;
- long m = month;
- long total = 0;
- total += 365 * y;
- if (y >= 0) {
- total += (y + 3) / 4 - (y + 99) / 100 + (y + 399) / 400;
- } else {
- total -= y / -4 - y / -100 + y / -400;
- }
- total += ((367 * m - 362) / 12);
- total += day - 1;
- if (m > 2) {
- total--;
- if (isLeapYear(year) == false) {
- total--;
- }
- }
- return total - DAYS_0000_TO_1970;
- }
-
- /**
- * Compares this date to another date.
- * <p>
- * The comparison is primarily based on the date, from earliest to latest.
- * It is "consistent with equals", as defined by {@link Comparable}.
- * <p>
- * If all the dates being compared are instances of {@code LocalDate},
- * then the comparison will be entirely based on the date.
- * If some dates being compared are in different chronologies, then the
- * chronology is also considered, see {@link java.time.temporal.ChronoLocalDate#compareTo}.
- *
- * @param other the other date to compare to, not null
- * @return the comparator value, negative if less, positive if greater
- */
- public int compareTo(LocalDate otherDate) {
- int cmp = (year - otherDate.year);
- if (cmp == 0) {
- cmp = (month - otherDate.month);
- if (cmp == 0) {
- cmp = (day - otherDate.day);
- }
- }
- return cmp;
- }
-
- /**
- * Checks if this date is equal to another date.
- * <p>
- * Compares this {@code LocalDate} with another ensuring that the date is the same.
- * <p>
- * Only objects of type {@code LocalDate} are compared, other types return false.
- * To compare the dates of two {@code TemporalAccessor} instances, including dates
- * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
- *
- * @param obj the object to check, null returns false
- * @return true if this is equal to the other date
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj instanceof LocalDate) {
- return compareTo((LocalDate) obj) == 0;
- }
- return false;
- }
-
- /**
- * A hash code for this date.
- *
- * @return a suitable hash code
- */
- @Override
- public int hashCode() {
- int yearValue = year;
- int monthValue = month;
- int dayValue = day;
- return (yearValue & 0xFFFFF800) ^ ((yearValue << 11) + (monthValue << 6) + (dayValue));
- }
-
-}
--- a/jdk/make/src/classes/build/tools/tzdb/LocalDateTime.java Mon Jun 23 10:40:20 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,427 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of JSR-310 nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package build.tools.tzdb;
-
-import static build.tools.tzdb.Utils.*;
-import static build.tools.tzdb.LocalTime.HOURS_PER_DAY;
-import static build.tools.tzdb.LocalTime.MICROS_PER_DAY;
-import static build.tools.tzdb.LocalTime.MILLIS_PER_DAY;
-import static build.tools.tzdb.LocalTime.MINUTES_PER_DAY;
-import static build.tools.tzdb.LocalTime.SECONDS_PER_DAY;
-import static build.tools.tzdb.LocalTime.SECONDS_PER_MINUTE;
-import static build.tools.tzdb.LocalTime.SECONDS_PER_HOUR;
-
-import java.util.Objects;
-
-/**
- * A date-time without a time-zone in the ISO-8601 calendar system,
- * such as {@code 2007-12-03T10:15:30}.
- *
- * @since 1.8
- */
-final class LocalDateTime {
-
- /**
- * The minimum supported {@code LocalDateTime}, '-999999999-01-01T00:00:00'.
- * This is the local date-time of midnight at the start of the minimum date.
- * This combines {@link LocalDate#MIN} and {@link LocalTime#MIN}.
- * This could be used by an application as a "far past" date-time.
- */
- public static final LocalDateTime MIN = LocalDateTime.of(LocalDate.MIN, LocalTime.MIN);
- /**
- * The maximum supported {@code LocalDateTime}, '+999999999-12-31T23:59:59.999999999'.
- * This is the local date-time just before midnight at the end of the maximum date.
- * This combines {@link LocalDate#MAX} and {@link LocalTime#MAX}.
- * This could be used by an application as a "far future" date-time.
- */
- public static final LocalDateTime MAX = LocalDateTime.of(LocalDate.MAX, LocalTime.MAX);
-
- /**
- * The date part.
- */
- private final LocalDate date;
- /**
- * The time part.
- */
- private final LocalTime time;
-
- /**
- * Obtains an instance of {@code LocalDateTime} from year, month,
- * day, hour and minute, setting the second and nanosecond to zero.
- * <p>
- * The day must be valid for the year and month, otherwise an exception will be thrown.
- * The second and nanosecond fields will be set to zero.
- *
- * @param year the year to represent, from MIN_YEAR to MAX_YEAR
- * @param month the month-of-year to represent, from 1 (January) to 12 (December)
- * @param dayOfMonth the day-of-month to represent, from 1 to 31
- * @param hour the hour-of-day to represent, from 0 to 23
- * @param minute the minute-of-hour to represent, from 0 to 59
- * @return the local date-time, not null
- * @throws DateTimeException if the value of any field is out of range
- * @throws DateTimeException if the day-of-month is invalid for the month-year
- */
- public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) {
- LocalDate date = LocalDate.of(year, month, dayOfMonth);
- LocalTime time = LocalTime.of(hour, minute);
- return new LocalDateTime(date, time);
- }
-
- /**
- * Obtains an instance of {@code LocalDateTime} from a date and time.
- *
- * @param date the local date, not null
- * @param time the local time, not null
- * @return the local date-time, not null
- */
- public static LocalDateTime of(LocalDate date, LocalTime time) {
- Objects.requireNonNull(date, "date");
- Objects.requireNonNull(time, "time");
- return new LocalDateTime(date, time);
- }
-
- /**
- * Obtains an instance of {@code LocalDateTime} using seconds from the
- * epoch of 1970-01-01T00:00:00Z.
- * <p>
- * This allows the {@link ChronoField#INSTANT_SECONDS epoch-second} field
- * to be converted to a local date-time. This is primarily intended for
- * low-level conversions rather than general application usage.
- *
- * @param epochSecond the number of seconds from the epoch of 1970-01-01T00:00:00Z
- * @param nanoOfSecond the nanosecond within the second, from 0 to 999,999,999
- * @param offset the zone offset, not null
- * @return the local date-time, not null
- * @throws DateTimeException if the result exceeds the supported range
- */
- public static LocalDateTime ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset) {
- Objects.requireNonNull(offset, "offset");
- long localSecond = epochSecond + offset.getTotalSeconds(); // overflow caught later
- long localEpochDay = floorDiv(localSecond, SECONDS_PER_DAY);
- int secsOfDay = (int)floorMod(localSecond, SECONDS_PER_DAY);
- LocalDate date = LocalDate.ofEpochDay(localEpochDay);
- LocalTime time = LocalTime.ofSecondOfDay(secsOfDay); // ignore nano
- return new LocalDateTime(date, time);
- }
-
- /**
- * Constructor.
- *
- * @param date the date part of the date-time, validated not null
- * @param time the time part of the date-time, validated not null
- */
- private LocalDateTime(LocalDate date, LocalTime time) {
- this.date = date;
- this.time = time;
- }
-
- /**
- * Returns a copy of this date-time with the new date and time, checking
- * to see if a new object is in fact required.
- *
- * @param newDate the date of the new date-time, not null
- * @param newTime the time of the new date-time, not null
- * @return the date-time, not null
- */
- private LocalDateTime with(LocalDate newDate, LocalTime newTime) {
- if (date == newDate && time == newTime) {
- return this;
- }
- return new LocalDateTime(newDate, newTime);
- }
-
- /**
- * Gets the {@code LocalDate} part of this date-time.
- * <p>
- * This returns a {@code LocalDate} with the same year, month and day
- * as this date-time.
- *
- * @return the date part of this date-time, not null
- */
- public LocalDate getDate() {
- return date;
- }
-
- /**
- * Gets the year field.
- * <p>
- * This method returns the primitive {@code int} value for the year.
- * <p>
- * The year returned by this method is proleptic as per {@code get(YEAR)}.
- * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}.
- *
- * @return the year, from MIN_YEAR to MAX_YEAR
- */
- public int getYear() {
- return date.getYear();
- }
-
- /**
- * Gets the month-of-year field as an int from 1 to 12.
- *
- * @return the month-of-year
- */
- public int getMonth() {
- return date.getMonth();
- }
-
- /**
- * Gets the day-of-month field.
- * <p>
- * This method returns the primitive {@code int} value for the day-of-month.
- *
- * @return the day-of-month, from 1 to 31
- */
- public int getDayOfMonth() {
- return date.getDayOfMonth();
- }
-
- /**
- * Gets the day-of-week field, which is an integer from 1 to 7.
- *
- * @return the day-of-week, from 1 to 7
- */
- public int getDayOfWeek() {
- return date.getDayOfWeek();
- }
-
- /**
- * Gets the {@code LocalTime} part of this date-time.
- * <p>
- * This returns a {@code LocalTime} with the same hour, minute, second and
- * nanosecond as this date-time.
- *
- * @return the time part of this date-time, not null
- */
- public LocalTime getTime() {
- return time;
- }
-
- /**
- * Gets the hour-of-day field.
- *
- * @return the hour-of-day, from 0 to 23
- */
- public int getHour() {
- return time.getHour();
- }
-
- /**
- * Gets the minute-of-hour field.
- *
- * @return the minute-of-hour, from 0 to 59
- */
- public int getMinute() {
- return time.getMinute();
- }
-
- /**
- * Gets the second-of-minute field.
- *
- * @return the second-of-minute, from 0 to 59
- */
- public int getSecond() {
- return time.getSecond();
- }
-
- /**
- * Converts this date-time to the number of seconds from the epoch
- * of 1970-01-01T00:00:00Z.
- * <p>
- * This combines this local date-time and the specified offset to calculate the
- * epoch-second value, which is the number of elapsed seconds from 1970-01-01T00:00:00Z.
- * Instants on the time-line after the epoch are positive, earlier are negative.
- * <p>
- * This default implementation calculates from the epoch-day of the date and the
- * second-of-day of the time.
- *
- * @param offset the offset to use for the conversion, not null
- * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z
- */
- public long toEpochSecond(ZoneOffset offset) {
- Objects.requireNonNull(offset, "offset");
- long epochDay = getDate().toEpochDay();
- long secs = epochDay * 86400 + getTime().toSecondOfDay();
- secs -= offset.getTotalSeconds();
- return secs;
- }
-
- /**
- * Returns a copy of this {@code LocalDateTime} with the specified period in days added.
- * <p>
- * This method adds the specified amount to the days field incrementing the
- * month and year fields as necessary to ensure the result remains valid.
- * The result is only invalid if the maximum/minimum year is exceeded.
- * <p>
- * For example, 2008-12-31 plus one day would result in 2009-01-01.
- * <p>
- * This instance is immutable and unaffected by this method call.
- *
- * @param days the days to add, may be negative
- * @return a {@code LocalDateTime} based on this date-time with the days added, not null
- * @throws DateTimeException if the result exceeds the supported date range
- */
- public LocalDateTime plusDays(long days) {
- LocalDate newDate = date.plusDays(days);
- return with(newDate, time);
- }
-
- /**
- * Returns a copy of this {@code LocalDateTime} with the specified period in seconds added.
- * <p>
- * This instance is immutable and unaffected by this method call.
- *
- * @param seconds the seconds to add, may be negative
- * @return a {@code LocalDateTime} based on this date-time with the seconds added, not null
- * @throws DateTimeException if the result exceeds the supported date range
- */
- public LocalDateTime plusSeconds(long seconds) {
- return plusWithOverflow(date, 0, 0, seconds, 1);
- }
-
- /**
- * Returns a copy of this {@code LocalDateTime} with the specified period added.
- * <p>
- * This instance is immutable and unaffected by this method call.
- *
- * @param newDate the new date to base the calculation on, not null
- * @param hours the hours to add, may be negative
- * @param minutes the minutes to add, may be negative
- * @param seconds the seconds to add, may be negative
- * @param nanos the nanos to add, may be negative
- * @param sign the sign to determine add or subtract
- * @return the combined result, not null
- */
- private LocalDateTime plusWithOverflow(LocalDate newDate, long hours, long minutes, long seconds, int sign) {
- if ((hours | minutes | seconds) == 0) {
- return with(newDate, time);
- }
- long totDays = seconds / SECONDS_PER_DAY + // max/24*60*60
- minutes / MINUTES_PER_DAY + // max/24*60
- hours / HOURS_PER_DAY; // max/24
- totDays *= sign; // total max*0.4237...
- long totSecs = (seconds % SECONDS_PER_DAY) +
- (minutes % MINUTES_PER_DAY) * SECONDS_PER_MINUTE +
- (hours % HOURS_PER_DAY) * SECONDS_PER_HOUR;
- long curSoD = time.toSecondOfDay();
- totSecs = totSecs * sign + curSoD; // total 432000000000000
- totDays += floorDiv(totSecs, SECONDS_PER_DAY);
-
- int newSoD = (int)floorMod(totSecs, SECONDS_PER_DAY);
- LocalTime newTime = (newSoD == curSoD ? time : LocalTime.ofSecondOfDay(newSoD));
- return with(newDate.plusDays(totDays), newTime);
- }
-
- /**
- * Compares this date-time to another date-time.
- * <p>
- * The comparison is primarily based on the date-time, from earliest to latest.
- * It is "consistent with equals", as defined by {@link Comparable}.
- * <p>
- * If all the date-times being compared are instances of {@code LocalDateTime},
- * then the comparison will be entirely based on the date-time.
- * If some dates being compared are in different chronologies, then the
- * chronology is also considered, see {@link ChronoLocalDateTime#compareTo}.
- *
- * @param other the other date-time to compare to, not null
- * @return the comparator value, negative if less, positive if greater
- */
- public int compareTo(LocalDateTime other) {
- int cmp = date.compareTo(other.getDate());
- if (cmp == 0) {
- cmp = time.compareTo(other.getTime());
- }
- return cmp;
- }
-
- /**
- * Checks if this date-time is equal to another date-time.
- * <p>
- * Compares this {@code LocalDateTime} with another ensuring that the date-time is the same.
- * Only objects of type {@code LocalDateTime} are compared, other types return false.
- *
- * @param obj the object to check, null returns false
- * @return true if this is equal to the other date-time
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj instanceof LocalDateTime) {
- LocalDateTime other = (LocalDateTime) obj;
- return date.equals(other.date) && time.equals(other.time);
- }
- return false;
- }
-
- /**
- * A hash code for this date-time.
- *
- * @return a suitable hash code
- */
- @Override
- public int hashCode() {
- return date.hashCode() ^ time.hashCode();
- }
-
-}
--- a/jdk/make/src/classes/build/tools/tzdb/LocalTime.java Mon Jun 23 10:40:20 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,388 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of JSR-310 nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package build.tools.tzdb;
-
-import static build.tools.tzdb.ChronoField.HOUR_OF_DAY;
-import static build.tools.tzdb.ChronoField.MINUTE_OF_HOUR;
-import static build.tools.tzdb.ChronoField.SECOND_OF_MINUTE;
-import static build.tools.tzdb.ChronoField.SECOND_OF_DAY;
-
-import java.util.Objects;
-
-/**
- * A time without time-zone in the ISO-8601 calendar system,
- * such as {@code 10:15:30}.
- *
- */
-final class LocalTime {
-
- /**
- * The minimum supported {@code LocalTime}, '00:00'.
- * This is the time of midnight at the start of the day.
- */
- public static final LocalTime MIN;
- /**
- * The minimum supported {@code LocalTime}, '23:59:59.999999999'.
- * This is the time just before midnight at the end of the day.
- */
- public static final LocalTime MAX;
- /**
- * The time of midnight at the start of the day, '00:00'.
- */
- public static final LocalTime MIDNIGHT;
- /**
- * The time of noon in the middle of the day, '12:00'.
- */
- public static final LocalTime NOON;
- /**
- * Constants for the local time of each hour.
- */
- private static final LocalTime[] HOURS = new LocalTime[24];
- static {
- for (int i = 0; i < HOURS.length; i++) {
- HOURS[i] = new LocalTime(i, 0, 0);
- }
- MIDNIGHT = HOURS[0];
- NOON = HOURS[12];
- MIN = HOURS[0];
- MAX = new LocalTime(23, 59, 59);
- }
-
- /**
- * Hours per day.
- */
- static final int HOURS_PER_DAY = 24;
- /**
- * Minutes per hour.
- */
- static final int MINUTES_PER_HOUR = 60;
- /**
- * Minutes per day.
- */
- static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
- /**
- * Seconds per minute.
- */
- static final int SECONDS_PER_MINUTE = 60;
- /**
- * Seconds per hour.
- */
- static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
- /**
- * Seconds per day.
- */
- static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
- /**
- * Milliseconds per day.
- */
- static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L;
- /**
- * Microseconds per day.
- */
- static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
-
- /**
- * The hour.
- */
- private final byte hour;
- /**
- * The minute.
- */
- private final byte minute;
- /**
- * The second.
- */
- private final byte second;
-
- /**
- * Obtains an instance of {@code LocalTime} from an hour and minute.
- * <p>
- * The second and nanosecond fields will be set to zero by this factory method.
- * <p>
- * This factory may return a cached value, but applications must not rely on this.
- *
- * @param hour the hour-of-day to represent, from 0 to 23
- * @param minute the minute-of-hour to represent, from 0 to 59
- * @return the local time, not null
- * @throws DateTimeException if the value of any field is out of range
- */
- public static LocalTime of(int hour, int minute) {
- HOUR_OF_DAY.checkValidValue(hour);
- if (minute == 0) {
- return HOURS[hour]; // for performance
- }
- MINUTE_OF_HOUR.checkValidValue(minute);
- return new LocalTime(hour, minute, 0);
- }
-
- /**
- * Obtains an instance of {@code LocalTime} from an hour, minute and second.
- * <p>
- * The nanosecond field will be set to zero by this factory method.
- * <p>
- * This factory may return a cached value, but applications must not rely on this.
- *
- * @param hour the hour-of-day to represent, from 0 to 23
- * @param minute the minute-of-hour to represent, from 0 to 59
- * @param second the second-of-minute to represent, from 0 to 59
- * @return the local time, not null
- * @throws DateTimeException if the value of any field is out of range
- */
- public static LocalTime of(int hour, int minute, int second) {
- HOUR_OF_DAY.checkValidValue(hour);
- if ((minute | second) == 0) {
- return HOURS[hour]; // for performance
- }
- MINUTE_OF_HOUR.checkValidValue(minute);
- SECOND_OF_MINUTE.checkValidValue(second);
- return new LocalTime(hour, minute, second);
- }
-
- /**
- * Obtains an instance of {@code LocalTime} from a second-of-day value.
- * <p>
- * This factory may return a cached value, but applications must not rely on this.
- *
- * @param secondOfDay the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1}
- * @return the local time, not null
- * @throws DateTimeException if the second-of-day value is invalid
- */
- public static LocalTime ofSecondOfDay(int secondOfDay) {
- SECOND_OF_DAY.checkValidValue(secondOfDay);
- int hours = secondOfDay / SECONDS_PER_HOUR;
- secondOfDay -= hours * SECONDS_PER_HOUR;
- int minutes = secondOfDay / SECONDS_PER_MINUTE;
- secondOfDay -= minutes * SECONDS_PER_MINUTE;
- return create(hours, minutes, secondOfDay);
- }
-
-
- /**
- * Creates a local time from the hour, minute, second and nanosecond fields.
- * <p>
- * This factory may return a cached value, but applications must not rely on this.
- *
- * @param hour the hour-of-day to represent, validated from 0 to 23
- * @param minute the minute-of-hour to represent, validated from 0 to 59
- * @param second the second-of-minute to represent, validated from 0 to 59
- * @return the local time, not null
- */
- private static LocalTime create(int hour, int minute, int second) {
- if ((minute | second) == 0) {
- return HOURS[hour];
- }
- return new LocalTime(hour, minute, second);
- }
-
- /**
- * Constructor, previously validated.
- *
- * @param hour the hour-of-day to represent, validated from 0 to 23
- * @param minute the minute-of-hour to represent, validated from 0 to 59
- * @param second the second-of-minute to represent, validated from 0 to 59
- */
- private LocalTime(int hour, int minute, int second) {
- this.hour = (byte) hour;
- this.minute = (byte) minute;
- this.second = (byte) second;
- }
-
- /**
- * Gets the hour-of-day field.
- *
- * @return the hour-of-day, from 0 to 23
- */
- public int getHour() {
- return hour;
- }
-
- /**
- * Gets the minute-of-hour field.
- *
- * @return the minute-of-hour, from 0 to 59
- */
- public int getMinute() {
- return minute;
- }
-
- /**
- * Gets the second-of-minute field.
- *
- * @return the second-of-minute, from 0 to 59
- */
- public int getSecond() {
- return second;
- }
-
- /**
- * Returns a copy of this {@code LocalTime} with the specified period in seconds added.
- * <p>
- * This adds the specified number of seconds to this time, returning a new time.
- * The calculation wraps around midnight.
- * <p>
- * This instance is immutable and unaffected by this method call.
- *
- * @param secondstoAdd the seconds to add, may be negative
- * @return a {@code LocalTime} based on this time with the seconds added, not null
- */
- public LocalTime plusSeconds(long secondstoAdd) {
- if (secondstoAdd == 0) {
- return this;
- }
- int sofd = hour * SECONDS_PER_HOUR +
- minute * SECONDS_PER_MINUTE + second;
- int newSofd = ((int) (secondstoAdd % SECONDS_PER_DAY) + sofd + SECONDS_PER_DAY) % SECONDS_PER_DAY;
- if (sofd == newSofd) {
- return this;
- }
- int newHour = newSofd / SECONDS_PER_HOUR;
- int newMinute = (newSofd / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
- int newSecond = newSofd % SECONDS_PER_MINUTE;
- return create(newHour, newMinute, newSecond);
- }
-
- /**
- * Returns a copy of this {@code LocalTime} with the specified period in seconds subtracted.
- * <p>
- * This subtracts the specified number of seconds from this time, returning a new time.
- * The calculation wraps around midnight.
- * <p>
- * This instance is immutable and unaffected by this method call.
- *
- * @param secondsToSubtract the seconds to subtract, may be negative
- * @return a {@code LocalTime} based on this time with the seconds subtracted, not null
- */
- public LocalTime minusSeconds(long secondsToSubtract) {
- return plusSeconds(-(secondsToSubtract % SECONDS_PER_DAY));
- }
-
- /**
- * Extracts the time as seconds of day,
- * from {@code 0} to {@code 24 * 60 * 60 - 1}.
- *
- * @return the second-of-day equivalent to this time
- */
- public int toSecondOfDay() {
- int total = hour * SECONDS_PER_HOUR;
- total += minute * SECONDS_PER_MINUTE;
- total += second;
- return total;
- }
-
- /**
- * Compares this {@code LocalTime} to another time.
- * <p>
- * The comparison is based on the time-line position of the local times within a day.
- * It is "consistent with equals", as defined by {@link Comparable}.
- *
- * @param other the other time to compare to, not null
- * @return the comparator value, negative if less, positive if greater
- * @throws NullPointerException if {@code other} is null
- */
- public int compareTo(LocalTime other) {
- int cmp = Integer.compare(hour, other.hour);
- if (cmp == 0) {
- cmp = Integer.compare(minute, other.minute);
- if (cmp == 0) {
- cmp = Integer.compare(second, other.second);
- }
- }
- return cmp;
- }
-
- /**
- * Checks if this time is equal to another time.
- * <p>
- * The comparison is based on the time-line position of the time within a day.
- * <p>
- * Only objects of type {@code LocalTime} are compared, other types return false.
- * To compare the date of two {@code TemporalAccessor} instances, use
- * {@link ChronoField#NANO_OF_DAY} as a comparator.
- *
- * @param obj the object to check, null returns false
- * @return true if this is equal to the other time
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj instanceof LocalTime) {
- LocalTime other = (LocalTime) obj;
- return hour == other.hour && minute == other.minute &&
- second == other.second;
- }
- return false;
- }
-
- /**
- * A hash code for this time.
- *
- * @return a suitable hash code
- */
- @Override
- public int hashCode() {
- long sod = toSecondOfDay();
- return (int) (sod ^ (sod >>> 32));
- }
-
-}
--- a/jdk/make/src/classes/build/tools/tzdb/TimeDefinition.java Mon Jun 23 10:40:20 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of JSR-310 nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package build.tools.tzdb;
-
-import java.util.Objects;
-
-/**
- * A definition of the way a local time can be converted to the actual
- * transition date-time.
- * <p>
- * Time zone rules are expressed in one of three ways:
- * <p><ul>
- * <li>Relative to UTC</li>
- * <li>Relative to the standard offset in force</li>
- * <li>Relative to the wall offset (what you would see on a clock on the wall)</li>
- * </ul><p>
- */
-public enum TimeDefinition {
- /** The local date-time is expressed in terms of the UTC offset. */
- UTC,
- /** The local date-time is expressed in terms of the wall offset. */
- WALL,
- /** The local date-time is expressed in terms of the standard offset. */
- STANDARD;
-
- /**
- * Converts the specified local date-time to the local date-time actually
- * seen on a wall clock.
- * <p>
- * This method converts using the type of this enum.
- * The output is defined relative to the 'before' offset of the transition.
- * <p>
- * The UTC type uses the UTC offset.
- * The STANDARD type uses the standard offset.
- * The WALL type returns the input date-time.
- * The result is intended for use with the wall-offset.
- *
- * @param dateTime the local date-time, not null
- * @param standardOffset the standard offset, not null
- * @param wallOffset the wall offset, not null
- * @return the date-time relative to the wall/before offset, not null
- */
- public LocalDateTime createDateTime(LocalDateTime dateTime, ZoneOffset standardOffset, ZoneOffset wallOffset) {
- switch (this) {
- case UTC: {
- int difference = wallOffset.getTotalSeconds() - ZoneOffset.UTC.getTotalSeconds();
- return dateTime.plusSeconds(difference);
- }
- case STANDARD: {
- int difference = wallOffset.getTotalSeconds() - standardOffset.getTotalSeconds();
- return dateTime.plusSeconds(difference);
- }
- default: // WALL
- return dateTime;
- }
- }
-
-}
--- a/jdk/make/src/classes/build/tools/tzdb/TzdbZoneRulesCompiler.java Mon Jun 23 10:40:20 2014 -0700
+++ b/jdk/make/src/classes/build/tools/tzdb/TzdbZoneRulesCompiler.java Mon Jun 23 12:12:30 2014 -0700
@@ -56,8 +56,6 @@
*/
package build.tools.tzdb;
-import static build.tools.tzdb.Utils.*;
-
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.nio.charset.StandardCharsets;
@@ -179,15 +177,41 @@
System.exit(1);
System.err.println("Source directory does not contain file: VERSION");
}
+
+ // load source files
printVerbose("Compiling TZDB version " + version);
- // parse source files
- for (Path file : srcFiles) {
- printVerbose("Parsing file: " + file);
- parseFile(file);
- }
+ TzdbZoneRulesProvider provider = new TzdbZoneRulesProvider(srcFiles);
+
// build zone rules
printVerbose("Building rules");
- buildZoneRules();
+
+ // Build the rules, zones and links into real zones.
+ SortedMap<String, ZoneRules> builtZones = new TreeMap<>();
+
+ // build zones
+ for (String zoneId : provider.getZoneIds()) {
+ printVerbose("Building zone " + zoneId);
+ builtZones.put(zoneId, provider.getZoneRules(zoneId));
+ }
+
+ // build aliases
+ Map<String, String> links = provider.getAliasMap();
+ for (String aliasId : links.keySet()) {
+ String realId = links.get(aliasId);
+ printVerbose("Linking alias " + aliasId + " to " + realId);
+ ZoneRules realRules = builtZones.get(realId);
+ if (realRules == null) {
+ realId = links.get(realId); // try again (handle alias liked to alias)
+ printVerbose("Relinking alias " + aliasId + " to " + realId);
+ realRules = builtZones.get(realId);
+ if (realRules == null) {
+ throw new IllegalArgumentException("Alias '" + aliasId + "' links to invalid zone '" + realId);
+ }
+ links.put(aliasId, realId);
+ }
+ builtZones.put(aliasId, realRules);
+ }
+
// output to file
printVerbose("Outputting tzdb file: " + dstFile);
outputFile(dstFile, version, builtZones, links);
@@ -269,361 +293,13 @@
}
}
- private static final Pattern YEAR = Pattern.compile("(?i)(?<min>min)|(?<max>max)|(?<only>only)|(?<year>[0-9]+)");
- private static final Pattern MONTH = Pattern.compile("(?i)(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec)");
- private static final Matcher DOW = Pattern.compile("(?i)(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)").matcher("");
- private static final Matcher TIME = Pattern.compile("(?<neg>-)?+(?<hour>[0-9]{1,2})(:(?<minute>[0-5][0-9]))?+(:(?<second>[0-5][0-9]))?+").matcher("");
-
- /** The TZDB rules. */
- private final Map<String, List<TZDBRule>> rules = new HashMap<>();
-
- /** The TZDB zones. */
- private final Map<String, List<TZDBZone>> zones = new HashMap<>();
-
- /** The TZDB links. */
- private final Map<String, String> links = new HashMap<>();
-
- /** The built zones. */
- private final SortedMap<String, ZoneRules> builtZones = new TreeMap<>();
-
/** Whether to output verbose messages. */
private boolean verbose;
/**
* private contructor
*/
- private TzdbZoneRulesCompiler() {
- }
-
- /**
- * Parses a source file.
- *
- * @param file the file being read, not null
- * @throws Exception if an error occurs
- */
- private void parseFile(Path file) throws Exception {
- int lineNumber = 1;
- String line = null;
- try {
- List<String> lines = Files.readAllLines(file, StandardCharsets.ISO_8859_1);
- List<TZDBZone> openZone = null;
- for (; lineNumber < lines.size(); lineNumber++) {
- line = lines.get(lineNumber);
- int index = line.indexOf('#'); // remove comments (doesn't handle # in quotes)
- if (index >= 0) {
- line = line.substring(0, index);
- }
- if (line.trim().length() == 0) { // ignore blank lines
- continue;
- }
- Scanner s = new Scanner(line);
- if (openZone != null && Character.isWhitespace(line.charAt(0)) && s.hasNext()) {
- if (parseZoneLine(s, openZone)) {
- openZone = null;
- }
- } else {
- if (s.hasNext()) {
- String first = s.next();
- if (first.equals("Zone")) {
- openZone = new ArrayList<>();
- try {
- zones.put(s.next(), openZone);
- if (parseZoneLine(s, openZone)) {
- openZone = null;
- }
- } catch (NoSuchElementException x) {
- printVerbose("Invalid Zone line in file: " + file + ", line: " + line);
- throw new IllegalArgumentException("Invalid Zone line");
- }
- } else {
- openZone = null;
- if (first.equals("Rule")) {
- try {
- parseRuleLine(s);
- } catch (NoSuchElementException x) {
- printVerbose("Invalid Rule line in file: " + file + ", line: " + line);
- throw new IllegalArgumentException("Invalid Rule line");
- }
- } else if (first.equals("Link")) {
- try {
- String realId = s.next();
- String aliasId = s.next();
- links.put(aliasId, realId);
- } catch (NoSuchElementException x) {
- printVerbose("Invalid Link line in file: " + file + ", line: " + line);
- throw new IllegalArgumentException("Invalid Link line");
- }
-
- } else {
- throw new IllegalArgumentException("Unknown line");
- }
- }
- }
- }
- }
- } catch (Exception ex) {
- throw new Exception("Failed while parsing file '" + file + "' on line " + lineNumber + " '" + line + "'", ex);
- }
- }
-
- /**
- * Parses a Rule line.
- *
- * @param s the line scanner, not null
- */
- private void parseRuleLine(Scanner s) {
- TZDBRule rule = new TZDBRule();
- String name = s.next();
- if (rules.containsKey(name) == false) {
- rules.put(name, new ArrayList<TZDBRule>());
- }
- rules.get(name).add(rule);
- rule.startYear = parseYear(s, 0);
- rule.endYear = parseYear(s, rule.startYear);
- if (rule.startYear > rule.endYear) {
- throw new IllegalArgumentException("Year order invalid: " + rule.startYear + " > " + rule.endYear);
- }
- parseOptional(s.next()); // type is unused
- parseMonthDayTime(s, rule);
- rule.savingsAmount = parsePeriod(s.next());
- rule.text = parseOptional(s.next());
- }
-
- /**
- * Parses a Zone line.
- *
- * @param s the line scanner, not null
- * @return true if the zone is complete
- */
- private boolean parseZoneLine(Scanner s, List<TZDBZone> zoneList) {
- TZDBZone zone = new TZDBZone();
- zoneList.add(zone);
- zone.standardOffset = parseOffset(s.next());
- String savingsRule = parseOptional(s.next());
- if (savingsRule == null) {
- zone.fixedSavingsSecs = 0;
- zone.savingsRule = null;
- } else {
- try {
- zone.fixedSavingsSecs = parsePeriod(savingsRule);
- zone.savingsRule = null;
- } catch (Exception ex) {
- zone.fixedSavingsSecs = null;
- zone.savingsRule = savingsRule;
- }
- }
- zone.text = s.next();
- if (s.hasNext()) {
- zone.year = Integer.parseInt(s.next());
- if (s.hasNext()) {
- parseMonthDayTime(s, zone);
- }
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * Parses a Rule line.
- *
- * @param s the line scanner, not null
- * @param mdt the object to parse into, not null
- */
- private void parseMonthDayTime(Scanner s, TZDBMonthDayTime mdt) {
- mdt.month = parseMonth(s);
- if (s.hasNext()) {
- String dayRule = s.next();
- if (dayRule.startsWith("last")) {
- mdt.dayOfMonth = -1;
- mdt.dayOfWeek = parseDayOfWeek(dayRule.substring(4));
- mdt.adjustForwards = false;
- } else {
- int index = dayRule.indexOf(">=");
- if (index > 0) {
- mdt.dayOfWeek = parseDayOfWeek(dayRule.substring(0, index));
- dayRule = dayRule.substring(index + 2);
- } else {
- index = dayRule.indexOf("<=");
- if (index > 0) {
- mdt.dayOfWeek = parseDayOfWeek(dayRule.substring(0, index));
- mdt.adjustForwards = false;
- dayRule = dayRule.substring(index + 2);
- }
- }
- mdt.dayOfMonth = Integer.parseInt(dayRule);
- }
- if (s.hasNext()) {
- String timeStr = s.next();
- int secsOfDay = parseSecs(timeStr);
- if (secsOfDay == 86400) {
- mdt.endOfDay = true;
- secsOfDay = 0;
- }
- LocalTime time = LocalTime.ofSecondOfDay(secsOfDay);
- mdt.time = time;
- mdt.timeDefinition = parseTimeDefinition(timeStr.charAt(timeStr.length() - 1));
- }
- }
- }
-
- private int parseYear(Scanner s, int defaultYear) {
- if (s.hasNext(YEAR)) {
- s.next(YEAR);
- MatchResult mr = s.match();
- if (mr.group(1) != null) {
- return 1900; // systemv has min
- } else if (mr.group(2) != null) {
- return YEAR_MAX_VALUE;
- } else if (mr.group(3) != null) {
- return defaultYear;
- }
- return Integer.parseInt(mr.group(4));
- /*
- if (mr.group("min") != null) {
- //return YEAR_MIN_VALUE;
- return 1900; // systemv has min
- } else if (mr.group("max") != null) {
- return YEAR_MAX_VALUE;
- } else if (mr.group("only") != null) {
- return defaultYear;
- }
- return Integer.parseInt(mr.group("year"));
- */
- }
- throw new IllegalArgumentException("Unknown year: " + s.next());
- }
-
- private int parseMonth(Scanner s) {
- if (s.hasNext(MONTH)) {
- s.next(MONTH);
- for (int moy = 1; moy < 13; moy++) {
- if (s.match().group(moy) != null) {
- return moy;
- }
- }
- }
- throw new IllegalArgumentException("Unknown month: " + s.next());
- }
-
- private int parseDayOfWeek(String str) {
- if (DOW.reset(str).matches()) {
- for (int dow = 1; dow < 8; dow++) {
- if (DOW.group(dow) != null) {
- return dow;
- }
- }
- }
- throw new IllegalArgumentException("Unknown day-of-week: " + str);
- }
-
- private String parseOptional(String str) {
- return str.equals("-") ? null : str;
- }
-
- private int parseSecs(String str) {
- if (str.equals("-")) {
- return 0;
- }
- try {
- if (TIME.reset(str).find()) {
- int secs = Integer.parseInt(TIME.group("hour")) * 60 * 60;
- if (TIME.group("minute") != null) {
- secs += Integer.parseInt(TIME.group("minute")) * 60;
- }
- if (TIME.group("second") != null) {
- secs += Integer.parseInt(TIME.group("second"));
- }
- if (TIME.group("neg") != null) {
- secs = -secs;
- }
- return secs;
- }
- } catch (NumberFormatException x) {}
- throw new IllegalArgumentException(str);
- }
-
- private ZoneOffset parseOffset(String str) {
- int secs = parseSecs(str);
- return ZoneOffset.ofTotalSeconds(secs);
- }
-
- private int parsePeriod(String str) {
- return parseSecs(str);
- }
-
- private TimeDefinition parseTimeDefinition(char c) {
- switch (c) {
- case 's':
- case 'S':
- // standard time
- return TimeDefinition.STANDARD;
- case 'u':
- case 'U':
- case 'g':
- case 'G':
- case 'z':
- case 'Z':
- // UTC
- return TimeDefinition.UTC;
- case 'w':
- case 'W':
- default:
- // wall time
- return TimeDefinition.WALL;
- }
- }
-
- /**
- * Build the rules, zones and links into real zones.
- *
- * @throws Exception if an error occurs
- */
- private void buildZoneRules() throws Exception {
- // build zones
- for (String zoneId : zones.keySet()) {
- printVerbose("Building zone " + zoneId);
- List<TZDBZone> tzdbZones = zones.get(zoneId);
- ZoneRulesBuilder bld = new ZoneRulesBuilder();
- for (TZDBZone tzdbZone : tzdbZones) {
- bld = tzdbZone.addToBuilder(bld, rules);
- }
- builtZones.put(zoneId, bld.toRules(zoneId));
- }
-
- // build aliases
- for (String aliasId : links.keySet()) {
- String realId = links.get(aliasId);
- printVerbose("Linking alias " + aliasId + " to " + realId);
- ZoneRules realRules = builtZones.get(realId);
- if (realRules == null) {
- realId = links.get(realId); // try again (handle alias liked to alias)
- printVerbose("Relinking alias " + aliasId + " to " + realId);
- realRules = builtZones.get(realId);
- if (realRules == null) {
- throw new IllegalArgumentException("Alias '" + aliasId + "' links to invalid zone '" + realId);
- }
- links.put(aliasId, realId);
- }
- builtZones.put(aliasId, realRules);
- }
- // remove UTC and GMT
- // builtZones.remove("UTC");
- // builtZones.remove("GMT");
- // builtZones.remove("GMT0");
- builtZones.remove("GMT+0");
- builtZones.remove("GMT-0");
- links.remove("GMT+0");
- links.remove("GMT-0");
- // remove ROC, which is not supported in j.u.tz
- builtZones.remove("ROC");
- links.remove("ROC");
- // remove EST, HST and MST. They are supported via
- // the short-id mapping
- builtZones.remove("EST");
- builtZones.remove("HST");
- builtZones.remove("MST");
- }
+ private TzdbZoneRulesCompiler() {}
/**
* Prints a verbose message.
@@ -635,109 +311,4 @@
System.out.println(message);
}
}
-
- /**
- * Class representing a month-day-time in the TZDB file.
- */
- abstract class TZDBMonthDayTime {
- /** The month of the cutover. */
- int month = 1;
- /** The day-of-month of the cutover. */
- int dayOfMonth = 1;
- /** Whether to adjust forwards. */
- boolean adjustForwards = true;
- /** The day-of-week of the cutover. */
- int dayOfWeek = -1;
- /** The time of the cutover. */
- LocalTime time = LocalTime.MIDNIGHT;
- /** Whether this is midnight end of day. */
- boolean endOfDay;
- /** The time of the cutover. */
- TimeDefinition timeDefinition = TimeDefinition.WALL;
- void adjustToFowards(int year) {
- if (adjustForwards == false && dayOfMonth > 0) {
- LocalDate adjustedDate = LocalDate.of(year, month, dayOfMonth).minusDays(6);
- dayOfMonth = adjustedDate.getDayOfMonth();
- month = adjustedDate.getMonth();
- adjustForwards = true;
- }
- }
- }
-
- /**
- * Class representing a rule line in the TZDB file.
- */
- final class TZDBRule extends TZDBMonthDayTime {
- /** The start year. */
- int startYear;
- /** The end year. */
- int endYear;
- /** The amount of savings. */
- int savingsAmount;
- /** The text name of the zone. */
- String text;
-
- void addToBuilder(ZoneRulesBuilder bld) {
- adjustToFowards(2004); // irrelevant, treat as leap year
- bld.addRuleToWindow(startYear, endYear, month, dayOfMonth, dayOfWeek, time, endOfDay, timeDefinition, savingsAmount);
- }
- }
-
- /**
- * Class representing a linked set of zone lines in the TZDB file.
- */
- final class TZDBZone extends TZDBMonthDayTime {
- /** The standard offset. */
- ZoneOffset standardOffset;
- /** The fixed savings amount. */
- Integer fixedSavingsSecs;
- /** The savings rule. */
- String savingsRule;
- /** The text name of the zone. */
- String text;
- /** The year of the cutover. */
- int year = YEAR_MAX_VALUE;
-
- ZoneRulesBuilder addToBuilder(ZoneRulesBuilder bld, Map<String, List<TZDBRule>> rules) {
- if (year != YEAR_MAX_VALUE) {
- bld.addWindow(standardOffset, toDateTime(year), timeDefinition);
- } else {
- bld.addWindowForever(standardOffset);
- }
- if (fixedSavingsSecs != null) {
- bld.setFixedSavingsToWindow(fixedSavingsSecs);
- } else {
- List<TZDBRule> tzdbRules = rules.get(savingsRule);
- if (tzdbRules == null) {
- throw new IllegalArgumentException("Rule not found: " + savingsRule);
- }
- for (TZDBRule tzdbRule : tzdbRules) {
- tzdbRule.addToBuilder(bld);
- }
- }
- return bld;
- }
-
- private LocalDateTime toDateTime(int year) {
- adjustToFowards(year);
- LocalDate date;
- if (dayOfMonth == -1) {
- dayOfMonth = lengthOfMonth(month, isLeapYear(year));
- date = LocalDate.of(year, month, dayOfMonth);
- if (dayOfWeek != -1) {
- date = previousOrSame(date, dayOfWeek);
- }
- } else {
- date = LocalDate.of(year, month, dayOfMonth);
- if (dayOfWeek != -1) {
- date = nextOrSame(date, dayOfWeek);
- }
- }
- LocalDateTime ldt = LocalDateTime.of(date, time);
- if (endOfDay) {
- ldt = ldt.plusDays(1);
- }
- return ldt;
- }
- }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/src/classes/build/tools/tzdb/TzdbZoneRulesProvider.java Mon Jun 23 12:12:30 2014 -0700
@@ -0,0 +1,843 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package build.tools.tzdb;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.time.*;
+import java.time.Year;
+import java.time.chrono.IsoChronology;
+import java.time.temporal.TemporalAdjusters;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneOffsetTransitionRule;
+import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition;
+import java.time.zone.ZoneRulesException;
+
+/**
+ * Compile and build time-zone rules from IANA timezone data
+ *
+ * @author Xueming Shen
+ * @author Stephen Colebourne
+ * @author Michael Nascimento Santos
+ *
+ * @since 1.9
+ */
+
+class TzdbZoneRulesProvider {
+
+ /**
+ * Creates an instance.
+ *
+ * @throws ZoneRulesException if unable to load
+ */
+ public TzdbZoneRulesProvider(List<Path> files) {
+ try {
+ load(files);
+ } catch (Exception ex) {
+ throw new ZoneRulesException("Unable to load TZDB time-zone rules", ex);
+ }
+ }
+
+ public Set<String> getZoneIds() {
+ return new TreeSet(regionIds);
+ }
+
+ public Map<String, String> getAliasMap() {
+ return links;
+ }
+
+ public ZoneRules getZoneRules(String zoneId) {
+ Object obj = zones.get(zoneId);
+ if (obj == null) {
+ String zoneId0 = zoneId;
+ if (links.containsKey(zoneId)) {
+ zoneId = links.get(zoneId);
+ obj = zones.get(zoneId);
+ }
+ if (obj == null) {
+ throw new ZoneRulesException("Unknown time-zone ID: " + zoneId0);
+ }
+ }
+ if (obj instanceof ZoneRules) {
+ return (ZoneRules)obj;
+ }
+ try {
+ ZoneRules zrules = buildRules(zoneId, (List<ZoneLine>)obj);
+ zones.put(zoneId, zrules);
+ return zrules;
+ } catch (Exception ex) {
+ throw new ZoneRulesException(
+ "Invalid binary time-zone data: TZDB:" + zoneId, ex);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * All the regions that are available.
+ */
+ private List<String> regionIds = new ArrayList<>(600);
+
+ /**
+ * Zone region to rules mapping
+ */
+ private final Map<String, Object> zones = new ConcurrentHashMap<>();
+
+ /**
+ * compatibility list
+ */
+ private static HashSet<String> excludedZones;
+ static {
+ // (1) exclude EST, HST and MST. They are supported
+ // via the short-id mapping
+ // (2) remove UTC and GMT
+ // (3) remove ROC, which is not supported in j.u.tz
+ excludedZones = new HashSet<>(10);
+ excludedZones.add("EST");
+ excludedZones.add("HST");
+ excludedZones.add("MST");
+ excludedZones.add("GMT+0");
+ excludedZones.add("GMT-0");
+ excludedZones.add("ROC");
+ }
+
+ private Map<String, String> links = new HashMap<>(150);
+ private Map<String, List<RuleLine>> rules = new HashMap<>(500);
+
+ private void load(List<Path> files) throws IOException {
+
+ for (Path file : files) {
+ List<ZoneLine> openZone = null;
+ try {
+ for (String line : Files.readAllLines(file, StandardCharsets.ISO_8859_1)) {
+ if (line.length() == 0 || line.charAt(0) == '#') {
+ continue;
+ }
+ //StringIterator itr = new StringIterator(line);
+ String[] tokens = split(line);
+ if (openZone != null && // continuing zone line
+ Character.isWhitespace(line.charAt(0)) &&
+ tokens.length > 0) {
+ ZoneLine zLine = new ZoneLine();
+ openZone.add(zLine);
+ if (zLine.parse(tokens, 0)) {
+ openZone = null;
+ }
+ continue;
+ }
+ if (line.startsWith("Zone")) { // parse Zone line
+ String name = tokens[1];
+ if (excludedZones.contains(name)){
+ continue;
+ }
+ if (zones.containsKey(name)) {
+ throw new IllegalArgumentException(
+ "Duplicated zone name in file: " + name +
+ ", line: [" + line + "]");
+ }
+ openZone = new ArrayList<>(10);
+ zones.put(name, openZone);
+ regionIds.add(name);
+ ZoneLine zLine = new ZoneLine();
+ openZone.add(zLine);
+ if (zLine.parse(tokens, 2)) {
+ openZone = null;
+ }
+ } else if (line.startsWith("Rule")) { // parse Rule line
+ String name = tokens[1];
+ if (!rules.containsKey(name)) {
+ rules.put(name, new ArrayList<RuleLine>(10));
+ }
+ rules.get(name).add(new RuleLine().parse(tokens));
+ } else if (line.startsWith("Link")) { // parse link line
+ if (tokens.length >= 3) {
+ String realId = tokens[1];
+ String aliasId = tokens[2];
+ if (excludedZones.contains(aliasId)){
+ continue;
+ }
+ links.put(aliasId, realId);
+ regionIds.add(aliasId);
+ } else {
+ throw new IllegalArgumentException(
+ "Invalid Link line in file" +
+ file + ", line: [" + line + "]");
+ }
+ } else {
+ // skip unknown line
+ }
+ }
+
+ } catch (Exception ex) {
+ throw new RuntimeException("Failed while processing file [" + file +
+ "]", ex);
+ }
+ }
+ }
+
+ private String[] split(String str) {
+ int off = 0;
+ int end = str.length();
+ ArrayList<String> list = new ArrayList<>(10);
+ while (off < end) {
+ char c = str.charAt(off);
+ if (c == '\t' || c == ' ') {
+ off++;
+ continue;
+ }
+ if (c == '#') { // comment
+ break;
+ }
+ int start = off;
+ while (off < end) {
+ c = str.charAt(off);
+ if (c == ' ' || c == '\t') {
+ break;
+ }
+ off++;
+ }
+ if (start != off) {
+ list.add(str.substring(start, off));
+ }
+ }
+ return list.toArray(new String[list.size()]);
+ }
+
+ /**
+ * Class representing a month-day-time in the TZDB file.
+ */
+ private static abstract class MonthDayTime {
+ /** The month of the cutover. */
+ Month month = Month.JANUARY;
+
+ /** The day-of-month of the cutover. */
+ int dayOfMonth = 1;
+
+ /** Whether to adjust forwards. */
+ boolean adjustForwards = true;
+
+ /** The day-of-week of the cutover. */
+ DayOfWeek dayOfWeek;
+
+ /** The time of the cutover, in second of day */
+ int secsOfDay = 0;
+
+ /** Whether this is midnight end of day. */
+ boolean endOfDay;
+ /** The time of the cutover. */
+
+ TimeDefinition timeDefinition = TimeDefinition.WALL;
+
+ void adjustToForwards(int year) {
+ if (adjustForwards == false && dayOfMonth > 0) {
+ // weekDay<=monthDay case, don't have it in tzdb data for now
+ LocalDate adjustedDate = LocalDate.of(year, month, dayOfMonth).minusDays(6);
+ dayOfMonth = adjustedDate.getDayOfMonth();
+ month = adjustedDate.getMonth();
+ adjustForwards = true;
+ }
+ }
+
+ LocalDateTime toDateTime(int year) {
+ LocalDate date;
+ if (dayOfMonth < 0) {
+ int monthLen = month.length(IsoChronology.INSTANCE.isLeapYear(year));
+ date = LocalDate.of(year, month, monthLen + 1 + dayOfMonth);
+ if (dayOfWeek != null) {
+ date = date.with(TemporalAdjusters.previousOrSame(dayOfWeek));
+ }
+ } else {
+ date = LocalDate.of(year, month, dayOfMonth);
+ if (dayOfWeek != null) {
+ date = date.with(TemporalAdjusters.nextOrSame(dayOfWeek));
+ }
+ }
+ if (endOfDay) {
+ date = date.plusDays(1);
+ }
+ return LocalDateTime.of(date, LocalTime.ofSecondOfDay(secsOfDay));
+ }
+
+ /**
+ * Parses the MonthDaytime segment of a tzdb line.
+ */
+ private void parse(String[] tokens, int off) {
+ month = parseMonth(tokens[off++]);
+ if (off < tokens.length) {
+ String dayRule = tokens[off++];
+ if (dayRule.startsWith("last")) {
+ dayOfMonth = -1;
+ dayOfWeek = parseDayOfWeek(dayRule.substring(4));
+ adjustForwards = false;
+ } else {
+ int index = dayRule.indexOf(">=");
+ if (index > 0) {
+ dayOfWeek = parseDayOfWeek(dayRule.substring(0, index));
+ dayRule = dayRule.substring(index + 2);
+ } else {
+ index = dayRule.indexOf("<=");
+ if (index > 0) {
+ dayOfWeek = parseDayOfWeek(dayRule.substring(0, index));
+ adjustForwards = false;
+ dayRule = dayRule.substring(index + 2);
+ }
+ }
+ dayOfMonth = Integer.parseInt(dayRule);
+ if (dayOfMonth < -28 || dayOfMonth > 31 || dayOfMonth == 0) {
+ throw new IllegalArgumentException(
+ "Day of month indicator must be between -28 and 31 inclusive excluding zero");
+ }
+ }
+ if (off < tokens.length) {
+ String timeStr = tokens[off++];
+ secsOfDay = parseSecs(timeStr);
+ if (secsOfDay == 86400) {
+ // time must be midnight when end of day flag is true
+ endOfDay = true;
+ secsOfDay = 0;
+ }
+ timeDefinition = parseTimeDefinition(timeStr.charAt(timeStr.length() - 1));
+ }
+ }
+ }
+
+ int parseYear(String year, int defaultYear) {
+ switch (year.toLowerCase()) {
+ case "min": return 1900;
+ case "max": return Year.MAX_VALUE;
+ case "only": return defaultYear;
+ }
+ return Integer.parseInt(year);
+ }
+
+ Month parseMonth(String mon) {
+ switch (mon) {
+ case "Jan": return Month.JANUARY;
+ case "Feb": return Month.FEBRUARY;
+ case "Mar": return Month.MARCH;
+ case "Apr": return Month.APRIL;
+ case "May": return Month.MAY;
+ case "Jun": return Month.JUNE;
+ case "Jul": return Month.JULY;
+ case "Aug": return Month.AUGUST;
+ case "Sep": return Month.SEPTEMBER;
+ case "Oct": return Month.OCTOBER;
+ case "Nov": return Month.NOVEMBER;
+ case "Dec": return Month.DECEMBER;
+ }
+ throw new IllegalArgumentException("Unknown month: " + mon);
+ }
+
+ DayOfWeek parseDayOfWeek(String dow) {
+ switch (dow) {
+ case "Mon": return DayOfWeek.MONDAY;
+ case "Tue": return DayOfWeek.TUESDAY;
+ case "Wed": return DayOfWeek.WEDNESDAY;
+ case "Thu": return DayOfWeek.THURSDAY;
+ case "Fri": return DayOfWeek.FRIDAY;
+ case "Sat": return DayOfWeek.SATURDAY;
+ case "Sun": return DayOfWeek.SUNDAY;
+ }
+ throw new IllegalArgumentException("Unknown day-of-week: " + dow);
+ }
+
+ String parseOptional(String str) {
+ return str.equals("-") ? null : str;
+ }
+
+ static final boolean isDigit(char c) {
+ return c >= '0' && c <= '9';
+ }
+
+ private int parseSecs(String time) {
+ if (time.equals("-")) {
+ return 0;
+ }
+ // faster hack
+ int secs = 0;
+ int sign = 1;
+ int off = 0;
+ int len = time.length();
+ if (off < len && time.charAt(off) == '-') {
+ sign = -1;
+ off++;
+ }
+ char c0, c1;
+ if (off < len && isDigit(c0 = time.charAt(off++))) {
+ int hour = c0 - '0';
+ if (off < len && isDigit(c1 = time.charAt(off))) {
+ hour = hour * 10 + c1 - '0';
+ off++;
+ }
+ secs = hour * 60 * 60;
+ if (off < len && time.charAt(off++) == ':') {
+ if (off + 1 < len &&
+ isDigit(c0 = time.charAt(off++)) &&
+ isDigit(c1 = time.charAt(off++))) {
+ // minutes
+ secs += ((c0 - '0') * 10 + c1 - '0') * 60;
+ if (off < len && time.charAt(off++) == ':') {
+ if (off + 1 < len &&
+ isDigit(c0 = time.charAt(off++)) &&
+ isDigit(c1 = time.charAt(off++))) {
+ // seconds
+ secs += ((c0 - '0') * 10 + c1 - '0');
+ }
+ }
+ }
+
+ }
+ return secs * sign;
+ }
+ throw new IllegalArgumentException("[" + time + "]");
+ }
+
+ int parseOffset(String str) {
+ int secs = parseSecs(str);
+ if (Math.abs(secs) > 18 * 60 * 60) {
+ throw new IllegalArgumentException(
+ "Zone offset not in valid range: -18:00 to +18:00");
+ }
+ return secs;
+ }
+
+ int parsePeriod(String str) {
+ return parseSecs(str);
+ }
+
+ TimeDefinition parseTimeDefinition(char c) {
+ switch (c) {
+ case 's':
+ case 'S':
+ // standard time
+ return TimeDefinition.STANDARD;
+ case 'u':
+ case 'U':
+ case 'g':
+ case 'G':
+ case 'z':
+ case 'Z':
+ // UTC
+ return TimeDefinition.UTC;
+ case 'w':
+ case 'W':
+ default:
+ // wall time
+ return TimeDefinition.WALL;
+ }
+ }
+ }
+
+ /**
+ * Class representing a rule line in the TZDB file.
+ */
+ private static class RuleLine extends MonthDayTime {
+ /** The start year. */
+ int startYear;
+
+ /** The end year. */
+ int endYear;
+
+ /** The amount of savings, in seconds. */
+ int savingsAmount;
+
+ /** The text name of the zone. */
+ String text;
+
+ /**
+ * Converts this to a transition rule.
+ *
+ * @param standardOffset the active standard offset, not null
+ * @param savingsBeforeSecs the active savings before the transition in seconds
+ * @return the transition, not null
+ */
+ ZoneOffsetTransitionRule toTransitionRule(ZoneOffset stdOffset, int savingsBefore) {
+ // rule shared by different zones, so don't change it
+ Month month = this.month;
+ int dayOfMonth = this.dayOfMonth;
+ DayOfWeek dayOfWeek = this.dayOfWeek;
+ boolean endOfDay = this.endOfDay;
+
+ // optimize stored format
+ if (dayOfMonth < 0) {
+ if (month != Month.FEBRUARY) { // not Month.FEBRUARY
+ dayOfMonth = month.maxLength() - 6;
+ }
+ }
+ if (endOfDay && dayOfMonth > 0 &&
+ (dayOfMonth == 28 && month == Month.FEBRUARY) == false) {
+ LocalDate date = LocalDate.of(2004, month, dayOfMonth).plusDays(1); // leap-year
+ month = date.getMonth();
+ dayOfMonth = date.getDayOfMonth();
+ if (dayOfWeek != null) {
+ dayOfWeek = dayOfWeek.plus(1);
+ }
+ endOfDay = false;
+ }
+ // build rule
+ return ZoneOffsetTransitionRule.of(
+ //month, dayOfMonth, dayOfWeek, time, endOfDay, timeDefinition,
+ month, dayOfMonth, dayOfWeek,
+ LocalTime.ofSecondOfDay(secsOfDay), endOfDay, timeDefinition,
+ stdOffset,
+ ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savingsBefore),
+ ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savingsAmount));
+ }
+
+ RuleLine parse(String[] tokens) {
+ startYear = parseYear(tokens[2], 0);
+ endYear = parseYear(tokens[3], startYear);
+ if (startYear > endYear) {
+ throw new IllegalArgumentException(
+ "Invalid <Rule> line/Year order invalid:" + startYear + " > " + endYear);
+ }
+ //parseOptional(s.next()); // type is unused
+ super.parse(tokens, 5); // monthdaytime parsing
+ savingsAmount = parsePeriod(tokens[8]);
+ //rule.text = parseOptional(s.next());
+ return this;
+ }
+ }
+
+ /**
+ * Class representing a linked set of zone lines in the TZDB file.
+ */
+ private static class ZoneLine extends MonthDayTime {
+ /** The standard offset. */
+ int stdOffsetSecs;
+
+ /** The fixed savings amount. */
+ int fixedSavingsSecs = 0;
+
+ /** The savings rule. */
+ String savingsRule;
+
+ /** The text name of the zone. */
+ String text;
+
+ /** The cutover year */
+ int year = Year.MAX_VALUE;
+
+ /** The cutover date time */
+ LocalDateTime ldt;
+
+ /** The cutover date/time in epoch seconds/UTC */
+ long ldtSecs = Long.MIN_VALUE;
+
+ LocalDateTime toDateTime() {
+ if (ldt == null) {
+ ldt = toDateTime(year);
+ }
+ return ldt;
+ }
+
+ /**
+ * Creates the date-time epoch second in the wall offset for the local
+ * date-time at the end of the window.
+ *
+ * @param savingsSecs the amount of savings in use in seconds
+ * @return the created date-time epoch second in the wall offset, not null
+ */
+ long toDateTimeEpochSecond(int savingsSecs) {
+ if (ldtSecs == Long.MIN_VALUE) {
+ ldtSecs = toDateTime().toEpochSecond(ZoneOffset.UTC);
+ }
+ switch(timeDefinition) {
+ case UTC: return ldtSecs;
+ case STANDARD: return ldtSecs - stdOffsetSecs;
+ default: return ldtSecs - (stdOffsetSecs + savingsSecs); // WALL
+ }
+ }
+
+ boolean parse(String[] tokens, int off) {
+ stdOffsetSecs = parseOffset(tokens[off++]);
+ savingsRule = parseOptional(tokens[off++]);
+ if (savingsRule != null && savingsRule.length() > 0 &&
+ (savingsRule.charAt(0) == '-' || isDigit(savingsRule.charAt(0)))) {
+ try {
+ fixedSavingsSecs = parsePeriod(savingsRule);
+ savingsRule = null;
+ } catch (Exception ex) {
+ fixedSavingsSecs = 0;
+ }
+ }
+ text = tokens[off++];
+ if (off < tokens.length) {
+ year = Integer.parseInt(tokens[off++]);
+ if (off < tokens.length) {
+ super.parse(tokens, off); // MonthDayTime
+ }
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Class representing a rule line in the TZDB file for a particular year.
+ */
+ private static class TransRule implements Comparable<TransRule>
+ {
+ private int year;
+ private RuleLine rule;
+
+ /** The trans date/time */
+ private LocalDateTime ldt;
+
+ /** The trans date/time in epoch seconds (assume UTC) */
+ long ldtSecs;
+
+ TransRule(int year, RuleLine rule) {
+ this.year = year;
+ this.rule = rule;
+ this.ldt = rule.toDateTime(year);
+ this.ldtSecs = ldt.toEpochSecond(ZoneOffset.UTC);
+ }
+
+ ZoneOffsetTransition toTransition(ZoneOffset standardOffset, int savingsBeforeSecs) {
+ // copy of code in ZoneOffsetTransitionRule to avoid infinite loop
+ ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(
+ standardOffset.getTotalSeconds() + savingsBeforeSecs);
+ ZoneOffset offsetAfter = ZoneOffset.ofTotalSeconds(
+ standardOffset.getTotalSeconds() + rule.savingsAmount);
+ LocalDateTime dt = rule.timeDefinition
+ .createDateTime(ldt, standardOffset, wallOffset);
+ return ZoneOffsetTransition.of(dt, wallOffset, offsetAfter);
+ }
+
+ long toEpochSecond(ZoneOffset stdOffset, int savingsBeforeSecs) {
+ switch(rule.timeDefinition) {
+ case UTC: return ldtSecs;
+ case STANDARD: return ldtSecs - stdOffset.getTotalSeconds();
+ default: return ldtSecs - (stdOffset.getTotalSeconds() + savingsBeforeSecs); // WALL
+ }
+ }
+
+ /**
+ * Tests if this a real transition with the active savings in seconds
+ *
+ * @param savingsBefore the active savings in seconds
+ * @return true, if savings changes
+ */
+ boolean isTransition(int savingsBefore) {
+ return rule.savingsAmount != savingsBefore;
+ }
+
+ public int compareTo(TransRule other) {
+ return (ldtSecs < other.ldtSecs)? -1 : ((ldtSecs == other.ldtSecs) ? 0 : 1);
+ }
+ }
+
+ private ZoneRules buildRules(String zoneId, List<ZoneLine> zones) {
+ if (zones.isEmpty()) {
+ throw new IllegalStateException("No available zone window");
+ }
+ final List<ZoneOffsetTransition> standardTransitionList = new ArrayList<>(4);
+ final List<ZoneOffsetTransition> transitionList = new ArrayList<>(256);
+ final List<ZoneOffsetTransitionRule> lastTransitionRuleList = new ArrayList<>(2);
+
+ final ZoneLine zone0 = zones.get(0);
+ // initialize the standard offset, wallOffset and savings for loop
+
+ //ZoneOffset stdOffset = zone0.standardOffset;
+ ZoneOffset stdOffset = ZoneOffset.ofTotalSeconds(zone0.stdOffsetSecs);
+
+ int savings = zone0.fixedSavingsSecs;
+ ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savings);
+
+ // start ldt of each zone window
+ LocalDateTime zoneStart = LocalDateTime.MIN;
+
+ // first stanard offset
+ ZoneOffset firstStdOffset = stdOffset;
+ // first wall offset
+ ZoneOffset firstWallOffset = wallOffset;
+
+ for (ZoneLine zone : zones) {
+ // check if standard offset changed, update it if yes
+ ZoneOffset stdOffsetPrev = stdOffset; // for effectiveSavings check
+ if (zone.stdOffsetSecs != stdOffset.getTotalSeconds()) {
+ ZoneOffset stdOffsetNew = ZoneOffset.ofTotalSeconds(zone.stdOffsetSecs);
+ standardTransitionList.add(
+ ZoneOffsetTransition.of(
+ LocalDateTime.ofEpochSecond(zoneStart.toEpochSecond(wallOffset),
+ 0,
+ stdOffset),
+ stdOffset,
+ stdOffsetNew));
+ stdOffset = stdOffsetNew;
+ }
+
+ LocalDateTime zoneEnd;
+ if (zone.year == Year.MAX_VALUE) {
+ zoneEnd = LocalDateTime.MAX;
+ } else {
+ zoneEnd = zone.toDateTime();
+ }
+ if (zoneEnd.compareTo(zoneStart) < 0) {
+ throw new IllegalStateException("Windows must be in date-time order: " +
+ zoneEnd + " < " + zoneStart);
+ }
+ // calculate effective savings at the start of the window
+ List<TransRule> trules = null;
+ List<TransRule> lastRules = null;
+
+ int effectiveSavings = zone.fixedSavingsSecs;
+ if (zone.savingsRule != null) {
+ List<RuleLine> tzdbRules = rules.get(zone.savingsRule);
+ if (tzdbRules == null) {
+ throw new IllegalArgumentException("<Rule> not found: " +
+ zone.savingsRule);
+ }
+ trules = new ArrayList<>(256);
+ lastRules = new ArrayList<>(2);
+ int lastRulesStartYear = Year.MIN_VALUE;
+
+ // merge the rules to transitions
+ for (RuleLine rule : tzdbRules) {
+ if (rule.startYear > zoneEnd.getYear()) {
+ // rules will not be used for this zone entry
+ continue;
+ }
+ rule.adjustToForwards(2004); // irrelevant, treat as leap year
+
+ int startYear = rule.startYear;
+ int endYear = rule.endYear;
+ if (zoneEnd.equals(LocalDateTime.MAX)) {
+ if (endYear == Year.MAX_VALUE) {
+ endYear = startYear;
+ lastRules.add(new TransRule(endYear, rule));
+ lastRulesStartYear = Math.max(startYear, lastRulesStartYear);
+ }
+ } else {
+ if (endYear == Year.MAX_VALUE) {
+ //endYear = zoneEnd.getYear();
+ endYear = zone.year;
+ }
+ }
+ int year = startYear;
+ while (year <= endYear) {
+ trules.add(new TransRule(year, rule));
+ year++;
+ }
+ }
+
+ // last rules, fill the gap years between different last rules
+ if (zoneEnd.equals(LocalDateTime.MAX)) {
+ lastRulesStartYear = Math.max(lastRulesStartYear, zoneStart.getYear()) + 1;
+ for (TransRule rule : lastRules) {
+ if (rule.year <= lastRulesStartYear) {
+ int year = rule.year;
+ while (year <= lastRulesStartYear) {
+ trules.add(new TransRule(year, rule.rule));
+ year++;
+ }
+ rule.year = lastRulesStartYear;
+ rule.ldt = rule.rule.toDateTime(year);
+ rule.ldtSecs = rule.ldt.toEpochSecond(ZoneOffset.UTC);
+ }
+ }
+ Collections.sort(lastRules);
+ }
+ // sort the merged rules
+ Collections.sort(trules);
+
+ effectiveSavings = 0;
+ for (TransRule rule : trules) {
+ if (rule.toEpochSecond(stdOffsetPrev, savings) >
+ zoneStart.toEpochSecond(wallOffset)) {
+ // previous savings amount found, which could be the
+ // savings amount at the instant that the window starts
+ // (hence isAfter)
+ break;
+ }
+ effectiveSavings = rule.rule.savingsAmount;
+ }
+ }
+ // check if the start of the window represents a transition
+ ZoneOffset effectiveWallOffset =
+ ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + effectiveSavings);
+
+ if (!wallOffset.equals(effectiveWallOffset)) {
+ transitionList.add(ZoneOffsetTransition.of(zoneStart,
+ wallOffset,
+ effectiveWallOffset));
+ }
+ savings = effectiveSavings;
+ // apply rules within the window
+ if (trules != null) {
+ long zoneStartEpochSecs = zoneStart.toEpochSecond(wallOffset);
+ for (TransRule trule : trules) {
+ if (trule.isTransition(savings)) {
+ long epochSecs = trule.toEpochSecond(stdOffset, savings);
+ if (epochSecs < zoneStartEpochSecs ||
+ epochSecs >= zone.toDateTimeEpochSecond(savings)) {
+ continue;
+ }
+ transitionList.add(trule.toTransition(stdOffset, savings));
+ savings = trule.rule.savingsAmount;
+ }
+ }
+ }
+ if (lastRules != null) {
+ for (TransRule trule : lastRules) {
+ lastTransitionRuleList.add(trule.rule.toTransitionRule(stdOffset, savings));
+ savings = trule.rule.savingsAmount;
+ }
+ }
+
+ // finally we can calculate the true end of the window, passing it to the next window
+ wallOffset = ZoneOffset.ofTotalSeconds(stdOffset.getTotalSeconds() + savings);
+ zoneStart = LocalDateTime.ofEpochSecond(zone.toDateTimeEpochSecond(savings),
+ 0,
+ wallOffset);
+ }
+ return new ZoneRules(firstStdOffset,
+ firstWallOffset,
+ standardTransitionList,
+ transitionList,
+ lastTransitionRuleList);
+ }
+
+}
--- a/jdk/make/src/classes/build/tools/tzdb/Utils.java Mon Jun 23 10:40:20 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,176 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of JSR-310 nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package build.tools.tzdb;
-
-import java.util.Objects;
-
-class Utils {
-
- // Returns the largest (closest to positive infinity)
- public static long floorDiv(long x, long y) {
- long r = x / y;
- // if the signs are different and modulo not zero, round down
- if ((x ^ y) < 0 && (r * y != x)) {
- r--;
- }
- return r;
- }
-
- // Returns the floor modulus of the {@code long} arguments.
- public static long floorMod(long x, long y) {
- return x - floorDiv(x, y) * y;
- }
-
- // Returns the sum of its arguments,
- public static long addExact(long x, long y) {
- long r = x + y;
- // HD 2-12 Overflow iff both arguments have the opposite sign of the result
- if (((x ^ r) & (y ^ r)) < 0) {
- throw new ArithmeticException("long overflow");
- }
- return r;
- }
-
- // Year
-
- // Returns true if the specified year is a leap year.
- public static boolean isLeapYear(int year) {
- return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
- }
-
- // The minimum supported year, '-999,999,999'.
- public static final int YEAR_MIN_VALUE = -999_999_999;
-
- // The maximum supported year, '+999,999,999'.
- public static final int YEAR_MAX_VALUE = 999_999_999;
-
-
- // Gets the length of the specified month in days.
- public static int lengthOfMonth(int month, boolean leapYear) {
- switch (month) {
- case 2: //FEBRUARY:
- return (leapYear ? 29 : 28);
- case 4: //APRIL:
- case 6: //JUNE:
- case 9: //SEPTEMBER:
- case 11: //NOVEMBER:
- return 30;
- default:
- return 31;
- }
- }
-
- // Gets the maximum length of the specified month in days.
- public static int maxLengthOfMonth(int month) {
- switch (month) {
- case 2: //FEBRUARY:
- return 29;
- case 4: //APRIL:
- case 6: //JUNE:
- case 9: //SEPTEMBER:
- case 11: //NOVEMBER:
- return 30;
- default:
- return 31;
- }
- }
-
- // DayOfWeek
-
- // Returns the day-of-week that is the specified number of days after
- // this one, from 1 to 7 for Monday to Sunday.
- public static int plusDayOfWeek(int dow, long days) {
- int amount = (int) (days % 7);
- return (dow - 1 + (amount + 7)) % 7 + 1;
- }
-
- // Returns the day-of-week that is the specified number of days before
- // this one, from 1 to 7 for Monday to Sunday.
- public static int minusDayOfWeek(int dow, long days) {
- return plusDayOfWeek(dow, -(days % 7));
- }
-
- // Adjusts the date to the first occurrence of the specified day-of-week
- // before the date being adjusted unless it is already on that day in
- // which case the same object is returned.
- public static LocalDate previousOrSame(LocalDate date, int dayOfWeek) {
- return adjust(date, dayOfWeek, 1);
- }
-
- // Adjusts the date to the first occurrence of the specified day-of-week
- // after the date being adjusted unless it is already on that day in
- // which case the same object is returned.
- public static LocalDate nextOrSame(LocalDate date, int dayOfWeek) {
- return adjust(date, dayOfWeek, 0);
- }
-
- // Implementation of next, previous or current day-of-week.
- // @param relative whether the current date is a valid answer
- private static final LocalDate adjust(LocalDate date, int dow, int relative) {
- int calDow = date.getDayOfWeek();
- if (relative < 2 && calDow == dow) {
- return date;
- }
- if ((relative & 1) == 0) {
- int daysDiff = calDow - dow;
- return date.plusDays(daysDiff >= 0 ? 7 - daysDiff : -daysDiff);
- } else {
- int daysDiff = dow - calDow;
- return date.minusDays(daysDiff >= 0 ? 7 - daysDiff : -daysDiff);
- }
- }
-
-}
--- a/jdk/make/src/classes/build/tools/tzdb/ZoneOffset.java Mon Jun 23 10:40:20 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,474 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of JSR-310 nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package build.tools.tzdb;
-
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-/**
- * A time-zone offset from Greenwich/UTC, such as {@code +02:00}.
- * <p>
- * A time-zone offset is the period of time that a time-zone differs from Greenwich/UTC.
- * This is usually a fixed number of hours and minutes.
- *
- * @since 1.8
- */
-final class ZoneOffset implements Comparable<ZoneOffset> {
-
- /** Cache of time-zone offset by offset in seconds. */
- private static final ConcurrentMap<Integer, ZoneOffset> SECONDS_CACHE = new ConcurrentHashMap<>(16, 0.75f, 4);
- /** Cache of time-zone offset by ID. */
- private static final ConcurrentMap<String, ZoneOffset> ID_CACHE = new ConcurrentHashMap<>(16, 0.75f, 4);
-
- /**
- * The number of seconds per hour.
- */
- private static final int SECONDS_PER_HOUR = 60 * 60;
- /**
- * The number of seconds per minute.
- */
- private static final int SECONDS_PER_MINUTE = 60;
- /**
- * The number of minutes per hour.
- */
- private static final int MINUTES_PER_HOUR = 60;
- /**
- * The abs maximum seconds.
- */
- private static final int MAX_SECONDS = 18 * SECONDS_PER_HOUR;
- /**
- * Serialization version.
- */
- private static final long serialVersionUID = 2357656521762053153L;
-
- /**
- * The time-zone offset for UTC, with an ID of 'Z'.
- */
- public static final ZoneOffset UTC = ZoneOffset.ofTotalSeconds(0);
- /**
- * Constant for the maximum supported offset.
- */
- public static final ZoneOffset MIN = ZoneOffset.ofTotalSeconds(-MAX_SECONDS);
- /**
- * Constant for the maximum supported offset.
- */
- public static final ZoneOffset MAX = ZoneOffset.ofTotalSeconds(MAX_SECONDS);
-
- /**
- * The total offset in seconds.
- */
- private final int totalSeconds;
- /**
- * The string form of the time-zone offset.
- */
- private final transient String id;
-
- //-----------------------------------------------------------------------
- /**
- * Obtains an instance of {@code ZoneOffset} using the ID.
- * <p>
- * This method parses the string ID of a {@code ZoneOffset} to
- * return an instance. The parsing accepts all the formats generated by
- * {@link #getId()}, plus some additional formats:
- * <p><ul>
- * <li>{@code Z} - for UTC
- * <li>{@code +h}
- * <li>{@code +hh}
- * <li>{@code +hh:mm}
- * <li>{@code -hh:mm}
- * <li>{@code +hhmm}
- * <li>{@code -hhmm}
- * <li>{@code +hh:mm:ss}
- * <li>{@code -hh:mm:ss}
- * <li>{@code +hhmmss}
- * <li>{@code -hhmmss}
- * </ul><p>
- * Note that ± means either the plus or minus symbol.
- * <p>
- * The ID of the returned offset will be normalized to one of the formats
- * described by {@link #getId()}.
- * <p>
- * The maximum supported range is from +18:00 to -18:00 inclusive.
- *
- * @param offsetId the offset ID, not null
- * @return the zone-offset, not null
- * @throws DateTimeException if the offset ID is invalid
- */
- @SuppressWarnings("fallthrough")
- public static ZoneOffset of(String offsetId) {
- Objects.requireNonNull(offsetId, "offsetId");
- // "Z" is always in the cache
- ZoneOffset offset = ID_CACHE.get(offsetId);
- if (offset != null) {
- return offset;
- }
-
- // parse - +h, +hh, +hhmm, +hh:mm, +hhmmss, +hh:mm:ss
- final int hours, minutes, seconds;
- switch (offsetId.length()) {
- case 2:
- offsetId = offsetId.charAt(0) + "0" + offsetId.charAt(1); // fallthru
- case 3:
- hours = parseNumber(offsetId, 1, false);
- minutes = 0;
- seconds = 0;
- break;
- case 5:
- hours = parseNumber(offsetId, 1, false);
- minutes = parseNumber(offsetId, 3, false);
- seconds = 0;
- break;
- case 6:
- hours = parseNumber(offsetId, 1, false);
- minutes = parseNumber(offsetId, 4, true);
- seconds = 0;
- break;
- case 7:
- hours = parseNumber(offsetId, 1, false);
- minutes = parseNumber(offsetId, 3, false);
- seconds = parseNumber(offsetId, 5, false);
- break;
- case 9:
- hours = parseNumber(offsetId, 1, false);
- minutes = parseNumber(offsetId, 4, true);
- seconds = parseNumber(offsetId, 7, true);
- break;
- default:
- throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid");
- }
- char first = offsetId.charAt(0);
- if (first != '+' && first != '-') {
- throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Plus/minus not found when expected");
- }
- if (first == '-') {
- return ofHoursMinutesSeconds(-hours, -minutes, -seconds);
- } else {
- return ofHoursMinutesSeconds(hours, minutes, seconds);
- }
- }
-
- /**
- * Parse a two digit zero-prefixed number.
- *
- * @param offsetId the offset ID, not null
- * @param pos the position to parse, valid
- * @param precededByColon should this number be prefixed by a precededByColon
- * @return the parsed number, from 0 to 99
- */
- private static int parseNumber(CharSequence offsetId, int pos, boolean precededByColon) {
- if (precededByColon && offsetId.charAt(pos - 1) != ':') {
- throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Colon not found when expected");
- }
- char ch1 = offsetId.charAt(pos);
- char ch2 = offsetId.charAt(pos + 1);
- if (ch1 < '0' || ch1 > '9' || ch2 < '0' || ch2 > '9') {
- throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Non numeric characters found");
- }
- return (ch1 - 48) * 10 + (ch2 - 48);
- }
-
- //-----------------------------------------------------------------------
- /**
- * Obtains an instance of {@code ZoneOffset} using an offset in hours.
- *
- * @param hours the time-zone offset in hours, from -18 to +18
- * @return the zone-offset, not null
- * @throws DateTimeException if the offset is not in the required range
- */
- public static ZoneOffset ofHours(int hours) {
- return ofHoursMinutesSeconds(hours, 0, 0);
- }
-
- /**
- * Obtains an instance of {@code ZoneOffset} using an offset in
- * hours and minutes.
- * <p>
- * The sign of the hours and minutes components must match.
- * Thus, if the hours is negative, the minutes must be negative or zero.
- * If the hours is zero, the minutes may be positive, negative or zero.
- *
- * @param hours the time-zone offset in hours, from -18 to +18
- * @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours
- * @return the zone-offset, not null
- * @throws DateTimeException if the offset is not in the required range
- */
- public static ZoneOffset ofHoursMinutes(int hours, int minutes) {
- return ofHoursMinutesSeconds(hours, minutes, 0);
- }
-
- /**
- * Obtains an instance of {@code ZoneOffset} using an offset in
- * hours, minutes and seconds.
- * <p>
- * The sign of the hours, minutes and seconds components must match.
- * Thus, if the hours is negative, the minutes and seconds must be negative or zero.
- *
- * @param hours the time-zone offset in hours, from -18 to +18
- * @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours and seconds
- * @param seconds the time-zone offset in seconds, from 0 to ±59, sign matches hours and minutes
- * @return the zone-offset, not null
- * @throws DateTimeException if the offset is not in the required range
- */
- public static ZoneOffset ofHoursMinutesSeconds(int hours, int minutes, int seconds) {
- validate(hours, minutes, seconds);
- int totalSeconds = totalSeconds(hours, minutes, seconds);
- return ofTotalSeconds(totalSeconds);
- }
-
- /**
- * Validates the offset fields.
- *
- * @param hours the time-zone offset in hours, from -18 to +18
- * @param minutes the time-zone offset in minutes, from 0 to ±59
- * @param seconds the time-zone offset in seconds, from 0 to ±59
- * @throws DateTimeException if the offset is not in the required range
- */
- private static void validate(int hours, int minutes, int seconds) {
- if (hours < -18 || hours > 18) {
- throw new DateTimeException("Zone offset hours not in valid range: value " + hours +
- " is not in the range -18 to 18");
- }
- if (hours > 0) {
- if (minutes < 0 || seconds < 0) {
- throw new DateTimeException("Zone offset minutes and seconds must be positive because hours is positive");
- }
- } else if (hours < 0) {
- if (minutes > 0 || seconds > 0) {
- throw new DateTimeException("Zone offset minutes and seconds must be negative because hours is negative");
- }
- } else if ((minutes > 0 && seconds < 0) || (minutes < 0 && seconds > 0)) {
- throw new DateTimeException("Zone offset minutes and seconds must have the same sign");
- }
- if (Math.abs(minutes) > 59) {
- throw new DateTimeException("Zone offset minutes not in valid range: abs(value) " +
- Math.abs(minutes) + " is not in the range 0 to 59");
- }
- if (Math.abs(seconds) > 59) {
- throw new DateTimeException("Zone offset seconds not in valid range: abs(value) " +
- Math.abs(seconds) + " is not in the range 0 to 59");
- }
- if (Math.abs(hours) == 18 && (Math.abs(minutes) > 0 || Math.abs(seconds) > 0)) {
- throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
- }
- }
-
- /**
- * Calculates the total offset in seconds.
- *
- * @param hours the time-zone offset in hours, from -18 to +18
- * @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours and seconds
- * @param seconds the time-zone offset in seconds, from 0 to ±59, sign matches hours and minutes
- * @return the total in seconds
- */
- private static int totalSeconds(int hours, int minutes, int seconds) {
- return hours * SECONDS_PER_HOUR + minutes * SECONDS_PER_MINUTE + seconds;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Obtains an instance of {@code ZoneOffset} specifying the total offset in seconds
- * <p>
- * The offset must be in the range {@code -18:00} to {@code +18:00}, which corresponds to -64800 to +64800.
- *
- * @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800
- * @return the ZoneOffset, not null
- * @throws DateTimeException if the offset is not in the required range
- */
- public static ZoneOffset ofTotalSeconds(int totalSeconds) {
- if (Math.abs(totalSeconds) > MAX_SECONDS) {
- throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
- }
- if (totalSeconds % (15 * SECONDS_PER_MINUTE) == 0) {
- Integer totalSecs = totalSeconds;
- ZoneOffset result = SECONDS_CACHE.get(totalSecs);
- if (result == null) {
- result = new ZoneOffset(totalSeconds);
- SECONDS_CACHE.putIfAbsent(totalSecs, result);
- result = SECONDS_CACHE.get(totalSecs);
- ID_CACHE.putIfAbsent(result.getId(), result);
- }
- return result;
- } else {
- return new ZoneOffset(totalSeconds);
- }
- }
-
- /**
- * Constructor.
- *
- * @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800
- */
- private ZoneOffset(int totalSeconds) {
- super();
- this.totalSeconds = totalSeconds;
- id = buildId(totalSeconds);
- }
-
- private static String buildId(int totalSeconds) {
- if (totalSeconds == 0) {
- return "Z";
- } else {
- int absTotalSeconds = Math.abs(totalSeconds);
- StringBuilder buf = new StringBuilder();
- int absHours = absTotalSeconds / SECONDS_PER_HOUR;
- int absMinutes = (absTotalSeconds / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
- buf.append(totalSeconds < 0 ? "-" : "+")
- .append(absHours < 10 ? "0" : "").append(absHours)
- .append(absMinutes < 10 ? ":0" : ":").append(absMinutes);
- int absSeconds = absTotalSeconds % SECONDS_PER_MINUTE;
- if (absSeconds != 0) {
- buf.append(absSeconds < 10 ? ":0" : ":").append(absSeconds);
- }
- return buf.toString();
- }
- }
-
- /**
- * Gets the total zone offset in seconds.
- * <p>
- * This is the primary way to access the offset amount.
- * It returns the total of the hours, minutes and seconds fields as a
- * single offset that can be added to a time.
- *
- * @return the total zone offset amount in seconds
- */
- public int getTotalSeconds() {
- return totalSeconds;
- }
-
- /**
- * Gets the normalized zone offset ID.
- * <p>
- * The ID is minor variation to the standard ISO-8601 formatted string
- * for the offset. There are three formats:
- * <p><ul>
- * <li>{@code Z} - for UTC (ISO-8601)
- * <li>{@code +hh:mm} or {@code -hh:mm} - if the seconds are zero (ISO-8601)
- * <li>{@code +hh:mm:ss} or {@code -hh:mm:ss} - if the seconds are non-zero (not ISO-8601)
- * </ul><p>
- *
- * @return the zone offset ID, not null
- */
- public String getId() {
- return id;
- }
-
- /**
- * Compares this offset to another offset in descending order.
- * <p>
- * The offsets are compared in the order that they occur for the same time
- * of day around the world. Thus, an offset of {@code +10:00} comes before an
- * offset of {@code +09:00} and so on down to {@code -18:00}.
- * <p>
- * The comparison is "consistent with equals", as defined by {@link Comparable}.
- *
- * @param other the other date to compare to, not null
- * @return the comparator value, negative if less, postive if greater
- * @throws NullPointerException if {@code other} is null
- */
- @Override
- public int compareTo(ZoneOffset other) {
- return other.totalSeconds - totalSeconds;
- }
-
- /**
- * Checks if this offset is equal to another offset.
- * <p>
- * The comparison is based on the amount of the offset in seconds.
- * This is equivalent to a comparison by ID.
- *
- * @param obj the object to check, null returns false
- * @return true if this is equal to the other offset
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj instanceof ZoneOffset) {
- return totalSeconds == ((ZoneOffset) obj).totalSeconds;
- }
- return false;
- }
-
- /**
- * A hash code for this offset.
- *
- * @return a suitable hash code
- */
- @Override
- public int hashCode() {
- return totalSeconds;
- }
-
- /**
- * Outputs this offset as a {@code String}, using the normalized ID.
- *
- * @return a string representation of this offset, not null
- */
- @Override
- public String toString() {
- return id;
- }
-
-}
--- a/jdk/make/src/classes/build/tools/tzdb/ZoneOffsetTransition.java Mon Jun 23 10:40:20 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,290 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of JSR-310 nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package build.tools.tzdb;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * A transition between two offsets caused by a discontinuity in the local time-line.
- *
- * @since 1.8
- */
-final class ZoneOffsetTransition implements Comparable<ZoneOffsetTransition> {
-
- /**
- * The local transition date-time at the transition.
- */
- private final LocalDateTime transition;
- /**
- * The offset before transition.
- */
- private final ZoneOffset offsetBefore;
- /**
- * The offset after transition.
- */
- private final ZoneOffset offsetAfter;
-
- /**
- * Creates an instance defining a transition between two offsets.
- *
- * @param transition the transition date-time with the offset before the transition, not null
- * @param offsetBefore the offset before the transition, not null
- * @param offsetAfter the offset at and after the transition, not null
- */
- ZoneOffsetTransition(LocalDateTime transition, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
- Objects.requireNonNull(transition, "transition");
- Objects.requireNonNull(offsetBefore, "offsetBefore");
- Objects.requireNonNull(offsetAfter, "offsetAfter");
- if (offsetBefore.equals(offsetAfter)) {
- throw new IllegalArgumentException("Offsets must not be equal");
- }
- this.transition = transition;
- this.offsetBefore = offsetBefore;
- this.offsetAfter = offsetAfter;
- }
-
- /**
- * Creates an instance from epoch-second and offsets.
- *
- * @param epochSecond the transition epoch-second
- * @param offsetBefore the offset before the transition, not null
- * @param offsetAfter the offset at and after the transition, not null
- */
- ZoneOffsetTransition(long epochSecond, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
- this.transition = LocalDateTime.ofEpochSecond(epochSecond, 0, offsetBefore);
- this.offsetBefore = offsetBefore;
- this.offsetAfter = offsetAfter;
- }
-
- /**
- * Gets the transition instant as an epoch second.
- *
- * @return the transition epoch second
- */
- public long toEpochSecond() {
- return transition.toEpochSecond(offsetBefore);
- }
-
- /**
- * Gets the local transition date-time, as would be expressed with the 'before' offset.
- * <p>
- * This is the date-time where the discontinuity begins expressed with the 'before' offset.
- * At this instant, the 'after' offset is actually used, therefore the combination of this
- * date-time and the 'before' offset will never occur.
- * <p>
- * The combination of the 'before' date-time and offset represents the same instant
- * as the 'after' date-time and offset.
- *
- * @return the transition date-time expressed with the before offset, not null
- */
- public LocalDateTime getDateTimeBefore() {
- return transition;
- }
-
- /**
- * Gets the local transition date-time, as would be expressed with the 'after' offset.
- * <p>
- * This is the first date-time after the discontinuity, when the new offset applies.
- * <p>
- * The combination of the 'before' date-time and offset represents the same instant
- * as the 'after' date-time and offset.
- *
- * @return the transition date-time expressed with the after offset, not null
- */
- public LocalDateTime getDateTimeAfter() {
- return transition.plusSeconds(getDurationSeconds());
- }
-
- /**
- * Gets the offset before the transition.
- * <p>
- * This is the offset in use before the instant of the transition.
- *
- * @return the offset before the transition, not null
- */
- public ZoneOffset getOffsetBefore() {
- return offsetBefore;
- }
-
- /**
- * Gets the offset after the transition.
- * <p>
- * This is the offset in use on and after the instant of the transition.
- *
- * @return the offset after the transition, not null
- */
- public ZoneOffset getOffsetAfter() {
- return offsetAfter;
- }
-
- /**
- * Gets the duration of the transition in seconds.
- *
- * @return the duration in seconds
- */
- private int getDurationSeconds() {
- return getOffsetAfter().getTotalSeconds() - getOffsetBefore().getTotalSeconds();
- }
-
- /**
- * Does this transition represent a gap in the local time-line.
- * <p>
- * Gaps occur where there are local date-times that simply do not not exist.
- * An example would be when the offset changes from {@code +01:00} to {@code +02:00}.
- * This might be described as 'the clocks will move forward one hour tonight at 1am'.
- *
- * @return true if this transition is a gap, false if it is an overlap
- */
- public boolean isGap() {
- return getOffsetAfter().getTotalSeconds() > getOffsetBefore().getTotalSeconds();
- }
-
- /**
- * Does this transition represent a gap in the local time-line.
- * <p>
- * Overlaps occur where there are local date-times that exist twice.
- * An example would be when the offset changes from {@code +02:00} to {@code +01:00}.
- * This might be described as 'the clocks will move back one hour tonight at 2am'.
- *
- * @return true if this transition is an overlap, false if it is a gap
- */
- public boolean isOverlap() {
- return getOffsetAfter().getTotalSeconds() < getOffsetBefore().getTotalSeconds();
- }
-
- /**
- * Checks if the specified offset is valid during this transition.
- * <p>
- * This checks to see if the given offset will be valid at some point in the transition.
- * A gap will always return false.
- * An overlap will return true if the offset is either the before or after offset.
- *
- * @param offset the offset to check, null returns false
- * @return true if the offset is valid during the transition
- */
- public boolean isValidOffset(ZoneOffset offset) {
- return isGap() ? false : (getOffsetBefore().equals(offset) || getOffsetAfter().equals(offset));
- }
-
- /**
- * Gets the valid offsets during this transition.
- * <p>
- * A gap will return an empty list, while an overlap will return both offsets.
- *
- * @return the list of valid offsets
- */
- List<ZoneOffset> getValidOffsets() {
- if (isGap()) {
- return Collections.emptyList();
- }
- return Arrays.asList(getOffsetBefore(), getOffsetAfter());
- }
-
- /**
- * Compares this transition to another based on the transition instant.
- * <p>
- * This compares the instants of each transition.
- * The offsets are ignored, making this order inconsistent with equals.
- *
- * @param transition the transition to compare to, not null
- * @return the comparator value, negative if less, positive if greater
- */
- @Override
- public int compareTo(ZoneOffsetTransition transition) {
- return Long.compare(this.toEpochSecond(), transition.toEpochSecond());
- }
-
- /**
- * Checks if this object equals another.
- * <p>
- * The entire state of the object is compared.
- *
- * @param other the other object to compare to, null returns false
- * @return true if equal
- */
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
- if (other instanceof ZoneOffsetTransition) {
- ZoneOffsetTransition d = (ZoneOffsetTransition) other;
- return transition.equals(d.transition) &&
- offsetBefore.equals(d.offsetBefore) && offsetAfter.equals(d.offsetAfter);
- }
- return false;
- }
-
- /**
- * Returns a suitable hash code.
- *
- * @return the hash code
- */
- @Override
- public int hashCode() {
- return transition.hashCode() ^ offsetBefore.hashCode() ^ Integer.rotateLeft(offsetAfter.hashCode(), 16);
- }
-
-}
--- a/jdk/make/src/classes/build/tools/tzdb/ZoneOffsetTransitionRule.java Mon Jun 23 10:40:20 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,223 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of JSR-310 nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package build.tools.tzdb;
-
-import static build.tools.tzdb.Utils.*;
-import java.util.Objects;
-
-/**
- * A rule expressing how to create a transition.
- * <p>
- * This class allows rules for identifying future transitions to be expressed.
- * A rule might be written in many forms:
- * <p><ul>
- * <li>the 16th March
- * <li>the Sunday on or after the 16th March
- * <li>the Sunday on or before the 16th March
- * <li>the last Sunday in February
- * </ul><p>
- * These different rule types can be expressed and queried.
- *
- * <h3>Specification for implementors</h3>
- * This class is immutable and thread-safe.
- *
- * @since 1.8
- */
-final class ZoneOffsetTransitionRule {
-
- /**
- * The month of the month-day of the first day of the cutover week.
- * The actual date will be adjusted by the dowChange field.
- */
- final int month;
- /**
- * The day-of-month of the month-day of the cutover week.
- * If positive, it is the start of the week where the cutover can occur.
- * If negative, it represents the end of the week where cutover can occur.
- * The value is the number of days from the end of the month, such that
- * {@code -1} is the last day of the month, {@code -2} is the second
- * to last day, and so on.
- */
- final byte dom;
- /**
- * The cutover day-of-week, -1 to retain the day-of-month.
- */
- final int dow;
- /**
- * The cutover time in the 'before' offset.
- */
- final LocalTime time;
- /**
- * Whether the cutover time is midnight at the end of day.
- */
- final boolean timeEndOfDay;
- /**
- * The definition of how the local time should be interpreted.
- */
- final TimeDefinition timeDefinition;
- /**
- * The standard offset at the cutover.
- */
- final ZoneOffset standardOffset;
- /**
- * The offset before the cutover.
- */
- final ZoneOffset offsetBefore;
- /**
- * The offset after the cutover.
- */
- final ZoneOffset offsetAfter;
-
- /**
- * Creates an instance defining the yearly rule to create transitions between two offsets.
- *
- * @param month the month of the month-day of the first day of the cutover week, from 1 to 12
- * @param dayOfMonthIndicator the day of the month-day of the cutover week, positive if the week is that
- * day or later, negative if the week is that day or earlier, counting from the last day of the month,
- * from -28 to 31 excluding 0
- * @param dayOfWeek the required day-of-week, -1 if the month-day should not be changed
- * @param time the cutover time in the 'before' offset, not null
- * @param timeEndOfDay whether the time is midnight at the end of day
- * @param timeDefnition how to interpret the cutover
- * @param standardOffset the standard offset in force at the cutover, not null
- * @param offsetBefore the offset before the cutover, not null
- * @param offsetAfter the offset after the cutover, not null
- * @throws IllegalArgumentException if the day of month indicator is invalid
- * @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
- */
- ZoneOffsetTransitionRule(
- int month,
- int dayOfMonthIndicator,
- int dayOfWeek,
- LocalTime time,
- boolean timeEndOfDay,
- TimeDefinition timeDefnition,
- ZoneOffset standardOffset,
- ZoneOffset offsetBefore,
- ZoneOffset offsetAfter) {
- Objects.requireNonNull(time, "time");
- Objects.requireNonNull(timeDefnition, "timeDefnition");
- Objects.requireNonNull(standardOffset, "standardOffset");
- Objects.requireNonNull(offsetBefore, "offsetBefore");
- Objects.requireNonNull(offsetAfter, "offsetAfter");
- if (month < 1 || month > 12) {
- throw new IllegalArgumentException("month must be between 1 and 12");
- }
- if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) {
- throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero");
- }
- if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
- throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
- }
- this.month = month;
- this.dom = (byte) dayOfMonthIndicator;
- this.dow = dayOfWeek;
- this.time = time;
- this.timeEndOfDay = timeEndOfDay;
- this.timeDefinition = timeDefnition;
- this.standardOffset = standardOffset;
- this.offsetBefore = offsetBefore;
- this.offsetAfter = offsetAfter;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Checks if this object equals another.
- * <p>
- * The entire state of the object is compared.
- *
- * @param otherRule the other object to compare to, null returns false
- * @return true if equal
- */
- @Override
- public boolean equals(Object otherRule) {
- if (otherRule == this) {
- return true;
- }
- if (otherRule instanceof ZoneOffsetTransitionRule) {
- ZoneOffsetTransitionRule other = (ZoneOffsetTransitionRule) otherRule;
- return month == other.month && dom == other.dom && dow == other.dow &&
- timeDefinition == other.timeDefinition &&
- time.equals(other.time) &&
- timeEndOfDay == other.timeEndOfDay &&
- standardOffset.equals(other.standardOffset) &&
- offsetBefore.equals(other.offsetBefore) &&
- offsetAfter.equals(other.offsetAfter);
- }
- return false;
- }
-
- /**
- * Returns a suitable hash code.
- *
- * @return the hash code
- */
- @Override
- public int hashCode() {
- int hash = ((time.toSecondOfDay() + (timeEndOfDay ? 1 : 0)) << 15) +
- (month << 11) + ((dom + 32) << 5) +
- ((dow == -1 ? 8 : dow) << 2) + (timeDefinition.ordinal());
- return hash ^ standardOffset.hashCode() ^
- offsetBefore.hashCode() ^ offsetAfter.hashCode();
- }
-
-}
--- a/jdk/make/src/classes/build/tools/tzdb/ZoneRules.java Mon Jun 23 10:40:20 2014 -0700
+++ b/jdk/make/src/classes/build/tools/tzdb/ZoneRules.java Mon Jun 23 12:12:30 2014 -0700
@@ -64,6 +64,12 @@
import java.io.DataOutput;
import java.io.IOException;
import java.io.ObjectOutput;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneOffset;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneOffsetTransitionRule;
+import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
@@ -224,15 +230,15 @@
* @throws IOException if an error occurs
*/
static void writeRule(ZoneOffsetTransitionRule rule, DataOutput out) throws IOException {
- int month = rule.month;
- byte dom = rule.dom;
- int dow = rule.dow;
- LocalTime time = rule.time;
- boolean timeEndOfDay = rule.timeEndOfDay;
- TimeDefinition timeDefinition = rule.timeDefinition;
- ZoneOffset standardOffset = rule.standardOffset;
- ZoneOffset offsetBefore = rule.offsetBefore;
- ZoneOffset offsetAfter = rule.offsetAfter;
+ int month = rule.getMonth().getValue();
+ byte dom = (byte)rule.getDayOfMonthIndicator();
+ int dow = rule.getDayOfWeek().getValue();
+ LocalTime time = rule.getLocalTime();
+ boolean timeEndOfDay = rule.isMidnightEndOfDay();
+ TimeDefinition timeDefinition = rule.getTimeDefinition();
+ ZoneOffset standardOffset = rule.getStandardOffset();
+ ZoneOffset offsetBefore = rule.getOffsetBefore();
+ ZoneOffset offsetAfter = rule.getOffsetAfter();
int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
int stdOffset = standardOffset.getTotalSeconds();
--- a/jdk/make/src/classes/build/tools/tzdb/ZoneRulesBuilder.java Mon Jun 23 10:40:20 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,743 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of JSR-310 nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package build.tools.tzdb;
-
-import static build.tools.tzdb.Utils.*;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * A mutable builder used to create all the rules for a historic time-zone.
- * <p>
- * The rules of a time-zone describe how the offset changes over time.
- * The rules are created by building windows on the time-line within which
- * the different rules apply. The rules may be one of two kinds:
- * <p><ul>
- * <li>Fixed savings - A single fixed amount of savings from the standard offset will apply.</li>
- * <li>Rules - A set of one or more rules describe how daylight savings changes during the window.</li>
- * </ul><p>
- *
- * <h4>Implementation notes</h4>
- * This class is a mutable builder used to create zone instances.
- * It must only be used from a single thread.
- * The created instances are immutable and thread-safe.
- *
- * @since 1.8
- */
-public class ZoneRulesBuilder {
-
- /**
- * The list of windows.
- */
- private List<TZWindow> windowList = new ArrayList<>();
-
- //-----------------------------------------------------------------------
- /**
- * Constructs an instance of the builder that can be used to create zone rules.
- * <p>
- * The builder is used by adding one or more windows representing portions
- * of the time-line. The standard offset from UTC/Greenwich will be constant
- * within a window, although two adjacent windows can have the same standard offset.
- * <p>
- * Within each window, there can either be a
- * {@link #setFixedSavingsToWindow fixed savings amount} or a
- * {@link #addRuleToWindow list of rules}.
- */
- public ZoneRulesBuilder() {
- }
-
- //-----------------------------------------------------------------------
- /**
- * Adds a window to the builder that can be used to filter a set of rules.
- * <p>
- * This method defines and adds a window to the zone where the standard offset is specified.
- * The window limits the effect of subsequent additions of transition rules
- * or fixed savings. If neither rules or fixed savings are added to the window
- * then the window will default to no savings.
- * <p>
- * Each window must be added sequentially, as the start instant of the window
- * is derived from the until instant of the previous window.
- *
- * @param standardOffset the standard offset, not null
- * @param until the date-time that the offset applies until, not null
- * @param untilDefinition the time type for the until date-time, not null
- * @return this, for chaining
- * @throws IllegalStateException if the window order is invalid
- */
- public ZoneRulesBuilder addWindow(
- ZoneOffset standardOffset,
- LocalDateTime until,
- TimeDefinition untilDefinition) {
- Objects.requireNonNull(standardOffset, "standardOffset");
- Objects.requireNonNull(until, "until");
- Objects.requireNonNull(untilDefinition, "untilDefinition");
- TZWindow window = new TZWindow(standardOffset, until, untilDefinition);
- if (windowList.size() > 0) {
- TZWindow previous = windowList.get(windowList.size() - 1);
- window.validateWindowOrder(previous);
- }
- windowList.add(window);
- return this;
- }
-
- /**
- * Adds a window that applies until the end of time to the builder that can be
- * used to filter a set of rules.
- * <p>
- * This method defines and adds a window to the zone where the standard offset is specified.
- * The window limits the effect of subsequent additions of transition rules
- * or fixed savings. If neither rules or fixed savings are added to the window
- * then the window will default to no savings.
- * <p>
- * This must be added after all other windows.
- * No more windows can be added after this one.
- *
- * @param standardOffset the standard offset, not null
- * @return this, for chaining
- * @throws IllegalStateException if a forever window has already been added
- */
- public ZoneRulesBuilder addWindowForever(ZoneOffset standardOffset) {
- return addWindow(standardOffset, LocalDateTime.MAX, TimeDefinition.WALL);
- }
-
- //-----------------------------------------------------------------------
- /**
- * Sets the previously added window to have fixed savings.
- * <p>
- * Setting a window to have fixed savings simply means that a single daylight
- * savings amount applies throughout the window. The window could be small,
- * such as a single summer, or large, such as a multi-year daylight savings.
- * <p>
- * A window can either have fixed savings or rules but not both.
- *
- * @param fixedSavingAmountSecs the amount of saving to use for the whole window, not null
- * @return this, for chaining
- * @throws IllegalStateException if no window has yet been added
- * @throws IllegalStateException if the window already has rules
- */
- public ZoneRulesBuilder setFixedSavingsToWindow(int fixedSavingAmountSecs) {
- if (windowList.isEmpty()) {
- throw new IllegalStateException("Must add a window before setting the fixed savings");
- }
- TZWindow window = windowList.get(windowList.size() - 1);
- window.setFixedSavings(fixedSavingAmountSecs);
- return this;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Adds a single transition rule to the current window.
- * <p>
- * This adds a rule such that the offset, expressed as a daylight savings amount,
- * changes at the specified date-time.
- *
- * @param transitionDateTime the date-time that the transition occurs as defined by timeDefintion, not null
- * @param timeDefinition the definition of how to convert local to actual time, not null
- * @param savingAmountSecs the amount of saving from the standard offset after the transition in seconds
- * @return this, for chaining
- * @throws IllegalStateException if no window has yet been added
- * @throws IllegalStateException if the window already has fixed savings
- * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
- */
- public ZoneRulesBuilder addRuleToWindow(
- LocalDateTime transitionDateTime,
- TimeDefinition timeDefinition,
- int savingAmountSecs) {
- Objects.requireNonNull(transitionDateTime, "transitionDateTime");
- return addRuleToWindow(
- transitionDateTime.getYear(), transitionDateTime.getYear(),
- transitionDateTime.getMonth(), transitionDateTime.getDayOfMonth(),
- -1, transitionDateTime.getTime(), false, timeDefinition, savingAmountSecs);
- }
-
- /**
- * Adds a single transition rule to the current window.
- * <p>
- * This adds a rule such that the offset, expressed as a daylight savings amount,
- * changes at the specified date-time.
- *
- * @param year the year of the transition, from MIN_YEAR to MAX_YEAR
- * @param month the month of the transition, not null
- * @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek,
- * from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
- * @param time the time that the transition occurs as defined by timeDefintion, not null
- * @param timeEndOfDay whether midnight is at the end of day
- * @param timeDefinition the definition of how to convert local to actual time, not null
- * @param savingAmountSecs the amount of saving from the standard offset after the transition in seconds
- * @return this, for chaining
- * @throws DateTimeException if a date-time field is out of range
- * @throws IllegalStateException if no window has yet been added
- * @throws IllegalStateException if the window already has fixed savings
- * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
- */
- public ZoneRulesBuilder addRuleToWindow(
- int year,
- int month,
- int dayOfMonthIndicator,
- LocalTime time,
- boolean timeEndOfDay,
- TimeDefinition timeDefinition,
- int savingAmountSecs) {
- return addRuleToWindow(year, year, month, dayOfMonthIndicator, -1, time, timeEndOfDay, timeDefinition, savingAmountSecs);
- }
-
- /**
- * Adds a multi-year transition rule to the current window.
- * <p>
- * This adds a rule such that the offset, expressed as a daylight savings amount,
- * changes at the specified date-time for each year in the range.
- *
- * @param startYear the start year of the rule, from MIN_YEAR to MAX_YEAR
- * @param endYear the end year of the rule, from MIN_YEAR to MAX_YEAR
- * @param month the month of the transition, from 1 to 12
- * @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek,
- * from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
- * @param dayOfWeek the day-of-week to adjust to, -1 if day-of-month should not be adjusted
- * @param time the time that the transition occurs as defined by timeDefintion, not null
- * @param timeEndOfDay whether midnight is at the end of day
- * @param timeDefinition the definition of how to convert local to actual time, not null
- * @param savingAmountSecs the amount of saving from the standard offset after the transition in seconds
- * @return this, for chaining
- * @throws DateTimeException if a date-time field is out of range
- * @throws IllegalArgumentException if the day of month indicator is invalid
- * @throws IllegalArgumentException if the end of day midnight flag does not match the time
- * @throws IllegalStateException if no window has yet been added
- * @throws IllegalStateException if the window already has fixed savings
- * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
- */
- public ZoneRulesBuilder addRuleToWindow(
- int startYear,
- int endYear,
- int month,
- int dayOfMonthIndicator,
- int dayOfWeek,
- LocalTime time,
- boolean timeEndOfDay,
- TimeDefinition timeDefinition,
- int savingAmountSecs) {
- Objects.requireNonNull(time, "time");
- Objects.requireNonNull(timeDefinition, "timeDefinition");
- if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) {
- throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero");
- }
- if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
- throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
- }
- if (windowList.isEmpty()) {
- throw new IllegalStateException("Must add a window before adding a rule");
- }
- TZWindow window = windowList.get(windowList.size() - 1);
- window.addRule(startYear, endYear, month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition, savingAmountSecs);
- return this;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Completes the build converting the builder to a set of time-zone rules.
- * <p>
- * Calling this method alters the state of the builder.
- * Further rules should not be added to this builder once this method is called.
- *
- * @param zoneId the time-zone ID, not null
- * @return the zone rules, not null
- * @throws IllegalStateException if no windows have been added
- * @throws IllegalStateException if there is only one rule defined as being forever for any given window
- */
- public ZoneRules toRules(String zoneId) {
- Objects.requireNonNull(zoneId, "zoneId");
- if (windowList.isEmpty()) {
- throw new IllegalStateException("No windows have been added to the builder");
- }
-
- final List<ZoneOffsetTransition> standardTransitionList = new ArrayList<>(4);
- final List<ZoneOffsetTransition> transitionList = new ArrayList<>(256);
- final List<ZoneOffsetTransitionRule> lastTransitionRuleList = new ArrayList<>(2);
-
- // initialize the standard offset calculation
- final TZWindow firstWindow = windowList.get(0);
- ZoneOffset loopStandardOffset = firstWindow.standardOffset;
- int loopSavings = 0;
- if (firstWindow.fixedSavingAmountSecs != null) {
- loopSavings = firstWindow.fixedSavingAmountSecs;
- }
- final ZoneOffset firstWallOffset = ZoneOffset.ofTotalSeconds(loopStandardOffset.getTotalSeconds() + loopSavings);
- LocalDateTime loopWindowStart = LocalDateTime.of(YEAR_MIN_VALUE, 1, 1, 0, 0);
- ZoneOffset loopWindowOffset = firstWallOffset;
-
- // build the windows and rules to interesting data
- for (TZWindow window : windowList) {
- // tidy the state
- window.tidy(loopWindowStart.getYear());
-
- // calculate effective savings at the start of the window
- Integer effectiveSavings = window.fixedSavingAmountSecs;
- if (effectiveSavings == null) {
- // apply rules from this window together with the standard offset and
- // savings from the last window to find the savings amount applicable
- // at start of this window
- effectiveSavings = 0;
- for (TZRule rule : window.ruleList) {
- if (rule.toEpochSecond(loopStandardOffset, loopSavings) > loopWindowStart.toEpochSecond(loopWindowOffset)) {
- // previous savings amount found, which could be the savings amount at
- // the instant that the window starts (hence isAfter)
- break;
- }
- effectiveSavings = rule.savingAmountSecs;
- }
- }
-
- // check if standard offset changed, and update it
- if (loopStandardOffset.equals(window.standardOffset) == false) {
- standardTransitionList.add(
- new ZoneOffsetTransition(
- LocalDateTime.ofEpochSecond(loopWindowStart.toEpochSecond(loopWindowOffset), 0, loopStandardOffset),
- loopStandardOffset, window.standardOffset));
- loopStandardOffset = window.standardOffset;
- }
-
- // check if the start of the window represents a transition
- ZoneOffset effectiveWallOffset = ZoneOffset.ofTotalSeconds(loopStandardOffset.getTotalSeconds() + effectiveSavings);
- if (loopWindowOffset.equals(effectiveWallOffset) == false) {
- transitionList.add(new ZoneOffsetTransition(loopWindowStart, loopWindowOffset, effectiveWallOffset));
- }
- loopSavings = effectiveSavings;
-
- // apply rules within the window
- for (TZRule rule : window.ruleList) {
- if (rule.isTransition(loopSavings)) {
- ZoneOffsetTransition trans = rule.toTransition(loopStandardOffset, loopSavings);
- if (trans.toEpochSecond() < loopWindowStart.toEpochSecond(loopWindowOffset) == false &&
- trans.toEpochSecond() < window.createDateTimeEpochSecond(loopSavings)) {
- transitionList.add(trans);
- loopSavings = rule.savingAmountSecs;
- }
- }
- }
-
- // calculate last rules
- for (TZRule lastRule : window.lastRuleList) {
- lastTransitionRuleList.add(lastRule.toTransitionRule(loopStandardOffset, loopSavings));
- loopSavings = lastRule.savingAmountSecs;
- }
-
- // finally we can calculate the true end of the window, passing it to the next window
- loopWindowOffset = window.createWallOffset(loopSavings);
- loopWindowStart = LocalDateTime.ofEpochSecond(
- window.createDateTimeEpochSecond(loopSavings), 0, loopWindowOffset);
- }
-
- return new ZoneRules(
- firstWindow.standardOffset, firstWallOffset, standardTransitionList,
- transitionList, lastTransitionRuleList);
- }
-
- //-----------------------------------------------------------------------
- /**
- * A definition of a window in the time-line.
- * The window will have one standard offset and will either have a
- * fixed DST savings or a set of rules.
- */
- class TZWindow {
- /** The standard offset during the window, not null. */
- private final ZoneOffset standardOffset;
- /** The end local time, not null. */
- private final LocalDateTime windowEnd;
- /** The type of the end time, not null. */
- private final TimeDefinition timeDefinition;
-
- /** The fixed amount of the saving to be applied during this window. */
- private Integer fixedSavingAmountSecs;
- /** The rules for the current window. */
- private List<TZRule> ruleList = new ArrayList<>();
- /** The latest year that the last year starts at. */
- private int maxLastRuleStartYear = YEAR_MIN_VALUE;
- /** The last rules. */
- private List<TZRule> lastRuleList = new ArrayList<>();
-
- /**
- * Constructor.
- *
- * @param standardOffset the standard offset applicable during the window, not null
- * @param windowEnd the end of the window, relative to the time definition, null if forever
- * @param timeDefinition the time definition for calculating the true end, not null
- */
- TZWindow(
- ZoneOffset standardOffset,
- LocalDateTime windowEnd,
- TimeDefinition timeDefinition) {
- super();
- this.windowEnd = windowEnd;
- this.timeDefinition = timeDefinition;
- this.standardOffset = standardOffset;
- }
-
- /**
- * Sets the fixed savings amount for the window.
- *
- * @param fixedSavingAmount the amount of daylight saving to apply throughout the window, may be null
- * @throws IllegalStateException if the window already has rules
- */
- void setFixedSavings(int fixedSavingAmount) {
- if (ruleList.size() > 0 || lastRuleList.size() > 0) {
- throw new IllegalStateException("Window has DST rules, so cannot have fixed savings");
- }
- this.fixedSavingAmountSecs = fixedSavingAmount;
- }
-
- /**
- * Adds a rule to the current window.
- *
- * @param startYear the start year of the rule, from MIN_YEAR to MAX_YEAR
- * @param endYear the end year of the rule, from MIN_YEAR to MAX_YEAR
- * @param month the month of the transition, not null
- * @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek,
- * from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
- * @param dayOfWeek the day-of-week to adjust to, null if day-of-month should not be adjusted
- * @param time the time that the transition occurs as defined by timeDefintion, not null
- * @param timeEndOfDay whether midnight is at the end of day
- * @param timeDefinition the definition of how to convert local to actual time, not null
- * @param savingAmountSecs the amount of saving from the standard offset in seconds
- * @throws IllegalStateException if the window already has fixed savings
- * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
- */
- void addRule(
- int startYear,
- int endYear,
- int month,
- int dayOfMonthIndicator,
- int dayOfWeek,
- LocalTime time,
- boolean timeEndOfDay,
- TimeDefinition timeDefinition,
- int savingAmountSecs) {
-
- if (fixedSavingAmountSecs != null) {
- throw new IllegalStateException("Window has a fixed DST saving, so cannot have DST rules");
- }
- if (ruleList.size() >= 2000) {
- throw new IllegalStateException("Window has reached the maximum number of allowed rules");
- }
- boolean lastRule = false;
- if (endYear == YEAR_MAX_VALUE) {
- lastRule = true;
- endYear = startYear;
- }
- int year = startYear;
- while (year <= endYear) {
- TZRule rule = new TZRule(year, month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition, savingAmountSecs);
- if (lastRule) {
- lastRuleList.add(rule);
- maxLastRuleStartYear = Math.max(startYear, maxLastRuleStartYear);
- } else {
- ruleList.add(rule);
- }
- year++;
- }
- }
-
- /**
- * Validates that this window is after the previous one.
- *
- * @param previous the previous window, not null
- * @throws IllegalStateException if the window order is invalid
- */
- void validateWindowOrder(TZWindow previous) {
- if (windowEnd.compareTo(previous.windowEnd) < 0) {
- throw new IllegalStateException("Windows must be added in date-time order: " +
- windowEnd + " < " + previous.windowEnd);
- }
- }
-
- /**
- * Adds rules to make the last rules all start from the same year.
- * Also add one more year to avoid weird case where penultimate year has odd offset.
- *
- * @param windowStartYear the window start year
- * @throws IllegalStateException if there is only one rule defined as being forever
- */
- void tidy(int windowStartYear) {
- if (lastRuleList.size() == 1) {
- throw new IllegalStateException("Cannot have only one rule defined as being forever");
- }
-
- // handle last rules
- if (windowEnd.equals(LocalDateTime.MAX)) {
- // setup at least one real rule, which closes off other windows nicely
- maxLastRuleStartYear = Math.max(maxLastRuleStartYear, windowStartYear) + 1;
- for (TZRule lastRule : lastRuleList) {
- addRule(lastRule.year, maxLastRuleStartYear, lastRule.month, lastRule.dayOfMonthIndicator,
- lastRule.dayOfWeek, lastRule.time, lastRule.timeEndOfDay, lastRule.timeDefinition, lastRule.savingAmountSecs);
- lastRule.year = maxLastRuleStartYear + 1;
- }
- if (maxLastRuleStartYear == YEAR_MAX_VALUE) {
- lastRuleList.clear();
- } else {
- maxLastRuleStartYear++;
- }
- } else {
- // convert all within the endYear limit
- int endYear = windowEnd.getYear();
- for (TZRule lastRule : lastRuleList) {
- addRule(lastRule.year, endYear + 1, lastRule.month, lastRule.dayOfMonthIndicator,
- lastRule.dayOfWeek, lastRule.time, lastRule.timeEndOfDay, lastRule.timeDefinition, lastRule.savingAmountSecs);
- }
- lastRuleList.clear();
- maxLastRuleStartYear = YEAR_MAX_VALUE;
- }
-
- // ensure lists are sorted
- Collections.sort(ruleList);
- Collections.sort(lastRuleList);
-
- // default fixed savings to zero
- if (ruleList.size() == 0 && fixedSavingAmountSecs == null) {
- fixedSavingAmountSecs = 0;
- }
- }
-
- /**
- * Checks if the window is empty.
- *
- * @return true if the window is only a standard offset
- */
- boolean isSingleWindowStandardOffset() {
- return windowEnd.equals(LocalDateTime.MAX) && timeDefinition == TimeDefinition.WALL &&
- fixedSavingAmountSecs == null && lastRuleList.isEmpty() && ruleList.isEmpty();
- }
-
- /**
- * Creates the wall offset for the local date-time at the end of the window.
- *
- * @param savingsSecs the amount of savings in use in seconds
- * @return the created date-time epoch second in the wall offset, not null
- */
- ZoneOffset createWallOffset(int savingsSecs) {
- return ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsSecs);
- }
-
- /**
- * Creates the offset date-time for the local date-time at the end of the window.
- *
- * @param savingsSecs the amount of savings in use in seconds
- * @return the created date-time epoch second in the wall offset, not null
- */
- long createDateTimeEpochSecond(int savingsSecs) {
- ZoneOffset wallOffset = createWallOffset(savingsSecs);
- LocalDateTime ldt = timeDefinition.createDateTime(windowEnd, standardOffset, wallOffset);
- return ldt.toEpochSecond(wallOffset);
- }
- }
-
- //-----------------------------------------------------------------------
- /**
- * A definition of the way a local time can be converted to an offset time.
- */
- class TZRule implements Comparable<TZRule> {
- private int year;
- private int month;
- private int dayOfMonthIndicator;
- private int dayOfWeek;
- private LocalTime time;
- private boolean timeEndOfDay; // Whether the local time is end of day.
- private TimeDefinition timeDefinition; // The type of the time.
- private int savingAmountSecs; // The amount of the saving to be applied after this point.
-
- /**
- * Constructor.
- *
- * @param year the year
- * @param month the month, value from 1 to 12
- * @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek,
- * from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
- * @param dayOfWeek the day-of-week, -1 if day-of-month is exact
- * @param time the time, not null
- * @param timeEndOfDay whether midnight is at the end of day
- * @param timeDefinition the time definition, not null
- * @param savingAfterSecs the savings amount in seconds
- */
- TZRule(int year, int month, int dayOfMonthIndicator,
- int dayOfWeek, LocalTime time, boolean timeEndOfDay,
- TimeDefinition timeDefinition, int savingAfterSecs) {
- this.year = year;
- this.month = month;
- this.dayOfMonthIndicator = dayOfMonthIndicator;
- this.dayOfWeek = dayOfWeek;
- this.time = time;
- this.timeEndOfDay = timeEndOfDay;
- this.timeDefinition = timeDefinition;
- this.savingAmountSecs = savingAfterSecs;
- }
-
- /**
- * Converts this to a transition.
- *
- * @param standardOffset the active standard offset, not null
- * @param savingsBeforeSecs the active savings in seconds
- * @return the transition, not null
- */
- ZoneOffsetTransition toTransition(ZoneOffset standardOffset, int savingsBeforeSecs) {
- // copy of code in ZoneOffsetTransitionRule to avoid infinite loop
- LocalDate date = toLocalDate();
- LocalDateTime ldt = LocalDateTime.of(date, time);
- ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsBeforeSecs);
- LocalDateTime dt = timeDefinition.createDateTime(ldt, standardOffset, wallOffset);
- ZoneOffset offsetAfter = ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingAmountSecs);
- return new ZoneOffsetTransition(dt, wallOffset, offsetAfter);
- }
-
- /**
- * Returns the apoch second of this rules with the specified
- * active standard offset and active savings
- *
- * @param standardOffset the active standard offset, not null
- * @param savingsBeforeSecs the active savings in seconds
- * @return the transition epoch second
- */
- long toEpochSecond(ZoneOffset standardOffset, int savingsBeforeSecs) {
- LocalDateTime ldt = LocalDateTime.of(toLocalDate(), time);
- ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsBeforeSecs);
- return timeDefinition.createDateTime(ldt, standardOffset, wallOffset)
- .toEpochSecond(wallOffset);
- }
-
- /**
- * Tests if this a real transition with the active savings in seconds
- *
- * @param savingsBeforeSecs the active savings in seconds
- * @return true, if savings in seconds changes
- */
- boolean isTransition(int savingsBeforeSecs) {
- return savingAmountSecs != savingsBeforeSecs;
- }
-
- /**
- * Converts this to a transition rule.
- *
- * @param standardOffset the active standard offset, not null
- * @param savingsBeforeSecs the active savings before the transition in seconds
- * @return the transition, not null
- */
- ZoneOffsetTransitionRule toTransitionRule(ZoneOffset standardOffset, int savingsBeforeSecs) {
- // optimize stored format
- if (dayOfMonthIndicator < 0) {
- if (month != 2) { // not Month.FEBRUARY
- dayOfMonthIndicator = maxLengthOfMonth(month) - 6;
- }
- }
- if (timeEndOfDay && dayOfMonthIndicator > 0 &&
- (dayOfMonthIndicator == 28 && month == 2) == false) {
- LocalDate date = LocalDate.of(2004, month, dayOfMonthIndicator).plusDays(1); // leap-year
- month = date.getMonth();
- dayOfMonthIndicator = date.getDayOfMonth();
- if (dayOfWeek != -1) {
- dayOfWeek = plusDayOfWeek(dayOfWeek, 1);
- }
- timeEndOfDay = false;
- }
- // build rule
- return new ZoneOffsetTransitionRule(
- month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition,
- standardOffset,
- ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsBeforeSecs),
- ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingAmountSecs));
- }
-
- public int compareTo(TZRule other) {
- int cmp = year - other.year;
- cmp = (cmp == 0 ? month - other.month : cmp);
- if (cmp == 0) {
- // convert to date to handle dow/domIndicator/timeEndOfDay
- LocalDate thisDate = toLocalDate();
- LocalDate otherDate = other.toLocalDate();
- cmp = thisDate.compareTo(otherDate);
- }
- cmp = (cmp == 0 ? time.compareTo(other.time) : cmp);
- return cmp;
- }
-
- private LocalDate toLocalDate() {
- LocalDate date;
- if (dayOfMonthIndicator < 0) {
- int monthLen = lengthOfMonth(month, isLeapYear(year));
- date = LocalDate.of(year, month, monthLen + 1 + dayOfMonthIndicator);
- if (dayOfWeek != -1) {
- date = previousOrSame(date, dayOfWeek);
- }
- } else {
- date = LocalDate.of(year, month, dayOfMonthIndicator);
- if (dayOfWeek != -1) {
- date = nextOrSame(date, dayOfWeek);
- }
- }
- if (timeEndOfDay) {
- date = date.plusDays(1);
- }
- return date;
- }
- }
-
-}