Index: 3rdParty_sources/joda-time/org/joda/time/Chronology.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/Chronology.java (.../Chronology.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/Chronology.java (.../Chronology.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,74 +1,32 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; -import org.joda.time.chrono.BuddhistChronology; -import org.joda.time.chrono.CopticChronology; -import org.joda.time.chrono.GJChronology; -import org.joda.time.chrono.GregorianChronology; -import org.joda.time.chrono.ISOChronology; -import org.joda.time.chrono.JulianChronology; /** * Chronology provides access to the individual date time fields for a * chronological calendar system. *

- * Various chronologies are supported by subclasses including ISO and GregorianJulian. - * This class provides static factory methods to access these chronologies. + * Various chronologies are supported by subclasses including ISO + * and GregorianJulian. To construct a Chronology you should use the + * factory methods on the chronology subclass in the chrono package. + *

* For example, to obtain the current time in the coptic calendar system: *

- * DateTime dt = new DateTime(Chronology.getCoptic());
+ * DateTime dt = new DateTime(CopticChronology.getInstance());
  * 
*

* The provided chronology implementations are: @@ -79,6 +37,7 @@ *

  • Julian - The Julian calendar system used for all time (proleptic) *
  • Buddhist - The Buddhist calendar system which is an offset in years from GJ *
  • Coptic - The Coptic calendar system which defines 30 day months + *
  • Ethiopic - The Ethiopic calendar system which defines 30 day months * * Hopefully future releases will contain more chronologies. *

    @@ -88,13 +47,14 @@ * For example, a week could be defined as 10 days and a month as 40 days in a * special WeirdChronology implementation. Clearly the GJ and ISO * implementations provided use the field names as you would expect. - * + * * @see org.joda.time.chrono.ISOChronology * @see org.joda.time.chrono.GJChronology * @see org.joda.time.chrono.GregorianChronology * @see org.joda.time.chrono.JulianChronology * @see org.joda.time.chrono.CopticChronology * @see org.joda.time.chrono.BuddhistChronology + * @see org.joda.time.chrono.EthiopicChronology * * @author Stephen Colebourne * @author Brian S O'Neill @@ -103,325 +63,10 @@ public abstract class Chronology { /** - * Gets an instance of the ISOChronology in the default zone. - *

    - * {@link ISOChronology} defines all fields in line with the ISO8601 standard. - * This chronology is the default, and is suitable for all normal datetime processing. - * It is unsuitable for historical datetimes before October 15, 1582 - * as it applies the modern Gregorian calendar rules before that date. - * - * @return the ISO chronology - */ - public static Chronology getISO() { - return ISOChronology.getInstance(); - } - - /** - * Gets an instance of the ISOChronology in the UTC zone. - *

    - * {@link ISOChronology} defines all fields in line with the ISO8601 standard. - * This chronology is the default, and is suitable for all normal datetime processing. - * It is unsuitable for historical datetimes before October 15, 1582 - * as it applies the modern Gregorian calendar rules before that date. - * - * @return the ISO chronology - */ - public static Chronology getISOUTC() { - return ISOChronology.getInstanceUTC(); - } - - /** - * Gets an instance of the ISOChronology in the specified zone. - *

    - * {@link ISOChronology} defines all fields in line with the ISO8601 standard. - * This chronology is the default, and is suitable for all normal datetime processing. - * It is unsuitable for historical datetimes before October 15, 1582 - * as it applies the modern Gregorian calendar rules before that date. - * - * @param zone the zone to use, null means default zone - * @return the ISO chronology - */ - public static Chronology getISO(DateTimeZone zone) { - return ISOChronology.getInstance(zone); - } - - //----------------------------------------------------------------------- - /** - * Gets an instance of the GJChronology in the default zone. - *

    - * {@link GJChronology} defines all fields using standard meanings. - * This chronology is intended to be used as a replacement for GregorianCalendar. - * The Gregorian calendar system is used after October 15, 1582, while the - * Julian calendar system is used before. - *

    - * Unlike GregorianCalendar, this chronology returns a year of -1 - * for 1 BCE, -2 for 2 BCE and so on. Thus there is no year zero. - *

    - * This method uses the standard Julian to Gregorian cutover date of - * October 15th 1582. If you require a cutover on a different date, then use - * the factories on GJChronology itself. - *

    - * When dealing solely with dates in the modern era, from 1600 onwards, - * we recommend using ISOChronology, which is the default. - * - * @return the GJ chronology - */ - public static Chronology getGJ() { - return GJChronology.getInstance(); - } - - /** - * Gets an instance of the GJChronology in the UTC zone. - *

    - * {@link GJChronology} defines all fields using standard meanings. - * This chronology is intended to be used as a replacement for GregorianCalendar. - * The Gregorian calendar system is used after October 15, 1582, while the - * Julian calendar system is used before. - *

    - * Unlike GregorianCalendar, this chronology returns a year of -1 - * for 1 BCE, -2 for 2 BCE and so on. Thus there is no year zero. - *

    - * This method uses the standard Julian to Gregorian cutover date of - * October 15th 1582. If you require a cutover on a different date, then use - * the factories on GJChronology itself. - *

    - * When dealing solely with dates in the modern era, from 1600 onwards, - * we recommend using ISOChronology, which is the default. - * - * @return the GJ chronology - */ - public static Chronology getGJUTC() { - return GJChronology.getInstanceUTC(); - } - - /** - * Gets an instance of the GJChronology in the specified zone. - *

    - * {@link GJChronology} defines all fields using standard meanings. - * This chronology is intended to be used as a replacement for GregorianCalendar. - * The Gregorian calendar system is used after October 15, 1582, while the - * Julian calendar system is used before. - *

    - * Unlike GregorianCalendar, this chronology returns a year of -1 - * for 1 BCE, -2 for 2 BCE and so on. Thus there is no year zero. - *

    - * This method uses the standard Julian to Gregorian cutover date of - * October 15th 1582. If you require a cutover on a different date, then use - * the factories on GJChronology itself. - *

    - * When dealing solely with dates in the modern era, from 1600 onwards, - * we recommend using ISOChronology, which is the default. - * - * @param zone the zone to use, null means default zone - * @return the GJ chronology - */ - public static Chronology getGJ(DateTimeZone zone) { - return GJChronology.getInstance(zone); - } - - //----------------------------------------------------------------------- - /** - * Gets an instance of the GregorianChronology in the default zone. - *

    - * {@link GregorianChronology} defines all fields using standard meanings. - * It uses the Gregorian calendar rules for all time (proleptic) - * thus it is NOT a replacement for GregorianCalendar. - * For that purpose, you should use {@link #getGJ()}. - *

    - * The Gregorian calendar system defines a leap year every four years, - * except that every 100 years is not leap, but every 400 is leap. - *

    - * Technically, this chronology is almost identical to the ISO chronology, - * thus we recommend using ISOChronology instead, which is the default. - * - * @return the Gregorian chronology - */ - public static Chronology getGregorian() { - return GregorianChronology.getInstance(); - } - - /** - * Gets an instance of the GregorianChronology in the UTC zone. - *

    - * {@link GregorianChronology} defines all fields using standard meanings. - * It uses the Gregorian calendar rules for all time (proleptic) - * thus it is NOT a replacement for GregorianCalendar. - * For that purpose, you should use {@link #getGJ()}. - *

    - * The Gregorian calendar system defines a leap year every four years, - * except that every 100 years is not leap, but every 400 is leap. - *

    - * Technically, this chronology is almost identical to the ISO chronology, - * thus we recommend using ISOChronology instead, which is the default. - * - * @return the Gregorian chronology - */ - public static Chronology getGregorianUTC() { - return GregorianChronology.getInstanceUTC(); - } - - /** - * Gets an instance of the GregorianChronology in the specified zone. - *

    - * {@link GregorianChronology} defines all fields using standard meanings. - * It uses the Gregorian calendar rules for all time (proleptic) - * thus it is NOT a replacement for GregorianCalendar. - * For that purpose, you should use {@link #getGJ()}. - *

    - * The Gregorian calendar system defines a leap year every four years, - * except that every 100 years is not leap, but every 400 is leap. - *

    - * Technically, this chronology is almost identical to the ISO chronology, - * thus we recommend using ISOChronology instead, which is the default. - * - * @param zone the zone to use, null means default zone - * @return the Gregorian chronology - */ - public static Chronology getGregorian(DateTimeZone zone) { - return GregorianChronology.getInstance(zone); - } - - //----------------------------------------------------------------------- - /** - * Gets an instance of the JulianChronology in the default zone. - *

    - * {@link JulianChronology} defines all fields using standard meanings. - * It uses the Julian calendar rules for all time (proleptic). - * The Julian calendar system defines a leap year every four years. - * - * @return the Julian chronology - */ - public static Chronology getJulian() { - return JulianChronology.getInstance(); - } - - /** - * Gets an instance of the JulianChronology in the UTC zone. - *

    - * {@link JulianChronology} defines all fields using standard meanings. - * It uses the Julian calendar rules for all time (proleptic). - * The Julian calendar system defines a leap year every four years. - * - * @return the Julian chronology - */ - public static Chronology getJulianUTC() { - return JulianChronology.getInstanceUTC(); - } - - /** - * Gets an instance of the JulianChronology in the specified zone. - *

    - * {@link JulianChronology} defines all fields using standard meanings. - * It uses the Julian calendar rules for all time (proleptic). - * The Julian calendar system defines a leap year every four years. - * - * @param zone the zone to use, null means default zone - * @return the Julian chronology - */ - public static Chronology getJulian(DateTimeZone zone) { - return JulianChronology.getInstance(zone); - } - - //----------------------------------------------------------------------- - /** - * Gets an instance of the BuddhistChronology in the default zone. - *

    - * {@link BuddhistChronology} defines all fields using standard meanings, - * however the year is offset by 543. The chronology cannot be used before - * year 1 in the Buddhist calendar. - * - * @return the Buddhist chronology - */ - public static Chronology getBuddhist() { - return BuddhistChronology.getInstance(); - } - - /** - * Gets an instance of the BuddhistChronology in the UTC zone. - *

    - * {@link BuddhistChronology} defines all fields using standard meanings, - * however the year is offset by 543. The chronology cannot be used before - * year 1 in the Buddhist calendar. - * - * @return the Buddhist chronology - */ - public static Chronology getBuddhistUTC() { - return BuddhistChronology.getInstanceUTC(); - } - - /** - * Gets an instance of the BuddhistChronology in the specified zone. - *

    - * {@link BuddhistChronology} defines all fields using standard meanings, - * however the year is offset by 543. The chronology cannot be used before - * year 1 in the Buddhist calendar. - * - * @param zone the zone to use, null means default zone - * @return the Buddhist chronology - */ - public static Chronology getBuddhist(DateTimeZone zone) { - return BuddhistChronology.getInstance(zone); - } - - //----------------------------------------------------------------------- - /** - * Gets an instance of the CopticChronology in the default zone. - *

    - * {@link CopticChronology} defines fields sensibly for the Coptic calendar system. - * The Coptic calendar system defines every fourth year as leap. - * The year is broken down into 12 months, each 30 days in length. - * An extra period at the end of the year is either 5 or 6 days in length - * and is returned as a 13th month. - * Year 1 in the Coptic calendar began on August 29, 284 CE (Julian). - * The chronology cannot be used before the first Coptic year. - * - * @return the Coptic chronology - */ - public static Chronology getCoptic() { - return CopticChronology.getInstance(); - } - - /** - * Gets an instance of the CopticChronology in the UTC zone. - *

    - * {@link CopticChronology} defines fields sensibly for the Coptic calendar system. - * The Coptic calendar system defines every fourth year as leap. - * The year is broken down into 12 months, each 30 days in length. - * An extra period at the end of the year is either 5 or 6 days in length - * and is returned as a 13th month. - * Year 1 in the Coptic calendar began on August 29, 284 CE (Julian). - * The chronology cannot be used before the first Coptic year. - * - * @return the Coptic chronology - */ - public static Chronology getCopticUTC() { - return CopticChronology.getInstanceUTC(); - } - - /** - * Gets an instance of the CopticChronology in the specified zone. - *

    - * {@link CopticChronology} defines fields sensibly for the Coptic calendar system. - * The Coptic calendar system defines every fourth year as leap. - * The year is broken down into 12 months, each 30 days in length. - * An extra period at the end of the year is either 5 or 6 days in length - * and is returned as a 13th month. - * Year 1 in the Coptic calendar began on August 29, 284 CE (Julian). - * The chronology cannot be used before the first Coptic year. - * - * @param zone the zone to use, null means default zone - * @return the Coptic chronology - */ - public static Chronology getCoptic(DateTimeZone zone) { - return CopticChronology.getInstance(zone); - } - - //----------------------------------------------------------------------- - /** * Returns the DateTimeZone that this Chronology operates in, or null if * unspecified. * - * @return DateTimeZone null if unspecified + * @return the DateTimeZone, null if unspecified */ public abstract DateTimeZone getZone(); Index: 3rdParty_sources/joda-time/org/joda/time/DateMidnight.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/DateMidnight.java (.../DateMidnight.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/DateMidnight.java (.../DateMidnight.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,63 +1,31 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Locale; +import org.joda.convert.FromString; import org.joda.time.base.BaseDateTime; import org.joda.time.field.AbstractReadableInstantFieldProperty; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; /** * DateMidnight defines a date where the time component is fixed at midnight. @@ -69,7 +37,7 @@ *

    * This class does not represent a day, but the millisecond instant at midnight. * If you need a class that represents the whole day, then an {@link Interval} or - * a {@link YearMonthDay} may be more suitable. + * a {@link LocalDate} may be more suitable. *

    * This class uses a Chronology internally. The Chronology determines how the * millisecond instant value is converted into the date time fields. @@ -107,12 +75,83 @@ /** Serialization lock */ private static final long serialVersionUID = 156371964018738L; - // Constructors //----------------------------------------------------------------------- /** + * Obtains a {@code DateMidnight} set to the current system millisecond time + * using ISOChronology in the default time zone. + * The constructed object will have a local time of midnight. + * + * @return the current date, not null + * @since 2.0 + */ + public static DateMidnight now() { + return new DateMidnight(); + } + + /** + * Obtains a {@code DateMidnight} set to the current system millisecond time + * using ISOChronology in the specified time zone. + * The constructed object will have a local time of midnight. + * + * @param zone the time zone, not null + * @return the current date, not null + * @since 2.0 + */ + public static DateMidnight now(DateTimeZone zone) { + if (zone == null) { + throw new NullPointerException("Zone must not be null"); + } + return new DateMidnight(zone); + } + + /** + * Obtains a {@code DateMidnight} set to the current system millisecond time + * using the specified chronology. + * The constructed object will have a local time of midnight. + * + * @param chronology the chronology, not null + * @return the current date, not null + * @since 2.0 + */ + public static DateMidnight now(Chronology chronology) { + if (chronology == null) { + throw new NullPointerException("Chronology must not be null"); + } + return new DateMidnight(chronology); + } + + //----------------------------------------------------------------------- + /** + * Parses a {@code DateMidnight} from the specified string. + *

    + * This uses {@link ISODateTimeFormat#dateTimeParser()}. + * + * @param str the string to parse, not null + * @since 2.0 + */ + @FromString + public static DateMidnight parse(String str) { + return parse(str, ISODateTimeFormat.dateTimeParser().withOffsetParsed()); + } + + /** + * Parses a {@code DateMidnight} from the specified string using a formatter. + * + * @param str the string to parse, not null + * @param formatter the formatter to use, not null + * @since 2.0 + */ + public static DateMidnight parse(String str, DateTimeFormatter formatter) { + return formatter.parseDateTime(str).toDateMidnight(); + } + + //----------------------------------------------------------------------- + /** * Constructs an instance set to the current system millisecond time * using ISOChronology in the default time zone. * The constructed object will have a local time of midnight. + * + * @see #now() */ public DateMidnight() { super(); @@ -126,6 +165,7 @@ * If the specified time zone is null, the default zone is used. * * @param zone the time zone, null means default zone + * @see #now(DateTimeZone) */ public DateMidnight(DateTimeZone zone) { super(zone); @@ -140,6 +180,7 @@ * in the default time zone is used. * * @param chronology the chronology, null means ISOChronology in default zone + * @see #now(Chronology) */ public DateMidnight(Chronology chronology) { super(chronology); @@ -199,6 +240,7 @@ * The recognised object types are defined in * {@link org.joda.time.convert.ConverterManager ConverterManager} and * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}. * * @param instant the datetime object, null means now * @throws IllegalArgumentException if the instant is invalid @@ -222,6 +264,7 @@ * The recognised object types are defined in * {@link org.joda.time.convert.ConverterManager ConverterManager} and * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}. * * @param instant the datetime object, null means now * @param zone the time zone, null means default time zone @@ -243,6 +286,7 @@ * The recognised object types are defined in * {@link org.joda.time.convert.ConverterManager ConverterManager} and * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}. * * @param instant the datetime object, null means now * @param chronology the chronology, null means ISOChronology in default zone @@ -300,10 +344,7 @@ } /** - * Rounds the specified instant as required by the subclass. - * This method must not access instance variables. - *

    - * This implementation performs no rounding and returns the instant. + * Rounds the specified instant to midnight. * * @param instant the milliseconds from 1970-01-01T00:00:00Z to round * @param chronology the chronology to use, not null @@ -315,7 +356,7 @@ //----------------------------------------------------------------------- /** - * Gets a copy of this instant with different millis. + * Returns a copy of this date with a different millisecond instant. * The returned object will have a local time of midnight. *

    * Only the millis will change, the chronology and time zone are kept. @@ -331,7 +372,7 @@ } /** - * Gets a copy of this instant with a different chronology, potentially + * Returns a copy of this date with a different chronology, potentially * changing the day in unexpected ways. *

    * This method creates a new DateMidnight using the midnight millisecond value @@ -356,7 +397,7 @@ } /** - * Gets a copy of this instant with a different time zone, preserving the day + * Returns a copy of this date with a different time zone, preserving the day * The returned object will have a local time of midnight in the new zone on * the same day as the original instant. * @@ -376,10 +417,10 @@ //----------------------------------------------------------------------- /** - * Gets a copy of this datetime with the partial set of fields replacing those + * Returns a copy of this date with the partial set of fields replacing those * from this instance. *

    - * For example, if the partial is a YearMonthDay then the date fields + * For example, if the partial is a LocalDate then the date fields * would be changed in the returned instance. * If the partial is null, then this is returned. * @@ -395,7 +436,7 @@ } /** - * Gets a copy of this datetime with the specified field set to a new value. + * Returns a copy of this date with the specified field set to a new value. *

    * For example, if the field type is dayOfMonth then the day of month * field would be changed in the returned instance. @@ -422,14 +463,15 @@ } /** - * Gets a copy of this datetime with the value of the specified field increased. + * Returns a copy of this date with the value of the specified field increased. *

    * If the addition is zero or the field is null, then this is returned. + *

    * These three lines are equivalent: *

    -     * DateTime added = dt.withFieldAdded(DateTimeFieldType.dayOfMonth(), 6);
    -     * DateTime added = dt.dayOfMonth().addToCopy(6);
    -     * DateTime added = dt.property(DateTimeFieldType.dayOfMonth()).addToCopy(6);
    +     * DateMidnight added = dt.withFieldAdded(DateTimeFieldType.year(), 6);
    +     * DateMidnight added = dt.plusYears(6);
    +     * DateMidnight added = dt.year().addToCopy(6);
          * 
    * * @param fieldType the field type to add to, not null @@ -451,7 +493,7 @@ //----------------------------------------------------------------------- /** - * Gets a copy of this datetime with the specified duration added. + * Returns a copy of this date with the specified duration added. *

    * If the addition is zero, then this is returned. * @@ -469,7 +511,7 @@ } /** - * Gets a copy of this datetime with the specified duration added. + * Returns a copy of this date with the specified duration added. *

    * If the addition is zero, then this is returned. * @@ -486,14 +528,14 @@ } /** - * Gets a copy of this datetime with the specified period added. + * Returns a copy of this date with the specified period added. *

    * If the addition is zero, then this is returned. *

    - * To add or subtract on a single field use the properties, for example: - *

    -     * DateTime added = dt.dayOfMonth().addToCopy(6);
    -     * 
    + * This method is typically used to add multiple copies of complex + * period instances. Adding one field is best achieved using methods + * like {@link #withFieldAdded(DurationFieldType, int)} + * or {@link #plusYears(int)}. * * @param period the period to add to this one, null means zero * @param scalar the amount of times to add, such as -1 to subtract once @@ -510,11 +552,11 @@ //----------------------------------------------------------------------- /** - * Gets a copy of this datetime with the specified duration added. + * Returns a copy of this date with the specified duration added. *

    - * If the amount is zero or null, then this is returned. + * If the amount is zero, then this is returned. * - * @param duration the duration to add to this one + * @param duration the duration, in millis, to add to this one * @return a copy of this datetime with the duration added * @throws ArithmeticException if the new datetime exceeds the capacity of a long */ @@ -523,7 +565,7 @@ } /** - * Gets a copy of this datetime with the specified duration added. + * Returns a copy of this date with the specified duration added. *

    * If the amount is zero or null, then this is returned. * @@ -536,15 +578,13 @@ } /** - * Gets a copy of this datetime with the specified period added. + * Returns a copy of this date with the specified period added. *

    * If the amount is zero or null, then this is returned. *

    - * The following two lines are identical in effect: - *

    -     * DateTime added = dt.hourOfDay().addToCopy(6);
    -     * DateTime added = dt.plus(Period.hours(6));
    -     * 
    + * This method is typically used to add complex period instances. + * Adding one field is best achieved using methods + * like {@link #plusYears(int)}. * * @param period the duration to add to this one, null means zero * @return a copy of this datetime with the period added @@ -556,11 +596,108 @@ //----------------------------------------------------------------------- /** - * Gets a copy of this datetime with the specified duration take away. + * Returns a copy of this date plus the specified number of years. *

    + * This datetime instance is immutable and unaffected by this method call. + *

    + * The following three lines are identical in effect: + *

    +     * DateMidnight added = dt.plusYears(6);
    +     * DateMidnight added = dt.plus(Period.years(6));
    +     * DateMidnight added = dt.withFieldAdded(DurationFieldType.years(), 6);
    +     * 
    + * + * @param years the amount of years to add, may be negative + * @return the new datetime plus the increased years + * @since 1.1 + */ + public DateMidnight plusYears(int years) { + if (years == 0) { + return this; + } + long instant = getChronology().years().add(getMillis(), years); + return withMillis(instant); + } + + /** + * Returns a copy of this date plus the specified number of months. + *

    + * This datetime instance is immutable and unaffected by this method call. + *

    + * The following three lines are identical in effect: + *

    +     * DateMidnight added = dt.plusMonths(6);
    +     * DateMidnight added = dt.plus(Period.months(6));
    +     * DateMidnight added = dt.withFieldAdded(DurationFieldType.months(), 6);
    +     * 
    + * + * @param months the amount of months to add, may be negative + * @return the new datetime plus the increased months + * @since 1.1 + */ + public DateMidnight plusMonths(int months) { + if (months == 0) { + return this; + } + long instant = getChronology().months().add(getMillis(), months); + return withMillis(instant); + } + + /** + * Returns a copy of this date plus the specified number of weeks. + *

    + * This datetime instance is immutable and unaffected by this method call. + *

    + * The following three lines are identical in effect: + *

    +     * DateMidnight added = dt.plusWeeks(6);
    +     * DateMidnight added = dt.plus(Period.weeks(6));
    +     * DateMidnight added = dt.withFieldAdded(DurationFieldType.weeks(), 6);
    +     * 
    + * + * @param weeks the amount of weeks to add, may be negative + * @return the new datetime plus the increased weeks + * @since 1.1 + */ + public DateMidnight plusWeeks(int weeks) { + if (weeks == 0) { + return this; + } + long instant = getChronology().weeks().add(getMillis(), weeks); + return withMillis(instant); + } + + /** + * Returns a copy of this date plus the specified number of days. + *

    + * This datetime instance is immutable and unaffected by this method call. + *

    + * The following three lines are identical in effect: + *

    +     * DateMidnight added = dt.plusDays(6);
    +     * DateMidnight added = dt.plus(Period.days(6));
    +     * DateMidnight added = dt.withFieldAdded(DurationFieldType.days(), 6);
    +     * 
    + * + * @param days the amount of days to add, may be negative + * @return the new datetime plus the increased days + * @since 1.1 + */ + public DateMidnight plusDays(int days) { + if (days == 0) { + return this; + } + long instant = getChronology().days().add(getMillis(), days); + return withMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the specified duration taken away. + *

    * If the amount is zero or null, then this is returned. * - * @param duration the duration to reduce this instant by + * @param duration the duration, in millis, to reduce this instant by * @return a copy of this datetime with the duration taken away * @throws ArithmeticException if the new datetime exceeds the capacity of a long */ @@ -569,7 +706,7 @@ } /** - * Gets a copy of this datetime with the specified duration take away. + * Returns a copy of this date with the specified duration taken away. *

    * If the amount is zero or null, then this is returned. * @@ -582,15 +719,13 @@ } /** - * Gets a copy of this datetime with the specified period take away. + * Returns a copy of this date with the specified period taken away. *

    * If the amount is zero or null, then this is returned. *

    - * The following two lines are identical in effect: - *

    -     * DateTime added = dt.hourOfDay().addToCopy(-6);
    -     * DateTime added = dt.minus(Period.hours(6));
    -     * 
    + * This method is typically used to subtract complex period instances. + * Subtracting one field is best achieved using methods + * like {@link #minusYears(int)}. * * @param period the period to reduce this instant by * @return a copy of this datetime with the period taken away @@ -602,13 +737,113 @@ //----------------------------------------------------------------------- /** + * Returns a copy of this date minus the specified number of years. + *

    + * This datetime instance is immutable and unaffected by this method call. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime subtracted = dt.minusYears(6);
    +     * DateTime subtracted = dt.minus(Period.years(6));
    +     * DateTime subtracted = dt.withFieldAdded(DurationFieldType.years(), -6);
    +     * 
    + * + * @param years the amount of years to subtract, may be negative + * @return the new datetime minus the increased years + * @since 1.1 + */ + public DateMidnight minusYears(int years) { + if (years == 0) { + return this; + } + long instant = getChronology().years().subtract(getMillis(), years); + return withMillis(instant); + } + + /** + * Returns a copy of this date minus the specified number of months. + *

    + * This datetime instance is immutable and unaffected by this method call. + *

    + * The following three lines are identical in effect: + *

    +     * DateMidnight subtracted = dt.minusMonths(6);
    +     * DateMidnight subtracted = dt.minus(Period.months(6));
    +     * DateMidnight subtracted = dt.withFieldAdded(DurationFieldType.months(), -6);
    +     * 
    + * + * @param months the amount of months to subtract, may be negative + * @return the new datetime minus the increased months + * @since 1.1 + */ + public DateMidnight minusMonths(int months) { + if (months == 0) { + return this; + } + long instant = getChronology().months().subtract(getMillis(), months); + return withMillis(instant); + } + + /** + * Returns a copy of this date minus the specified number of weeks. + *

    + * This datetime instance is immutable and unaffected by this method call. + *

    + * The following three lines are identical in effect: + *

    +     * DateMidnight subtracted = dt.minusWeeks(6);
    +     * DateMidnight subtracted = dt.minus(Period.weeks(6));
    +     * DateMidnight subtracted = dt.withFieldAdded(DurationFieldType.weeks(), -6);
    +     * 
    + * + * @param weeks the amount of weeks to subtract, may be negative + * @return the new datetime minus the increased weeks + * @since 1.1 + */ + public DateMidnight minusWeeks(int weeks) { + if (weeks == 0) { + return this; + } + long instant = getChronology().weeks().subtract(getMillis(), weeks); + return withMillis(instant); + } + + /** + * Returns a copy of this date minus the specified number of days. + *

    + * This datetime instance is immutable and unaffected by this method call. + *

    + * The following three lines are identical in effect: + *

    +     * DateMidnight subtracted = dt.minusDays(6);
    +     * DateMidnight subtracted = dt.minus(Period.days(6));
    +     * DateMidnight subtracted = dt.withFieldAdded(DurationFieldType.days(), -6);
    +     * 
    + * + * @param days the amount of days to subtract, may be negative + * @return the new datetime minus the increased days + * @since 1.1 + */ + public DateMidnight minusDays(int days) { + if (days == 0) { + return this; + } + long instant = getChronology().days().subtract(getMillis(), days); + return withMillis(instant); + } + + //----------------------------------------------------------------------- + /** * Gets the property object for the specified type, which contains many useful methods. * * @param type the field type to get the chronology for * @return the property object * @throws IllegalArgumentException if the field is null or unsupported */ public Property property(DateTimeFieldType type) { + if (type == null) { + throw new IllegalArgumentException("The DateTimeFieldType must not be null"); + } DateTimeField field = type.getField(getChronology()); if (field.isSupported() == false) { throw new IllegalArgumentException("Field '" + type + "' is not supported"); @@ -618,21 +853,36 @@ //----------------------------------------------------------------------- /** - * Converts this object to a YearMonthDay using the same millis and chronology. + * Converts this object to a YearMonthDay using the + * same date and chronology. * * @return a YearMonthDay using the same millis and chronology + * @deprecated Use LocalDate instead of YearMonthDay */ + @Deprecated public YearMonthDay toYearMonthDay() { return new YearMonthDay(getMillis(), getChronology()); } /** - * Converts this object to an Interval encompassing the whole of this day. + * Converts this object to a LocalDate with the + * same date and chronology. + * + * @return a LocalDate with the same date and chronology + * @since 1.3 + */ + public LocalDate toLocalDate() { + return new LocalDate(getMillis(), getChronology()); + } + + /** + * Converts this object to an Interval encompassing + * the whole of this day. *

    * The interval starts at midnight 00:00 and ends at 00:00 the following day, * (which is not included in the interval, as intervals are half-open). * - * @return a YearMonthDay using the same millis and chronology + * @return an interval over the day */ public Interval toInterval() { Chronology chrono = getChronology(); @@ -641,10 +891,198 @@ return new Interval(start, end, chrono); } + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the era field updated. + *

    + * DateMidnight is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * era changed. + * + * @param era the era to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateMidnight withEra(int era) { + return withMillis(getChronology().era().set(getMillis(), era)); + } + + /** + * Returns a copy of this date with the century of era field updated. + *

    + * DateMidnight is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * century of era changed. + * + * @param centuryOfEra the centurey of era to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateMidnight withCenturyOfEra(int centuryOfEra) { + return withMillis(getChronology().centuryOfEra().set(getMillis(), centuryOfEra)); + } + + /** + * Returns a copy of this date with the year of era field updated. + *

    + * DateMidnight is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year of era changed. + * + * @param yearOfEra the year of era to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateMidnight withYearOfEra(int yearOfEra) { + return withMillis(getChronology().yearOfEra().set(getMillis(), yearOfEra)); + } + + /** + * Returns a copy of this date with the year of century field updated. + *

    + * DateMidnight is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year of century changed. + * + * @param yearOfCentury the year of century to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateMidnight withYearOfCentury(int yearOfCentury) { + return withMillis(getChronology().yearOfCentury().set(getMillis(), yearOfCentury)); + } + + /** + * Returns a copy of this date with the year field updated. + *

    + * DateMidnight is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year changed. + * + * @param year the year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateMidnight withYear(int year) { + return withMillis(getChronology().year().set(getMillis(), year)); + } + + /** + * Returns a copy of this date with the weekyear field updated. + *

    + * The weekyear is the year that matches with the weekOfWeekyear field. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + * The weekyear allows you to query the effective year for that day. + *

    + * DateMidnight is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * weekyear changed. + * + * @param weekyear the weekyear to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateMidnight withWeekyear(int weekyear) { + return withMillis(getChronology().weekyear().set(getMillis(), weekyear)); + } + + /** + * Returns a copy of this date with the month of year field updated. + *

    + * DateMidnight is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * month of year changed. + * + * @param monthOfYear the month of year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateMidnight withMonthOfYear(int monthOfYear) { + return withMillis(getChronology().monthOfYear().set(getMillis(), monthOfYear)); + } + + /** + * Returns a copy of this date with the week of weekyear field updated. + *

    + * This field is associated with the "weekyear" via {@link #withWeekyear(int)}. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + *

    + * DateMidnight is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * week of weekyear changed. + * + * @param weekOfWeekyear the week of weekyear to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateMidnight withWeekOfWeekyear(int weekOfWeekyear) { + return withMillis(getChronology().weekOfWeekyear().set(getMillis(), weekOfWeekyear)); + } + + /** + * Returns a copy of this date with the day of year field updated. + *

    + * DateMidnight is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of year changed. + * + * @param dayOfYear the day of year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateMidnight withDayOfYear(int dayOfYear) { + return withMillis(getChronology().dayOfYear().set(getMillis(), dayOfYear)); + } + + /** + * Returns a copy of this date with the day of month field updated. + *

    + * DateMidnight is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of month changed. + * + * @param dayOfMonth the day of month to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateMidnight withDayOfMonth(int dayOfMonth) { + return withMillis(getChronology().dayOfMonth().set(getMillis(), dayOfMonth)); + } + + /** + * Returns a copy of this date with the day of week field updated. + *

    + * DateMidnight is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of week changed. + * + * @param dayOfWeek the day of week to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateMidnight withDayOfWeek(int dayOfWeek) { + return withMillis(getChronology().dayOfWeek().set(getMillis(), dayOfWeek)); + } + // Date properties //----------------------------------------------------------------------- /** - * Get the era property. + * Get the era property which provides access to advanced functionality. * * @return the era property */ @@ -653,7 +1091,7 @@ } /** - * Get the century of era property. + * Get the century of era property which provides access to advanced functionality. * * @return the year of era property */ @@ -662,7 +1100,7 @@ } /** - * Get the year of century property. + * Get the year of century property which provides access to advanced functionality. * * @return the year of era property */ @@ -671,7 +1109,7 @@ } /** - * Get the year of era property. + * Get the year of era property which provides access to advanced functionality. * * @return the year of era property */ @@ -680,7 +1118,7 @@ } /** - * Get the year property. + * Get the year property which provides access to advanced functionality. * * @return the year property */ @@ -689,7 +1127,7 @@ } /** - * Get the year of a week based year property. + * Get the year of a week based year property which provides access to advanced functionality. * * @return the year of a week based year property */ @@ -698,7 +1136,7 @@ } /** - * Get the month of year property. + * Get the month of year property which provides access to advanced functionality. * * @return the month of year property */ @@ -707,7 +1145,7 @@ } /** - * Get the week of a week based year property. + * Get the week of a week based year property which provides access to advanced functionality. * * @return the week of a week based year property */ @@ -716,7 +1154,7 @@ } /** - * Get the day of year property. + * Get the day of year property which provides access to advanced functionality. * * @return the day of year property */ @@ -725,7 +1163,7 @@ } /** - * Get the day of month property. + * Get the day of month property which provides access to advanced functionality. * * @return the day of month property */ @@ -734,7 +1172,7 @@ } /** - * Get the day of week property. + * Get the day of week property which provides access to advanced functionality. * * @return the day of week property */ @@ -777,10 +1215,10 @@ private static final long serialVersionUID = 257629620L; /** The instant this property is working against */ - private final DateMidnight iInstant; + private DateMidnight iInstant; /** The field this property is working against */ - private final DateTimeField iField; - + private DateTimeField iField; + /** * Constructor. * @@ -793,6 +1231,23 @@ iField = field; } + /** + * Writes the property in a safe serialization format. + */ + private void writeObject(ObjectOutputStream oos) throws IOException { + oos.writeObject(iInstant); + oos.writeObject(iField.getType()); + } + + /** + * Reads the property from a safe serialization format. + */ + private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException { + iInstant = (DateMidnight) oos.readObject(); + DateTimeFieldType type = (DateTimeFieldType) oos.readObject(); + iField = type.getField(iInstant.getChronology()); + } + //----------------------------------------------------------------------- /** * Gets the field being used. @@ -804,15 +1259,25 @@ } /** - * Gets the instant being used. + * Gets the milliseconds of the datetime that this property is linked to. * - * @return the instant + * @return the milliseconds */ - public ReadableInstant getReadableInstant() { - return iInstant; + protected long getMillis() { + return iInstant.getMillis(); } /** + * Gets the chronology of the datetime that this property is linked to. + * + * @return the chronology + * @since 1.4 + */ + protected Chronology getChronology() { + return iInstant.getChronology(); + } + + /** * Gets the datetime being used. * * @return the datetime @@ -924,6 +1389,39 @@ //----------------------------------------------------------------------- /** + * Returns a new DateMidnight with this field set to the maximum value + * for this field. + *

    + * This operation is useful for obtaining a DateTime on the last day + * of the month, as month lengths vary. + *

    +         * DateMidnight lastDayOfMonth = dt.dayOfMonth().withMaximumValue();
    +         * 
    + *

    + * The DateMidnight attached to this property is unchanged by this call. + * + * @return a copy of the DateMidnight with this field set to its maximum + * @since 1.2 + */ + public DateMidnight withMaximumValue() { + return setCopy(getMaximumValue()); + } + + /** + * Returns a new DateMidnight with this field set to the minimum value + * for this field. + *

    + * The DateMidnight attached to this property is unchanged by this call. + * + * @return a copy of the DateMidnight with this field set to its minimum + * @since 1.2 + */ + public DateMidnight withMinimumValue() { + return setCopy(getMinimumValue()); + } + + //----------------------------------------------------------------------- + /** * Rounds to the lowest whole unit of this field on a copy of this DateMidnight. * * @return a copy of the DateMidnight with the field value changed Index: 3rdParty_sources/joda-time/org/joda/time/DateTime.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/DateTime.java (.../DateTime.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/DateTime.java (.../DateTime.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,75 +1,50 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Locale; +import org.joda.convert.FromString; import org.joda.time.base.BaseDateTime; import org.joda.time.chrono.ISOChronology; import org.joda.time.field.AbstractReadableInstantFieldProperty; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; /** * DateTime is the standard implementation of an unmodifiable datetime class. - * It holds the datetime as milliseconds from the Java epoch of 1970-01-01T00:00:00Z. *

    - * This class uses a Chronology internally. The Chronology determines how the + * DateTime is the most widely used implementation of + * {@link ReadableInstant}. As with all instants, it represents an exact + * point on the time-line, but limited to the precision of milliseconds. + * A DateTime calculates its fields with respect to a + * {@link DateTimeZone time zone}. + *

    + * Internally, the class holds two pieces of data. Firstly, it holds the + * datetime as milliseconds from the Java epoch of 1970-01-01T00:00:00Z. + * Secondly, it holds a {@link Chronology} which determines how the * millisecond instant value is converted into the date time fields. - * The default Chronology is ISOChronology which is the agreed - * international standard and compatable with the modern Gregorian calendar. - * - *

    Each individual field can be queried in two ways: + * The default Chronology is {@link ISOChronology} which is the agreed + * international standard and compatible with the modern Gregorian calendar. + *

    + * Each individual field can be queried in two ways: *

      *
    • getHourOfDay() *
    • hourOfDay().get() @@ -85,7 +60,6 @@ *
    • set *
    • rounding *
    - * *

    * DateTime is thread-safe and immutable, provided that the Chronology is as well. * All standard Chronology classes supplied are thread-safe and immutable. @@ -105,8 +79,77 @@ //----------------------------------------------------------------------- /** + * Obtains a {@code DateTime} set to the current system millisecond time + * using ISOChronology in the default time zone. + * + * @return the current date-time, not null + * @since 2.0 + */ + public static DateTime now() { + return new DateTime(); + } + + /** + * Obtains a {@code DateTime} set to the current system millisecond time + * using ISOChronology in the specified time zone. + * + * @param zone the time zone, not null + * @return the current date-time, not null + * @since 2.0 + */ + public static DateTime now(DateTimeZone zone) { + if (zone == null) { + throw new NullPointerException("Zone must not be null"); + } + return new DateTime(zone); + } + + /** + * Obtains a {@code DateTime} set to the current system millisecond time + * using the specified chronology. + * + * @param chronology the chronology, not null + * @return the current date-time, not null + * @since 2.0 + */ + public static DateTime now(Chronology chronology) { + if (chronology == null) { + throw new NullPointerException("Chronology must not be null"); + } + return new DateTime(chronology); + } + + //----------------------------------------------------------------------- + /** + * Parses a {@code DateTime} from the specified string. + *

    + * This uses {@link ISODateTimeFormat#dateTimeParser()}. + * + * @param str the string to parse, not null + * @since 2.0 + */ + @FromString + public static DateTime parse(String str) { + return parse(str, ISODateTimeFormat.dateTimeParser().withOffsetParsed()); + } + + /** + * Parses a {@code DateTime} from the specified string using a formatter. + * + * @param str the string to parse, not null + * @param formatter the formatter to use, not null + * @since 2.0 + */ + public static DateTime parse(String str, DateTimeFormatter formatter) { + return formatter.parseDateTime(str); + } + + //----------------------------------------------------------------------- + /** * Constructs an instance set to the current system millisecond time * using ISOChronology in the default time zone. + * + * @see #now() */ public DateTime() { super(); @@ -119,6 +162,7 @@ * If the specified time zone is null, the default zone is used. * * @param zone the time zone, null means default zone + * @see #now(DateTimeZone) */ public DateTime(DateTimeZone zone) { super(zone); @@ -132,6 +176,7 @@ * in the default time zone is used. * * @param chronology the chronology, null means ISOChronology in default zone + * @see #now(Chronology) */ public DateTime(Chronology chronology) { super(chronology); @@ -187,6 +232,7 @@ * The recognised object types are defined in * {@link org.joda.time.convert.ConverterManager ConverterManager} and * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}. * * @param instant the datetime object, null means now * @throws IllegalArgumentException if the instant is invalid @@ -209,6 +255,7 @@ * The recognised object types are defined in * {@link org.joda.time.convert.ConverterManager ConverterManager} and * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}. * * @param instant the datetime object, null means now * @param zone the time zone, null means default time zone @@ -229,6 +276,7 @@ * The recognised object types are defined in * {@link org.joda.time.convert.ConverterManager ConverterManager} and * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}. * * @param instant the datetime object, null means now * @param chronology the chronology, null means ISO in default zone @@ -248,7 +296,157 @@ * @param dayOfMonth the day of the month * @param hourOfDay the hour of the day * @param minuteOfHour the minute of the hour + * @since 2.0 + */ + public DateTime( + int year, + int monthOfYear, + int dayOfMonth, + int hourOfDay, + int minuteOfHour) { + super(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, 0, 0); + } + + /** + * Constructs an instance from datetime field values + * using ISOChronology in the specified time zone. + *

    + * If the specified time zone is null, the default zone is used. + * + * @param year the year + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + * @param zone the time zone, null means default time zone + * @since 2.0 + */ + public DateTime( + int year, + int monthOfYear, + int dayOfMonth, + int hourOfDay, + int minuteOfHour, + DateTimeZone zone) { + super(year, monthOfYear, dayOfMonth, + hourOfDay, minuteOfHour, 0, 0, zone); + } + + /** + * Constructs an instance from datetime field values + * using the specified chronology. + *

    + * If the chronology is null, ISOChronology + * in the default time zone is used. + * + * @param year the year + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + * @param chronology the chronology, null means ISOChronology in default zone + * @since 2.0 + */ + public DateTime( + int year, + int monthOfYear, + int dayOfMonth, + int hourOfDay, + int minuteOfHour, + Chronology chronology) { + super(year, monthOfYear, dayOfMonth, + hourOfDay, minuteOfHour, 0, 0, chronology); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance from datetime field values + * using ISOChronology in the default time zone. + * + * @param year the year + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour * @param secondOfMinute the second of the minute + * @since 2.0 + */ + public DateTime( + int year, + int monthOfYear, + int dayOfMonth, + int hourOfDay, + int minuteOfHour, + int secondOfMinute) { + super(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, 0); + } + + /** + * Constructs an instance from datetime field values + * using ISOChronology in the specified time zone. + *

    + * If the specified time zone is null, the default zone is used. + * + * @param year the year + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + * @param secondOfMinute the second of the minute + * @param zone the time zone, null means default time zone + * @since 2.0 + */ + public DateTime( + int year, + int monthOfYear, + int dayOfMonth, + int hourOfDay, + int minuteOfHour, + int secondOfMinute, + DateTimeZone zone) { + super(year, monthOfYear, dayOfMonth, + hourOfDay, minuteOfHour, secondOfMinute, 0, zone); + } + + /** + * Constructs an instance from datetime field values + * using the specified chronology. + *

    + * If the chronology is null, ISOChronology + * in the default time zone is used. + * + * @param year the year + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + * @param secondOfMinute the second of the minute + * @param chronology the chronology, null means ISOChronology in default zone + * @since 2.0 + */ + public DateTime( + int year, + int monthOfYear, + int dayOfMonth, + int hourOfDay, + int minuteOfHour, + int secondOfMinute, + Chronology chronology) { + super(year, monthOfYear, dayOfMonth, + hourOfDay, minuteOfHour, secondOfMinute, 0, chronology); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance from datetime field values + * using ISOChronology in the default time zone. + * + * @param year the year + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + * @param secondOfMinute the second of the minute * @param millisOfSecond the millisecond of the second */ public DateTime( @@ -372,11 +570,10 @@ //----------------------------------------------------------------------- /** - * Gets a copy of this datetime with different millis. + * Returns a copy of this datetime with different millis. *

    - * The returned object will be a new instance of the same implementation type. - * Only the millis will change, the chronology and time zone are kept. * The returned object will be either be a new instance or this. + * Only the millis will change, the chronology and time zone are kept. * * @param newMillis the new millis, from 1970-01-01T00:00:00Z * @return a copy of this datetime with different millis @@ -386,11 +583,10 @@ } /** - * Gets a copy of this datetime with a different chronology. + * Returns a copy of this datetime with a different chronology. *

    - * The returned object will be a new instance of the same implementation type. - * Only the chronology will change, the millis are kept. * The returned object will be either be a new instance or this. + * Only the chronology will change, the millis are kept. * * @param newChronology the new chronology, null means ISO default * @return a copy of this datetime with a different chronology @@ -402,15 +598,15 @@ //----------------------------------------------------------------------- /** - * Gets a copy of this datetime with a different time zone, preserving the + * Returns a copy of this datetime with a different time zone, preserving the * millisecond instant. *

    * This method is useful for finding the local time in another timezone. * For example, if this instant holds 12:30 in Europe/London, the result * from this method with Europe/Paris would be 13:30. *

    * The returned object will be a new instance of the same implementation type. - * This method changes alters the time zone, and does not change the + * This method changes the time zone, and does not change the * millisecond instant, with the effect that the field values usually change. * The returned object will be either be a new instance or this. * @@ -423,15 +619,15 @@ } /** - * Gets a copy of this datetime with a different time zone, preserving the + * Returns a copy of this datetime with a different time zone, preserving the * field values. *

    * This method is useful for finding the millisecond time in another timezone. * For example, if this instant holds 12:30 in Europe/London (ie. 12:30Z), * the result from this method with Europe/Paris would be 12:30 (ie. 11:30Z). *

    * The returned object will be a new instance of the same implementation type. - * This method alters the time zone and the millisecond instant to keep + * This method changes the time zone and the millisecond instant to keep * the field values the same. * The returned object will be either be a new instance or this. * @@ -450,16 +646,58 @@ return new DateTime(millis, getChronology().withZone(newZone)); } + /** + * Returns a copy of this ZonedDateTime changing the zone offset to the earlier + * of the two valid offsets at a local time-line overlap. + *

    + * This method only has any effect when the local time-line overlaps, such as at + * an autumn daylight savings cutover. In this scenario, there are two valid offsets + * for the local date-time. Calling this method will return a date-time with the + * earlier of the two selected. + *

    + * If this method is called when it is not an overlap, this is returned. + *

    + * This instance is immutable and unaffected by this method call. + * + * @return a copy of this datetime with the earliest valid offset for the local datetime + */ + public DateTime withEarlierOffsetAtOverlap() { + long newMillis = getZone().adjustOffset(getMillis(), false); + return withMillis(newMillis); + } + + /** + * Returns a copy of this ZonedDateTime changing the zone offset to the later + * of the two valid offsets at a local time-line overlap. + *

    + * This method only has any effect when the local time-line overlaps, such as at + * an autumn daylight savings cutover. In this scenario, there are two valid offsets + * for the local date-time. Calling this method will return a date-time with the + * later of the two selected. + *

    + * If this method is called when it is not an overlap, this is returned. + *

    + * This instance is immutable and unaffected by this method call. + * + * @return a copy of this datetime with the latest valid offset for the local datetime + */ + public DateTime withLaterOffsetAtOverlap() { + long newMillis = getZone().adjustOffset(getMillis(), true); + return withMillis(newMillis); + } + //----------------------------------------------------------------------- /** - * Gets a copy of this datetime with the specified date, retaining the time fields. + * Returns a copy of this datetime with the specified date, retaining the time fields. *

    * If the date is already the date passed in, then this is returned. *

    * To set a single field use the properties, for example: *

          * DateTime set = monthOfYear().setCopy(6);
          * 
    + *

    + * This instance is immutable and unaffected by this method call. * * @param year the new year value * @param monthOfYear the new monthOfYear value @@ -477,14 +715,16 @@ } /** - * Gets a copy of this datetime with the specified time, retaining the date fields. + * Returns a copy of this datetime with the specified time, retaining the date fields. *

    * If the time is already the time passed in, then this is returned. *

    * To set a single field use the properties, for example: *

          * DateTime set = dt.hourOfDay().setCopy(6);
          * 
    + *

    + * This instance is immutable and unaffected by this method call. * * @param hourOfDay the hour of the day * @param minuteOfHour the minute of the hour @@ -503,9 +743,25 @@ return withMillis(instant); } + /** + * Returns a copy of this datetime with the time set to the start of the day. + *

    + * The time will normally be midnight, as that is the earliest time on + * any given day. However, in some time zones when Daylight Savings Time + * starts, there is no midnight because time jumps from 11:59 to 01:00. + * This method handles that situation by returning 01:00 on that date. + *

    + * This instance is immutable and unaffected by this method call. + * + * @return a copy of this datetime with the time set to the start of the day, not null + */ + public DateTime withTimeAtStartOfDay() { + return toLocalDate().toDateTimeAtStartOfDay(getZone()); + } + //----------------------------------------------------------------------- /** - * Gets a copy of this datetime with the partial set of fields replacing those + * Returns a copy of this datetime with the partial set of fields replacing those * from this instance. *

    * For example, if the partial is a TimeOfDay then the time fields @@ -524,7 +780,7 @@ } /** - * Gets a copy of this datetime with the specified field set to a new value. + * Returns a copy of this datetime with the specified field set to a new value. *

    * For example, if the field type is hourOfDay then the hour of day * field would be changed in the returned instance. @@ -551,15 +807,15 @@ } /** - * Gets a copy of this datetime with the value of the specified field increased. + * Returns a copy of this datetime with the value of the specified field increased. *

    * If the addition is zero or the field is null, then this is returned. *

    * These three lines are equivalent: *

    -     * DateTime added = dt.withField(DateTimeFieldType.dayOfMonth(), 6);
    -     * DateTime added = dt.dayOfMonth().addToCopy(6);
    -     * DateTime added = dt.property(DateTimeFieldType.dayOfMonth()).addToCopy(6);
    +     * DateTime added = dt.withFieldAdded(DurationFieldType.years(), 6);
    +     * DateTime added = dt.plusYears(6);
    +     * DateTime added = dt.plus(Period.years(6));
          * 
    * * @param fieldType the field type to add to, not null @@ -581,7 +837,7 @@ //----------------------------------------------------------------------- /** - * Gets a copy of this datetime with the specified duration added. + * Returns a copy of this datetime with the specified duration added. *

    * If the addition is zero, then this is returned. * @@ -599,7 +855,7 @@ } /** - * Gets a copy of this datetime with the specified duration added. + * Returns a copy of this datetime with the specified duration added. *

    * If the addition is zero, then this is returned. * @@ -616,14 +872,14 @@ } /** - * Gets a copy of this datetime with the specified period added. + * Returns a copy of this datetime with the specified period added. *

    * If the addition is zero, then this is returned. *

    - * To add or subtract on a single field use the properties, for example: - *

    -     * DateTime added = dt.hourOfDay().addToCopy(6);
    -     * 
    + * This method is typically used to add multiple copies of complex + * period instances. Adding one field is best achieved using methods + * like {@link #withFieldAdded(DurationFieldType, int)} + * or {@link #plusYears(int)}. * * @param period the period to add to this one, null means zero * @param scalar the amount of times to add, such as -1 to subtract once @@ -640,11 +896,12 @@ //----------------------------------------------------------------------- /** - * Gets a copy of this datetime with the specified duration added. + * Returns a copy of this datetime with the specified duration added. *

    * If the amount is zero or null, then this is returned. + * This datetime instance is immutable and unaffected by this method call. * - * @param duration the duration to add to this one + * @param duration the duration, in millis, to add to this one * @return a copy of this datetime with the duration added * @throws ArithmeticException if the new datetime exceeds the capacity of a long */ @@ -653,9 +910,10 @@ } /** - * Gets a copy of this datetime with the specified duration added. + * Returns a copy of this datetime with the specified duration added. *

    * If the amount is zero or null, then this is returned. + * This datetime instance is immutable and unaffected by this method call. * * @param duration the duration to add to this one, null means zero * @return a copy of this datetime with the duration added @@ -666,15 +924,22 @@ } /** - * Gets a copy of this datetime with the specified period added. + * Returns a copy of this datetime with the specified period added. *

    - * If the amount is zero or null, then this is returned. + * This method will add each element of the period one by one, from largest + * to smallest, adjusting the datetime to be accurate between each. *

    - * The following two lines are identical in effect: - *

    -     * DateTime added = dt.hourOfDay().addToCopy(6);
    -     * DateTime added = dt.plus(Period.hours(6));
    -     * 
    + * Thus, adding a period of one month and one day to 2007-03-31 will + * work as follows: + * First add one month and adjust, resulting in 2007-04-30 + * Then add one day and adjust, resulting in 2007-05-01. + *

    + * This method is typically used to add complex period instances. + * Adding one field is best achieved using methods + * like {@link #plusYears(int)}. + *

    + * If the amount is zero or null, then this is returned. + * This datetime instance is immutable and unaffected by this method call. * * @param period the duration to add to this one, null means zero * @return a copy of this datetime with the period added @@ -686,11 +951,245 @@ //----------------------------------------------------------------------- /** - * Gets a copy of this datetime with the specified duration take away. + * Returns a copy of this datetime plus the specified number of years. *

    + * The calculation will do its best to only change the year field + * retaining the same month of year. + * However, in certain circumstances, it may be necessary to alter + * smaller fields. For example, 2008-02-29 plus one year cannot result + * in 2009-02-29, so the day of month is adjusted to 2009-02-28. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime added = dt.plusYears(6);
    +     * DateTime added = dt.plus(Period.years(6));
    +     * DateTime added = dt.withFieldAdded(DurationFieldType.years(), 6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param years the amount of years to add, may be negative + * @return the new datetime plus the increased years + * @since 1.1 + */ + public DateTime plusYears(int years) { + if (years == 0) { + return this; + } + long instant = getChronology().years().add(getMillis(), years); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime plus the specified number of months. + *

    + * The calculation will do its best to only change the month field + * retaining the same day of month. + * However, in certain circumstances, it may be necessary to alter + * smaller fields. For example, 2007-03-31 plus one month cannot result + * in 2007-04-31, so the day of month is adjusted to 2007-04-30. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime added = dt.plusMonths(6);
    +     * DateTime added = dt.plus(Period.months(6));
    +     * DateTime added = dt.withFieldAdded(DurationFieldType.months(), 6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param months the amount of months to add, may be negative + * @return the new datetime plus the increased months + * @since 1.1 + */ + public DateTime plusMonths(int months) { + if (months == 0) { + return this; + } + long instant = getChronology().months().add(getMillis(), months); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime plus the specified number of weeks. + *

    + * The calculation operates as if it were adding the equivalent in days. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime added = dt.plusWeeks(6);
    +     * DateTime added = dt.plus(Period.weeks(6));
    +     * DateTime added = dt.withFieldAdded(DurationFieldType.weeks(), 6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param weeks the amount of weeks to add, may be negative + * @return the new datetime plus the increased weeks + * @since 1.1 + */ + public DateTime plusWeeks(int weeks) { + if (weeks == 0) { + return this; + } + long instant = getChronology().weeks().add(getMillis(), weeks); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime plus the specified number of days. + *

    + * The calculation will do its best to only change the day field + * retaining the same time of day. + * However, in certain circumstances, typically daylight savings cutover, + * it may be necessary to alter the time fields. + *

    + * In spring an hour is typically removed. If adding one day results in + * the time being within the cutover then the time is adjusted to be + * within summer time. For example, if the cutover is from 01:59 to 03:00 + * and the result of this method would have been 02:30, then the result + * will be adjusted to 03:30. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime added = dt.plusDays(6);
    +     * DateTime added = dt.plus(Period.days(6));
    +     * DateTime added = dt.withFieldAdded(DurationFieldType.days(), 6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param days the amount of days to add, may be negative + * @return the new datetime plus the increased days + * @since 1.1 + */ + public DateTime plusDays(int days) { + if (days == 0) { + return this; + } + long instant = getChronology().days().add(getMillis(), days); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime plus the specified number of hours. + *

    + * The calculation will add a duration equivalent to the number of hours + * expressed in milliseconds. + *

    + * For example, if a spring daylight savings cutover is from 01:59 to 03:00 + * then adding one hour to 01:30 will result in 03:30. This is a duration + * of one hour later, even though the hour field value changed from 1 to 3. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime added = dt.plusHours(6);
    +     * DateTime added = dt.plus(Period.hours(6));
    +     * DateTime added = dt.withFieldAdded(DurationFieldType.hours(), 6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param hours the amount of hours to add, may be negative + * @return the new datetime plus the increased hours + * @since 1.1 + */ + public DateTime plusHours(int hours) { + if (hours == 0) { + return this; + } + long instant = getChronology().hours().add(getMillis(), hours); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime plus the specified number of minutes. + *

    + * The calculation will add a duration equivalent to the number of minutes + * expressed in milliseconds. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime added = dt.plusMinutes(6);
    +     * DateTime added = dt.plus(Period.minutes(6));
    +     * DateTime added = dt.withFieldAdded(DurationFieldType.minutes(), 6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param minutes the amount of minutes to add, may be negative + * @return the new datetime plus the increased minutes + * @since 1.1 + */ + public DateTime plusMinutes(int minutes) { + if (minutes == 0) { + return this; + } + long instant = getChronology().minutes().add(getMillis(), minutes); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime plus the specified number of seconds. + *

    + * The calculation will add a duration equivalent to the number of seconds + * expressed in milliseconds. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime added = dt.plusSeconds(6);
    +     * DateTime added = dt.plus(Period.seconds(6));
    +     * DateTime added = dt.withFieldAdded(DurationFieldType.seconds(), 6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param seconds the amount of seconds to add, may be negative + * @return the new datetime plus the increased seconds + * @since 1.1 + */ + public DateTime plusSeconds(int seconds) { + if (seconds == 0) { + return this; + } + long instant = getChronology().seconds().add(getMillis(), seconds); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime plus the specified number of millis. + *

    + * The calculation will add a duration equivalent to the number of milliseconds. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime added = dt.plusMillis(6);
    +     * DateTime added = dt.plus(Period.millis(6));
    +     * DateTime added = dt.withFieldAdded(DurationFieldType.millis(), 6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param millis the amount of millis to add, may be negative + * @return the new datetime plus the increased millis + * @since 1.1 + */ + public DateTime plusMillis(int millis) { + if (millis == 0) { + return this; + } + long instant = getChronology().millis().add(getMillis(), millis); + return withMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime with the specified duration taken away. + *

    * If the amount is zero or null, then this is returned. + * This datetime instance is immutable and unaffected by this method call. * - * @param duration the duration to reduce this instant by + * @param duration the duration, in millis, to reduce this instant by * @return a copy of this datetime with the duration taken away * @throws ArithmeticException if the new datetime exceeds the capacity of a long */ @@ -699,9 +1198,10 @@ } /** - * Gets a copy of this datetime with the specified duration take away. + * Returns a copy of this datetime with the specified duration taken away. *

    * If the amount is zero or null, then this is returned. + * This datetime instance is immutable and unaffected by this method call. * * @param duration the duration to reduce this instant by * @return a copy of this datetime with the duration taken away @@ -712,15 +1212,23 @@ } /** - * Gets a copy of this datetime with the specified period take away. + * Returns a copy of this datetime with the specified period taken away. *

    - * If the amount is zero or null, then this is returned. + * This method will subtract each element of the period one by one, from + * largest to smallest, adjusting the datetime to be accurate between each. *

    - * The following two lines are identical in effect: - *

    -     * DateTime added = dt.hourOfDay().addToCopy(-6);
    -     * DateTime added = dt.minus(Period.hours(6));
    -     * 
    + * Thus, subtracting a period of one month and one day from 2007-05-31 will + * work as follows: + * First subtract one month and adjust, resulting in 2007-04-30 + * Then subtract one day and adjust, resulting in 2007-04-29. + * Note that the day has been adjusted by two. + *

    + * This method is typically used to subtract complex period instances. + * Subtracting one field is best achieved using methods + * like {@link #minusYears(int)}. + *

    + * If the amount is zero or null, then this is returned. + * This datetime instance is immutable and unaffected by this method call. * * @param period the period to reduce this instant by * @return a copy of this datetime with the period taken away @@ -732,13 +1240,251 @@ //----------------------------------------------------------------------- /** + * Returns a copy of this datetime minus the specified number of years. + *

    + * The calculation will do its best to only change the year field + * retaining the same month of year. + * However, in certain circumstances, it may be necessary to alter + * smaller fields. For example, 2008-02-29 minus one year cannot result + * in 2007-02-29, so the day of month is adjusted to 2007-02-28. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime subtracted = dt.minusYears(6);
    +     * DateTime subtracted = dt.minus(Period.years(6));
    +     * DateTime subtracted = dt.withFieldAdded(DurationFieldType.years(), -6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param years the amount of years to subtract, may be negative + * @return the new datetime minus the increased years + * @since 1.1 + */ + public DateTime minusYears(int years) { + if (years == 0) { + return this; + } + long instant = getChronology().years().subtract(getMillis(), years); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime minus the specified number of months. + *

    + * The calculation will do its best to only change the month field + * retaining the same day of month. + * However, in certain circumstances, it may be necessary to alter + * smaller fields. For example, 2007-05-31 minus one month cannot result + * in 2007-04-31, so the day of month is adjusted to 2007-04-30. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime subtracted = dt.minusMonths(6);
    +     * DateTime subtracted = dt.minus(Period.months(6));
    +     * DateTime subtracted = dt.withFieldAdded(DurationFieldType.months(), -6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param months the amount of months to subtract, may be negative + * @return the new datetime minus the increased months + * @since 1.1 + */ + public DateTime minusMonths(int months) { + if (months == 0) { + return this; + } + long instant = getChronology().months().subtract(getMillis(), months); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime minus the specified number of weeks. + *

    + * The calculation operates as if it were subtracting the equivalent in days. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime subtracted = dt.minusWeeks(6);
    +     * DateTime subtracted = dt.minus(Period.weeks(6));
    +     * DateTime subtracted = dt.withFieldAdded(DurationFieldType.weeks(), -6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param weeks the amount of weeks to subtract, may be negative + * @return the new datetime minus the increased weeks + * @since 1.1 + */ + public DateTime minusWeeks(int weeks) { + if (weeks == 0) { + return this; + } + long instant = getChronology().weeks().subtract(getMillis(), weeks); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime minus the specified number of days. + *

    + * The calculation will do its best to only change the day field + * retaining the same time of day. + * However, in certain circumstances, typically daylight savings cutover, + * it may be necessary to alter the time fields. + *

    + * In spring an hour is typically removed. If subtracting one day results + * in the time being within the cutover then the time is adjusted to be + * within summer time. For example, if the cutover is from 01:59 to 03:00 + * and the result of this method would have been 02:30, then the result + * will be adjusted to 03:30. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime subtracted = dt.minusDays(6);
    +     * DateTime subtracted = dt.minus(Period.days(6));
    +     * DateTime subtracted = dt.withFieldAdded(DurationFieldType.days(), -6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param days the amount of days to subtract, may be negative + * @return the new datetime minus the increased days + * @since 1.1 + */ + public DateTime minusDays(int days) { + if (days == 0) { + return this; + } + long instant = getChronology().days().subtract(getMillis(), days); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime minus the specified number of hours. + *

    + * The calculation will subtract a duration equivalent to the number of + * hours expressed in milliseconds. + *

    + * For example, if a spring daylight savings cutover is from 01:59 to 03:00 + * then subtracting one hour from 03:30 will result in 01:30. This is a + * duration of one hour earlier, even though the hour field value changed + * from 3 to 1. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime subtracted = dt.minusHours(6);
    +     * DateTime subtracted = dt.minus(Period.hours(6));
    +     * DateTime subtracted = dt.withFieldAdded(DurationFieldType.hours(), -6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param hours the amount of hours to subtract, may be negative + * @return the new datetime minus the increased hours + * @since 1.1 + */ + public DateTime minusHours(int hours) { + if (hours == 0) { + return this; + } + long instant = getChronology().hours().subtract(getMillis(), hours); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime minus the specified number of minutes. + *

    + * The calculation will subtract a duration equivalent to the number of + * minutes expressed in milliseconds. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime subtracted = dt.minusMinutes(6);
    +     * DateTime subtracted = dt.minus(Period.minutes(6));
    +     * DateTime subtracted = dt.withFieldAdded(DurationFieldType.minutes(), -6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param minutes the amount of minutes to subtract, may be negative + * @return the new datetime minus the increased minutes + * @since 1.1 + */ + public DateTime minusMinutes(int minutes) { + if (minutes == 0) { + return this; + } + long instant = getChronology().minutes().subtract(getMillis(), minutes); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime minus the specified number of seconds. + *

    + * The calculation will subtract a duration equivalent to the number of + * seconds expressed in milliseconds. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime subtracted = dt.minusSeconds(6);
    +     * DateTime subtracted = dt.minus(Period.seconds(6));
    +     * DateTime subtracted = dt.withFieldAdded(DurationFieldType.seconds(), -6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param seconds the amount of seconds to subtract, may be negative + * @return the new datetime minus the increased seconds + * @since 1.1 + */ + public DateTime minusSeconds(int seconds) { + if (seconds == 0) { + return this; + } + long instant = getChronology().seconds().subtract(getMillis(), seconds); + return withMillis(instant); + } + + /** + * Returns a copy of this datetime minus the specified number of millis. + *

    + * The calculation will subtract a duration equivalent to the number of + * milliseconds. + *

    + * The following three lines are identical in effect: + *

    +     * DateTime subtracted = dt.minusMillis(6);
    +     * DateTime subtracted = dt.minus(Period.millis(6));
    +     * DateTime subtracted = dt.withFieldAdded(DurationFieldType.millis(), -6);
    +     * 
    + *

    + * This datetime instance is immutable and unaffected by this method call. + * + * @param millis the amount of millis to subtract, may be negative + * @return the new datetime minus the increased millis + * @since 1.1 + */ + public DateTime minusMillis(int millis) { + if (millis == 0) { + return this; + } + long instant = getChronology().millis().subtract(getMillis(), millis); + return withMillis(instant); + } + + //----------------------------------------------------------------------- + /** * Gets the property object for the specified type, which contains many useful methods. * * @param type the field type to get the chronology for * @return the property object * @throws IllegalArgumentException if the field is null or unsupported */ public Property property(DateTimeFieldType type) { + if (type == null) { + throw new IllegalArgumentException("The DateTimeFieldType must not be null"); + } DateTimeField field = type.getField(getChronology()); if (field.isSupported() == false) { throw new IllegalArgumentException("Field '" + type + "' is not supported"); @@ -748,7 +1494,8 @@ //----------------------------------------------------------------------- /** - * Converts this object to a DateMidnight using the same millis and chronology. + * Converts this object to a DateMidnight using the + * same millis and chronology. * * @return a DateMidnight using the same millis and chronology */ @@ -757,27 +1504,335 @@ } /** - * Converts this object to a YearMonthDay using the same millis and chronology. + * Converts this object to a YearMonthDay using the + * same millis and chronology. * * @return a YearMonthDay using the same millis and chronology + * @deprecated Use LocalDate instead of YearMonthDay */ + @Deprecated public YearMonthDay toYearMonthDay() { return new YearMonthDay(getMillis(), getChronology()); } /** - * Converts this object to a TimeOfDay using the same millis and chronology. + * Converts this object to a TimeOfDay using the + * same millis and chronology. * * @return a TimeOfDay using the same millis and chronology + * @deprecated Use LocalTime instead of TimeOfDay */ + @Deprecated public TimeOfDay toTimeOfDay() { return new TimeOfDay(getMillis(), getChronology()); } + /** + * Converts this object to a LocalDateTime with + * the same datetime and chronology. + * + * @return a LocalDateTime with the same datetime and chronology + * @since 1.3 + */ + public LocalDateTime toLocalDateTime() { + return new LocalDateTime(getMillis(), getChronology()); + } + + /** + * Converts this object to a LocalDate with the + * same date and chronology. + * + * @return a LocalDate with the same date and chronology + * @since 1.3 + */ + public LocalDate toLocalDate() { + return new LocalDate(getMillis(), getChronology()); + } + + /** + * Converts this object to a LocalTime with the + * same time and chronology. + * + * @return a LocalTime with the same time and chronology + * @since 1.3 + */ + public LocalTime toLocalTime() { + return new LocalTime(getMillis(), getChronology()); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime with the era field updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * era changed. + * + * @param era the era to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withEra(int era) { + return withMillis(getChronology().era().set(getMillis(), era)); + } + + /** + * Returns a copy of this datetime with the century of era field updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * century of era changed. + * + * @param centuryOfEra the centurey of era to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withCenturyOfEra(int centuryOfEra) { + return withMillis(getChronology().centuryOfEra().set(getMillis(), centuryOfEra)); + } + + /** + * Returns a copy of this datetime with the year of era field updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year of era changed. + * + * @param yearOfEra the year of era to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withYearOfEra(int yearOfEra) { + return withMillis(getChronology().yearOfEra().set(getMillis(), yearOfEra)); + } + + /** + * Returns a copy of this datetime with the year of century field updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year of century changed. + * + * @param yearOfCentury the year of century to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withYearOfCentury(int yearOfCentury) { + return withMillis(getChronology().yearOfCentury().set(getMillis(), yearOfCentury)); + } + + /** + * Returns a copy of this datetime with the year field updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year changed. + * + * @param year the year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withYear(int year) { + return withMillis(getChronology().year().set(getMillis(), year)); + } + + /** + * Returns a copy of this datetime with the weekyear field updated. + *

    + * The weekyear is the year that matches with the weekOfWeekyear field. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + * The weekyear allows you to query the effective year for that day. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * weekyear changed. + * + * @param weekyear the weekyear to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withWeekyear(int weekyear) { + return withMillis(getChronology().weekyear().set(getMillis(), weekyear)); + } + + /** + * Returns a copy of this datetime with the month of year field updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * month of year changed. + * + * @param monthOfYear the month of year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withMonthOfYear(int monthOfYear) { + return withMillis(getChronology().monthOfYear().set(getMillis(), monthOfYear)); + } + + /** + * Returns a copy of this datetime with the week of weekyear field updated. + *

    + * This field is associated with the "weekyear" via {@link #withWeekyear(int)}. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * week of weekyear changed. + * + * @param weekOfWeekyear the week of weekyear to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withWeekOfWeekyear(int weekOfWeekyear) { + return withMillis(getChronology().weekOfWeekyear().set(getMillis(), weekOfWeekyear)); + } + + /** + * Returns a copy of this datetime with the day of year field updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of year changed. + * + * @param dayOfYear the day of year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withDayOfYear(int dayOfYear) { + return withMillis(getChronology().dayOfYear().set(getMillis(), dayOfYear)); + } + + /** + * Returns a copy of this datetime with the day of month field updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of month changed. + * + * @param dayOfMonth the day of month to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withDayOfMonth(int dayOfMonth) { + return withMillis(getChronology().dayOfMonth().set(getMillis(), dayOfMonth)); + } + + /** + * Returns a copy of this datetime with the day of week field updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of week changed. + * + * @param dayOfWeek the day of week to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withDayOfWeek(int dayOfWeek) { + return withMillis(getChronology().dayOfWeek().set(getMillis(), dayOfWeek)); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime with the hour of day field updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * hour of day changed. + * + * @param hour the hour of day to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withHourOfDay(int hour) { + return withMillis(getChronology().hourOfDay().set(getMillis(), hour)); + } + + /** + * Returns a copy of this datetime with the minute of hour updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * minute of hour changed. + * + * @param minute the minute of hour to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withMinuteOfHour(int minute) { + return withMillis(getChronology().minuteOfHour().set(getMillis(), minute)); + } + + /** + * Returns a copy of this datetime with the second of minute field updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * second of minute changed. + * + * @param second the second of minute to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withSecondOfMinute(int second) { + return withMillis(getChronology().secondOfMinute().set(getMillis(), second)); + } + + /** + * Returns a copy of this datetime with the millis of second field updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * millis of second changed. + * + * @param millis the millis of second to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withMillisOfSecond(int millis) { + return withMillis(getChronology().millisOfSecond().set(getMillis(), millis)); + } + + /** + * Returns a copy of this datetime with the millis of day field updated. + *

    + * DateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * millis of day changed. + * + * @param millis the millis of day to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public DateTime withMillisOfDay(int millis) { + return withMillis(getChronology().millisOfDay().set(getMillis(), millis)); + } + // Date properties //----------------------------------------------------------------------- /** - * Get the era property. + * Get the era property which provides access to advanced functionality. * * @return the era property */ @@ -786,7 +1841,7 @@ } /** - * Get the century of era property. + * Get the century of era property which provides access to advanced functionality. * * @return the year of era property */ @@ -795,7 +1850,7 @@ } /** - * Get the year of century property. + * Get the year of century property which provides access to advanced functionality. * * @return the year of era property */ @@ -804,7 +1859,7 @@ } /** - * Get the year of era property. + * Get the year of era property which provides access to advanced functionality. * * @return the year of era property */ @@ -813,7 +1868,7 @@ } /** - * Get the year property. + * Get the year property which provides access to advanced functionality. * * @return the year property */ @@ -822,7 +1877,7 @@ } /** - * Get the year of a week based year property. + * Get the year of a week based year property which provides access to advanced functionality. * * @return the year of a week based year property */ @@ -831,7 +1886,7 @@ } /** - * Get the month of year property. + * Get the month of year property which provides access to advanced functionality. * * @return the month of year property */ @@ -840,7 +1895,7 @@ } /** - * Get the week of a week based year property. + * Get the week of a week based year property which provides access to advanced functionality. * * @return the week of a week based year property */ @@ -849,7 +1904,7 @@ } /** - * Get the day of year property. + * Get the day of year property which provides access to advanced functionality. * * @return the day of year property */ @@ -858,7 +1913,7 @@ } /** - * Get the day of month property. + * Get the day of month property which provides access to advanced functionality. * * @return the day of month property */ @@ -867,7 +1922,7 @@ } /** - * Get the day of week property. + * Get the day of week property which provides access to advanced functionality. * * @return the day of week property */ @@ -878,7 +1933,7 @@ // Time properties //----------------------------------------------------------------------- /** - * Get the hour of day field property + * Get the hour of day field property which provides access to advanced functionality. * * @return the hour of day property */ @@ -887,7 +1942,7 @@ } /** - * Get the minute of day property + * Get the minute of day property which provides access to advanced functionality. * * @return the minute of day property */ @@ -896,7 +1951,7 @@ } /** - * Get the minute of hour field property + * Get the minute of hour field property which provides access to advanced functionality. * * @return the minute of hour property */ @@ -905,7 +1960,7 @@ } /** - * Get the second of day property + * Get the second of day property which provides access to advanced functionality. * * @return the second of day property */ @@ -914,7 +1969,7 @@ } /** - * Get the second of minute field property + * Get the second of minute field property which provides access to advanced functionality. * * @return the second of minute property */ @@ -923,7 +1978,7 @@ } /** - * Get the millis of day property + * Get the millis of day property which provides access to advanced functionality. * * @return the millis of day property */ @@ -932,7 +1987,7 @@ } /** - * Get the millis of second property + * Get the millis of second property which provides access to advanced functionality. * * @return the millis of second property */ @@ -976,9 +2031,9 @@ private static final long serialVersionUID = -6983323811635733510L; /** The instant this property is working against */ - private final DateTime iInstant; + private DateTime iInstant; /** The field this property is working against */ - private final DateTimeField iField; + private DateTimeField iField; /** * Constructor. @@ -992,6 +2047,23 @@ iField = field; } + /** + * Writes the property in a safe serialization format. + */ + private void writeObject(ObjectOutputStream oos) throws IOException { + oos.writeObject(iInstant); + oos.writeObject(iField.getType()); + } + + /** + * Reads the property from a safe serialization format. + */ + private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException { + iInstant = (DateTime) oos.readObject(); + DateTimeFieldType type = (DateTimeFieldType) oos.readObject(); + iField = type.getField(iInstant.getChronology()); + } + //----------------------------------------------------------------------- /** * Gets the field being used. @@ -1003,15 +2075,25 @@ } /** - * Gets the instant being used. + * Gets the milliseconds of the datetime that this property is linked to. * - * @return the instant + * @return the milliseconds */ - public ReadableInstant getReadableInstant() { - return iInstant; + protected long getMillis() { + return iInstant.getMillis(); } /** + * Gets the chronology of the datetime that this property is linked to. + * + * @return the chronology + * @since 1.4 + */ + protected Chronology getChronology() { + return iInstant.getChronology(); + } + + /** * Gets the datetime being used. * * @return the datetime @@ -1123,6 +2205,47 @@ //----------------------------------------------------------------------- /** + * Returns a new DateTime with this field set to the maximum value + * for this field. + *

    + * This operation is useful for obtaining a DateTime on the last day + * of the month, as month lengths vary. + *

    +         * DateTime lastDayOfMonth = dt.dayOfMonth().withMaximumValue();
    +         * 
    + *

    + * Where possible, the offset from UTC will be retained, thus applications + * may need to call {@link DateTime#withLaterOffsetAtOverlap()} on the result + * to force the later time during a DST overlap if desired. + *

    + * The DateTime attached to this property is unchanged by this call. + * + * @return a copy of the DateTime with this field set to its maximum + * @since 1.2 + */ + public DateTime withMaximumValue() { + return setCopy(getMaximumValue()); + } + + /** + * Returns a new DateTime with this field set to the minimum value + * for this field. + *

    + * Where possible, the offset from UTC will be retained, thus applications + * may need to call {@link DateTime#withEarlierOffsetAtOverlap()} on the result + * to force the earlier time during a DST overlap if desired. + *

    + * The DateTime attached to this property is unchanged by this call. + * + * @return a copy of the DateTime with this field set to its minimum + * @since 1.2 + */ + public DateTime withMinimumValue() { + return setCopy(getMinimumValue()); + } + + //----------------------------------------------------------------------- + /** * Rounds to the lowest whole unit of this field on a copy of this DateTime. * * @return a copy of the DateTime with the field value changed Index: 3rdParty_sources/joda-time/org/joda/time/DateTimeComparator.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/DateTimeComparator.java (.../DateTimeComparator.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/DateTimeComparator.java (.../DateTimeComparator.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; @@ -83,7 +45,7 @@ * @author Brian S O'Neill * @since 1.0 */ -public class DateTimeComparator implements Comparator, Serializable { +public class DateTimeComparator implements Comparator, Serializable { /** Serialization lock */ private static final long serialVersionUID = -6097339773320178364L; Index: 3rdParty_sources/joda-time/org/joda/time/DateTimeConstants.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/DateTimeConstants.java (.../DateTimeConstants.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/DateTimeConstants.java (.../DateTimeConstants.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; @@ -107,22 +69,22 @@ /** Constant (1) representing Monday, the first day of the week (ISO) */ public static final int MONDAY = 1; - /** Constant (2) representing Monday, the second day of the week (ISO) */ + /** Constant (2) representing Tuesday, the second day of the week (ISO) */ public static final int TUESDAY = 2; - /** Constant (3) representing Monday, the third day of the week (ISO) */ + /** Constant (3) representing Wednesday, the third day of the week (ISO) */ public static final int WEDNESDAY = 3; - /** Constant (4) representing Monday, the fourth day of the week (ISO) */ + /** Constant (4) representing Thursday, the fourth day of the week (ISO) */ public static final int THURSDAY = 4; - /** Constant (5) representing Monday, the fifth day of the week (ISO) */ + /** Constant (5) representing Friday, the fifth day of the week (ISO) */ public static final int FRIDAY = 5; - /** Constant (6) representing Monday, the sixth day of the week (ISO) */ + /** Constant (6) representing Saturday, the sixth day of the week (ISO) */ public static final int SATURDAY = 6; - /** Constant (7) representing Monday, the seventh day of the week (ISO) */ + /** Constant (7) representing Sunday, the seventh day of the week (ISO) */ public static final int SUNDAY = 7; @@ -138,9 +100,23 @@ /** Alternative constant (0) representing BCE, Before Common Era (secular) */ public static final int BCE = 0; - /** Constant (1) representing AD, years after zero (from Calendar) */ + /** + * Constant (1) representing AD, years after zero (from Calendar). + *

    + * All new chronologies with differrent Era values should try to assign + * eras as follows. The era that was in force at 1970-01-01 (ISO) is assigned + * the value 1. Earlier eras are assigned sequentially smaller numbers. + * Later eras are assigned sequentially greater numbers. + */ public static final int AD = 1; - /** Alternative constant (1) representing CE, Common Era (secular) */ + /** + * Alternative constant (1) representing CE, Common Era (secular). + *

    + * All new chronologies with differrent Era values should try to assign + * eras as follows. The era that was in force at 1970-01-01 (ISO) is assigned + * the value 1. Earlier eras are assigned sequentially smaller numbers. + * Later eras are assigned sequentially greater numbers. + */ public static final int CE = 1; Index: 3rdParty_sources/joda-time/org/joda/time/DateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/DateTimeField.java (.../DateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/DateTimeField.java (.../DateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; @@ -155,6 +117,16 @@ public abstract String getAsText(ReadablePartial partial, Locale locale); /** + * Get the human-readable, text value of this field from the field value. + * If the specified locale is null, the default locale is used. + * + * @param fieldValue the numeric value to convert to text + * @param locale the locale to use for selecting a text symbol, null for default + * @return the text value of the field + */ + public abstract String getAsText(int fieldValue, Locale locale); + + /** * Get the human-readable, short text value of this field from the * milliseconds. If the specified locale is null, the default locale is used. * @@ -195,6 +167,16 @@ public abstract String getAsShortText(ReadablePartial partial, Locale locale); /** + * Get the human-readable, short text value of this field from the field value. + * If the specified locale is null, the default locale is used. + * + * @param fieldValue the numeric value to convert to text + * @param locale the locale to use for selecting a text symbol, null for default + * @return the text value of the field + */ + public abstract String getAsShortText(int fieldValue, Locale locale); + + /** * Adds a value (which may be negative) to the millis value, * overflowing into larger fields if necessary. *

    @@ -259,6 +241,35 @@ public abstract int[] add(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd); /** + * Adds a value (which may be negative) to the partial instant, + * wrapping the whole partial if the maximum size of the partial is reached. + *

    + * The value will be added to this field, overflowing into larger fields + * if necessary. Smaller fields should be unaffected, except where the + * result would be an invalid value for a smaller field. In this case the + * smaller field is adjusted to be in range. + *

    + * Partial instants only contain some fields. This may result in a maximum + * possible value, such as TimeOfDay normally being limited to 23:59:59:999. + * If ths limit is reached by the addition, this method will wrap back to + * 00:00:00.000. In fact, you would generally only use this method for + * classes that have a limitation such as this. + *

    + * For example, in the ISO chronology:
    + * 10:20:30 add 20 minutes is 10:40:30
    + * 10:20:30 add 45 minutes is 11:05:30
    + * 10:20:30 add 16 hours is 02:20:30
    + * + * @param instant the partial instant + * @param fieldIndex the index of this field in the partial + * @param values the values of the partial instant which should be updated + * @param valueToAdd the value to add, in the units of the field + * @return the passed in values + * @throws IllegalArgumentException if the value is invalid or the maximum instant is reached + */ + public abstract int[] addWrapPartial(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd); + + /** * Adds a value (which may be negative) to the millis value, * wrapping within this field. *

    Index: 3rdParty_sources/joda-time/org/joda/time/DateTimeFieldType.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/DateTimeFieldType.java (.../DateTimeFieldType.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/DateTimeFieldType.java (.../DateTimeFieldType.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; @@ -70,6 +32,7 @@ * If required, you can create your own field, for example a quarterOfYear. * You must create a subclass of DateTimeFieldType that defines the field type. * This class returns the actual calculation engine from {@link #getField(Chronology)}. + * The subclass should implement equals and hashCode. * * @author Stephen Colebourne * @author Brian S O'Neill @@ -495,6 +458,24 @@ } /** @inheritdoc */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof StandardDateTimeFieldType) { + return iOrdinal == ((StandardDateTimeFieldType) obj).iOrdinal; + } + return false; + } + + /** @inheritdoc */ + @Override + public int hashCode() { + return (1 << iOrdinal); + } + + /** @inheritdoc */ public DateTimeField getField(Chronology chronology) { chronology = DateTimeUtils.getChronology(chronology); Index: 3rdParty_sources/joda-time/org/joda/time/DateTimeUtils.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/DateTimeUtils.java (.../DateTimeUtils.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/DateTimeUtils.java (.../DateTimeUtils.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,62 +1,28 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2010 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; +import java.lang.reflect.Method; +import java.text.DateFormatSymbols; +import java.util.Locale; + import org.joda.time.chrono.ISOChronology; /** - * DateTimeUtils provide public utility methods for the datetime library. + * DateTimeUtils provide public utility methods for the date-time library. *

    * DateTimeUtils is thread-safe although shared static variables are used. * @@ -65,11 +31,10 @@ */ public class DateTimeUtils { - /** The singleton instance of the system millisecond provider */ + /** The singleton instance of the system millisecond provider. */ private static final SystemMillisProvider SYSTEM_MILLIS_PROVIDER = new SystemMillisProvider(); - - /** The millisecond provider currently in use */ - private static MillisProvider cMillisProvider = SYSTEM_MILLIS_PROVIDER; + /** The millisecond provider currently in use. */ + private static volatile MillisProvider cMillisProvider = SYSTEM_MILLIS_PROVIDER; /** * Restrictive constructor @@ -130,10 +95,32 @@ */ public static final void setCurrentMillisOffset(long offsetMillis) throws SecurityException { checkPermission(); - cMillisProvider = new OffsetMillisProvider(offsetMillis); + if (offsetMillis == 0) { + cMillisProvider = SYSTEM_MILLIS_PROVIDER; + } else { + cMillisProvider = new OffsetMillisProvider(offsetMillis); + } } /** + * Sets the provider of the current time to class specified. + *

    + * This method changes the behaviour of {@link #currentTimeMillis()}. + * Whenever the current time is queried, the specified class will be called. + * + * @param millisProvider the provider of the current time to use, not null + * @throws SecurityException if the application does not have sufficient security rights + * @since 2.0 + */ + public static final void setCurrentMillisProvider(MillisProvider millisProvider) throws SecurityException { + if (millisProvider == null) { + throw new IllegalArgumentException("The MillisProvider must not be null"); + } + checkPermission(); + cMillisProvider = millisProvider; + } + + /** * Checks whether the provider may be changed using permission 'CurrentTime.setProvider'. * * @throws SecurityException if the provider may not be changed @@ -233,6 +220,26 @@ //----------------------------------------------------------------------- /** + * Gets the interval handling null. + *

    + * If the interval is null, an interval representing now + * to now in the {@link ISOChronology#getInstance() ISOChronology} + * will be returned. Otherwise, the interval specified is returned. + * + * @param interval the interval to use, null means now to now + * @return the interval, never null + * @since 1.1 + */ + public static final ReadableInterval getReadableInterval(ReadableInterval interval) { + if (interval == null) { + long now = DateTimeUtils.currentTimeMillis(); + interval = new Interval(now, now); + } + return interval; + } + + //----------------------------------------------------------------------- + /** * Gets the chronology handling null. *

    * If the chronology is null, {@link ISOChronology#getInstance()} @@ -301,33 +308,102 @@ //----------------------------------------------------------------------- /** - * Base class defining a millisecond provider. + * Checks whether the partial is contiguous. + *

    + * A partial is contiguous if one field starts where another ends. + *

    + * For example LocalDate is contiguous because DayOfMonth has + * the same range (Month) as the unit of the next field (MonthOfYear), and + * MonthOfYear has the same range (Year) as the unit of the next field (Year). + *

    + * Similarly, LocalTime is contiguous, as it consists of + * MillisOfSecond, SecondOfMinute, MinuteOfHour and HourOfDay (note how + * the names of each field 'join up'). + *

    + * However, a Year/HourOfDay partial is not contiguous because the range + * field Day is not equal to the next field Year. + * Similarly, a DayOfWeek/DayOfMonth partial is not contiguous because + * the range Month is not equal to the next field Day. + * + * @param partial the partial to check + * @return true if the partial is contiguous + * @throws IllegalArgumentException if the partial is null + * @since 1.1 */ - abstract static class MillisProvider { + public static final boolean isContiguous(ReadablePartial partial) { + if (partial == null) { + throw new IllegalArgumentException("Partial must not be null"); + } + DurationFieldType lastType = null; + for (int i = 0; i < partial.size(); i++) { + DateTimeField loopField = partial.getField(i); + if (i > 0) { + if (loopField.getRangeDurationField().getType() != lastType) { + return false; + } + } + lastType = loopField.getDurationField().getType(); + } + return true; + } + + //----------------------------------------------------------------------- + /** + * Gets the {@link DateFormatSymbols} based on the given locale. + *

    + * If JDK 6 or newer is being used, DateFormatSymbols.getInstance(locale) will + * be used in order to allow the use of locales defined as extensions. + * Otherwise, new DateFormatSymbols(locale) will be used. + * See JDK 6 {@link DateFormatSymbols} for further information. + * + * @param locale the {@link Locale} used to get the correct {@link DateFormatSymbols} + * @return the symbols + * @since 2.0 + */ + public static final DateFormatSymbols getDateFormatSymbols(Locale locale) { + try { + Method method = DateFormatSymbols.class.getMethod("getInstance", new Class[] {Locale.class}); + return (DateFormatSymbols) method.invoke(null, new Object[] {locale}); + } catch (Exception ex) { + return new DateFormatSymbols(locale); + } + } + + //----------------------------------------------------------------------- + /** + * A millisecond provider, allowing control of the system clock. + * + * @author Stephen Colebourne + * @since 2.0 (previously private) + */ + public static interface MillisProvider { /** * Gets the current time. - * @return the current time in millis + *

    + * Implementations of this method must be thread-safe. + * + * @return the current time in milliseconds */ - abstract long getMillis(); + long getMillis(); } /** * System millis provider. */ - static class SystemMillisProvider extends MillisProvider { + static class SystemMillisProvider implements MillisProvider { /** * Gets the current time. * @return the current time in millis */ - long getMillis() { + public long getMillis() { return System.currentTimeMillis(); } } /** * Fixed millisecond provider. */ - static class FixedMillisProvider extends MillisProvider { + static class FixedMillisProvider implements MillisProvider { /** The fixed millis value. */ private final long iMillis; @@ -343,15 +419,15 @@ * Gets the current time. * @return the current time in millis */ - long getMillis() { + public long getMillis() { return iMillis; } } /** * Offset from system millis provider. */ - static class OffsetMillisProvider extends MillisProvider { + static class OffsetMillisProvider implements MillisProvider { /** The millis offset. */ private final long iMillis; @@ -367,7 +443,7 @@ * Gets the current time. * @return the current time in millis */ - long getMillis() { + public long getMillis() { return System.currentTimeMillis() + iMillis; } } Index: 3rdParty_sources/joda-time/org/joda/time/DateTimeZone.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/DateTimeZone.java (.../DateTimeZone.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/DateTimeZone.java (.../DateTimeZone.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2012 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; @@ -64,8 +26,13 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.TimeZone; +import org.joda.convert.FromString; +import org.joda.convert.ToString; +import org.joda.time.chrono.BaseChronology; import org.joda.time.field.FieldUtils; +import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatterBuilder; import org.joda.time.format.FormatUtils; @@ -93,7 +60,7 @@ * obtained from UTC by adding -08:00, that is, by subtracting 8 hours. *

    * The offset differs in the summer because of daylight saving time, or DST. - * The folowing definitions of time are generally used: + * The following definitions of time are generally used: *

      *
    • UTC - The reference time. *
    • Standard Time - The local time without a daylight saving time offset. @@ -132,62 +99,72 @@ /** The instance that is providing time zone names. */ private static NameProvider cNameProvider; /** The set of ID strings. */ - private static Set cAvailableIDs; + private static Set cAvailableIDs; /** The default time zone. */ - private static DateTimeZone cDefault; + private static volatile DateTimeZone cDefault; /** A formatter for printing and parsing zones. */ private static DateTimeFormatter cOffsetFormatter; /** Cache that maps fixed offset strings to softly referenced DateTimeZones */ - private static Map iFixedOffsetCache; + private static Map> iFixedOffsetCache; /** Cache of old zone IDs to new zone IDs */ - private static Map cZoneIdConversion; + private static Map cZoneIdConversion; static { setProvider0(null); setNameProvider0(null); - - // Because of the cyclic initializer dependencies between many of the - // main classes, and because cOffsetFormatter is built from those main - // classes, a user time zone with an explicit offset fails. Rather than - // duplicate all the code used by DateTimeFormatterBuilder's offset - // formatter, DateTimeFormatterBuilder's constructor tests if - // DateTimeZone.getDefault() is null, in which case it allows the - // chronology to be null. This breaks the dependency cycle and allows - // cOffsetFormatter to be defined. In order for this inelegant solution - // to work propery, cDefault must be left as null until after an - // attempt has been made to set the user time zone. - - try { - try { - cDefault = getInstance(System.getProperty("user.timezone")); - } catch (RuntimeException ex) { - // ignored - } - if (cDefault == null) { - cDefault = getInstance(java.util.TimeZone.getDefault()); - } - } catch (IllegalArgumentException ex) { - // ignored - } - - if (cDefault == null) { - cDefault = UTC; - } } + //----------------------------------------------------------------------- /** * Gets the default time zone. + *

      + * The default time zone is derived from the system property {@code user.timezone}. + * If that is {@code null} or is not a valid identifier, then the value of the + * JDK {@code TimeZone} default is converted. If that fails, {@code UTC} is used. + *

      + * NOTE: If the {@code java.util.TimeZone} default is updated after calling this + * method, then the change will not be picked up here. * * @return the default datetime zone object */ public static DateTimeZone getDefault() { - return cDefault; + DateTimeZone zone = cDefault; + if (zone == null) { + synchronized(DateTimeZone.class) { + zone = cDefault; + if (zone == null) { + DateTimeZone temp = null; + try { + try { + String id = System.getProperty("user.timezone"); + if (id != null) { // null check avoids stack overflow + temp = forID(id); + } + } catch (RuntimeException ex) { + // ignored + } + if (temp == null) { + temp = forTimeZone(TimeZone.getDefault()); + } + } catch (IllegalArgumentException ex) { + // ignored + } + if (temp == null) { + temp = UTC; + } + cDefault = zone = temp; + } + } + } + return zone; } /** * Sets the default time zone. + *

      + * NOTE: Calling this method does not set the {@code java.util.TimeZone} default. * * @param zone the default datetime zone object, must not be null * @throws IllegalArgumentException if the zone is null @@ -201,11 +178,14 @@ if (zone == null) { throw new IllegalArgumentException("The datetime zone must not be null"); } - cDefault = zone; + synchronized(DateTimeZone.class) { + cDefault = zone; + } } + //----------------------------------------------------------------------- /** - * Get the time zone by id. + * Gets a time zone instance for the specified time zone id. *

      * The time zone id may be one of those returned by getAvailableIDs. * Short ids, as accepted by {@link java.util.TimeZone}, are not accepted. @@ -219,7 +199,8 @@ * @return the DateTimeZone object for the ID * @throws IllegalArgumentException if the ID is not recognised */ - public static DateTimeZone getInstance(String id) throws IllegalArgumentException { + @FromString + public static DateTimeZone forID(String id) { if (id == null) { return getDefault(); } @@ -231,20 +212,19 @@ return zone; } if (id.startsWith("+") || id.startsWith("-")) { - int offset = -(int) offsetFormatter().parseMillis(id); + int offset = parseOffset(id); if (offset == 0L) { return DateTimeZone.UTC; } else { - StringBuffer buf = new StringBuffer(); - id = printTimeZone(offset); + id = printOffset(offset); return fixedOffsetZone(id, offset); } } - throw new IllegalArgumentException("The datetime zone id is not recognised: " + id); + throw new IllegalArgumentException("The datetime zone id '" + id + "' is not recognised"); } /** - * Get the time zone by the number of hours difference from UTC. + * Gets a time zone instance for the specified offset to UTC in hours. * This method assumes standard length hours. *

      * This factory is a convenient way of constructing zones with a fixed offset. @@ -253,24 +233,24 @@ * @return the DateTimeZone object for the offset * @throws IllegalArgumentException if the offset is too large or too small */ - public static DateTimeZone getInstance(int hoursOffset) throws IllegalArgumentException { - return getInstance(hoursOffset, 0); + public static DateTimeZone forOffsetHours(int hoursOffset) throws IllegalArgumentException { + return forOffsetHoursMinutes(hoursOffset, 0); } /** - * Get the time zone by the number of hours and minutes difference from UTC. + * Gets a time zone instance for the specified offset to UTC in hours and minutes. * This method assumes 60 minutes in an hour, and standard length minutes. *

      * This factory is a convenient way of constructing zones with a fixed offset. * The minutes value is always positive and in the range 0 to 59. - * If constructed with the values (-2, 30), the resultiong zone is '-02:30'. + * If constructed with the values (-2, 30), the resulting zone is '-02:30'. * * @param hoursOffset the offset in hours from UTC * @param minutesOffset the offset in minutes from UTC, must be between 0 and 59 inclusive * @return the DateTimeZone object for the offset * @throws IllegalArgumentException if the offset or minute is too large or too small */ - public static DateTimeZone getInstance(int hoursOffset, int minutesOffset) throws IllegalArgumentException { + public static DateTimeZone forOffsetHoursMinutes(int hoursOffset, int minutesOffset) throws IllegalArgumentException { if (hoursOffset == 0 && minutesOffset == 0) { return DateTimeZone.UTC; } @@ -279,33 +259,46 @@ } int offset = 0; try { - int hoursInMinutes = FieldUtils.safeMultiplyToInt(hoursOffset, 60); + int hoursInMinutes = FieldUtils.safeMultiply(hoursOffset, 60); if (hoursInMinutes < 0) { minutesOffset = FieldUtils.safeAdd(hoursInMinutes, -minutesOffset); } else { minutesOffset = FieldUtils.safeAdd(hoursInMinutes, minutesOffset); } - offset = FieldUtils.safeMultiplyToInt(minutesOffset, DateTimeConstants.MILLIS_PER_MINUTE); + offset = FieldUtils.safeMultiply(minutesOffset, DateTimeConstants.MILLIS_PER_MINUTE); } catch (ArithmeticException ex) { throw new IllegalArgumentException("Offset is too large"); } - String id = printTimeZone(offset); - return fixedOffsetZone(id, offset); + return forOffsetMillis(offset); } /** - * Get the time zone by Java TimeZone. + * Gets a time zone instance for the specified offset to UTC in milliseconds. + * + * @param millisOffset the offset in millis from UTC + * @return the DateTimeZone object for the offset + */ + public static DateTimeZone forOffsetMillis(int millisOffset) { + String id = printOffset(millisOffset); + return fixedOffsetZone(id, millisOffset); + } + + /** + * Gets a time zone instance for a JDK TimeZone. *

      * DateTimeZone only accepts a subset of the IDs from TimeZone. The * excluded IDs are the short three letter form (except UTC). This * method will attempt to convert between time zones created using the * short IDs and the full version. + *

      + * This method is not designed to parse time zones with rules created by + * applications using SimpleTimeZone directly. * * @param zone the zone to convert, null means default * @return the DateTimeZone object for the zone * @throws IllegalArgumentException if the zone is not recognised */ - public static DateTimeZone getInstance(java.util.TimeZone zone) { + public static DateTimeZone forTimeZone(TimeZone zone) { if (zone == null) { return getDefault(); } @@ -329,22 +322,22 @@ // Support GMT+/-hh:mm formats if (convId == null) { - convId = zone.getDisplayName(); + convId = zone.getID(); if (convId.startsWith("GMT+") || convId.startsWith("GMT-")) { convId = convId.substring(3); - int offset = -(int) offsetFormatter().parseMillis(convId); + int offset = parseOffset(convId); if (offset == 0L) { return DateTimeZone.UTC; } else { - convId = printTimeZone(offset); + convId = printOffset(offset); return fixedOffsetZone(convId, offset); } } } - - throw new IllegalArgumentException("The datetime zone id is not recognised: " + id); + throw new IllegalArgumentException("The datetime zone id '" + id + "' is not recognised"); } + //----------------------------------------------------------------------- /** * Gets the zone using a fixed offset amount. * @@ -353,19 +346,22 @@ * @return the zone */ private static synchronized DateTimeZone fixedOffsetZone(String id, int offset) { + if (offset == 0) { + return DateTimeZone.UTC; + } if (iFixedOffsetCache == null) { - iFixedOffsetCache = new HashMap(); + iFixedOffsetCache = new HashMap>(); } DateTimeZone zone; - Reference ref = (Reference) iFixedOffsetCache.get(id); + Reference ref = iFixedOffsetCache.get(id); if (ref != null) { - zone = (DateTimeZone) ref.get(); + zone = ref.get(); if (zone != null) { return zone; } } zone = new FixedDateTimeZone(id, null, offset, offset); - iFixedOffsetCache.put(id, new SoftReference(zone)); + iFixedOffsetCache.put(id, new SoftReference(zone)); return zone; } @@ -374,7 +370,7 @@ * * @return an unmodifiable Set of String IDs */ - public static Set getAvailableIDs() { + public static Set getAvailableIDs() { return cAvailableIDs; } @@ -419,7 +415,7 @@ if (provider == null) { provider = getDefaultProvider(); } - Set ids = provider.getAvailableIDs(); + Set ids = provider.getAvailableIDs(); if (ids == null || ids.size() == 0) { throw new IllegalArgumentException ("The provider doesn't have any available ids"); @@ -560,36 +556,37 @@ * @return the new style id, null if not found */ private static synchronized String getConvertedId(String id) { - Map map = cZoneIdConversion; + Map map = cZoneIdConversion; if (map == null) { // Backwards compatibility with TimeZone. - map = new HashMap(); + map = new HashMap(); map.put("GMT", "UTC"); + map.put("WET", "WET"); + map.put("CET", "CET"); + map.put("MET", "CET"); + map.put("ECT", "CET"); + map.put("EET", "EET"); map.put("MIT", "Pacific/Apia"); - map.put("HST", "Pacific/Honolulu"); + map.put("HST", "Pacific/Honolulu"); // JDK 1.1 compatible map.put("AST", "America/Anchorage"); map.put("PST", "America/Los_Angeles"); - map.put("MST", "America/Denver"); + map.put("MST", "America/Denver"); // JDK 1.1 compatible map.put("PNT", "America/Phoenix"); map.put("CST", "America/Chicago"); - map.put("EST", "America/New_York"); - map.put("IET", "America/Indianapolis"); + map.put("EST", "America/New_York"); // JDK 1.1 compatible + map.put("IET", "America/Indiana/Indianapolis"); map.put("PRT", "America/Puerto_Rico"); map.put("CNT", "America/St_Johns"); - map.put("AGT", "America/Buenos_Aires"); + map.put("AGT", "America/Argentina/Buenos_Aires"); map.put("BET", "America/Sao_Paulo"); - map.put("WET", "Europe/London"); - map.put("ECT", "Europe/Paris"); map.put("ART", "Africa/Cairo"); map.put("CAT", "Africa/Harare"); - map.put("EET", "Europe/Bucharest"); map.put("EAT", "Africa/Addis_Ababa"); - map.put("MET", "Asia/Tehran"); map.put("NET", "Asia/Yerevan"); map.put("PLT", "Asia/Karachi"); - map.put("IST", "Asia/Calcutta"); + map.put("IST", "Asia/Kolkata"); map.put("BST", "Asia/Dhaka"); - map.put("VST", "Asia/Saigon"); + map.put("VST", "Asia/Ho_Chi_Minh"); map.put("CTT", "Asia/Shanghai"); map.put("JST", "Asia/Tokyo"); map.put("ACT", "Australia/Darwin"); @@ -598,33 +595,39 @@ map.put("NST", "Pacific/Auckland"); cZoneIdConversion = map; } - return (String) map.get(id); + return map.get(id); } - /** - * Gets a printer/parser for managing the offset id formatting. - * - * @return the formatter - */ - private static synchronized DateTimeFormatter offsetFormatter() { - if (cOffsetFormatter == null) { - cOffsetFormatter = new DateTimeFormatterBuilder() - .appendTimeZoneOffset(null, true, 2, 4) - .toFormatter(); - } - return cOffsetFormatter; + private static int parseOffset(String str) { + // Can't use a real chronology if called during class + // initialization. Offset parser doesn't need it anyhow. + Chronology chrono = new BaseChronology() { + public DateTimeZone getZone() { + return null; + } + public Chronology withUTC() { + return this; + } + public Chronology withZone(DateTimeZone zone) { + return this; + } + public String toString() { + return getClass().getName(); + } + }; + return -(int) offsetFormatter().withChronology(chrono).parseMillis(str); } /** * Formats a timezone offset string. *

      - * This method is kept separate from the formatting classe to speed and + * This method is kept separate from the formatting classes to speed and * simplify startup and classloading. * * @param offset the offset in milliseconds * @return the time zone string */ - private static String printTimeZone(int offset) { + private static String printOffset(int offset) { StringBuffer buf = new StringBuffer(); if (offset >= 0) { buf.append('+'); @@ -658,6 +661,20 @@ return buf.toString(); } + /** + * Gets a printer/parser for managing the offset id formatting. + * + * @return the formatter + */ + private static synchronized DateTimeFormatter offsetFormatter() { + if (cOffsetFormatter == null) { + cOffsetFormatter = new DateTimeFormatterBuilder() + .appendTimeZoneOffset(null, true, 2, 4) + .toFormatter(); + } + return cOffsetFormatter; + } + // Instance fields and methods //-------------------------------------------------------------------- @@ -684,6 +701,7 @@ * * @return the ID of this datetime zone */ + @ToString public final String getID() { return iID; } @@ -734,7 +752,7 @@ if (name != null) { return name; } - return printTimeZone(getOffset(instant)); + return printOffset(getOffset(instant)); } /** @@ -774,7 +792,7 @@ if (name != null) { return name; } - return printTimeZone(getOffset(instant)); + return printOffset(getOffset(instant)); } /** @@ -808,6 +826,25 @@ public abstract int getStandardOffset(long instant); /** + * Checks whether, at a particular instant, the offset is standard or not. + *

      + * This method can be used to determine whether Summer Time (DST) applies. + * As a general rule, if the offset at the specified instant is standard, + * then either Winter time applies, or there is no Summer Time. If the + * instant is not standard, then Summer Time applies. + *

      + * The implementation of the method is simply whether {@link #getOffset(long)} + * equals {@link #getStandardOffset(long)} at the specified instant. + * + * @param instant milliseconds from 1970-01-01T00:00:00Z to get the offset for + * @return true if the offset at the given instant is the standard offset + * @since 1.5 + */ + public boolean isStandardOffset(long instant) { + return getOffset(instant) == getStandardOffset(instant); + } + + /** * Gets the millisecond offset to subtract from local time to get UTC time. * This offset can be used to undo adding the offset obtained by getOffset. * @@ -816,19 +853,168 @@ * millisUTC == millisLocal - getOffsetFromLocal(millisLocal) * * - * Note: After calculating millisLocal, some error may be introduced. At + * NOTE: After calculating millisLocal, some error may be introduced. At * offset transitions (due to DST or other historical changes), ranges of * local times may map to different UTC times. + *

      + * This method will return an offset suitable for calculating an instant + * after any DST gap. For example, consider a zone with a cutover + * from 01:00 to 01:59:
      + * Input: 00:00 Output: 00:00
      + * Input: 00:30 Output: 00:30
      + * Input: 01:00 Output: 02:00
      + * Input: 01:30 Output: 02:30
      + * Input: 02:00 Output: 02:00
      + * Input: 02:30 Output: 02:30
      + *

      + * During a DST overlap (where the local time is ambiguous) this method will return + * the earlier instant. The combination of these two rules is to always favour + * daylight (summer) time over standard (winter) time. + *

      + * NOTE: Prior to v2.0, the DST overlap behaviour was not defined and varied by hemisphere. + * Prior to v1.5, the DST gap behaviour was also not defined. * - * @param instantLocal the millisecond instant, relative to this time zone, to - * get the offset for + * @param instantLocal the millisecond instant, relative to this time zone, to get the offset for * @return the millisecond offset to subtract from local time to get UTC time */ public int getOffsetFromLocal(long instantLocal) { - return getOffset(instantLocal - getOffset(instantLocal)); + // get the offset at instantLocal (first estimate) + final int offsetLocal = getOffset(instantLocal); + // adjust instantLocal using the estimate and recalc the offset + final long instantAdjusted = instantLocal - offsetLocal; + final int offsetAdjusted = getOffset(instantAdjusted); + // if the offsets differ, we must be near a DST boundary + if (offsetLocal != offsetAdjusted) { + // we need to ensure that time is always after the DST gap + // this happens naturally for positive offsets, but not for negative + if ((offsetLocal - offsetAdjusted) < 0) { + // if we just return offsetAdjusted then the time is pushed + // back before the transition, whereas it should be + // on or after the transition + long nextLocal = nextTransition(instantAdjusted); + long nextAdjusted = nextTransition(instantLocal - offsetAdjusted); + if (nextLocal != nextAdjusted) { + return offsetLocal; + } + } + } else if (offsetLocal >= 0) { + long prev = previousTransition(instantAdjusted); + if (prev < instantAdjusted) { + int offsetPrev = getOffset(prev); + int diff = offsetPrev - offsetLocal; + if (instantAdjusted - prev <= diff) { + return offsetPrev; + } + } + } + return offsetAdjusted; } /** + * Converts a standard UTC instant to a local instant with the same + * local time. This conversion is used before performing a calculation + * so that the calculation can be done using a simple local zone. + * + * @param instantUTC the UTC instant to convert to local + * @return the local instant with the same local time + * @throws ArithmeticException if the result overflows a long + * @since 1.5 + */ + public long convertUTCToLocal(long instantUTC) { + int offset = getOffset(instantUTC); + long instantLocal = instantUTC + offset; + // If there is a sign change, but the two values have the same sign... + if ((instantUTC ^ instantLocal) < 0 && (instantUTC ^ offset) >= 0) { + throw new ArithmeticException("Adding time zone offset caused overflow"); + } + return instantLocal; + } + + /** + * Converts a local instant to a standard UTC instant with the same + * local time attempting to use the same offset as the original. + *

      + * This conversion is used after performing a calculation + * where the calculation was done using a simple local zone. + * Whenever possible, the same offset as the original offset will be used. + * This is most significant during a daylight savings overlap. + * + * @param instantLocal the local instant to convert to UTC + * @param strict whether the conversion should reject non-existent local times + * @param originalInstantUTC the original instant that the calculation is based on + * @return the UTC instant with the same local time, + * @throws ArithmeticException if the result overflows a long + * @throws IllegalArgumentException if the zone has no equivalent local time + * @since 2.0 + */ + public long convertLocalToUTC(long instantLocal, boolean strict, long originalInstantUTC) { + int offsetOriginal = getOffset(originalInstantUTC); + long instantUTC = instantLocal - offsetOriginal; + int offsetLocalFromOriginal = getOffset(instantUTC); + if (offsetLocalFromOriginal == offsetOriginal) { + return instantUTC; + } + return convertLocalToUTC(instantLocal, strict); + } + + /** + * Converts a local instant to a standard UTC instant with the same + * local time. This conversion is used after performing a calculation + * where the calculation was done using a simple local zone. + * + * @param instantLocal the local instant to convert to UTC + * @param strict whether the conversion should reject non-existent local times + * @return the UTC instant with the same local time, + * @throws ArithmeticException if the result overflows a long + * @throws IllegalArgumentException if the zone has no equivalent local time + * @since 1.5 + */ + public long convertLocalToUTC(long instantLocal, boolean strict) { + // get the offset at instantLocal (first estimate) + int offsetLocal = getOffset(instantLocal); + // adjust instantLocal using the estimate and recalc the offset + int offset = getOffset(instantLocal - offsetLocal); + // if the offsets differ, we must be near a DST boundary + if (offsetLocal != offset) { + // if strict then always check if in DST gap + // otherwise only check if zone in Western hemisphere (as the + // value of offset is already correct for Eastern hemisphere) + if (strict || offsetLocal < 0) { + // determine if we are in the DST gap + long nextLocal = nextTransition(instantLocal - offsetLocal); + if (nextLocal == (instantLocal - offsetLocal)) { + nextLocal = Long.MAX_VALUE; + } + long nextAdjusted = nextTransition(instantLocal - offset); + if (nextAdjusted == (instantLocal - offset)) { + nextAdjusted = Long.MAX_VALUE; + } + if (nextLocal != nextAdjusted) { + // yes we are in the DST gap + if (strict) { + // DST gap is not acceptable + throw new IllegalArgumentException("Illegal instant due to time zone offset transition: " + + DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS").print(new Instant(instantLocal)) + + " (" + getID() + ")"); + } else { + // DST gap is acceptable, but for the Western hemisphere + // the offset is wrong and will result in local times + // before the cutover so use the offsetLocal instead + offset = offsetLocal; + } + } + } + } + // check for overflow + long instantUTC = instantLocal - offset; + // If there is a sign change, but the two values have different signs... + if ((instantLocal ^ instantUTC) < 0 && (instantLocal ^ offset) < 0) { + throw new ArithmeticException("Subtracting time zone offset caused overflow"); + } + return instantUTC; + } + + /** * Gets the millisecond instant in another zone keeping the same local time. *

      * The conversion is performed by converting the specified UTC millis to local @@ -842,11 +1028,173 @@ if (newZone == null) { newZone = DateTimeZone.getDefault(); } - long instantLocal = oldInstant + getOffset(oldInstant); - return instantLocal - newZone.getOffsetFromLocal(instantLocal); + if (newZone == this) { + return oldInstant; + } + long instantLocal = convertUTCToLocal(oldInstant); + return newZone.convertLocalToUTC(instantLocal, false, oldInstant); } +// //----------------------------------------------------------------------- +// /** +// * Checks if the given {@link LocalDateTime} is within an overlap. +// *

      +// * When switching from Daylight Savings Time to standard time there is +// * typically an overlap where the same clock hour occurs twice. This +// * method identifies whether the local datetime refers to such an overlap. +// * +// * @param localDateTime the time to check, not null +// * @return true if the given datetime refers to an overlap +// */ +// public boolean isLocalDateTimeOverlap(LocalDateTime localDateTime) { +// if (isFixed()) { +// return false; +// } +// long instantLocal = localDateTime.toDateTime(DateTimeZone.UTC).getMillis(); +// // get the offset at instantLocal (first estimate) +// int offsetLocal = getOffset(instantLocal); +// // adjust instantLocal using the estimate and recalc the offset +// int offset = getOffset(instantLocal - offsetLocal); +// // if the offsets differ, we must be near a DST boundary +// if (offsetLocal != offset) { +// long nextLocal = nextTransition(instantLocal - offsetLocal); +// long nextAdjusted = nextTransition(instantLocal - offset); +// if (nextLocal != nextAdjusted) { +// // in DST gap +// return false; +// } +// long diff = Math.abs(offset - offsetLocal); +// DateTime dateTime = localDateTime.toDateTime(this); +// DateTime adjusted = dateTime.plus(diff); +// if (dateTime.getHourOfDay() == adjusted.getHourOfDay() && +// dateTime.getMinuteOfHour() == adjusted.getMinuteOfHour() && +// dateTime.getSecondOfMinute() == adjusted.getSecondOfMinute()) { +// return true; +// } +// adjusted = dateTime.minus(diff); +// if (dateTime.getHourOfDay() == adjusted.getHourOfDay() && +// dateTime.getMinuteOfHour() == adjusted.getMinuteOfHour() && +// dateTime.getSecondOfMinute() == adjusted.getSecondOfMinute()) { +// return true; +// } +// return false; +// } +// return false; +// } +// +// +// DateTime dateTime = null; +// try { +// dateTime = localDateTime.toDateTime(this); +// } catch (IllegalArgumentException ex) { +// return false; // it is a gap, not an overlap +// } +// long offset1 = Math.abs(getOffset(dateTime.getMillis() + 1) - getStandardOffset(dateTime.getMillis() + 1)); +// long offset2 = Math.abs(getOffset(dateTime.getMillis() - 1) - getStandardOffset(dateTime.getMillis() - 1)); +// long offset = Math.max(offset1, offset2); +// if (offset == 0) { +// return false; +// } +// DateTime adjusted = dateTime.plus(offset); +// if (dateTime.getHourOfDay() == adjusted.getHourOfDay() && +// dateTime.getMinuteOfHour() == adjusted.getMinuteOfHour() && +// dateTime.getSecondOfMinute() == adjusted.getSecondOfMinute()) { +// return true; +// } +// adjusted = dateTime.minus(offset); +// if (dateTime.getHourOfDay() == adjusted.getHourOfDay() && +// dateTime.getMinuteOfHour() == adjusted.getMinuteOfHour() && +// dateTime.getSecondOfMinute() == adjusted.getSecondOfMinute()) { +// return true; +// } +// return false; + +// long millis = dateTime.getMillis(); +// long nextTransition = nextTransition(millis); +// long previousTransition = previousTransition(millis); +// long deltaToPreviousTransition = millis - previousTransition; +// long deltaToNextTransition = nextTransition - millis; +// if (deltaToNextTransition < deltaToPreviousTransition) { +// int offset = getOffset(nextTransition); +// int standardOffset = getStandardOffset(nextTransition); +// if (Math.abs(offset - standardOffset) >= deltaToNextTransition) { +// return true; +// } +// } else { +// int offset = getOffset(previousTransition); +// int standardOffset = getStandardOffset(previousTransition); +// if (Math.abs(offset - standardOffset) >= deltaToPreviousTransition) { +// return true; +// } +// } +// return false; +// } + /** + * Checks if the given {@link LocalDateTime} is within a gap. + *

      + * When switching from standard time to Daylight Savings Time there is + * typically a gap where a clock hour is missing. This method identifies + * whether the local datetime refers to such a gap. + * + * @param localDateTime the time to check, not null + * @return true if the given datetime refers to a gap + * @since 1.6 + */ + public boolean isLocalDateTimeGap(LocalDateTime localDateTime) { + if (isFixed()) { + return false; + } + try { + localDateTime.toDateTime(this); + return false; + } catch (IllegalArgumentException ex) { + return true; + } + } + + /** + * Adjusts the offset to be the earlier or later one during an overlap. + * + * @param instant the instant to adjust + * @param earlierOrLater false for earlier, true for later + * @return the adjusted instant millis + */ + public long adjustOffset(long instant, boolean earlierOrLater) { + // a bit messy, but will work in all non-pathological cases + + // evaluate 3 hours before and after to work out if anything is happening + long instantBefore = instant - 3 * DateTimeConstants.MILLIS_PER_HOUR; + long instantAfter = instant + 3 * DateTimeConstants.MILLIS_PER_HOUR; + long offsetBefore = getOffset(instantBefore); + long offsetAfter = getOffset(instantAfter); + if (offsetBefore <= offsetAfter) { + return instant; // not an overlap (less than is a gap, equal is normal case) + } + + // work out range of instants that have duplicate local times + long diff = offsetBefore - offsetAfter; + long transition = nextTransition(instantBefore); + long overlapStart = transition - diff; + long overlapEnd = transition + diff; + if (instant < overlapStart || instant >= overlapEnd) { + return instant; // not an overlap + } + + // calculate result + long afterStart = instant - overlapStart; + if (afterStart >= diff) { + // currently in later offset + return earlierOrLater ? instant : instant - diff; + } else { + // currently in earlier offset + return earlierOrLater ? instant + diff : instant; + } + } +// System.out.println(new DateTime(transitionStart, DateTimeZone.UTC) + " " + new DateTime(transitionStart, this)); + + //----------------------------------------------------------------------- + /** * Returns true if this time zone has no transitions. * * @return true if no transitions @@ -879,7 +1227,7 @@ /** * Get the datetime zone as a {@link java.util.TimeZone}. * - * @return the equivalent TimeZone object + * @return the closest matching TimeZone object */ public java.util.TimeZone toTimeZone() { return java.util.TimeZone.getTimeZone(iID); @@ -946,7 +1294,8 @@ } private Object readResolve() throws ObjectStreamException { - return getInstance(iID); + return forID(iID); } } + } Index: 3rdParty_sources/joda-time/org/joda/time/Days.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/Days.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/Days.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,491 @@ +/* + * Copyright 2001-2010 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; +import org.joda.time.base.BaseSingleFieldPeriod; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.ISOPeriodFormat; +import org.joda.time.format.PeriodFormatter; + +/** + * An immutable time period representing a number of days. + *

      + * Days is an immutable period that can only store days. + * It does not store years, months or hours for example. As such it is a + * type-safe way of representing a number of days in an application. + *

      + * The number of days is set in the constructor, and may be queried using + * getDays(). Basic mathematical operations are provided - + * plus(), minus(), multipliedBy() and + * dividedBy(). + *

      + * Days is thread-safe and immutable. + * + * @author Stephen Colebourne + * @since 1.4 + */ +public final class Days extends BaseSingleFieldPeriod { + + /** Constant representing zero days. */ + public static final Days ZERO = new Days(0); + /** Constant representing one day. */ + public static final Days ONE = new Days(1); + /** Constant representing two days. */ + public static final Days TWO = new Days(2); + /** Constant representing three days. */ + public static final Days THREE = new Days(3); + /** Constant representing four days. */ + public static final Days FOUR = new Days(4); + /** Constant representing five days. */ + public static final Days FIVE = new Days(5); + /** Constant representing six days. */ + public static final Days SIX = new Days(6); + /** Constant representing seven days. */ + public static final Days SEVEN = new Days(7); + /** Constant representing the maximum number of days that can be stored in this object. */ + public static final Days MAX_VALUE = new Days(Integer.MAX_VALUE); + /** Constant representing the minimum number of days that can be stored in this object. */ + public static final Days MIN_VALUE = new Days(Integer.MIN_VALUE); + + /** The paser to use for this class. */ + private static final PeriodFormatter PARSER = ISOPeriodFormat.standard().withParseType(PeriodType.days()); + /** Serialization version. */ + private static final long serialVersionUID = 87525275727380865L; + + //----------------------------------------------------------------------- + /** + * Obtains an instance of Days that may be cached. + * Days is immutable, so instances can be cached and shared. + * This factory method provides access to shared instances. + * + * @param days the number of days to obtain an instance for + * @return the instance of Days + */ + public static Days days(int days) { + switch (days) { + case 0: + return ZERO; + case 1: + return ONE; + case 2: + return TWO; + case 3: + return THREE; + case 4: + return FOUR; + case 5: + return FIVE; + case 6: + return SIX; + case 7: + return SEVEN; + case Integer.MAX_VALUE: + return MAX_VALUE; + case Integer.MIN_VALUE: + return MIN_VALUE; + default: + return new Days(days); + } + } + + //----------------------------------------------------------------------- + /** + * Creates a Days representing the number of whole days + * between the two specified datetimes. This method corectly handles + * any daylight savings time changes that may occur during the interval. + * + * @param start the start instant, must not be null + * @param end the end instant, must not be null + * @return the period in days + * @throws IllegalArgumentException if the instants are null or invalid + */ + public static Days daysBetween(ReadableInstant start, ReadableInstant end) { + int amount = BaseSingleFieldPeriod.between(start, end, DurationFieldType.days()); + return Days.days(amount); + } + + /** + * Creates a Days representing the number of whole days + * between the two specified partial datetimes. + *

      + * The two partials must contain the same fields, for example you can specify + * two LocalDate objects. + * + * @param start the start partial date, must not be null + * @param end the end partial date, must not be null + * @return the period in days + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Days daysBetween(ReadablePartial start, ReadablePartial end) { + if (start instanceof LocalDate && end instanceof LocalDate) { + Chronology chrono = DateTimeUtils.getChronology(start.getChronology()); + int days = chrono.days().getDifference( + ((LocalDate) end).getLocalMillis(), ((LocalDate) start).getLocalMillis()); + return Days.days(days); + } + int amount = BaseSingleFieldPeriod.between(start, end, ZERO); + return Days.days(amount); + } + + /** + * Creates a Days representing the number of whole days + * in the specified interval. This method corectly handles any daylight + * savings time changes that may occur during the interval. + * + * @param interval the interval to extract days from, null returns zero + * @return the period in days + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Days daysIn(ReadableInterval interval) { + if (interval == null) { + return Days.ZERO; + } + int amount = BaseSingleFieldPeriod.between(interval.getStart(), interval.getEnd(), DurationFieldType.days()); + return Days.days(amount); + } + + /** + * Creates a new Days representing the number of complete + * standard length days in the specified period. + *

      + * This factory method converts all fields from the period to hours using standardised + * durations for each field. Only those fields which have a precise duration in + * the ISO UTC chronology can be converted. + *

        + *
      • One week consists of 7 days. + *
      • One day consists of 24 hours. + *
      • One hour consists of 60 minutes. + *
      • One minute consists of 60 seconds. + *
      • One second consists of 1000 milliseconds. + *
      + * Months and Years are imprecise and periods containing these values cannot be converted. + * + * @param period the period to get the number of hours from, null returns zero + * @return the period in days + * @throws IllegalArgumentException if the period contains imprecise duration values + */ + public static Days standardDaysIn(ReadablePeriod period) { + int amount = BaseSingleFieldPeriod.standardPeriodIn(period, DateTimeConstants.MILLIS_PER_DAY); + return Days.days(amount); + } + + /** + * Creates a new Days by parsing a string in the ISO8601 format 'PnD'. + *

      + * The parse will accept the full ISO syntax of PnYnMnWnDTnHnMnS however only the + * days component may be non-zero. If any other component is non-zero, an exception + * will be thrown. + * + * @param periodStr the period string, null returns zero + * @return the period in days + * @throws IllegalArgumentException if the string format is invalid + */ + @FromString + public static Days parseDays(String periodStr) { + if (periodStr == null) { + return Days.ZERO; + } + Period p = PARSER.parsePeriod(periodStr); + return Days.days(p.getDays()); + } + + //----------------------------------------------------------------------- + /** + * Creates a new instance representing a number of days. + * You should consider using the factory method {@link #days(int)} + * instead of the constructor. + * + * @param days the number of days to represent + */ + private Days(int days) { + super(days); + } + + /** + * Resolves singletons. + * + * @return the singleton instance + */ + private Object readResolve() { + return Days.days(getValue()); + } + + //----------------------------------------------------------------------- + /** + * Gets the duration field type, which is days. + * + * @return the period type + */ + public DurationFieldType getFieldType() { + return DurationFieldType.days(); + } + + /** + * Gets the period type, which is days. + * + * @return the period type + */ + public PeriodType getPeriodType() { + return PeriodType.days(); + } + + //----------------------------------------------------------------------- + /** + * Converts this period in days to a period in weeks assuming a + * 7 day week. + *

      + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all weeks are + * 7 days long. + * This may not be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of weeks for this number of days + */ + public Weeks toStandardWeeks() { + return Weeks.weeks(getValue() / DateTimeConstants.DAYS_PER_WEEK); + } + + /** + * Converts this period in days to a period in hours assuming a + * 24 hour day. + *

      + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all days are 24 hours long. + * This is not true when daylight savings is considered and may also not + * be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of hours for this number of days + * @throws ArithmeticException if the number of hours is too large to be represented + */ + public Hours toStandardHours() { + return Hours.hours(FieldUtils.safeMultiply(getValue(), DateTimeConstants.HOURS_PER_DAY)); + } + + /** + * Converts this period in days to a period in minutes assuming a + * 24 hour day and 60 minute hour. + *

      + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all days are 24 hours + * long and all hours are 60 minutes long. + * This is not true when daylight savings is considered and may also not + * be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of minutes for this number of days + * @throws ArithmeticException if the number of minutes is too large to be represented + */ + public Minutes toStandardMinutes() { + return Minutes.minutes(FieldUtils.safeMultiply(getValue(), DateTimeConstants.MINUTES_PER_DAY)); + } + + /** + * Converts this period in days to a period in seconds assuming a + * 24 hour day, 60 minute hour and 60 second minute. + *

      + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all days are 24 hours + * long, all hours are 60 minutes long and all minutes are 60 seconds long. + * This is not true when daylight savings is considered and may also not + * be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of seconds for this number of days + * @throws ArithmeticException if the number of seconds is too large to be represented + */ + public Seconds toStandardSeconds() { + return Seconds.seconds(FieldUtils.safeMultiply(getValue(), DateTimeConstants.SECONDS_PER_DAY)); + } + + //----------------------------------------------------------------------- + /** + * Converts this period in days to a duration in milliseconds assuming a + * 24 hour day, 60 minute hour and 60 second minute. + *

      + * This method allows you to convert from a period to a duration. + * However to achieve this it makes the assumption that all days are 24 hours + * long, all hours are 60 minutes and all minutes are 60 seconds. + * This is not true when daylight savings time is considered, and may also + * not be true for some unusual chronologies. However, it is included as it + * is a useful operation for many applications and business rules. + * + * @return a duration equivalent to this number of days + */ + public Duration toStandardDuration() { + long days = getValue(); // assign to a long + return new Duration(days * DateTimeConstants.MILLIS_PER_DAY); + } + + //----------------------------------------------------------------------- + /** + * Gets the number of days that this period represents. + * + * @return the number of days in the period + */ + public int getDays() { + return getValue(); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of days added. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param days the amount of days to add, may be negative + * @return the new period plus the specified number of days + * @throws ArithmeticException if the result overflows an int + */ + public Days plus(int days) { + if (days == 0) { + return this; + } + return Days.days(FieldUtils.safeAdd(getValue(), days)); + } + + /** + * Returns a new instance with the specified number of days added. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param days the amount of days to add, may be negative, null means zero + * @return the new period plus the specified number of days + * @throws ArithmeticException if the result overflows an int + */ + public Days plus(Days days) { + if (days == null) { + return this; + } + return plus(days.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of days taken away. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param days the amount of days to take away, may be negative + * @return the new period minus the specified number of days + * @throws ArithmeticException if the result overflows an int + */ + public Days minus(int days) { + return plus(FieldUtils.safeNegate(days)); + } + + /** + * Returns a new instance with the specified number of days taken away. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param days the amount of days to take away, may be negative, null means zero + * @return the new period minus the specified number of days + * @throws ArithmeticException if the result overflows an int + */ + public Days minus(Days days) { + if (days == null) { + return this; + } + return minus(days.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the days multiplied by the specified scalar. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param scalar the amount to multiply by, may be negative + * @return the new period multiplied by the specified scalar + * @throws ArithmeticException if the result overflows an int + */ + public Days multipliedBy(int scalar) { + return Days.days(FieldUtils.safeMultiply(getValue(), scalar)); + } + + /** + * Returns a new instance with the days divided by the specified divisor. + * The calculation uses integer division, thus 3 divided by 2 is 1. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param divisor the amount to divide by, may be negative + * @return the new period divided by the specified divisor + * @throws ArithmeticException if the divisor is zero + */ + public Days dividedBy(int divisor) { + if (divisor == 1) { + return this; + } + return Days.days(getValue() / divisor); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the days value negated. + * + * @return the new period with a negated value + * @throws ArithmeticException if the result overflows an int + */ + public Days negated() { + return Days.days(FieldUtils.safeNegate(getValue())); + } + + //----------------------------------------------------------------------- + /** + * Is this days instance greater than the specified number of days. + * + * @param other the other period, null means zero + * @return true if this days instance is greater than the specified one + */ + public boolean isGreaterThan(Days other) { + if (other == null) { + return getValue() > 0; + } + return getValue() > other.getValue(); + } + + /** + * Is this days instance less than the specified number of days. + * + * @param other the other period, null means zero + * @return true if this days instance is less than the specified one + */ + public boolean isLessThan(Days other) { + if (other == null) { + return getValue() < 0; + } + return getValue() < other.getValue(); + } + + //----------------------------------------------------------------------- + /** + * Gets this instance as a String in the ISO8601 duration format. + *

      + * For example, "P4D" represents 4 days. + * + * @return the value as an ISO8601 string + */ + @ToString + public String toString() { + return "P" + String.valueOf(getValue()) + "D"; + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/Duration.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/Duration.java (.../Duration.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/Duration.java (.../Duration.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,60 +1,23 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2010 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; import java.io.Serializable; +import org.joda.convert.FromString; import org.joda.time.base.BaseDuration; import org.joda.time.field.FieldUtils; @@ -82,7 +45,129 @@ /** Serialization version */ private static final long serialVersionUID = 2471658376918L; + //----------------------------------------------------------------------- /** + * Parses a {@code Duration} from the specified string. + *

      + * This parses the format {@code PTa.bS}, as per {@link #toString()}. + * + * @param str the string to parse, not null + * @since 2.0 + */ + @FromString + public static Duration parse(String str) { + return new Duration(str); + } + + //----------------------------------------------------------------------- + /** + * Create a duration with the specified number of days assuming that + * there are the standard number of milliseconds in a day. + *

      + * This method assumes that there are 24 hours in a day, + * 60 minutes in an hour, 60 seconds in a minute and 1000 milliseconds in + * a second. This will be true for most days, however days with Daylight + * Savings changes will not have 24 hours, so use this method with care. + *

      + * A Duration is a representation of an amount of time. If you want to express + * the concepts of 'days' you should consider using the {@link Days} class. + * + * @param days the number of standard days in this duration + * @return the duration, never null + * @throws ArithmeticException if the days value is too large + * @since 1.6 + */ + public static Duration standardDays(long days) { + if (days == 0) { + return ZERO; + } + return new Duration(FieldUtils.safeMultiply(days, DateTimeConstants.MILLIS_PER_DAY)); + } + + /** + * Create a duration with the specified number of hours assuming that + * there are the standard number of milliseconds in an hour. + *

      + * This method assumes that there are 60 minutes in an hour, + * 60 seconds in a minute and 1000 milliseconds in a second. + * All currently supplied chronologies use this definition. + *

      + * A Duration is a representation of an amount of time. If you want to express + * the concepts of 'hours' you should consider using the {@link Hours} class. + * + * @param hours the number of standard hours in this duration + * @return the duration, never null + * @throws ArithmeticException if the hours value is too large + * @since 1.6 + */ + public static Duration standardHours(long hours) { + if (hours == 0) { + return ZERO; + } + return new Duration(FieldUtils.safeMultiply(hours, DateTimeConstants.MILLIS_PER_HOUR)); + } + + /** + * Create a duration with the specified number of minutes assuming that + * there are the standard number of milliseconds in a minute. + *

      + * This method assumes that there are 60 seconds in a minute and + * 1000 milliseconds in a second. + * All currently supplied chronologies use this definition. + *

      + * A Duration is a representation of an amount of time. If you want to express + * the concepts of 'minutes' you should consider using the {@link Minutes} class. + * + * @param minutes the number of standard minutes in this duration + * @return the duration, never null + * @throws ArithmeticException if the minutes value is too large + * @since 1.6 + */ + public static Duration standardMinutes(long minutes) { + if (minutes == 0) { + return ZERO; + } + return new Duration(FieldUtils.safeMultiply(minutes, DateTimeConstants.MILLIS_PER_MINUTE)); + } + + /** + * Create a duration with the specified number of seconds assuming that + * there are the standard number of milliseconds in a second. + *

      + * This method assumes that there are 1000 milliseconds in a second. + * All currently supplied chronologies use this definition. + *

      + * A Duration is a representation of an amount of time. If you want to express + * the concepts of 'seconds' you should consider using the {@link Seconds} class. + * + * @param seconds the number of standard seconds in this duration + * @return the duration, never null + * @throws ArithmeticException if the seconds value is too large + * @since 1.6 + */ + public static Duration standardSeconds(long seconds) { + if (seconds == 0) { + return ZERO; + } + return new Duration(FieldUtils.safeMultiply(seconds, DateTimeConstants.MILLIS_PER_SECOND)); + } + + /** + * Create a duration with the specified number of milliseconds. + * + * @param millis the number of standard milliseconds in this duration + * @return the duration, never null + * @since 2.0 + */ + public static Duration millis(long millis) { + if (millis == 0) { + return ZERO; + } + return new Duration(millis); + } + + //----------------------------------------------------------------------- + /** * Creates a duration from the given millisecond duration. * * @param duration the duration, in milliseconds @@ -126,6 +211,79 @@ //----------------------------------------------------------------------- /** + * Gets the length of this duration in days assuming that there are the + * standard number of milliseconds in a day. + *

      + * This method assumes that there are 24 hours in a day, + * 60 minutes in an hour, 60 seconds in a minute and 1000 milliseconds in + * a second. This will be true for most days, however days with Daylight + * Savings changes will not have 24 hours, so use this method with care. + *

      + * This returns getMillis() / MILLIS_PER_DAY. + * The result is an integer division, thus excess milliseconds are truncated. + * + * @return the length of the duration in standard seconds + * @since 2.0 + */ + public long getStandardDays() { + return getMillis() / DateTimeConstants.MILLIS_PER_DAY; + } + + /** + * Gets the length of this duration in hours assuming that there are the + * standard number of milliseconds in an hour. + *

      + * This method assumes that there are 60 minutes in an hour, + * 60 seconds in a minute and 1000 milliseconds in a second. + * All currently supplied chronologies use this definition. + *

      + * This returns getMillis() / MILLIS_PER_HOUR. + * The result is an integer division, thus excess milliseconds are truncated. + * + * @return the length of the duration in standard seconds + * @since 2.0 + */ + public long getStandardHours() { + return getMillis() / DateTimeConstants.MILLIS_PER_HOUR; + } + + /** + * Gets the length of this duration in minutes assuming that there are the + * standard number of milliseconds in a minute. + *

      + * This method assumes that there are 60 seconds in a minute and + * 1000 milliseconds in a second. + * All currently supplied chronologies use this definition. + *

      + * This returns getMillis() / 60000. + * The result is an integer division, thus excess milliseconds are truncated. + * + * @return the length of the duration in standard seconds + * @since 2.0 + */ + public long getStandardMinutes() { + return getMillis() / DateTimeConstants.MILLIS_PER_MINUTE; + } + + /** + * Gets the length of this duration in seconds assuming that there are the + * standard number of milliseconds in a second. + *

      + * This method assumes that there are 1000 milliseconds in a second. + * All currently supplied chronologies use this definition. + *

      + * This returns getMillis() / 1000. + * The result is an integer division, so 2999 millis returns 2 seconds. + * + * @return the length of the duration in standard seconds + * @since 1.6 + */ + public long getStandardSeconds() { + return getMillis() / DateTimeConstants.MILLIS_PER_SECOND; + } + + //----------------------------------------------------------------------- + /** * Get this duration as an immutable Duration object * by returning this. * @@ -135,6 +293,74 @@ return this; } + /** + * Converts this duration to a period in days assuming that there are the + * standard number of milliseconds in a day. + *

      + * This method assumes that there are 24 hours in a day, + * 60 minutes in an hour, 60 seconds in a minute and 1000 milliseconds in + * a second. This will be true for most days, however days with Daylight + * Savings changes will not have 24 hours, so use this method with care. + * + * @return a period representing the number of standard days in this period, never null + * @throws ArithmeticException if the number of days is too large to be represented + * @since 2.0 + */ + public Days toStandardDays() { + long days = getStandardDays(); + return Days.days(FieldUtils.safeToInt(days)); + } + + /** + * Converts this duration to a period in hours assuming that there are the + * standard number of milliseconds in an hour. + *

      + * This method assumes that there are 60 minutes in an hour, + * 60 seconds in a minute and 1000 milliseconds in a second. + * All currently supplied chronologies use this definition. + * + * @return a period representing the number of standard hours in this period, never null + * @throws ArithmeticException if the number of hours is too large to be represented + * @since 2.0 + */ + public Hours toStandardHours() { + long hours = getStandardHours(); + return Hours.hours(FieldUtils.safeToInt(hours)); + } + + /** + * Converts this duration to a period in minutes assuming that there are the + * standard number of milliseconds in a minute. + *

      + * This method assumes that there are 60 seconds in a minute and + * 1000 milliseconds in a second. + * All currently supplied chronologies use this definition. + * + * @return a period representing the number of standard minutes in this period, never null + * @throws ArithmeticException if the number of minutes is too large to be represented + * @since 2.0 + */ + public Minutes toStandardMinutes() { + long minutes = getStandardMinutes(); + return Minutes.minutes(FieldUtils.safeToInt(minutes)); + } + + /** + * Converts this duration to a period in seconds assuming that there are the + * standard number of milliseconds in a second. + *

      + * This method assumes that there are 1000 milliseconds in a second. + * All currently supplied chronologies use this definition. + * + * @return a period representing the number of standard seconds in this period, never null + * @throws ArithmeticException if the number of seconds is too large to be represented + * @since 1.6 + */ + public Seconds toStandardSeconds() { + long seconds = getStandardSeconds(); + return Seconds.seconds(FieldUtils.safeToInt(seconds)); + } + //----------------------------------------------------------------------- /** * Creates a new Duration instance with a different milisecond length. Index: 3rdParty_sources/joda-time/org/joda/time/DurationField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/DurationField.java (.../DurationField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/DurationField.java (.../DurationField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; @@ -65,7 +27,7 @@ * @author Brian S O'Neill * @since 1.0 */ -public abstract class DurationField implements Comparable { +public abstract class DurationField implements Comparable { /** * Get the type of the field. @@ -236,6 +198,36 @@ public abstract long add(long instant, long value); /** + * Subtracts a duration value (which may be negative) from the instant. + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z to subtract from + * @param value the value to subtract, in the units of the field + * @return the updated milliseconds + * @since 1.1 + */ + public long subtract(long instant, int value) { + if (value == Integer.MIN_VALUE) { + return subtract(instant, (long) value); + } + return add(instant, -value); + } + + /** + * Subtracts a duration value (which may be negative) from the instant. + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z to subtract from + * @param value the value to subtract, in the units of the field + * @return the updated milliseconds + * @since 1.1 + */ + public long subtract(long instant, long value) { + if (value == Long.MIN_VALUE) { + throw new ArithmeticException("Long.MIN_VALUE cannot be negated"); + } + return add(instant, -value); + } + + /** * Computes the difference between two instants, as measured in the units * of this field. Any fractional units are dropped from the result. Calling * getDifference reverses the effect of calling add. In the following code: @@ -277,17 +269,19 @@ */ public abstract long getDifferenceAsLong(long minuendInstant, long subtrahendInstant); - /** - * Compares this duration field with another duration field for ascending - * unit millisecond order. This ordering is inconsistent with equals, as it - * ignores name and precision. - * - * @param durationField a duration field to check against - * @return negative value if this is less, 0 if equal, or positive value if greater - * @throws NullPointerException if the object is null - * @throws ClassCastException if the object type is not supported - */ - public abstract int compareTo(Object durationField); + // Adding this definition would be backwards incompatible with earlier subclasses + // This definition of compareTo was present in previous versions, and still applies +// /** +// * Compares this duration field with another duration field for ascending +// * unit millisecond order. This ordering is inconsistent with equals, as it +// * ignores name and precision. +// * +// * @param durationField a duration field to check against +// * @return negative value if this is less, 0 if equal, or positive value if greater +// * @throws NullPointerException if the object is null +// * @throws ClassCastException if the object type is not supported +// */ +// public abstract int compareTo(DurationField durationField); /** * Returns a localized unit name of this field, using the given value as an Index: 3rdParty_sources/joda-time/org/joda/time/DurationFieldType.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/DurationFieldType.java (.../DurationFieldType.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/DurationFieldType.java (.../DurationFieldType.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; @@ -298,6 +260,24 @@ iOrdinal = ordinal; } + /** @inheritdoc */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof StandardDurationFieldType) { + return iOrdinal == ((StandardDurationFieldType) obj).iOrdinal; + } + return false; + } + + /** @inheritdoc */ + @Override + public int hashCode() { + return (1 << iOrdinal); + } + public DurationField getField(Chronology chronology) { chronology = DateTimeUtils.getChronology(chronology); @@ -368,6 +348,5 @@ return this; } } - } } Index: 3rdParty_sources/joda-time/org/joda/time/Hours.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/Hours.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/Hours.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,490 @@ +/* + * Copyright 2001-2010 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; +import org.joda.time.base.BaseSingleFieldPeriod; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.ISOPeriodFormat; +import org.joda.time.format.PeriodFormatter; + +/** + * An immutable time period representing a number of hours. + *

      + * Hours is an immutable period that can only store hours. + * It does not store years, months or minutes for example. As such it is a + * type-safe way of representing a number of hours in an application. + *

      + * The number of hours is set in the constructor, and may be queried using + * getHours(). Basic mathematical operations are provided - + * plus(), minus(), multipliedBy() and + * dividedBy(). + *

      + * Hours is thread-safe and immutable. + * + * @author Stephen Colebourne + * @since 1.4 + */ +public final class Hours extends BaseSingleFieldPeriod { + + /** Constant representing zero hours. */ + public static final Hours ZERO = new Hours(0); + /** Constant representing one hour. */ + public static final Hours ONE = new Hours(1); + /** Constant representing two hours. */ + public static final Hours TWO = new Hours(2); + /** Constant representing three hours. */ + public static final Hours THREE = new Hours(3); + /** Constant representing four hours. */ + public static final Hours FOUR = new Hours(4); + /** Constant representing five hours. */ + public static final Hours FIVE = new Hours(5); + /** Constant representing six hours. */ + public static final Hours SIX = new Hours(6); + /** Constant representing seven hours. */ + public static final Hours SEVEN = new Hours(7); + /** Constant representing eight hours. */ + public static final Hours EIGHT = new Hours(8); + /** Constant representing the maximum number of hours that can be stored in this object. */ + public static final Hours MAX_VALUE = new Hours(Integer.MAX_VALUE); + /** Constant representing the minimum number of hours that can be stored in this object. */ + public static final Hours MIN_VALUE = new Hours(Integer.MIN_VALUE); + + /** The paser to use for this class. */ + private static final PeriodFormatter PARSER = ISOPeriodFormat.standard().withParseType(PeriodType.hours()); + /** Serialization version. */ + private static final long serialVersionUID = 87525275727380864L; + + //----------------------------------------------------------------------- + /** + * Obtains an instance of Hours that may be cached. + * Hours is immutable, so instances can be cached and shared. + * This factory method provides access to shared instances. + * + * @param hours the number of hours to obtain an instance for + * @return the instance of Hours + */ + public static Hours hours(int hours) { + switch (hours) { + case 0: + return ZERO; + case 1: + return ONE; + case 2: + return TWO; + case 3: + return THREE; + case 4: + return FOUR; + case 5: + return FIVE; + case 6: + return SIX; + case 7: + return SEVEN; + case 8: + return EIGHT; + case Integer.MAX_VALUE: + return MAX_VALUE; + case Integer.MIN_VALUE: + return MIN_VALUE; + default: + return new Hours(hours); + } + } + + //----------------------------------------------------------------------- + /** + * Creates a Hours representing the number of whole hours + * between the two specified datetimes. + * + * @param start the start instant, must not be null + * @param end the end instant, must not be null + * @return the period in hours + * @throws IllegalArgumentException if the instants are null or invalid + */ + public static Hours hoursBetween(ReadableInstant start, ReadableInstant end) { + int amount = BaseSingleFieldPeriod.between(start, end, DurationFieldType.hours()); + return Hours.hours(amount); + } + + /** + * Creates a Hours representing the number of whole hours + * between the two specified partial datetimes. + *

      + * The two partials must contain the same fields, for example you can specify + * two LocalTime objects. + * + * @param start the start partial date, must not be null + * @param end the end partial date, must not be null + * @return the period in hours + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Hours hoursBetween(ReadablePartial start, ReadablePartial end) { + if (start instanceof LocalTime && end instanceof LocalTime) { + Chronology chrono = DateTimeUtils.getChronology(start.getChronology()); + int hours = chrono.hours().getDifference( + ((LocalTime) end).getLocalMillis(), ((LocalTime) start).getLocalMillis()); + return Hours.hours(hours); + } + int amount = BaseSingleFieldPeriod.between(start, end, ZERO); + return Hours.hours(amount); + } + + /** + * Creates a Hours representing the number of whole hours + * in the specified interval. + * + * @param interval the interval to extract hours from, null returns zero + * @return the period in hours + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Hours hoursIn(ReadableInterval interval) { + if (interval == null) { + return Hours.ZERO; + } + int amount = BaseSingleFieldPeriod.between(interval.getStart(), interval.getEnd(), DurationFieldType.hours()); + return Hours.hours(amount); + } + + /** + * Creates a new Hours representing the number of complete + * standard length hours in the specified period. + *

      + * This factory method converts all fields from the period to hours using standardised + * durations for each field. Only those fields which have a precise duration in + * the ISO UTC chronology can be converted. + *

        + *
      • One week consists of 7 days. + *
      • One day consists of 24 hours. + *
      • One hour consists of 60 minutes. + *
      • One minute consists of 60 seconds. + *
      • One second consists of 1000 milliseconds. + *
      + * Months and Years are imprecise and periods containing these values cannot be converted. + * + * @param period the period to get the number of hours from, null returns zero + * @return the period in hours + * @throws IllegalArgumentException if the period contains imprecise duration values + */ + public static Hours standardHoursIn(ReadablePeriod period) { + int amount = BaseSingleFieldPeriod.standardPeriodIn(period, DateTimeConstants.MILLIS_PER_HOUR); + return Hours.hours(amount); + } + + /** + * Creates a new Hours by parsing a string in the ISO8601 format 'PTnH'. + *

      + * The parse will accept the full ISO syntax of PnYnMnWnDTnHnMnS however only the + * hours component may be non-zero. If any other component is non-zero, an exception + * will be thrown. + * + * @param periodStr the period string, null returns zero + * @return the period in hours + * @throws IllegalArgumentException if the string format is invalid + */ + @FromString + public static Hours parseHours(String periodStr) { + if (periodStr == null) { + return Hours.ZERO; + } + Period p = PARSER.parsePeriod(periodStr); + return Hours.hours(p.getHours()); + } + + //----------------------------------------------------------------------- + /** + * Creates a new instance representing a number of hours. + * You should consider using the factory method {@link #hours(int)} + * instead of the constructor. + * + * @param hours the number of hours to represent + */ + private Hours(int hours) { + super(hours); + } + + /** + * Resolves singletons. + * + * @return the singleton instance + */ + private Object readResolve() { + return Hours.hours(getValue()); + } + + //----------------------------------------------------------------------- + /** + * Gets the duration field type, which is hours. + * + * @return the period type + */ + public DurationFieldType getFieldType() { + return DurationFieldType.hours(); + } + + /** + * Gets the period type, which is hours. + * + * @return the period type + */ + public PeriodType getPeriodType() { + return PeriodType.hours(); + } + + //----------------------------------------------------------------------- + /** + * Converts this period in hours to a period in weeks assuming a + * 7 day week and 24 hour day. + *

      + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all weeks are 7 days + * long and all days are 24 hours long. + * This is not true when daylight savings time is considered, and may also + * not be true for some unusual chronologies. However, it is included as it + * is a useful operation for many applications and business rules. + * + * @return a period representing the number of whole weeks for this number of hours + */ + public Weeks toStandardWeeks() { + return Weeks.weeks(getValue() / DateTimeConstants.HOURS_PER_WEEK); + } + + /** + * Converts this period in hours to a period in days assuming a + * 24 hour day. + *

      + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all days are 24 hours long. + * This is not true when daylight savings time is considered, and may also + * not be true for some unusual chronologies. However, it is included as it + * is a useful operation for many applications and business rules. + * + * @return a period representing the number of whole days for this number of hours + */ + public Days toStandardDays() { + return Days.days(getValue() / DateTimeConstants.HOURS_PER_DAY); + } + + /** + * Converts this period in hours to a period in minutes assuming a + * 60 minute hour. + *

      + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all hours are 60 minutes long. + * This may not be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of minutes for this number of hours + * @throws ArithmeticException if the number of minutes is too large to be represented + */ + public Minutes toStandardMinutes() { + return Minutes.minutes(FieldUtils.safeMultiply(getValue(), DateTimeConstants.MINUTES_PER_HOUR)); + } + + /** + * Converts this period in hours to a period in seconds assuming a + * 60 minute hour and 60 second minute. + *

      + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all hours are + * 60 minutes long and all minutes are 60 seconds long. + * This may not be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of seconds for this number of hours + * @throws ArithmeticException if the number of seconds is too large to be represented + */ + public Seconds toStandardSeconds() { + return Seconds.seconds(FieldUtils.safeMultiply(getValue(), DateTimeConstants.SECONDS_PER_HOUR)); + } + + //----------------------------------------------------------------------- + /** + * Converts this period in hours to a duration in milliseconds assuming a + * 60 minute hour and 60 second minute. + *

      + * This method allows you to convert from a period to a duration. + * However to achieve this it makes the assumption that all hours are + * 60 minutes and all minutes are 60 seconds. This might not be true for an + * unusual chronology, for example one that takes leap seconds into account. + * However, the method is included as it is a useful operation for many + * applications and business rules. + * + * @return a duration equivalent to this number of hours + */ + public Duration toStandardDuration() { + long hours = getValue(); // assign to a long + return new Duration(hours * DateTimeConstants.MILLIS_PER_HOUR); + } + + //----------------------------------------------------------------------- + /** + * Gets the number of hours that this period represents. + * + * @return the number of hours in the period + */ + public int getHours() { + return getValue(); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of hours added. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param hours the amount of hours to add, may be negative + * @return the new period plus the specified number of hours + * @throws ArithmeticException if the result overflows an int + */ + public Hours plus(int hours) { + if (hours == 0) { + return this; + } + return Hours.hours(FieldUtils.safeAdd(getValue(), hours)); + } + + /** + * Returns a new instance with the specified number of hours added. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param hours the amount of hours to add, may be negative, null means zero + * @return the new period plus the specified number of hours + * @throws ArithmeticException if the result overflows an int + */ + public Hours plus(Hours hours) { + if (hours == null) { + return this; + } + return plus(hours.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of hours taken away. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param hours the amount of hours to take away, may be negative + * @return the new period minus the specified number of hours + * @throws ArithmeticException if the result overflows an int + */ + public Hours minus(int hours) { + return plus(FieldUtils.safeNegate(hours)); + } + + /** + * Returns a new instance with the specified number of hours taken away. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param hours the amount of hours to take away, may be negative, null means zero + * @return the new period minus the specified number of hours + * @throws ArithmeticException if the result overflows an int + */ + public Hours minus(Hours hours) { + if (hours == null) { + return this; + } + return minus(hours.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the hours multiplied by the specified scalar. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param scalar the amount to multiply by, may be negative + * @return the new period multiplied by the specified scalar + * @throws ArithmeticException if the result overflows an int + */ + public Hours multipliedBy(int scalar) { + return Hours.hours(FieldUtils.safeMultiply(getValue(), scalar)); + } + + /** + * Returns a new instance with the hours divided by the specified divisor. + * The calculation uses integer division, thus 3 divided by 2 is 1. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param divisor the amount to divide by, may be negative + * @return the new period divided by the specified divisor + * @throws ArithmeticException if the divisor is zero + */ + public Hours dividedBy(int divisor) { + if (divisor == 1) { + return this; + } + return Hours.hours(getValue() / divisor); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the hours value negated. + * + * @return the new period with a negated value + * @throws ArithmeticException if the result overflows an int + */ + public Hours negated() { + return Hours.hours(FieldUtils.safeNegate(getValue())); + } + + //----------------------------------------------------------------------- + /** + * Is this hours instance greater than the specified number of hours. + * + * @param other the other period, null means zero + * @return true if this hours instance is greater than the specified one + */ + public boolean isGreaterThan(Hours other) { + if (other == null) { + return getValue() > 0; + } + return getValue() > other.getValue(); + } + + /** + * Is this hours instance less than the specified number of hours. + * + * @param other the other period, null means zero + * @return true if this hours instance is less than the specified one + */ + public boolean isLessThan(Hours other) { + if (other == null) { + return getValue() < 0; + } + return getValue() < other.getValue(); + } + + //----------------------------------------------------------------------- + /** + * Gets this instance as a String in the ISO8601 duration format. + *

      + * For example, "PT4H" represents 4 hours. + * + * @return the value as an ISO8601 string + */ + @ToString + public String toString() { + return "PT" + String.valueOf(getValue()) + "H"; + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/IllegalFieldValueException.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/IllegalFieldValueException.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/IllegalFieldValueException.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,329 @@ +/* + * Copyright 2001-2006 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +/** + * Exception thrown when attempting to set a field outside its supported range. + * + * @author Brian S O'Neill + * @since 1.1 + */ +public class IllegalFieldValueException extends IllegalArgumentException { + + /** Serialization lock. */ + private static final long serialVersionUID = 6305711765985447737L; + + /** + * Creates a message for the exception. + * + * @param fieldName the field name + * @param value the value rejected + * @param lowerBound the lower bound allowed + * @param upperBound the uppe bound allowed + * @param explain an explanation + * @return the message + */ + private static String createMessage(String fieldName, Number value, + Number lowerBound, Number upperBound, String explain) { + StringBuffer buf = new StringBuffer() + .append("Value ").append(value).append(" for ").append(fieldName).append(' '); + + if (lowerBound == null) { + if (upperBound == null) { + buf.append("is not supported"); + } else { + buf.append("must not be larger than ").append(upperBound); + } + } else if (upperBound == null) { + buf.append("must not be smaller than ").append(lowerBound); + } else { + buf.append("must be in the range [") + .append(lowerBound) + .append(',') + .append(upperBound) + .append(']'); + } + if (explain != null) { + buf.append(": ").append(explain); + } + + return buf.toString(); + } + + /** + * Creates a message for the exception. + * + * @param fieldName the field name + * @param value the value rejected + * @return the message + */ + private static String createMessage(String fieldName, String value) { + StringBuffer buf = new StringBuffer().append("Value "); + + if (value == null) { + buf.append("null"); + } else { + buf.append('"'); + buf.append(value); + buf.append('"'); + } + + buf.append(" for ").append(fieldName).append(' ').append("is not supported"); + + return buf.toString(); + } + + private final DateTimeFieldType iDateTimeFieldType; + private final DurationFieldType iDurationFieldType; + private final String iFieldName; + private final Number iNumberValue; + private final String iStringValue; + private final Number iLowerBound; + private final Number iUpperBound; + private String iMessage; + + /** + * Constructor. + * + * @param fieldType type of field being set + * @param value illegal value being set + * @param lowerBound lower legal field value, or null if not applicable + * @param upperBound upper legal field value, or null if not applicable + */ + public IllegalFieldValueException(DateTimeFieldType fieldType, + Number value, Number lowerBound, Number upperBound) { + super(createMessage(fieldType.getName(), value, lowerBound, upperBound, null)); + iDateTimeFieldType = fieldType; + iDurationFieldType = null; + iFieldName = fieldType.getName(); + iNumberValue = value; + iStringValue = null; + iLowerBound = lowerBound; + iUpperBound = upperBound; + iMessage = super.getMessage(); + } + + /** + * Constructor. + * + * @param fieldType type of field being set + * @param value illegal value being set + * @param explain an explanation + * @since 1.5 + */ + public IllegalFieldValueException(DateTimeFieldType fieldType, + Number value, String explain) { + super(createMessage(fieldType.getName(), value, null, null, explain)); + iDateTimeFieldType = fieldType; + iDurationFieldType = null; + iFieldName = fieldType.getName(); + iNumberValue = value; + iStringValue = null; + iLowerBound = null; + iUpperBound = null; + iMessage = super.getMessage(); + } + + /** + * Constructor. + * + * @param fieldType type of field being set + * @param value illegal value being set + * @param lowerBound lower legal field value, or null if not applicable + * @param upperBound upper legal field value, or null if not applicable + */ + public IllegalFieldValueException(DurationFieldType fieldType, + Number value, Number lowerBound, Number upperBound) { + super(createMessage(fieldType.getName(), value, lowerBound, upperBound, null)); + iDateTimeFieldType = null; + iDurationFieldType = fieldType; + iFieldName = fieldType.getName(); + iNumberValue = value; + iStringValue = null; + iLowerBound = lowerBound; + iUpperBound = upperBound; + iMessage = super.getMessage(); + } + + /** + * Constructor. + * + * @param fieldName name of field being set + * @param value illegal value being set + * @param lowerBound lower legal field value, or null if not applicable + * @param upperBound upper legal field value, or null if not applicable + */ + public IllegalFieldValueException(String fieldName, + Number value, Number lowerBound, Number upperBound) { + super(createMessage(fieldName, value, lowerBound, upperBound, null)); + iDateTimeFieldType = null; + iDurationFieldType = null; + iFieldName = fieldName; + iNumberValue = value; + iStringValue = null; + iLowerBound = lowerBound; + iUpperBound = upperBound; + iMessage = super.getMessage(); + } + + /** + * Constructor. + * + * @param fieldType type of field being set + * @param value illegal value being set + */ + public IllegalFieldValueException(DateTimeFieldType fieldType, String value) { + super(createMessage(fieldType.getName(), value)); + iDateTimeFieldType = fieldType; + iDurationFieldType = null; + iFieldName = fieldType.getName(); + iStringValue = value; + iNumberValue = null; + iLowerBound = null; + iUpperBound = null; + iMessage = super.getMessage(); + } + + /** + * Constructor. + * + * @param fieldType type of field being set + * @param value illegal value being set + */ + public IllegalFieldValueException(DurationFieldType fieldType, String value) { + super(createMessage(fieldType.getName(), value)); + iDateTimeFieldType = null; + iDurationFieldType = fieldType; + iFieldName = fieldType.getName(); + iStringValue = value; + iNumberValue = null; + iLowerBound = null; + iUpperBound = null; + iMessage = super.getMessage(); + } + + /** + * Constructor. + * + * @param fieldName name of field being set + * @param value illegal value being set + */ + public IllegalFieldValueException(String fieldName, String value) { + super(createMessage(fieldName, value)); + iDateTimeFieldType = null; + iDurationFieldType = null; + iFieldName = fieldName; + iStringValue = value; + iNumberValue = null; + iLowerBound = null; + iUpperBound = null; + iMessage = super.getMessage(); + } + + //----------------------------------------------------------------------- + /** + * Returns the DateTimeFieldType whose value was invalid, or null if not applicable. + * + * @return the datetime field type + */ + public DateTimeFieldType getDateTimeFieldType() { + return iDateTimeFieldType; + } + + /** + * Returns the DurationFieldType whose value was invalid, or null if not applicable. + * + * @return the duration field type + */ + public DurationFieldType getDurationFieldType() { + return iDurationFieldType; + } + + /** + * Returns the name of the field whose value was invalid. + * + * @return the field name + */ + public String getFieldName() { + return iFieldName; + } + + /** + * Returns the illegal integer value assigned to the field, or null if not applicable. + * + * @return the value + */ + public Number getIllegalNumberValue() { + return iNumberValue; + } + + /** + * Returns the illegal string value assigned to the field, or null if not applicable. + * + * @return the value + */ + public String getIllegalStringValue() { + return iStringValue; + } + + /** + * Returns the illegal value assigned to the field as a non-null string. + * + * @return the value + */ + public String getIllegalValueAsString() { + String value = iStringValue; + if (value == null) { + value = String.valueOf(iNumberValue); + } + return value; + } + + /** + * Returns the lower bound of the legal value range, or null if not applicable. + * + * @return the lower bound + */ + public Number getLowerBound() { + return iLowerBound; + } + + /** + * Returns the upper bound of the legal value range, or null if not applicable. + * + * @return the upper bound + */ + public Number getUpperBound() { + return iUpperBound; + } + + public String getMessage() { + return iMessage; + } + + /** + * Provide additional detail by prepending a message to the existing message. + * A colon is separator is automatically inserted between the messages. + * @since 1.3 + */ + public void prependMessage(String message) { + if (iMessage == null) { + iMessage = message; + } else if (message != null) { + iMessage = message + ": " + iMessage; + } + } +} Index: 3rdParty_sources/joda-time/org/joda/time/Instant.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/Instant.java (.../Instant.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/Instant.java (.../Instant.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,78 +1,47 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2010 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; import java.io.Serializable; +import org.joda.convert.FromString; import org.joda.time.base.AbstractInstant; +import org.joda.time.chrono.ISOChronology; import org.joda.time.convert.ConverterManager; import org.joda.time.convert.InstantConverter; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; /** * Instant is the standard implementation of a fully immutable instant in time. - * It holds the instant as milliseconds from the Java Epoch of 1970-01-01T00:00:00Z. *

      - * The chronology used is always ISO in the UTC time zone. - * This corresponds to the definition of the Java Epoch. + * Instant is an implementation of {@link ReadableInstant}. + * As with all instants, it represents an exact point on the time-line, + * but limited to the precision of milliseconds. An Instant + * should be used to represent a point in time irrespective of any other + * factor, such as chronology or time zone. *

      - * An Instant can be used to compare two DateTime objects: + * Internally, the class holds one piece of data, the instant as milliseconds + * from the Java epoch of 1970-01-01T00:00:00Z. + *

      + * For example, an Instant can be used to compare two DateTime + * objects irrespective of chronology or time zone. *

        * boolean sameInstant = dt1.toInstant().equals(dt2.toInstant());
        * 
      - * This code will return true if the two DateTime objects represent - * the same instant regardless of chronology or time zone. - *

      * Note that the following code will also perform the same check: *

        * boolean sameInstant = dt1.isEqual(dt2);
      @@ -95,7 +64,45 @@
       
           //-----------------------------------------------------------------------
           /**
      +     * Obtains an {@code Instant} set to the current system millisecond time.
      +     * 
      +     * @return the current instant, not null
      +     * @since 2.0
      +     */
      +    public static Instant now() {
      +        return new Instant();
      +    }
      +
      +    //-----------------------------------------------------------------------
      +    /**
      +     * Parses a {@code Instant} from the specified string.
      +     * 

      + * This uses {@link ISODateTimeFormat#dateTimeParser()}. + * + * @param str the string to parse, not null + * @since 2.0 + */ + @FromString + public static Instant parse(String str) { + return parse(str, ISODateTimeFormat.dateTimeParser()); + } + + /** + * Parses a {@code Instant} from the specified string using a formatter. + * + * @param str the string to parse, not null + * @param formatter the formatter to use, not null + * @since 2.0 + */ + public static Instant parse(String str, DateTimeFormatter formatter) { + return formatter.parseDateTime(str).toInstant(); + } + + //----------------------------------------------------------------------- + /** * Constructs an instance set to the current system millisecond time. + * + * @see #now() */ public Instant() { super(); @@ -124,7 +131,7 @@ public Instant(Object instant) { super(); InstantConverter converter = ConverterManager.getInstance().getInstantConverter(instant); - iMillis = converter.getInstantMillis(instant, Chronology.getISOUTC()); + iMillis = converter.getInstantMillis(instant, ISOChronology.getInstanceUTC()); } //----------------------------------------------------------------------- @@ -251,11 +258,107 @@ /** * Gets the chronology of the instant, which is ISO in the UTC zone. + *

      + * This method returns {@link ISOChronology#getInstanceUTC()} which + * corresponds to the definition of the Java epoch 1970-01-01T00:00:00Z. * * @return ISO in the UTC zone */ public Chronology getChronology() { - return Chronology.getISOUTC(); + return ISOChronology.getInstanceUTC(); } + //----------------------------------------------------------------------- + /** + * Get this object as a DateTime using ISOChronology in the default zone. + *

      + * This method returns a DateTime object in the default zone. + * This differs from the similarly named method on DateTime, DateMidnight + * or MutableDateTime which retains the time zone. The difference is + * because Instant really represents a time without a zone, + * thus calling this method we really have no zone to 'retain' and + * hence expect to switch to the default zone. + *

      + * This method definition preserves compatibility with earlier versions + * of Joda-Time. + * + * @return a DateTime using the same millis + */ + public DateTime toDateTime() { + return new DateTime(getMillis(), ISOChronology.getInstance()); + } + + /** + * Get this object as a DateTime using ISOChronology in the default zone. + * This method is identical to toDateTime(). + *

      + * This method returns a DateTime object in the default zone. + * This differs from the similarly named method on DateTime, DateMidnight + * or MutableDateTime which retains the time zone. The difference is + * because Instant really represents a time without a zone, + * thus calling this method we really have no zone to 'retain' and + * hence expect to switch to the default zone. + *

      + * This method is deprecated because it is a duplicate of {@link #toDateTime()}. + * However, removing it would cause the superclass implementation to be used, + * which would create silent bugs in any caller depending on this implementation. + * As such, the method itself is not currently planned to be removed. + *

      + * This method definition preserves compatibility with earlier versions + * of Joda-Time. + * + * @return a DateTime using the same millis with ISOChronology + * @deprecated Use toDateTime() as it is identical + */ + @Deprecated + public DateTime toDateTimeISO() { + return toDateTime(); + } + + /** + * Get this object as a MutableDateTime using ISOChronology in the default zone. + *

      + * This method returns a MutableDateTime object in the default zone. + * This differs from the similarly named method on DateTime, DateMidnight + * or MutableDateTime which retains the time zone. The difference is + * because Instant really represents a time without a zone, + * thus calling this method we really have no zone to 'retain' and + * hence expect to switch to the default zone. + *

      + * This method definition preserves compatibility with earlier versions + * of Joda-Time. + * + * @return a MutableDateTime using the same millis + */ + public MutableDateTime toMutableDateTime() { + return new MutableDateTime(getMillis(), ISOChronology.getInstance()); + } + + /** + * Get this object as a MutableDateTime using ISOChronology in the default zone. + * This method is identical to toMutableDateTime(). + *

      + * This method returns a MutableDateTime object in the default zone. + * This differs from the similarly named method on DateTime, DateMidnight + * or MutableDateTime which retains the time zone. The difference is + * because Instant really represents a time without a zone, + * thus calling this method we really have no zone to 'retain' and + * hence expect to switch to the default zone. + *

      + * This method is deprecated because it is a duplicate of {@link #toMutableDateTime()}. + * However, removing it would cause the superclass implementation to be used, + * which would create silent bugs in any caller depending on this implementation. + * As such, the method itself is not currently planned to be removed. + *

      + * This method definition preserves compatibility with earlier versions + * of Joda-Time. + * + * @return a MutableDateTime using the same millis with ISOChronology + * @deprecated Use toMutableDateTime() as it is identical + */ + @Deprecated + public MutableDateTime toMutableDateTimeISO() { + return toMutableDateTime(); + } + } Index: 3rdParty_sources/joda-time/org/joda/time/Interval.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/Interval.java (.../Interval.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/Interval.java (.../Interval.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,61 +1,26 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2006 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; import java.io.Serializable; import org.joda.time.base.BaseInterval; +import org.joda.time.chrono.ISOChronology; +import org.joda.time.format.ISODateTimeFormat; +import org.joda.time.format.ISOPeriodFormat; /** * Interval is the standard implementation of an immutable time interval. @@ -79,6 +44,7 @@ * @author Brian S O'Neill * @author Sean Geoghegan * @author Stephen Colebourne + * @author Julen Parra * @since 1.0 */ public final class Interval @@ -90,8 +56,24 @@ //----------------------------------------------------------------------- /** - * Constructs an interval from a start and end instant with the ISO default chronology. + * Parses a {@code Interval} from the specified string. + *

      + * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()} + * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime', + * 'datetime/period' or 'period/datetime'. * + * @param str the string to parse, not null + * @since 2.0 + */ + public static Interval parse(String str) { + return new Interval(str); + } + + //----------------------------------------------------------------------- + /** + * Constructs an interval from a start and end instant with the ISO + * default chronology in the default time zone. + * * @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z. * @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z. * @throws IllegalArgumentException if the end is before the start @@ -101,8 +83,23 @@ } /** - * Constructs an interval from a start and end instant with a chronology. + * Constructs an interval from a start and end instant with the ISO + * default chronology in the specified time zone. * + * @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z. + * @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z. + * @param zone the time zone to use, null means default zone + * @throws IllegalArgumentException if the end is before the start + * @since 1.5 + */ + public Interval(long startInstant, long endInstant, DateTimeZone zone) { + super(startInstant, endInstant, ISOChronology.getInstance(zone)); + } + + /** + * Constructs an interval from a start and end instant with the + * specified chronology. + * * @param chronology the chronology to use, null is ISO default * @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z. * @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z. @@ -181,6 +178,13 @@ /** * Constructs a time interval by converting or copying from another object. + *

      + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadableInterval and String. + * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()} + * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime', + * 'datetime/period' or 'period/datetime'. * * @param interval the time interval to copy * @throws IllegalArgumentException if the interval is invalid @@ -192,6 +196,13 @@ /** * Constructs a time interval by converting or copying from another object, * overriding the chronology. + *

      + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadableInterval and String. + * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()} + * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime', + * 'datetime/period' or 'period/datetime'. * * @param interval the time interval to copy * @param chronology the chronology to use, null means ISO default @@ -214,6 +225,127 @@ //----------------------------------------------------------------------- /** + * Gets the overlap between this interval and another interval. + *

      + * Intervals are inclusive of the start instant and exclusive of the end. + * An interval overlaps another if it shares some common part of the + * datetime continuum. This method returns the amount of the overlap, + * only if the intervals actually do overlap. + * If the intervals do not overlap, then null is returned. + *

      + * When two intervals are compared the result is one of three states: + * (a) they abut, (b) there is a gap between them, (c) they overlap. + * The abuts state takes precedence over the other two, thus a zero duration + * interval at the start of a larger interval abuts and does not overlap. + *

      + * The chronology of the returned interval is the same as that of + * this interval (the chronology of the interval parameter is not used). + * Note that the use of the chronology was only correctly implemented + * in version 1.3. + * + * @param interval the interval to examine, null means now + * @return the overlap interval, null if no overlap + * @since 1.1 + */ + public Interval overlap(ReadableInterval interval) { + interval = DateTimeUtils.getReadableInterval(interval); + if (overlaps(interval) == false) { + return null; + } + long start = Math.max(getStartMillis(), interval.getStartMillis()); + long end = Math.min(getEndMillis(), interval.getEndMillis()); + return new Interval(start, end, getChronology()); + } + + //----------------------------------------------------------------------- + /** + * Gets the gap between this interval and another interval. + * The other interval can be either before or after this interval. + *

      + * Intervals are inclusive of the start instant and exclusive of the end. + * An interval has a gap to another interval if there is a non-zero + * duration between them. This method returns the amount of the gap only + * if the intervals do actually have a gap between them. + * If the intervals overlap or abut, then null is returned. + *

      + * When two intervals are compared the result is one of three states: + * (a) they abut, (b) there is a gap between them, (c) they overlap. + * The abuts state takes precedence over the other two, thus a zero duration + * interval at the start of a larger interval abuts and does not overlap. + *

      + * The chronology of the returned interval is the same as that of + * this interval (the chronology of the interval parameter is not used). + * Note that the use of the chronology was only correctly implemented + * in version 1.3. + * + * @param interval the interval to examine, null means now + * @return the gap interval, null if no gap + * @since 1.1 + */ + public Interval gap(ReadableInterval interval) { + interval = DateTimeUtils.getReadableInterval(interval); + long otherStart = interval.getStartMillis(); + long otherEnd = interval.getEndMillis(); + long thisStart = getStartMillis(); + long thisEnd = getEndMillis(); + if (thisStart > otherEnd) { + return new Interval(otherEnd, thisStart, getChronology()); + } else if (otherStart > thisEnd) { + return new Interval(thisEnd, otherStart, getChronology()); + } else { + return null; + } + } + + //----------------------------------------------------------------------- + /** + * Does this interval abut with the interval specified. + *

      + * Intervals are inclusive of the start instant and exclusive of the end. + * An interval abuts if it starts immediately after, or ends immediately + * before this interval without overlap. + * A zero duration interval abuts with itself. + *

      + * When two intervals are compared the result is one of three states: + * (a) they abut, (b) there is a gap between them, (c) they overlap. + * The abuts state takes precedence over the other two, thus a zero duration + * interval at the start of a larger interval abuts and does not overlap. + *

      + * For example: + *

      +     * [09:00 to 10:00) abuts [08:00 to 08:30)  = false (completely before)
      +     * [09:00 to 10:00) abuts [08:00 to 09:00)  = true
      +     * [09:00 to 10:00) abuts [08:00 to 09:01)  = false (overlaps)
      +     * 
      +     * [09:00 to 10:00) abuts [09:00 to 09:00)  = true
      +     * [09:00 to 10:00) abuts [09:00 to 09:01)  = false (overlaps)
      +     * 
      +     * [09:00 to 10:00) abuts [10:00 to 10:00)  = true
      +     * [09:00 to 10:00) abuts [10:00 to 10:30)  = true
      +     * 
      +     * [09:00 to 10:00) abuts [10:30 to 11:00)  = false (completely after)
      +     * 
      +     * [14:00 to 14:00) abuts [14:00 to 14:00)  = true
      +     * [14:00 to 14:00) abuts [14:00 to 15:00)  = true
      +     * [14:00 to 14:00) abuts [13:00 to 14:00)  = true
      +     * 
      + * + * @param interval the interval to examine, null means now + * @return true if the interval abuts + * @since 1.1 + */ + public boolean abuts(ReadableInterval interval) { + if (interval == null) { + long now = DateTimeUtils.currentTimeMillis(); + return (getStartMillis() == now || getEndMillis() == now); + } else { + return (interval.getEndMillis() == getStartMillis() || + getEndMillis() == interval.getStartMillis()); + } + } + + //----------------------------------------------------------------------- + /** * Creates a new interval with the same start and end, but a different chronology. * * @param chronology the chronology to use, null means ISO default Index: 3rdParty_sources/joda-time/org/joda/time/JodaTimePermission.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/JodaTimePermission.java (.../JodaTimePermission.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/JodaTimePermission.java (.../JodaTimePermission.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; Index: 3rdParty_sources/joda-time/org/joda/time/LocalDate.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/LocalDate.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/LocalDate.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,2099 @@ +/* + * Copyright 2001-2011 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; +import java.util.TimeZone; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; +import org.joda.time.base.BaseLocal; +import org.joda.time.chrono.ISOChronology; +import org.joda.time.convert.ConverterManager; +import org.joda.time.convert.PartialConverter; +import org.joda.time.field.AbstractReadableInstantFieldProperty; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; + +/** + * LocalDate is an immutable datetime class representing a date + * without a time zone. + *

      + * LocalDate implements the {@link ReadablePartial} interface. + * To do this, the interface methods focus on the key fields - + * Year, MonthOfYear and DayOfMonth. + * However, all date fields may in fact be queried. + *

      + * LocalDate differs from DateMidnight in that this class does not + * have a time zone and does not represent a single instant in time. + *

      + * Calculations on LocalDate are performed using a {@link Chronology}. + * This chronology will be set internally to be in the UTC time zone + * for all calculations. + * + *

      Each individual field can be queried in two ways: + *

        + *
      • getMonthOfYear() + *
      • monthOfYear().get() + *
      + * The second technique also provides access to other useful methods on the + * field: + *
        + *
      • numeric value + *
      • text value + *
      • short text value + *
      • maximum/minimum values + *
      • add/subtract + *
      • set + *
      • rounding + *
      + * + *

      + * LocalDate is thread-safe and immutable, provided that the Chronology is as well. + * All standard Chronology classes supplied are thread-safe and immutable. + * + * @author Stephen Colebourne + * @since 1.3 + */ +public final class LocalDate + extends BaseLocal + implements ReadablePartial, Serializable { + + /** Serialization lock */ + private static final long serialVersionUID = -8775358157899L; + + /** The index of the year field in the field array */ + private static final int YEAR = 0; + /** The index of the monthOfYear field in the field array */ + private static final int MONTH_OF_YEAR = 1; + /** The index of the dayOfMonth field in the field array */ + private static final int DAY_OF_MONTH = 2; + /** Set of known duration types. */ + private static final Set DATE_DURATION_TYPES = new HashSet(); + static { + DATE_DURATION_TYPES.add(DurationFieldType.days()); + DATE_DURATION_TYPES.add(DurationFieldType.weeks()); + DATE_DURATION_TYPES.add(DurationFieldType.months()); + DATE_DURATION_TYPES.add(DurationFieldType.weekyears()); + DATE_DURATION_TYPES.add(DurationFieldType.years()); + DATE_DURATION_TYPES.add(DurationFieldType.centuries()); + // eras are supported, although the DurationField generally isn't + DATE_DURATION_TYPES.add(DurationFieldType.eras()); + } + + /** The local millis from 1970-01-01T00:00:00 */ + private final long iLocalMillis; + /** The chronology to use in UTC. */ + private final Chronology iChronology; + /** The cached hash code. */ + private transient volatile int iHash; + + //----------------------------------------------------------------------- + /** + * Obtains a {@code LocalDate} set to the current system millisecond time + * using ISOChronology in the default time zone. + * + * @return the current date-time, not null + * @since 2.0 + */ + public static LocalDate now() { + return new LocalDate(); + } + + /** + * Obtains a {@code LocalDate} set to the current system millisecond time + * using ISOChronology in the specified time zone. + * + * @param zone the time zone, not null + * @return the current date-time, not null + * @since 2.0 + */ + public static LocalDate now(DateTimeZone zone) { + if (zone == null) { + throw new NullPointerException("Zone must not be null"); + } + return new LocalDate(zone); + } + + /** + * Obtains a {@code LocalDate} set to the current system millisecond time + * using the specified chronology. + * + * @param chronology the chronology, not null + * @return the current date-time, not null + * @since 2.0 + */ + public static LocalDate now(Chronology chronology) { + if (chronology == null) { + throw new NullPointerException("Chronology must not be null"); + } + return new LocalDate(chronology); + } + + //----------------------------------------------------------------------- + /** + * Parses a {@code LocalDate} from the specified string. + *

      + * This uses {@link ISODateTimeFormat#localDateParser()}. + * + * @param str the string to parse, not null + * @since 2.0 + */ + @FromString + public static LocalDate parse(String str) { + return parse(str, ISODateTimeFormat.localDateParser()); + } + + /** + * Parses a {@code LocalDate} from the specified string using a formatter. + * + * @param str the string to parse, not null + * @param formatter the formatter to use, not null + * @since 2.0 + */ + public static LocalDate parse(String str, DateTimeFormatter formatter) { + return formatter.parseLocalDate(str); + } + + //----------------------------------------------------------------------- + /** + * Constructs a LocalDate from a java.util.Calendar + * using exactly the same field values. + *

      + * Each field is queried from the Calendar and assigned to the LocalDate. + * This is useful if you have been using the Calendar as a local date, + * ignoring the zone. + *

      + * One advantage of this method is that this method is unaffected if the + * version of the time zone data differs between the JDK and Joda-Time. + * That is because the local field values are transferred, calculated using + * the JDK time zone data and without using the Joda-Time time zone data. + *

      + * This factory method ignores the type of the calendar and always + * creates a LocalDate with ISO chronology. It is expected that you + * will only pass in instances of GregorianCalendar however + * this is not validated. + * + * @param calendar the Calendar to extract fields from + * @return the created LocalDate + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the date is invalid for the ISO chronology + */ + public static LocalDate fromCalendarFields(Calendar calendar) { + if (calendar == null) { + throw new IllegalArgumentException("The calendar must not be null"); + } + return new LocalDate( + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH) + 1, + calendar.get(Calendar.DAY_OF_MONTH) + ); + } + + /** + * Constructs a LocalDate from a java.util.Date + * using exactly the same field values. + *

      + * Each field is queried from the Date and assigned to the LocalDate. + * This is useful if you have been using the Date as a local date, + * ignoring the zone. + *

      + * One advantage of this method is that this method is unaffected if the + * version of the time zone data differs between the JDK and Joda-Time. + * That is because the local field values are transferred, calculated using + * the JDK time zone data and without using the Joda-Time time zone data. + *

      + * This factory method always creates a LocalDate with ISO chronology. + * + * @param date the Date to extract fields from + * @return the created LocalDate + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the date is invalid for the ISO chronology + */ + @SuppressWarnings("deprecation") + public static LocalDate fromDateFields(Date date) { + if (date == null) { + throw new IllegalArgumentException("The date must not be null"); + } + return new LocalDate( + date.getYear() + 1900, + date.getMonth() + 1, + date.getDate() + ); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance set to the current local time evaluated using + * ISO chronology in the default zone. + *

      + * Once the constructor is completed, the zone is no longer used. + * + * @see #now() + */ + public LocalDate() { + this(DateTimeUtils.currentTimeMillis(), ISOChronology.getInstance()); + } + + /** + * Constructs an instance set to the current local time evaluated using + * ISO chronology in the specified zone. + *

      + * If the specified time zone is null, the default zone is used. + * Once the constructor is completed, the zone is no longer used. + * + * @param zone the time zone, null means default zone + * @see #now(DateTimeZone) + */ + public LocalDate(DateTimeZone zone) { + this(DateTimeUtils.currentTimeMillis(), ISOChronology.getInstance(zone)); + } + + /** + * Constructs an instance set to the current local time evaluated using + * specified chronology. + *

      + * If the chronology is null, ISO chronology in the default time zone is used. + * Once the constructor is completed, the zone is no longer used. + * + * @param chronology the chronology, null means ISOChronology in default zone + * @see #now(Chronology) + */ + public LocalDate(Chronology chronology) { + this(DateTimeUtils.currentTimeMillis(), chronology); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance set to the local time defined by the specified + * instant evaluated using ISO chronology in the default zone. + *

      + * Once the constructor is completed, the zone is no longer used. + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z + */ + public LocalDate(long instant) { + this(instant, ISOChronology.getInstance()); + } + + /** + * Constructs an instance set to the local time defined by the specified + * instant evaluated using ISO chronology in the specified zone. + *

      + * If the specified time zone is null, the default zone is used. + * Once the constructor is completed, the zone is no longer used. + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z + * @param zone the time zone, null means default zone + */ + public LocalDate(long instant, DateTimeZone zone) { + this(instant, ISOChronology.getInstance(zone)); + } + + /** + * Constructs an instance set to the local time defined by the specified + * instant evaluated using the specified chronology. + *

      + * If the chronology is null, ISO chronology in the default zone is used. + * Once the constructor is completed, the zone is no longer used. + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z + * @param chronology the chronology, null means ISOChronology in default zone + */ + public LocalDate(long instant, Chronology chronology) { + chronology = DateTimeUtils.getChronology(chronology); + + long localMillis = chronology.getZone().getMillisKeepLocal(DateTimeZone.UTC, instant); + chronology = chronology.withUTC(); + iLocalMillis = chronology.dayOfMonth().roundFloor(localMillis); + iChronology = chronology; + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance from an Object that represents a datetime. + * The time zone will be retrieved from the object if possible, + * otherwise the default time zone will be used. + *

      + * If the object contains no chronology, ISOChronology is used. + * Once the constructor is completed, the zone is no longer used. + *

      + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePartial, ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#localDateParser()}. + * The default String converter ignores the zone and only parses the field values. + * + * @param instant the datetime object + * @throws IllegalArgumentException if the instant is invalid + */ + public LocalDate(Object instant) { + this(instant, (Chronology) null); + } + + /** + * Constructs an instance from an Object that represents a datetime, + * forcing the time zone to that specified. + *

      + * If the object contains no chronology, ISOChronology is used. + * If the specified time zone is null, the default zone is used. + * Once the constructor is completed, the zone is no longer used. + *

      + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePartial, ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#localDateParser()}. + * The default String converter ignores the zone and only parses the field values. + * + * @param instant the datetime object + * @param zone the time zone + * @throws IllegalArgumentException if the instant is invalid + */ + public LocalDate(Object instant, DateTimeZone zone) { + PartialConverter converter = ConverterManager.getInstance().getPartialConverter(instant); + Chronology chronology = converter.getChronology(instant, zone); + chronology = DateTimeUtils.getChronology(chronology); + iChronology = chronology.withUTC(); + int[] values = converter.getPartialValues(this, instant, chronology, ISODateTimeFormat.localDateParser()); + iLocalMillis = iChronology.getDateTimeMillis(values[0], values[1], values[2], 0); + } + + /** + * Constructs an instance from an Object that represents a datetime, + * using the specified chronology. + *

      + * If the chronology is null, ISO in the default time zone is used. + * Once the constructor is completed, the zone is no longer used. + *

      + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePartial, ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#localDateParser()}. + * The default String converter ignores the zone and only parses the field values. + * + * @param instant the datetime object + * @param chronology the chronology + * @throws IllegalArgumentException if the instant is invalid + */ + public LocalDate(Object instant, Chronology chronology) { + PartialConverter converter = ConverterManager.getInstance().getPartialConverter(instant); + chronology = converter.getChronology(instant, chronology); + chronology = DateTimeUtils.getChronology(chronology); + iChronology = chronology.withUTC(); + int[] values = converter.getPartialValues(this, instant, chronology, ISODateTimeFormat.localDateParser()); + iLocalMillis = iChronology.getDateTimeMillis(values[0], values[1], values[2], 0); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance set to the specified date and time + * using ISOChronology. + * + * @param year the year + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + */ + public LocalDate( + int year, + int monthOfYear, + int dayOfMonth) { + this(year, monthOfYear, dayOfMonth, ISOChronology.getInstanceUTC()); + } + + /** + * Constructs an instance set to the specified date and time + * using the specified chronology, whose zone is ignored. + *

      + * If the chronology is null, ISOChronology is used. + * + * @param year the year + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + * @param chronology the chronology, null means ISOChronology in default zone + */ + public LocalDate( + int year, + int monthOfYear, + int dayOfMonth, + Chronology chronology) { + super(); + chronology = DateTimeUtils.getChronology(chronology).withUTC(); + long instant = chronology.getDateTimeMillis(year, monthOfYear, dayOfMonth, 0); + iChronology = chronology; + iLocalMillis = instant; + } + + /** + * Handle broken serialization from other tools. + * @return the resolved object, not null + */ + private Object readResolve() { + if (iChronology == null) { + return new LocalDate(iLocalMillis, ISOChronology.getInstanceUTC()); + } + if (DateTimeZone.UTC.equals(iChronology.getZone()) == false) { + return new LocalDate(iLocalMillis, iChronology.withUTC()); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets the number of fields in this partial, which is three. + * The supported fields are Year, MonthOfYear and DayOfMonth. + * Note that all fields from day and above may in fact be queried via + * other methods. + * + * @return the field count, three + */ + public int size() { + return 3; + } + + /** + * Gets the field for a specific index in the chronology specified. + *

      + * This method must not use any instance variables. + * + * @param index the index to retrieve + * @param chrono the chronology to use + * @return the field + */ + protected DateTimeField getField(int index, Chronology chrono) { + switch (index) { + case YEAR: + return chrono.year(); + case MONTH_OF_YEAR: + return chrono.monthOfYear(); + case DAY_OF_MONTH: + return chrono.dayOfMonth(); + default: + throw new IndexOutOfBoundsException("Invalid index: " + index); + } + } + + /** + * Gets the value of the field at the specifed index. + *

      + * This method is required to support the ReadablePartial + * interface. The supported fields are Year, MonthOfYear and DayOfMonth. + * Note that all fields from day and above may in fact be queried via + * other methods. + * + * @param index the index, zero to two + * @return the value + * @throws IndexOutOfBoundsException if the index is invalid + */ + public int getValue(int index) { + switch (index) { + case YEAR: + return getChronology().year().get(getLocalMillis()); + case MONTH_OF_YEAR: + return getChronology().monthOfYear().get(getLocalMillis()); + case DAY_OF_MONTH: + return getChronology().dayOfMonth().get(getLocalMillis()); + default: + throw new IndexOutOfBoundsException("Invalid index: " + index); + } + } + + //----------------------------------------------------------------------- + /** + * Get the value of one of the fields of a datetime. + *

      + * This method gets the value of the specified field. + * For example: + *

      +     * LocalDate dt = LocalDate.nowDefaultZone();
      +     * int year = dt.get(DateTimeFieldType.year());
      +     * 
      + * + * @param fieldType a field type, usually obtained from DateTimeFieldType, not null + * @return the value of that field + * @throws IllegalArgumentException if the field type is null or unsupported + */ + public int get(DateTimeFieldType fieldType) { + if (fieldType == null) { + throw new IllegalArgumentException("The DateTimeFieldType must not be null"); + } + if (isSupported(fieldType) == false) { + throw new IllegalArgumentException("Field '" + fieldType + "' is not supported"); + } + return fieldType.getField(getChronology()).get(getLocalMillis()); + } + + /** + * Checks if the field type specified is supported by this + * local date and chronology. + * This can be used to avoid exceptions in {@link #get(DateTimeFieldType)}. + * + * @param type a field type, usually obtained from DateTimeFieldType + * @return true if the field type is supported + */ + public boolean isSupported(DateTimeFieldType type) { + if (type == null) { + return false; + } + DurationFieldType durType = type.getDurationType(); + if (DATE_DURATION_TYPES.contains(durType) || + durType.getField(getChronology()).getUnitMillis() >= + getChronology().days().getUnitMillis()) { + return type.getField(getChronology()).isSupported(); + } + return false; + } + + /** + * Checks if the duration type specified is supported by this + * local date and chronology. + * + * @param type a duration type, usually obtained from DurationFieldType + * @return true if the field type is supported + */ + public boolean isSupported(DurationFieldType type) { + if (type == null) { + return false; + } + DurationField field = type.getField(getChronology()); + if (DATE_DURATION_TYPES.contains(type) || + field.getUnitMillis() >= getChronology().days().getUnitMillis()) { + return field.isSupported(); + } + return false; + } + + //----------------------------------------------------------------------- + /** + * Gets the local milliseconds from the Java epoch + * of 1970-01-01T00:00:00 (not fixed to any specific time zone). + * + * @return the number of milliseconds since 1970-01-01T00:00:00 + * @since 1.5 (previously private) + */ + protected long getLocalMillis() { + return iLocalMillis; + } + + /** + * Gets the chronology of the date. + * + * @return the Chronology that the date is using + */ + public Chronology getChronology() { + return iChronology; + } + + //----------------------------------------------------------------------- + /** + * Compares this ReadablePartial with another returning true if the chronology, + * field types and values are equal. + * + * @param partial an object to check against + * @return true if fields and values are equal + */ + public boolean equals(Object partial) { + // override to perform faster + if (this == partial) { + return true; + } + if (partial instanceof LocalDate) { + LocalDate other = (LocalDate) partial; + if (iChronology.equals(other.iChronology)) { + return iLocalMillis == other.iLocalMillis; + } + } + return super.equals(partial); + } + + /** + * Gets a hash code for the instant as defined in ReadablePartial. + * + * @return a suitable hash code + */ + public int hashCode() { + // override for performance + int hash = iHash; + if (hash == 0) { + hash = iHash = super.hashCode(); + } + return hash; + } + + /** + * Compares this partial with another returning an integer + * indicating the order. + *

      + * The fields are compared in order, from largest to smallest. + * The first field that is non-equal is used to determine the result. + *

      + * The specified object must be a partial instance whose field types + * match those of this partial. + * + * @param partial an object to check against + * @return negative if this is less, zero if equal, positive if greater + * @throws ClassCastException if the partial is the wrong class + * or if it has field types that don't match + * @throws NullPointerException if the partial is null + */ + public int compareTo(ReadablePartial partial) { + // override to perform faster + if (this == partial) { + return 0; + } + if (partial instanceof LocalDate) { + LocalDate other = (LocalDate) partial; + if (iChronology.equals(other.iChronology)) { + return (iLocalMillis < other.iLocalMillis ? -1 : + (iLocalMillis == other.iLocalMillis ? 0 : 1)); + + } + } + return super.compareTo(partial); + } + + //----------------------------------------------------------------------- + /** + * Converts this LocalDate to a full datetime at the earliest valid time + * for the date using the default time zone. + *

      + * The time will normally be midnight, as that is the earliest time on + * any given day. However, in some time zones when Daylight Savings Time + * starts, there is no midnight because time jumps from 11:59 to 01:00. + * This method handles that situation by returning 01:00 on that date. + *

      + * This instance is immutable and unaffected by this method call. + * + * @return this date as a datetime at the start of the day + * @since 1.5 + */ + public DateTime toDateTimeAtStartOfDay() { + return toDateTimeAtStartOfDay(null); + } + + /** + * Converts this LocalDate to a full datetime at the earliest valid time + * for the date using the specified time zone. + *

      + * The time will normally be midnight, as that is the earliest time on + * any given day. However, in some time zones when Daylight Savings Time + * starts, there is no midnight because time jumps from 11:59 to 01:00. + * This method handles that situation by returning 01:00 on that date. + *

      + * This method uses the chronology from this instance plus the time zone + * specified. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param zone the zone to use, null means default zone + * @return this date as a datetime at the start of the day + * @since 1.5 + */ + public DateTime toDateTimeAtStartOfDay(DateTimeZone zone) { + zone = DateTimeUtils.getZone(zone); + Chronology chrono = getChronology().withZone(zone); + long localMillis = getLocalMillis() + 6L * DateTimeConstants.MILLIS_PER_HOUR; + long instant = zone.convertLocalToUTC(localMillis, false); + instant = chrono.dayOfMonth().roundFloor(instant); + return new DateTime(instant, chrono); + } + + //----------------------------------------------------------------------- + /** + * Converts this LocalDate to a full datetime at midnight using the default + * time zone. + *

      + * This method will throw an exception if the default time zone switches + * to Daylight Savings Time at midnight and this LocalDate represents + * that switchover date. The problem is that there is no such time as + * midnight on the required date, and as such an exception is thrown. + *

      + * This instance is immutable and unaffected by this method call. + * + * @return this date as a datetime at midnight + * @deprecated Use {@link #toDateTimeAtStartOfDay()} which won't throw an exception + */ + @Deprecated + public DateTime toDateTimeAtMidnight() { + return toDateTimeAtMidnight(null); + } + + /** + * Converts this LocalDate to a full datetime at midnight using the + * specified time zone. + *

      + * This method will throw an exception if the time zone switches + * to Daylight Savings Time at midnight and this LocalDate represents + * that switchover date. The problem is that there is no such time as + * midnight on the required date, and as such an exception is thrown. + *

      + * This method uses the chronology from this instance plus the time zone + * specified. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param zone the zone to use, null means default zone + * @return this date as a datetime at midnight + * @deprecated Use {@link #toDateTimeAtStartOfDay(DateTimeZone)} which won't throw an exception + */ + @Deprecated + public DateTime toDateTimeAtMidnight(DateTimeZone zone) { + zone = DateTimeUtils.getZone(zone); + Chronology chrono = getChronology().withZone(zone); + return new DateTime(getYear(), getMonthOfYear(), getDayOfMonth(), 0, 0, 0, 0, chrono); + } + + //----------------------------------------------------------------------- + /** + * Converts this LocalDate to a full datetime using the default time zone + * setting the date fields from this instance and the time fields from + * the current time. + *

      + * This method will throw an exception if the datetime that would be + * created does not exist when the time zone is taken into account. + *

      + * This instance is immutable and unaffected by this method call. + * + * @return this date as a datetime with the time as the current time + */ + public DateTime toDateTimeAtCurrentTime() { + return toDateTimeAtCurrentTime(null); + } + + /** + * Converts this LocalDate to a full datetime using the specified time zone + * setting the date fields from this instance and the time fields from + * the current time. + *

      + * This method uses the chronology from this instance plus the time zone + * specified. + *

      + * This method will throw an exception if the datetime that would be + * created does not exist when the time zone is taken into account. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param zone the zone to use, null means default zone + * @return this date as a datetime with the time as the current time + */ + public DateTime toDateTimeAtCurrentTime(DateTimeZone zone) { + zone = DateTimeUtils.getZone(zone); + Chronology chrono = getChronology().withZone(zone); + long instantMillis = DateTimeUtils.currentTimeMillis(); + long resolved = chrono.set(this, instantMillis); + return new DateTime(resolved, chrono); + } + + //----------------------------------------------------------------------- + /** + * Converts this LocalDate to a DateMidnight in the default time zone. + *

      + * As from v1.5, you are recommended to avoid DateMidnight and use + * {@link #toDateTimeAtStartOfDay()} instead because of the exception + * detailed below. + *

      + * This method will throw an exception if the default time zone switches + * to Daylight Savings Time at midnight and this LocalDate represents + * that switchover date. The problem is that there is no such time as + * midnight on the required date, and as such an exception is thrown. + *

      + * This instance is immutable and unaffected by this method call. + * + * @return the DateMidnight instance in the default zone + */ + public DateMidnight toDateMidnight() { + return toDateMidnight(null); + } + + /** + * Converts this LocalDate to a DateMidnight. + *

      + * As from v1.5, you are recommended to avoid DateMidnight and use + * {@link #toDateTimeAtStartOfDay()} instead because of the exception + * detailed below. + *

      + * This method will throw an exception if the time zone switches + * to Daylight Savings Time at midnight and this LocalDate represents + * that switchover date. The problem is that there is no such time as + * midnight on the required date, and as such an exception is thrown. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param zone the zone to get the DateMidnight in, null means default zone + * @return the DateMidnight instance + */ + public DateMidnight toDateMidnight(DateTimeZone zone) { + zone = DateTimeUtils.getZone(zone); + Chronology chrono = getChronology().withZone(zone); + return new DateMidnight(getYear(), getMonthOfYear(), getDayOfMonth(), chrono); + } + + //----------------------------------------------------------------------- + /** + * Converts this object to a LocalDateTime using a LocalTime to fill in + * the missing fields. + *

      + * The resulting chronology is determined by the chronology of this + * LocalDate. The chronology of the time must also match. + * If the time is null an exception is thrown. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param time the time of day to use, must not be null + * @return the LocalDateTime instance + * @throws IllegalArgumentException if the time is null + * @throws IllegalArgumentException if the chronology of the time does not match + * @since 1.5 + */ + public LocalDateTime toLocalDateTime(LocalTime time) { + if (time == null) { + throw new IllegalArgumentException("The time must not be null"); + } + if (getChronology() != time.getChronology()) { + throw new IllegalArgumentException("The chronology of the time does not match"); + } + long localMillis = getLocalMillis() + time.getLocalMillis(); + return new LocalDateTime(localMillis, getChronology()); + } + + //----------------------------------------------------------------------- + /** + * Converts this object to a DateTime using a LocalTime to fill in the + * missing fields and using the default time zone. + *

      + * The resulting chronology is determined by the chronology of this + * LocalDate. The chronology of the time must match. + * If the time is null, the current time in the date's chronology is used. + *

      + * This method will throw an exception if the datetime that would be + * created does not exist when the time zone is taken into account. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param time the time of day to use, null means current time + * @return the DateTime instance + * @throws IllegalArgumentException if the chronology of the time does not match + */ + public DateTime toDateTime(LocalTime time) { + return toDateTime(time, null); + } + + /** + * Converts this object to a DateTime using a LocalTime to fill in the + * missing fields. + *

      + * The resulting chronology is determined by the chronology of this + * LocalDate plus the time zone. The chronology of the time must match. + * If the time is null, the current time in the date's chronology is used. + *

      + * This method will throw an exception if the datetime that would be + * created does not exist when the time zone is taken into account. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param time the time of day to use, null means current time + * @param zone the zone to get the DateTime in, null means default + * @return the DateTime instance + * @throws IllegalArgumentException if the chronology of the time does not match + */ + public DateTime toDateTime(LocalTime time, DateTimeZone zone) { + if (time != null && getChronology() != time.getChronology()) { + throw new IllegalArgumentException("The chronology of the time does not match"); + } + Chronology chrono = getChronology().withZone(zone); + long instant = DateTimeUtils.currentTimeMillis(); + instant = chrono.set(this, instant); + if (time != null) { + instant = chrono.set(time, instant); + } + return new DateTime(instant, chrono); + } + + //----------------------------------------------------------------------- + /** + * Converts this object to an Interval representing the whole day + * in the default time zone. + *

      + * The interval may have more or less than 24 hours if this is a daylight + * savings cutover date. + *

      + * This instance is immutable and unaffected by this method call. + * + * @return a interval over the day + */ + public Interval toInterval() { + return toInterval(null); + } + + /** + * Converts this object to an Interval representing the whole day. + *

      + * The interval may have more or less than 24 hours if this is a daylight + * savings cutover date. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param zone the zone to get the Interval in, null means default + * @return a interval over the day + */ + public Interval toInterval(DateTimeZone zone) { + zone = DateTimeUtils.getZone(zone); + DateTime start = toDateTimeAtStartOfDay(zone); + DateTime end = plusDays(1).toDateTimeAtStartOfDay(zone); + return new Interval(start, end); + } + + //----------------------------------------------------------------------- + /** + * Get the date time as a java.util.Date. + *

      + * The Date object created has exactly the same year, month and day + * as this date. The time will be set to the earliest valid time for that date. + *

      + * Converting to a JDK Date is full of complications as the JDK Date constructor + * doesn't behave as you might expect around DST transitions. This method works + * by taking a first guess and then adjusting the JDK date until it has the + * earliest valid instant. This also handles the situation where the JDK time + * zone data differs from the Joda-Time time zone data. + * + * @return a Date initialised with this date, never null + * @since 2.0 + */ + @SuppressWarnings("deprecation") + public Date toDate() { + int dom = getDayOfMonth(); + Date date = new Date(getYear() - 1900, getMonthOfYear() - 1, dom); + LocalDate check = LocalDate.fromDateFields(date); + if (check.isBefore(this)) { + // DST gap (no midnight) + // move forward in units of one hour until date correct + while (check.equals(this) == false) { + date.setTime(date.getTime() + 3600000); + check = LocalDate.fromDateFields(date); + } + // move back in units of one second until date wrong + while (date.getDate() == dom) { + date.setTime(date.getTime() - 1000); + } + // fix result + date.setTime(date.getTime() + 1000); + } else if (check.equals(this)) { + // check for DST overlap (two midnights) + Date earlier = new Date(date.getTime() - TimeZone.getDefault().getDSTSavings()); + if (earlier.getDate() == dom) { + date = earlier; + } + } + return date; + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with different local millis. + *

      + * The returned object will be a new instance of the same type. + * Only the millis will change, the chronology is kept. + * The returned object will be either be a new instance or this. + * + * @param newMillis the new millis, from 1970-01-01T00:00:00 + * @return a copy of this date with different millis + */ + LocalDate withLocalMillis(long newMillis) { + newMillis = iChronology.dayOfMonth().roundFloor(newMillis); + return (newMillis == getLocalMillis() ? this : new LocalDate(newMillis, getChronology())); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the partial set of fields replacing + * those from this instance. + *

      + * For example, if the partial contains a year and a month then those two + * fields will be changed in the returned instance. + * Unsupported fields are ignored. + * If the partial is null, then this is returned. + * + * @param partial the partial set of fields to apply to this date, null ignored + * @return a copy of this date with a different set of fields + * @throws IllegalArgumentException if any value is invalid + */ + public LocalDate withFields(ReadablePartial partial) { + if (partial == null) { + return this; + } + return withLocalMillis(getChronology().set(partial, getLocalMillis())); + } + + /** + * Returns a copy of this date with the specified field set to a new value. + *

      + * For example, if the field type is monthOfYear then the + * month of year field will be changed in the returned instance. + * If the field type is null, then this is returned. + *

      + * These two lines are equivalent: + *

      +     * LocalDate updated = dt.withDayOfMonth(6);
      +     * LocalDate updated = dt.withField(DateTimeFieldType.dayOfMonth(), 6);
      +     * 
      + * + * @param fieldType the field type to set, not null + * @param value the value to set + * @return a copy of this date with the field set + * @throws IllegalArgumentException if the field is null or unsupported + */ + public LocalDate withField(DateTimeFieldType fieldType, int value) { + if (fieldType == null) { + throw new IllegalArgumentException("Field must not be null"); + } + if (isSupported(fieldType) == false) { + throw new IllegalArgumentException("Field '" + fieldType + "' is not supported"); + } + long instant = fieldType.getField(getChronology()).set(getLocalMillis(), value); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this date with the value of the specified field increased. + *

      + * If the addition is zero or the field is null, then this is returned. + *

      + * These three lines are equivalent: + *

      +     * LocalDate added = dt.withFieldAdded(DurationFieldType.years(), 6);
      +     * LocalDate added = dt.plusYears(6);
      +     * LocalDate added = dt.plus(Period.years(6));
      +     * 
      + * + * @param fieldType the field type to add to, not null + * @param amount the amount to add + * @return a copy of this date with the field updated + * @throws IllegalArgumentException if the field is null or unsupported + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalDate withFieldAdded(DurationFieldType fieldType, int amount) { + if (fieldType == null) { + throw new IllegalArgumentException("Field must not be null"); + } + if (isSupported(fieldType) == false) { + throw new IllegalArgumentException("Field '" + fieldType + "' is not supported"); + } + if (amount == 0) { + return this; + } + long instant = fieldType.getField(getChronology()).add(getLocalMillis(), amount); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the specified period added. + *

      + * If the addition is zero, then this is returned. + *

      + * This method is typically used to add multiple copies of complex + * period instances. Adding one field is best achieved using methods + * like {@link #withFieldAdded(DurationFieldType, int)} + * or {@link #plusYears(int)}. + *

      + * Unsupported time fields are ignored, thus adding a period of 24 hours + * will not have any effect. + * + * @param period the period to add to this one, null means zero + * @param scalar the amount of times to add, such as -1 to subtract once + * @return a copy of this date with the period added + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalDate withPeriodAdded(ReadablePeriod period, int scalar) { + if (period == null || scalar == 0) { + return this; + } + long instant = getLocalMillis(); + Chronology chrono = getChronology(); + for (int i = 0; i < period.size(); i++) { + long value = FieldUtils.safeMultiply(period.getValue(i), scalar); + DurationFieldType type = period.getFieldType(i); + if (isSupported(type)) { + instant = type.getField(chrono).add(instant, value); + } + } + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the specified period added. + *

      + * If the amount is zero or null, then this is returned. + *

      + * This method is typically used to add complex period instances. + * Adding one field is best achieved using methods + * like {@link #plusYears(int)}. + *

      + * Unsupported time fields are ignored, thus adding a period of 24 hours + * will not have any effect. + * + * @param period the period to add to this one, null means zero + * @return a copy of this date with the period added + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalDate plus(ReadablePeriod period) { + return withPeriodAdded(period, 1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date plus the specified number of years. + *

      + * This adds the specified number of years to the date. + * If adding years makes the day-of-month invalid, it is adjusted to the last valid day in the month. + * This LocalDate instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDate added = dt.plusYears(6);
      +     * LocalDate added = dt.plus(Period.years(6));
      +     * LocalDate added = dt.withFieldAdded(DurationFieldType.years(), 6);
      +     * 
      + * + * @param years the amount of years to add, may be negative + * @return the new LocalDate plus the increased years + */ + public LocalDate plusYears(int years) { + if (years == 0) { + return this; + } + long instant = getChronology().years().add(getLocalMillis(), years); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this date plus the specified number of months. + *

      + * This adds the specified number of months to the date. + * The addition may change the year, but the day-of-month is normally unchanged. + * If adding months makes the day-of-month invalid, it is adjusted to the last valid day in the month. + * This LocalDate instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDate added = dt.plusMonths(6);
      +     * LocalDate added = dt.plus(Period.months(6));
      +     * LocalDate added = dt.withFieldAdded(DurationFieldType.months(), 6);
      +     * 
      + * + * @param months the amount of months to add, may be negative + * @return the new LocalDate plus the increased months + */ + public LocalDate plusMonths(int months) { + if (months == 0) { + return this; + } + long instant = getChronology().months().add(getLocalMillis(), months); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this date plus the specified number of weeks. + *

      + * This LocalDate instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDate added = dt.plusWeeks(6);
      +     * LocalDate added = dt.plus(Period.weeks(6));
      +     * LocalDate added = dt.withFieldAdded(DurationFieldType.weeks(), 6);
      +     * 
      + * + * @param weeks the amount of weeks to add, may be negative + * @return the new LocalDate plus the increased weeks + */ + public LocalDate plusWeeks(int weeks) { + if (weeks == 0) { + return this; + } + long instant = getChronology().weeks().add(getLocalMillis(), weeks); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this date plus the specified number of days. + *

      + * This LocalDate instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDate added = dt.plusDays(6);
      +     * LocalDate added = dt.plus(Period.days(6));
      +     * LocalDate added = dt.withFieldAdded(DurationFieldType.days(), 6);
      +     * 
      + * + * @param days the amount of days to add, may be negative + * @return the new LocalDate plus the increased days + */ + public LocalDate plusDays(int days) { + if (days == 0) { + return this; + } + long instant = getChronology().days().add(getLocalMillis(), days); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the specified period taken away. + *

      + * If the amount is zero or null, then this is returned. + *

      + * This method is typically used to subtract complex period instances. + * Subtracting one field is best achieved using methods + * like {@link #minusYears(int)}. + *

      + * Unsupported time fields are ignored, thus subtracting a period of 24 hours + * will not have any effect. + * + * @param period the period to reduce this instant by + * @return a copy of this LocalDate with the period taken away + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalDate minus(ReadablePeriod period) { + return withPeriodAdded(period, -1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date minus the specified number of years. + *

      + * This subtracts the specified number of years from the date. + * If subtracting years makes the day-of-month invalid, it is adjusted to the last valid day in the month. + * This LocalDate instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDate subtracted = dt.minusYears(6);
      +     * LocalDate subtracted = dt.minus(Period.years(6));
      +     * LocalDate subtracted = dt.withFieldAdded(DurationFieldType.years(), -6);
      +     * 
      + * + * @param years the amount of years to subtract, may be negative + * @return the new LocalDate minus the increased years + */ + public LocalDate minusYears(int years) { + if (years == 0) { + return this; + } + long instant = getChronology().years().subtract(getLocalMillis(), years); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this date minus the specified number of months. + *

      + * This subtracts the specified number of months from the date. + * The subtraction may change the year, but the day-of-month is normally unchanged. + * If subtracting months makes the day-of-month invalid, it is adjusted to the last valid day in the month. + * This LocalDate instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDate subtracted = dt.minusMonths(6);
      +     * LocalDate subtracted = dt.minus(Period.months(6));
      +     * LocalDate subtracted = dt.withFieldAdded(DurationFieldType.months(), -6);
      +     * 
      + * + * @param months the amount of months to subtract, may be negative + * @return the new LocalDate minus the increased months + */ + public LocalDate minusMonths(int months) { + if (months == 0) { + return this; + } + long instant = getChronology().months().subtract(getLocalMillis(), months); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this date minus the specified number of weeks. + *

      + * This LocalDate instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDate subtracted = dt.minusWeeks(6);
      +     * LocalDate subtracted = dt.minus(Period.weeks(6));
      +     * LocalDate subtracted = dt.withFieldAdded(DurationFieldType.weeks(), -6);
      +     * 
      + * + * @param weeks the amount of weeks to subtract, may be negative + * @return the new LocalDate minus the increased weeks + */ + public LocalDate minusWeeks(int weeks) { + if (weeks == 0) { + return this; + } + long instant = getChronology().weeks().subtract(getLocalMillis(), weeks); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this date minus the specified number of days. + *

      + * This LocalDate instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDate subtracted = dt.minusDays(6);
      +     * LocalDate subtracted = dt.minus(Period.days(6));
      +     * LocalDate subtracted = dt.withFieldAdded(DurationFieldType.days(), -6);
      +     * 
      + * + * @param days the amount of days to subtract, may be negative + * @return the new LocalDate minus the increased days + */ + public LocalDate minusDays(int days) { + if (days == 0) { + return this; + } + long instant = getChronology().days().subtract(getLocalMillis(), days); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Gets the property object for the specified type, which contains many + * useful methods. + * + * @param fieldType the field type to get the chronology for + * @return the property object + * @throws IllegalArgumentException if the field is null or unsupported + */ + public Property property(DateTimeFieldType fieldType) { + if (fieldType == null) { + throw new IllegalArgumentException("The DateTimeFieldType must not be null"); + } + if (isSupported(fieldType) == false) { + throw new IllegalArgumentException("Field '" + fieldType + "' is not supported"); + } + return new Property(this, fieldType.getField(getChronology())); + } + + //----------------------------------------------------------------------- + /** + * Get the era field value. + * + * @return the era + */ + public int getEra() { + return getChronology().era().get(getLocalMillis()); + } + + /** + * Get the year of era field value. + * + * @return the year of era + */ + public int getCenturyOfEra() { + return getChronology().centuryOfEra().get(getLocalMillis()); + } + + /** + * Get the year of era field value. + * + * @return the year of era + */ + public int getYearOfEra() { + return getChronology().yearOfEra().get(getLocalMillis()); + } + + /** + * Get the year of century field value. + * + * @return the year of century + */ + public int getYearOfCentury() { + return getChronology().yearOfCentury().get(getLocalMillis()); + } + + /** + * Get the year field value. + * + * @return the year + */ + public int getYear() { + return getChronology().year().get(getLocalMillis()); + } + + /** + * Get the weekyear field value. + *

      + * The weekyear is the year that matches with the weekOfWeekyear field. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + * The weekyear allows you to query the effective year for that day. + * + * @return the weekyear + */ + public int getWeekyear() { + return getChronology().weekyear().get(getLocalMillis()); + } + + /** + * Get the month of year field value. + * + * @return the month of year + */ + public int getMonthOfYear() { + return getChronology().monthOfYear().get(getLocalMillis()); + } + + /** + * Get the week of weekyear field value. + *

      + * This field is associated with the "weekyear" via {@link #getWeekyear()}. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + * + * @return the week of a week based year + */ + public int getWeekOfWeekyear() { + return getChronology().weekOfWeekyear().get(getLocalMillis()); + } + + /** + * Get the day of year field value. + * + * @return the day of year + */ + public int getDayOfYear() { + return getChronology().dayOfYear().get(getLocalMillis()); + } + + /** + * Get the day of month field value. + *

      + * The values for the day of month are defined in {@link org.joda.time.DateTimeConstants}. + * + * @return the day of month + */ + public int getDayOfMonth() { + return getChronology().dayOfMonth().get(getLocalMillis()); + } + + /** + * Get the day of week field value. + *

      + * The values for the day of week are defined in {@link org.joda.time.DateTimeConstants}. + * + * @return the day of week + */ + public int getDayOfWeek() { + return getChronology().dayOfWeek().get(getLocalMillis()); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the era field updated. + *

      + * LocalDate is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * era changed. + * + * @param era the era to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDate withEra(int era) { + return withLocalMillis(getChronology().era().set(getLocalMillis(), era)); + } + + /** + * Returns a copy of this date with the century of era field updated. + *

      + * LocalDate is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * century of era changed. + * + * @param centuryOfEra the centurey of era to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDate withCenturyOfEra(int centuryOfEra) { + return withLocalMillis(getChronology().centuryOfEra().set(getLocalMillis(), centuryOfEra)); + } + + /** + * Returns a copy of this date with the year of era field updated. + *

      + * LocalDate is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year of era changed. + * + * @param yearOfEra the year of era to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDate withYearOfEra(int yearOfEra) { + return withLocalMillis(getChronology().yearOfEra().set(getLocalMillis(), yearOfEra)); + } + + /** + * Returns a copy of this date with the year of century field updated. + *

      + * LocalDate is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year of century changed. + * + * @param yearOfCentury the year of century to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDate withYearOfCentury(int yearOfCentury) { + return withLocalMillis(getChronology().yearOfCentury().set(getLocalMillis(), yearOfCentury)); + } + + /** + * Returns a copy of this date with the year field updated. + *

      + * LocalDate is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year changed. + * + * @param year the year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDate withYear(int year) { + return withLocalMillis(getChronology().year().set(getLocalMillis(), year)); + } + + /** + * Returns a copy of this date with the weekyear field updated. + *

      + * The weekyear is the year that matches with the weekOfWeekyear field. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + * The weekyear allows you to query the effective year for that day. + *

      + * LocalDate is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * weekyear changed. + * + * @param weekyear the weekyear to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDate withWeekyear(int weekyear) { + return withLocalMillis(getChronology().weekyear().set(getLocalMillis(), weekyear)); + } + + /** + * Returns a copy of this date with the month of year field updated. + *

      + * LocalDate is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * month of year changed. + * + * @param monthOfYear the month of year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDate withMonthOfYear(int monthOfYear) { + return withLocalMillis(getChronology().monthOfYear().set(getLocalMillis(), monthOfYear)); + } + + /** + * Returns a copy of this date with the week of weekyear field updated. + *

      + * This field is associated with the "weekyear" via {@link #withWeekyear(int)}. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + *

      + * LocalDate is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * week of weekyear changed. + * + * @param weekOfWeekyear the week of weekyear to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDate withWeekOfWeekyear(int weekOfWeekyear) { + return withLocalMillis(getChronology().weekOfWeekyear().set(getLocalMillis(), weekOfWeekyear)); + } + + /** + * Returns a copy of this date with the day of year field updated. + *

      + * LocalDate is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of year changed. + * + * @param dayOfYear the day of year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDate withDayOfYear(int dayOfYear) { + return withLocalMillis(getChronology().dayOfYear().set(getLocalMillis(), dayOfYear)); + } + + /** + * Returns a copy of this date with the day of month field updated. + *

      + * LocalDate is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of month changed. + * + * @param dayOfMonth the day of month to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDate withDayOfMonth(int dayOfMonth) { + return withLocalMillis(getChronology().dayOfMonth().set(getLocalMillis(), dayOfMonth)); + } + + /** + * Returns a copy of this date with the day of week field updated. + *

      + * LocalDate is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of week changed. + * + * @param dayOfWeek the day of week to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDate withDayOfWeek(int dayOfWeek) { + return withLocalMillis(getChronology().dayOfWeek().set(getLocalMillis(), dayOfWeek)); + } + + //----------------------------------------------------------------------- + /** + * Get the era property which provides access to advanced functionality. + * + * @return the era property + */ + public Property era() { + return new Property(this, getChronology().era()); + } + + /** + * Get the century of era property which provides access to advanced functionality. + * + * @return the year of era property + */ + public Property centuryOfEra() { + return new Property(this, getChronology().centuryOfEra()); + } + + /** + * Get the year of century property which provides access to advanced functionality. + * + * @return the year of era property + */ + public Property yearOfCentury() { + return new Property(this, getChronology().yearOfCentury()); + } + + /** + * Get the year of era property which provides access to advanced functionality. + * + * @return the year of era property + */ + public Property yearOfEra() { + return new Property(this, getChronology().yearOfEra()); + } + + /** + * Get the year property which provides access to advanced functionality. + * + * @return the year property + */ + public Property year() { + return new Property(this, getChronology().year()); + } + + /** + * Get the weekyear property which provides access to advanced functionality. + * + * @return the weekyear property + */ + public Property weekyear() { + return new Property(this, getChronology().weekyear()); + } + + /** + * Get the month of year property which provides access to advanced functionality. + * + * @return the month of year property + */ + public Property monthOfYear() { + return new Property(this, getChronology().monthOfYear()); + } + + /** + * Get the week of a week based year property which provides access to advanced functionality. + * + * @return the week of a week based year property + */ + public Property weekOfWeekyear() { + return new Property(this, getChronology().weekOfWeekyear()); + } + + /** + * Get the day of year property which provides access to advanced functionality. + * + * @return the day of year property + */ + public Property dayOfYear() { + return new Property(this, getChronology().dayOfYear()); + } + + /** + * Get the day of month property which provides access to advanced functionality. + * + * @return the day of month property + */ + public Property dayOfMonth() { + return new Property(this, getChronology().dayOfMonth()); + } + + /** + * Get the day of week property which provides access to advanced functionality. + * + * @return the day of week property + */ + public Property dayOfWeek() { + return new Property(this, getChronology().dayOfWeek()); + } + + //----------------------------------------------------------------------- + /** + * Output the date time in ISO8601 format (yyyy-MM-dd). + * + * @return ISO8601 time formatted string. + */ + @ToString + public String toString() { + return ISODateTimeFormat.date().print(this); + } + + /** + * Output the date using the specified format pattern. + * + * @param pattern the pattern specification, null means use toString + * @see org.joda.time.format.DateTimeFormat + */ + public String toString(String pattern) { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).print(this); + } + + /** + * Output the date using the specified format pattern. + * + * @param pattern the pattern specification, null means use toString + * @param locale Locale to use, null means default + * @see org.joda.time.format.DateTimeFormat + */ + public String toString(String pattern, Locale locale) throws IllegalArgumentException { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this); + } + + //----------------------------------------------------------------------- + /** + * LocalDate.Property binds a LocalDate to a DateTimeField allowing + * powerful datetime functionality to be easily accessed. + *

      + * The simplest use of this class is as an alternative get method, here used to + * get the year '1972' (as an int) and the month 'December' (as a String). + *

      +     * LocalDate dt = new LocalDate(1972, 12, 3, 0, 0);
      +     * int year = dt.year().get();
      +     * String monthStr = dt.month().getAsText();
      +     * 
      + *

      + * Methods are also provided that allow date modification. These return + * new instances of LocalDate - they do not modify the original. The example + * below yields two independent immutable date objects 20 years apart. + *

      +     * LocalDate dt = new LocalDate(1972, 12, 3);
      +     * LocalDate dt1920 = dt.year().setCopy(1920);
      +     * 
      + *

      + * LocalDate.Property itself is thread-safe and immutable, as well as the + * LocalDate being operated on. + * + * @author Stephen Colebourne + * @author Brian S O'Neill + * @since 1.3 + */ + public static final class Property extends AbstractReadableInstantFieldProperty { + + /** Serialization version */ + private static final long serialVersionUID = -3193829732634L; + + /** The instant this property is working against */ + private transient LocalDate iInstant; + /** The field this property is working against */ + private transient DateTimeField iField; + + /** + * Constructor. + * + * @param instant the instant to set + * @param field the field to use + */ + Property(LocalDate instant, DateTimeField field) { + super(); + iInstant = instant; + iField = field; + } + + /** + * Writes the property in a safe serialization format. + */ + private void writeObject(ObjectOutputStream oos) throws IOException { + oos.writeObject(iInstant); + oos.writeObject(iField.getType()); + } + + /** + * Reads the property from a safe serialization format. + */ + private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException { + iInstant = (LocalDate) oos.readObject(); + DateTimeFieldType type = (DateTimeFieldType) oos.readObject(); + iField = type.getField(iInstant.getChronology()); + } + + //----------------------------------------------------------------------- + /** + * Gets the field being used. + * + * @return the field + */ + public DateTimeField getField() { + return iField; + } + + /** + * Gets the milliseconds of the date that this property is linked to. + * + * @return the milliseconds + */ + protected long getMillis() { + return iInstant.getLocalMillis(); + } + + /** + * Gets the chronology of the datetime that this property is linked to. + * + * @return the chronology + * @since 1.4 + */ + protected Chronology getChronology() { + return iInstant.getChronology(); + } + + /** + * Gets the LocalDate object linked to this property. + * + * @return the linked LocalDate + */ + public LocalDate getLocalDate() { + return iInstant; + } + + //----------------------------------------------------------------------- + /** + * Adds to this field in a copy of this LocalDate. + *

      + * The LocalDate attached to this property is unchanged by this call. + * + * @param value the value to add to the field in the copy + * @return a copy of the LocalDate with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public LocalDate addToCopy(int value) { + return iInstant.withLocalMillis(iField.add(iInstant.getLocalMillis(), value)); + } + + /** + * Adds to this field, possibly wrapped, in a copy of this LocalDate. + * A field wrapped operation only changes this field. + * Thus 31st January addWrapField one day goes to the 1st January. + *

      + * The LocalDate attached to this property is unchanged by this call. + * + * @param value the value to add to the field in the copy + * @return a copy of the LocalDate with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public LocalDate addWrapFieldToCopy(int value) { + return iInstant.withLocalMillis(iField.addWrapField(iInstant.getLocalMillis(), value)); + } + + //----------------------------------------------------------------------- + /** + * Sets this field in a copy of the LocalDate. + *

      + * The LocalDate attached to this property is unchanged by this call. + * + * @param value the value to set the field in the copy to + * @return a copy of the LocalDate with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public LocalDate setCopy(int value) { + return iInstant.withLocalMillis(iField.set(iInstant.getLocalMillis(), value)); + } + + /** + * Sets this field in a copy of the LocalDate to a parsed text value. + *

      + * The LocalDate attached to this property is unchanged by this call. + * + * @param text the text value to set + * @param locale optional locale to use for selecting a text symbol + * @return a copy of the LocalDate with the field value changed + * @throws IllegalArgumentException if the text value isn't valid + */ + public LocalDate setCopy(String text, Locale locale) { + return iInstant.withLocalMillis(iField.set(iInstant.getLocalMillis(), text, locale)); + } + + /** + * Sets this field in a copy of the LocalDate to a parsed text value. + *

      + * The LocalDate attached to this property is unchanged by this call. + * + * @param text the text value to set + * @return a copy of the LocalDate with the field value changed + * @throws IllegalArgumentException if the text value isn't valid + */ + public LocalDate setCopy(String text) { + return setCopy(text, null); + } + + //----------------------------------------------------------------------- + /** + * Returns a new LocalDate with this field set to the maximum value + * for this field. + *

      + * This operation is useful for obtaining a LocalDate on the last day + * of the month, as month lengths vary. + *

      +         * LocalDate lastDayOfMonth = dt.dayOfMonth().withMaximumValue();
      +         * 
      + *

      + * The LocalDate attached to this property is unchanged by this call. + * + * @return a copy of the LocalDate with this field set to its maximum + */ + public LocalDate withMaximumValue() { + return setCopy(getMaximumValue()); + } + + /** + * Returns a new LocalDate with this field set to the minimum value + * for this field. + *

      + * The LocalDate attached to this property is unchanged by this call. + * + * @return a copy of the LocalDate with this field set to its minimum + */ + public LocalDate withMinimumValue() { + return setCopy(getMinimumValue()); + } + + //----------------------------------------------------------------------- + /** + * Rounds to the lowest whole unit of this field on a copy of this + * LocalDate. + *

      + * For example, rounding floor on the hourOfDay field of a LocalDate + * where the time is 10:30 would result in new LocalDate with the + * time of 10:00. + * + * @return a copy of the LocalDate with the field value changed + */ + public LocalDate roundFloorCopy() { + return iInstant.withLocalMillis(iField.roundFloor(iInstant.getLocalMillis())); + } + + /** + * Rounds to the highest whole unit of this field on a copy of this + * LocalDate. + *

      + * For example, rounding floor on the hourOfDay field of a LocalDate + * where the time is 10:30 would result in new LocalDate with the + * time of 11:00. + * + * @return a copy of the LocalDate with the field value changed + */ + public LocalDate roundCeilingCopy() { + return iInstant.withLocalMillis(iField.roundCeiling(iInstant.getLocalMillis())); + } + + /** + * Rounds to the nearest whole unit of this field on a copy of this + * LocalDate, favoring the floor if halfway. + * + * @return a copy of the LocalDate with the field value changed + */ + public LocalDate roundHalfFloorCopy() { + return iInstant.withLocalMillis(iField.roundHalfFloor(iInstant.getLocalMillis())); + } + + /** + * Rounds to the nearest whole unit of this field on a copy of this + * LocalDate, favoring the ceiling if halfway. + * + * @return a copy of the LocalDate with the field value changed + */ + public LocalDate roundHalfCeilingCopy() { + return iInstant.withLocalMillis(iField.roundHalfCeiling(iInstant.getLocalMillis())); + } + + /** + * Rounds to the nearest whole unit of this field on a copy of this + * LocalDate. If halfway, the ceiling is favored over the floor + * only if it makes this field's value even. + * + * @return a copy of the LocalDate with the field value changed + */ + public LocalDate roundHalfEvenCopy() { + return iInstant.withLocalMillis(iField.roundHalfEven(iInstant.getLocalMillis())); + } + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/LocalDateTime.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/LocalDateTime.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/LocalDateTime.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,2324 @@ +/* + * Copyright 2001-2011 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; +import org.joda.time.base.BaseLocal; +import org.joda.time.chrono.ISOChronology; +import org.joda.time.convert.ConverterManager; +import org.joda.time.convert.PartialConverter; +import org.joda.time.field.AbstractReadableInstantFieldProperty; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; + +/** + * LocalDateTime is an unmodifiable datetime class representing a + * datetime without a time zone. + *

      + * LocalDateTime implements the {@link ReadablePartial} interface. + * To do this, certain methods focus on key fields Year, MonthOfYear, + * DayOfYear and MillisOfDay. + * However, all fields may in fact be queried. + *

      + * Internally, LocalDateTime uses a single millisecond-based value to + * represent the local datetime. This value is only used internally and + * is not exposed to applications. + *

      + * Calculations on LocalDateTime are performed using a {@link Chronology}. + * This chronology will be set internally to be in the UTC time zone + * for all calculations. + * + *

      Each individual field can be queried in two ways: + *

        + *
      • getHourOfDay() + *
      • hourOfDay().get() + *
      + * The second technique also provides access to other useful methods on the + * field: + *
        + *
      • numeric value + *
      • text value + *
      • short text value + *
      • maximum/minimum values + *
      • add/subtract + *
      • set + *
      • rounding + *
      + * + *

      + * LocalDateTime is thread-safe and immutable, provided that the Chronology is as well. + * All standard Chronology classes supplied are thread-safe and immutable. + * + * @author Stephen Colebourne + * @since 1.3 + */ +public final class LocalDateTime + extends BaseLocal + implements ReadablePartial, Serializable { + + /** Serialization lock */ + private static final long serialVersionUID = -268716875315837168L; + + /** The index of the year field in the field array */ + private static final int YEAR = 0; + /** The index of the monthOfYear field in the field array */ + private static final int MONTH_OF_YEAR = 1; + /** The index of the dayOfMonth field in the field array */ + private static final int DAY_OF_MONTH = 2; + /** The index of the millis field in the field array */ + private static final int MILLIS_OF_DAY = 3; + + /** The local millis from 1970-01-01T00:00:00 */ + private final long iLocalMillis; + /** The chronology to use in UTC */ + private final Chronology iChronology; + + //----------------------------------------------------------------------- + /** + * Obtains a {@code LocalDateTime} set to the current system millisecond time + * using ISOChronology in the default time zone. + * The resulting object does not use the zone. + * + * @return the current date, not null + * @since 2.0 + */ + public static LocalDateTime now() { + return new LocalDateTime(); + } + + /** + * Obtains a {@code LocalDateTime} set to the current system millisecond time + * using ISOChronology in the specified time zone. + * The resulting object does not use the zone. + * + * @param zone the time zone, not null + * @return the current date, not null + * @since 2.0 + */ + public static LocalDateTime now(DateTimeZone zone) { + if (zone == null) { + throw new NullPointerException("Zone must not be null"); + } + return new LocalDateTime(zone); + } + + /** + * Obtains a {@code LocalDateTime} set to the current system millisecond time + * using the specified chronology. + * The resulting object does not use the zone. + * + * @param chronology the chronology, not null + * @return the current date, not null + * @since 2.0 + */ + public static LocalDateTime now(Chronology chronology) { + if (chronology == null) { + throw new NullPointerException("Chronology must not be null"); + } + return new LocalDateTime(chronology); + } + + //----------------------------------------------------------------------- + /** + * Parses a {@code LocalDateTime} from the specified string. + *

      + * This uses {@link ISODateTimeFormat#localDateOptionalTimeParser()}. + * + * @param str the string to parse, not null + * @since 2.0 + */ + @FromString + public static LocalDateTime parse(String str) { + return parse(str, ISODateTimeFormat.localDateOptionalTimeParser()); + } + + /** + * Parses a {@code LocalDateTime} from the specified string using a formatter. + * + * @param str the string to parse, not null + * @param formatter the formatter to use, not null + * @since 2.0 + */ + public static LocalDateTime parse(String str, DateTimeFormatter formatter) { + return formatter.parseLocalDateTime(str); + } + + //----------------------------------------------------------------------- + /** + * Constructs a LocalDateTime from a java.util.Calendar + * using exactly the same field values. + *

      + * Each field is queried from the Calendar and assigned to the LocalDateTime. + * This is useful if you have been using the Calendar as a local date, + * ignoring the zone. + *

      + * One advantage of this method is that this method is unaffected if the + * version of the time zone data differs between the JDK and Joda-Time. + * That is because the local field values are transferred, calculated using + * the JDK time zone data and without using the Joda-Time time zone data. + *

      + * This factory method ignores the type of the calendar and always + * creates a LocalDateTime with ISO chronology. It is expected that you + * will only pass in instances of GregorianCalendar however + * this is not validated. + * + * @param calendar the Calendar to extract fields from + * @return the created LocalDateTime + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the date is invalid for the ISO chronology + */ + public static LocalDateTime fromCalendarFields(Calendar calendar) { + if (calendar == null) { + throw new IllegalArgumentException("The calendar must not be null"); + } + return new LocalDateTime( + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH) + 1, + calendar.get(Calendar.DAY_OF_MONTH), + calendar.get(Calendar.HOUR_OF_DAY), + calendar.get(Calendar.MINUTE), + calendar.get(Calendar.SECOND), + calendar.get(Calendar.MILLISECOND) + ); + } + + /** + * Constructs a LocalDateTime from a java.util.Date + * using exactly the same field values. + *

      + * Each field is queried from the Date and assigned to the LocalDateTime. + * This is useful if you have been using the Date as a local date, + * ignoring the zone. + *

      + * One advantage of this method is that this method is unaffected if the + * version of the time zone data differs between the JDK and Joda-Time. + * That is because the local field values are transferred, calculated using + * the JDK time zone data and without using the Joda-Time time zone data. + *

      + * This factory method always creates a LocalDateTime with ISO chronology. + * + * @param date the Date to extract fields from + * @return the created LocalDateTime + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the date is invalid for the ISO chronology + */ + @SuppressWarnings("deprecation") + public static LocalDateTime fromDateFields(Date date) { + if (date == null) { + throw new IllegalArgumentException("The date must not be null"); + } + return new LocalDateTime( + date.getYear() + 1900, + date.getMonth() + 1, + date.getDate(), + date.getHours(), + date.getMinutes(), + date.getSeconds(), + (int) (date.getTime() % 1000) + ); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance set to the current local time evaluated using + * ISO chronology in the default zone. + *

      + * Once the constructor is completed, the zone is no longer used. + * + * @see #now() + */ + public LocalDateTime() { + this(DateTimeUtils.currentTimeMillis(), ISOChronology.getInstance()); + } + + /** + * Constructs an instance set to the current local time evaluated using + * ISO chronology in the specified zone. + *

      + * If the specified time zone is null, the default zone is used. + * Once the constructor is completed, the zone is no longer used. + * + * @param zone the time zone, null means default zone + * @see #now(DateTimeZone) + */ + public LocalDateTime(DateTimeZone zone) { + this(DateTimeUtils.currentTimeMillis(), ISOChronology.getInstance(zone)); + } + + /** + * Constructs an instance set to the current local time evaluated using + * specified chronology. + *

      + * If the chronology is null, ISO chronology in the default time zone is used. + * Once the constructor is completed, the zone is no longer used. + * + * @param chronology the chronology, null means ISOChronology in default zone + * @see #now(Chronology) + */ + public LocalDateTime(Chronology chronology) { + this(DateTimeUtils.currentTimeMillis(), chronology); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance set to the local time defined by the specified + * instant evaluated using ISO chronology in the default zone. + *

      + * Once the constructor is completed, the zone is no longer used. + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z + */ + public LocalDateTime(long instant) { + this(instant, ISOChronology.getInstance()); + } + + /** + * Constructs an instance set to the local time defined by the specified + * instant evaluated using ISO chronology in the specified zone. + *

      + * If the specified time zone is null, the default zone is used. + * Once the constructor is completed, the zone is no longer used. + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z + * @param zone the time zone, null means default zone + */ + public LocalDateTime(long instant, DateTimeZone zone) { + this(instant, ISOChronology.getInstance(zone)); + } + + /** + * Constructs an instance set to the local time defined by the specified + * instant evaluated using the specified chronology. + *

      + * If the chronology is null, ISO chronology in the default zone is used. + * Once the constructor is completed, the zone is no longer used. + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z + * @param chronology the chronology, null means ISOChronology in default zone + */ + public LocalDateTime(long instant, Chronology chronology) { + chronology = DateTimeUtils.getChronology(chronology); + + long localMillis = chronology.getZone().getMillisKeepLocal(DateTimeZone.UTC, instant); + iLocalMillis = localMillis; + iChronology = chronology.withUTC(); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance from an Object that represents a datetime. + *

      + * If the object contains no chronology, ISOChronology is used. + * If the object contains no time zone, the default zone is used. + * Once the constructor is completed, the zone is no longer used. + *

      + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePartial, ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#localDateOptionalTimeParser()}. + * The default String converter ignores the zone and only parses the field values. + * + * @param instant the datetime object + * @throws IllegalArgumentException if the instant is invalid + */ + public LocalDateTime(Object instant) { + this(instant, (Chronology) null); + } + + /** + * Constructs an instance from an Object that represents a datetime, + * forcing the time zone to that specified. + *

      + * If the object contains no chronology, ISOChronology is used. + * If the specified time zone is null, the default zone is used. + * Once the constructor is completed, the zone is no longer used. + *

      + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePartial, ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#localDateOptionalTimeParser()}. + * The default String converter ignores the zone and only parses the field values. + * + * @param instant the datetime object + * @param zone the time zone + * @throws IllegalArgumentException if the instant is invalid + */ + public LocalDateTime(Object instant, DateTimeZone zone) { + PartialConverter converter = ConverterManager.getInstance().getPartialConverter(instant); + Chronology chronology = converter.getChronology(instant, zone); + chronology = DateTimeUtils.getChronology(chronology); + iChronology = chronology.withUTC(); + int[] values = converter.getPartialValues(this, instant, chronology, ISODateTimeFormat.localDateOptionalTimeParser()); + iLocalMillis = iChronology.getDateTimeMillis(values[0], values[1], values[2], values[3]); + } + + /** + * Constructs an instance from an Object that represents a datetime, + * using the specified chronology. + *

      + * If the chronology is null, ISO in the default time zone is used. + * Once the constructor is completed, the zone is no longer used. + *

      + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePartial, ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#localDateOptionalTimeParser()}. + * The default String converter ignores the zone and only parses the field values. + * + * @param instant the datetime object + * @param chronology the chronology + * @throws IllegalArgumentException if the instant is invalid + */ + public LocalDateTime(Object instant, Chronology chronology) { + PartialConverter converter = ConverterManager.getInstance().getPartialConverter(instant); + chronology = converter.getChronology(instant, chronology); + chronology = DateTimeUtils.getChronology(chronology); + iChronology = chronology.withUTC(); + int[] values = converter.getPartialValues(this, instant, chronology, ISODateTimeFormat.localDateOptionalTimeParser()); + iLocalMillis = iChronology.getDateTimeMillis(values[0], values[1], values[2], values[3]); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance set to the specified date and time + * using ISOChronology. + * + * @param year the year + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + */ + public LocalDateTime( + int year, + int monthOfYear, + int dayOfMonth, + int hourOfDay, + int minuteOfHour) { + this(year, monthOfYear, dayOfMonth, hourOfDay, + minuteOfHour, 0, 0, ISOChronology.getInstanceUTC()); + } + + /** + * Constructs an instance set to the specified date and time + * using ISOChronology. + * + * @param year the year + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + * @param secondOfMinute the second of the minute + */ + public LocalDateTime( + int year, + int monthOfYear, + int dayOfMonth, + int hourOfDay, + int minuteOfHour, + int secondOfMinute) { + this(year, monthOfYear, dayOfMonth, hourOfDay, + minuteOfHour, secondOfMinute, 0, ISOChronology.getInstanceUTC()); + } + + /** + * Constructs an instance set to the specified date and time + * using ISOChronology. + * + * @param year the year + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + * @param secondOfMinute the second of the minute + * @param millisOfSecond the millisecond of the second + */ + public LocalDateTime( + int year, + int monthOfYear, + int dayOfMonth, + int hourOfDay, + int minuteOfHour, + int secondOfMinute, + int millisOfSecond) { + this(year, monthOfYear, dayOfMonth, hourOfDay, + minuteOfHour, secondOfMinute, millisOfSecond, ISOChronology.getInstanceUTC()); + } + + /** + * Constructs an instance set to the specified date and time + * using the specified chronology, whose zone is ignored. + *

      + * If the chronology is null, ISOChronology is used. + * + * @param year the year + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + * @param secondOfMinute the second of the minute + * @param millisOfSecond the millisecond of the second + * @param chronology the chronology, null means ISOChronology in default zone + */ + public LocalDateTime( + int year, + int monthOfYear, + int dayOfMonth, + int hourOfDay, + int minuteOfHour, + int secondOfMinute, + int millisOfSecond, + Chronology chronology) { + super(); + chronology = DateTimeUtils.getChronology(chronology).withUTC(); + long instant = chronology.getDateTimeMillis(year, monthOfYear, dayOfMonth, + hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond); + iChronology = chronology; + iLocalMillis = instant; + } + + /** + * Handle broken serialization from other tools. + * @return the resolved object, not null + */ + private Object readResolve() { + if (iChronology == null) { + return new LocalDateTime(iLocalMillis, ISOChronology.getInstanceUTC()); + } + if (DateTimeZone.UTC.equals(iChronology.getZone()) == false) { + return new LocalDateTime(iLocalMillis, iChronology.withUTC()); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets the number of fields in this partial, which is four. + * The supported fields are Year, MonthOfDay, DayOfMonth and MillisOfDay. + * + * @return the field count, four + */ + public int size() { + return 4; + } + + /** + * Gets the field for a specific index in the chronology specified. + *

      + * This method must not use any instance variables. + * + * @param index the index to retrieve + * @param chrono the chronology to use + * @return the field + */ + protected DateTimeField getField(int index, Chronology chrono) { + switch (index) { + case YEAR: + return chrono.year(); + case MONTH_OF_YEAR: + return chrono.monthOfYear(); + case DAY_OF_MONTH: + return chrono.dayOfMonth(); + case MILLIS_OF_DAY: + return chrono.millisOfDay(); + default: + throw new IndexOutOfBoundsException("Invalid index: " + index); + } + } + + /** + * Gets the value of the field at the specifed index. + *

      + * This method is required to support the ReadablePartial + * interface. The supported fields are Year, MonthOfDay, DayOfMonth and MillisOfDay. + * + * @param index the index, zero to two + * @return the value + * @throws IndexOutOfBoundsException if the index is invalid + */ + public int getValue(int index) { + switch (index) { + case YEAR: + return getChronology().year().get(getLocalMillis()); + case MONTH_OF_YEAR: + return getChronology().monthOfYear().get(getLocalMillis()); + case DAY_OF_MONTH: + return getChronology().dayOfMonth().get(getLocalMillis()); + case MILLIS_OF_DAY: + return getChronology().millisOfDay().get(getLocalMillis()); + default: + throw new IndexOutOfBoundsException("Invalid index: " + index); + } + } + + //----------------------------------------------------------------------- + /** + * Get the value of one of the fields of a datetime. + *

      + * This method gets the value of the specified field. + * For example: + *

      +     * DateTime dt = new DateTime();
      +     * int year = dt.get(DateTimeFieldType.year());
      +     * 
      + * + * @param type a field type, usually obtained from DateTimeFieldType, not null + * @return the value of that field + * @throws IllegalArgumentException if the field type is null + */ + public int get(DateTimeFieldType type) { + if (type == null) { + throw new IllegalArgumentException("The DateTimeFieldType must not be null"); + } + return type.getField(getChronology()).get(getLocalMillis()); + } + + /** + * Checks if the field type specified is supported by this + * local datetime and chronology. + * This can be used to avoid exceptions in {@link #get(DateTimeFieldType)}. + * + * @param type a field type, usually obtained from DateTimeFieldType + * @return true if the field type is supported + */ + public boolean isSupported(DateTimeFieldType type) { + if (type == null) { + return false; + } + return type.getField(getChronology()).isSupported(); + } + + /** + * Checks if the duration type specified is supported by this + * local datetime and chronology. + * + * @param type a duration type, usually obtained from DurationFieldType + * @return true if the field type is supported + */ + public boolean isSupported(DurationFieldType type) { + if (type == null) { + return false; + } + return type.getField(getChronology()).isSupported(); + } + + //----------------------------------------------------------------------- + /** + * Gets the milliseconds of the datetime instant from the Java epoch + * of 1970-01-01T00:00:00 (not fixed to any specific time zone). + * + * @return the number of milliseconds since 1970-01-01T00:00:00 + * @since 1.5 (previously private) + */ + protected long getLocalMillis() { + return iLocalMillis; + } + + /** + * Gets the chronology of the datetime. + * + * @return the Chronology that the datetime is using + */ + public Chronology getChronology() { + return iChronology; + } + + //----------------------------------------------------------------------- + /** + * Compares this ReadablePartial with another returning true if the chronology, + * field types and values are equal. + * + * @param partial an object to check against + * @return true if fields and values are equal + */ + public boolean equals(Object partial) { + // override to perform faster + if (this == partial) { + return true; + } + if (partial instanceof LocalDateTime) { + LocalDateTime other = (LocalDateTime) partial; + if (iChronology.equals(other.iChronology)) { + return iLocalMillis == other.iLocalMillis; + } + } + return super.equals(partial); + } + + /** + * Compares this partial with another returning an integer + * indicating the order. + *

      + * The fields are compared in order, from largest to smallest. + * The first field that is non-equal is used to determine the result. + *

      + * The specified object must be a partial instance whose field types + * match those of this partial. + * + * @param partial an object to check against + * @return negative if this is less, zero if equal, positive if greater + * @throws ClassCastException if the partial is the wrong class + * or if it has field types that don't match + * @throws NullPointerException if the partial is null + */ + public int compareTo(ReadablePartial partial) { + // override to perform faster + if (this == partial) { + return 0; + } + if (partial instanceof LocalDateTime) { + LocalDateTime other = (LocalDateTime) partial; + if (iChronology.equals(other.iChronology)) { + return (iLocalMillis < other.iLocalMillis ? -1 : + (iLocalMillis == other.iLocalMillis ? 0 : 1)); + + } + } + return super.compareTo(partial); + } + + //----------------------------------------------------------------------- + /** + * Converts this object to a DateTime using the default zone. + *

      + * This method will throw an exception if the datetime that would be + * created does not exist when the time zone is taken into account. + * + * @return this + */ + public DateTime toDateTime() { + return toDateTime((DateTimeZone) null); + } + + /** + * Converts this object to a DateTime using the specified zone. + *

      + * This method will throw an exception if the datetime that would be + * created does not exist when the time zone is taken into account. + * + * @param zone time zone to apply, or default if null + * @return a DateTime using the same millis + */ + public DateTime toDateTime(DateTimeZone zone) { + zone = DateTimeUtils.getZone(zone); + Chronology chrono = iChronology.withZone(zone); + return new DateTime( + getYear(), getMonthOfYear(), getDayOfMonth(), + getHourOfDay(), getMinuteOfHour(), + getSecondOfMinute(), getMillisOfSecond(), chrono); + } + + //----------------------------------------------------------------------- + /** + * Converts this object to a LocalDate with the same date and chronology. + * + * @return a LocalDate with the same date and chronology + */ + public LocalDate toLocalDate() { + return new LocalDate(getLocalMillis(), getChronology()); + } + + /** + * Converts this object to a LocalTime with the same time and chronology. + * + * @return a LocalTime with the same time and chronology + */ + public LocalTime toLocalTime() { + return new LocalTime(getLocalMillis(), getChronology()); + } + + //----------------------------------------------------------------------- + /** + * Get the date time as a java.util.Date. + *

      + * The Date object created has exactly the same fields as this + * date-time, except when the time would be invalid due to a daylight savings + * gap. In that case, the time will be set to the earliest valid time after the gap. + *

      + * In the case of a daylight savings overlap, the earlier instant is selected. + *

      + * Converting to a JDK Date is full of complications as the JDK Date constructor + * doesn't behave as you might expect around DST transitions. This method works + * by taking a first guess and then adjusting. This also handles the situation + * where the JDK time zone data differs from the Joda-Time time zone data. + * + * @return a Date initialised with this date-time, never null + * @since 2.0 + */ + @SuppressWarnings("deprecation") + public Date toDate() { + int dom = getDayOfMonth(); + Date date = new Date(getYear() - 1900, getMonthOfYear() - 1, dom, + getHourOfDay(), getMinuteOfHour(), getSecondOfMinute()); + date.setTime(date.getTime() + getMillisOfSecond()); + LocalDateTime check = LocalDateTime.fromDateFields(date); + if (check.isBefore(this)) { + // DST gap + // move forward in units of one minute until equal/after + while (check.isBefore(this)) { + date.setTime(date.getTime() + 60000); + check = LocalDateTime.fromDateFields(date); + } + // move back in units of one second until date wrong + while (check.isBefore(this) == false) { + date.setTime(date.getTime() - 1000); + check = LocalDateTime.fromDateFields(date); + } + date.setTime(date.getTime() + 1000); + } else if (check.equals(this)) { + // check for DST overlap + Date earlier = new Date(date.getTime() - TimeZone.getDefault().getDSTSavings()); + check = LocalDateTime.fromDateFields(earlier); + if (check.equals(this)) { + date = earlier; + } + } + return date; + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime with different local millis. + *

      + * The returned object will be a new instance of the same type. + * Only the millis will change, the chronology is kept. + * The returned object will be either be a new instance or this. + * + * @param newMillis the new millis, from 1970-01-01T00:00:00 + * @return a copy of this datetime with different millis + */ + LocalDateTime withLocalMillis(long newMillis) { + return (newMillis == getLocalMillis() ? this : new LocalDateTime(newMillis, getChronology())); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime with the specified date, + * retaining the time fields. + *

      + * If the date is already the date passed in, then this is returned. + *

      + * To set a single field use the properties, for example: + *

      +     * DateTime set = dt.monthOfYear().setCopy(6);
      +     * 
      + * + * @param year the new year value + * @param monthOfYear the new monthOfYear value + * @param dayOfMonth the new dayOfMonth value + * @return a copy of this datetime with a different date + * @throws IllegalArgumentException if any value if invalid + */ + public LocalDateTime withDate(int year, int monthOfYear, int dayOfMonth) { + Chronology chrono = getChronology(); + long instant = getLocalMillis(); + instant = chrono.year().set(instant, year); + instant = chrono.monthOfYear().set(instant, monthOfYear); + instant = chrono.dayOfMonth().set(instant, dayOfMonth); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime with the specified time, + * retaining the date fields. + *

      + * If the time is already the time passed in, then this is returned. + *

      + * To set a single field use the properties, for example: + *

      +     * LocalDateTime set = dt.hourOfDay().setCopy(6);
      +     * 
      + * + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + * @param secondOfMinute the second of the minute + * @param millisOfSecond the millisecond of the second + * @return a copy of this datetime with a different time + * @throws IllegalArgumentException if any value if invalid + */ + public LocalDateTime withTime(int hourOfDay, int minuteOfHour, int secondOfMinute, int millisOfSecond) { + Chronology chrono = getChronology(); + long instant = getLocalMillis(); + instant = chrono.hourOfDay().set(instant, hourOfDay); + instant = chrono.minuteOfHour().set(instant, minuteOfHour); + instant = chrono.secondOfMinute().set(instant, secondOfMinute); + instant = chrono.millisOfSecond().set(instant, millisOfSecond); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime with the partial set of fields + * replacing those from this instance. + *

      + * For example, if the partial is a TimeOfDay then the time fields + * would be changed in the returned instance. + * If the partial is null, then this is returned. + * + * @param partial the partial set of fields to apply to this datetime, null ignored + * @return a copy of this datetime with a different set of fields + * @throws IllegalArgumentException if any value is invalid + */ + public LocalDateTime withFields(ReadablePartial partial) { + if (partial == null) { + return this; + } + return withLocalMillis(getChronology().set(partial, getLocalMillis())); + } + + /** + * Returns a copy of this datetime with the specified field set to a new value. + *

      + * For example, if the field type is hourOfDay then the hour of day + * field would be changed in the returned instance. + * If the field type is null, then this is returned. + *

      + * These three lines are equivalent: + *

      +     * LocalDateTime updated = dt.withField(DateTimeFieldType.dayOfMonth(), 6);
      +     * LocalDateTime updated = dt.dayOfMonth().setCopy(6);
      +     * LocalDateTime updated = dt.property(DateTimeFieldType.dayOfMonth()).setCopy(6);
      +     * 
      + * + * @param fieldType the field type to set, not null + * @param value the value to set + * @return a copy of this datetime with the field set + * @throws IllegalArgumentException if the value is null or invalid + */ + public LocalDateTime withField(DateTimeFieldType fieldType, int value) { + if (fieldType == null) { + throw new IllegalArgumentException("Field must not be null"); + } + long instant = fieldType.getField(getChronology()).set(getLocalMillis(), value); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime with the value of the specified + * field increased. + *

      + * If the addition is zero or the field is null, then this is returned. + *

      + * These three lines are equivalent: + *

      +     * LocalDateTime added = dt.withFieldAdded(DurationFieldType.years(), 6);
      +     * LocalDateTime added = dt.plusYears(6);
      +     * LocalDateTime added = dt.plus(Period.years(6));
      +     * 
      + * + * @param fieldType the field type to add to, not null + * @param amount the amount to add + * @return a copy of this datetime with the field updated + * @throws IllegalArgumentException if the value is null or invalid + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalDateTime withFieldAdded(DurationFieldType fieldType, int amount) { + if (fieldType == null) { + throw new IllegalArgumentException("Field must not be null"); + } + if (amount == 0) { + return this; + } + long instant = fieldType.getField(getChronology()).add(getLocalMillis(), amount); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime with the specified duration added. + *

      + * If the addition is zero, then this is returned. + * + * @param durationToAdd the duration to add to this one, null means zero + * @param scalar the amount of times to add, such as -1 to subtract once + * @return a copy of this datetime with the duration added + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalDateTime withDurationAdded(ReadableDuration durationToAdd, int scalar) { + if (durationToAdd == null || scalar == 0) { + return this; + } + long instant = getChronology().add(getLocalMillis(), durationToAdd.getMillis(), scalar); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime with the specified period added. + *

      + * If the addition is zero, then this is returned. + *

      + * This method is typically used to add multiple copies of complex + * period instances. Adding one field is best achieved using methods + * like {@link #withFieldAdded(DurationFieldType, int)} + * or {@link #plusYears(int)}. + * + * @param period the period to add to this one, null means zero + * @param scalar the amount of times to add, such as -1 to subtract once + * @return a copy of this datetime with the period added + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalDateTime withPeriodAdded(ReadablePeriod period, int scalar) { + if (period == null || scalar == 0) { + return this; + } + long instant = getChronology().add(period, getLocalMillis(), scalar); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime with the specified duration added. + *

      + * If the amount is zero or null, then this is returned. + * + * @param duration the duration to add to this one, null means zero + * @return a copy of this datetime with the duration added + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalDateTime plus(ReadableDuration duration) { + return withDurationAdded(duration, 1); + } + + /** + * Returns a copy of this datetime with the specified period added. + *

      + * If the amount is zero or null, then this is returned. + *

      + * This method is typically used to add complex period instances. + * Adding one field is best achieved using methods + * like {@link #plusYears(int)}. + * + * @param period the period to add to this one, null means zero + * @return a copy of this datetime with the period added + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalDateTime plus(ReadablePeriod period) { + return withPeriodAdded(period, 1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime plus the specified number of years. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime added = dt.plusYears(6);
      +     * LocalDateTime added = dt.plus(Period.years(6));
      +     * LocalDateTime added = dt.withFieldAdded(DurationFieldType.years(), 6);
      +     * 
      + * + * @param years the amount of years to add, may be negative + * @return the new LocalDateTime plus the increased years + */ + public LocalDateTime plusYears(int years) { + if (years == 0) { + return this; + } + long instant = getChronology().years().add(getLocalMillis(), years); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime plus the specified number of months. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime added = dt.plusMonths(6);
      +     * LocalDateTime added = dt.plus(Period.months(6));
      +     * LocalDateTime added = dt.withFieldAdded(DurationFieldType.months(), 6);
      +     * 
      + * + * @param months the amount of months to add, may be negative + * @return the new LocalDateTime plus the increased months + */ + public LocalDateTime plusMonths(int months) { + if (months == 0) { + return this; + } + long instant = getChronology().months().add(getLocalMillis(), months); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime plus the specified number of weeks. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime added = dt.plusWeeks(6);
      +     * LocalDateTime added = dt.plus(Period.weeks(6));
      +     * LocalDateTime added = dt.withFieldAdded(DurationFieldType.weeks(), 6);
      +     * 
      + * + * @param weeks the amount of weeks to add, may be negative + * @return the new LocalDateTime plus the increased weeks + */ + public LocalDateTime plusWeeks(int weeks) { + if (weeks == 0) { + return this; + } + long instant = getChronology().weeks().add(getLocalMillis(), weeks); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime plus the specified number of days. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime added = dt.plusDays(6);
      +     * LocalDateTime added = dt.plus(Period.days(6));
      +     * LocalDateTime added = dt.withFieldAdded(DurationFieldType.days(), 6);
      +     * 
      + * + * @param days the amount of days to add, may be negative + * @return the new LocalDateTime plus the increased days + */ + public LocalDateTime plusDays(int days) { + if (days == 0) { + return this; + } + long instant = getChronology().days().add(getLocalMillis(), days); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime plus the specified number of hours. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime added = dt.plusHours(6);
      +     * LocalDateTime added = dt.plus(Period.hours(6));
      +     * LocalDateTime added = dt.withFieldAdded(DurationFieldType.hours(), 6);
      +     * 
      + * + * @param hours the amount of hours to add, may be negative + * @return the new LocalDateTime plus the increased hours + */ + public LocalDateTime plusHours(int hours) { + if (hours == 0) { + return this; + } + long instant = getChronology().hours().add(getLocalMillis(), hours); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime plus the specified number of minutes. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime added = dt.plusMinutes(6);
      +     * LocalDateTime added = dt.plus(Period.minutes(6));
      +     * LocalDateTime added = dt.withFieldAdded(DurationFieldType.minutes(), 6);
      +     * 
      + * + * @param minutes the amount of minutes to add, may be negative + * @return the new LocalDateTime plus the increased minutes + */ + public LocalDateTime plusMinutes(int minutes) { + if (minutes == 0) { + return this; + } + long instant = getChronology().minutes().add(getLocalMillis(), minutes); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime plus the specified number of seconds. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime added = dt.plusSeconds(6);
      +     * LocalDateTime added = dt.plus(Period.seconds(6));
      +     * LocalDateTime added = dt.withFieldAdded(DurationFieldType.seconds(), 6);
      +     * 
      + * + * @param seconds the amount of seconds to add, may be negative + * @return the new LocalDateTime plus the increased seconds + */ + public LocalDateTime plusSeconds(int seconds) { + if (seconds == 0) { + return this; + } + long instant = getChronology().seconds().add(getLocalMillis(), seconds); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime plus the specified number of millis. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime added = dt.plusMillis(6);
      +     * LocalDateTime added = dt.plus(Period.millis(6));
      +     * LocalDateTime added = dt.withFieldAdded(DurationFieldType.millis(), 6);
      +     * 
      + * + * @param millis the amount of millis to add, may be negative + * @return the new LocalDateTime plus the increased millis + */ + public LocalDateTime plusMillis(int millis) { + if (millis == 0) { + return this; + } + long instant = getChronology().millis().add(getLocalMillis(), millis); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime with the specified duration taken away. + *

      + * If the amount is zero or null, then this is returned. + * + * @param duration the duration to reduce this instant by + * @return a copy of this datetime with the duration taken away + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalDateTime minus(ReadableDuration duration) { + return withDurationAdded(duration, -1); + } + + /** + * Returns a copy of this datetime with the specified period taken away. + *

      + * If the amount is zero or null, then this is returned. + *

      + * This method is typically used to subtract complex period instances. + * Subtracting one field is best achieved using methods + * like {@link #minusYears(int)}. + * + * @param period the period to reduce this instant by + * @return a copy of this datetime with the period taken away + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalDateTime minus(ReadablePeriod period) { + return withPeriodAdded(period, -1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime minus the specified number of years. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime subtracted = dt.minusYears(6);
      +     * LocalDateTime subtracted = dt.minus(Period.years(6));
      +     * LocalDateTime subtracted = dt.withFieldAdded(DurationFieldType.years(), -6);
      +     * 
      + * + * @param years the amount of years to subtract, may be negative + * @return the new LocalDateTime minus the increased years + */ + public LocalDateTime minusYears(int years) { + if (years == 0) { + return this; + } + long instant = getChronology().years().subtract(getLocalMillis(), years); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime minus the specified number of months. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime subtracted = dt.minusMonths(6);
      +     * LocalDateTime subtracted = dt.minus(Period.months(6));
      +     * LocalDateTime subtracted = dt.withFieldAdded(DurationFieldType.months(), -6);
      +     * 
      + * + * @param months the amount of months to subtract, may be negative + * @return the new LocalDateTime minus the increased months + */ + public LocalDateTime minusMonths(int months) { + if (months == 0) { + return this; + } + long instant = getChronology().months().subtract(getLocalMillis(), months); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime minus the specified number of weeks. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime subtracted = dt.minusWeeks(6);
      +     * LocalDateTime subtracted = dt.minus(Period.weeks(6));
      +     * LocalDateTime subtracted = dt.withFieldAdded(DurationFieldType.weeks(), -6);
      +     * 
      + * + * @param weeks the amount of weeks to subtract, may be negative + * @return the new LocalDateTime minus the increased weeks + */ + public LocalDateTime minusWeeks(int weeks) { + if (weeks == 0) { + return this; + } + long instant = getChronology().weeks().subtract(getLocalMillis(), weeks); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime minus the specified number of days. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime subtracted = dt.minusDays(6);
      +     * LocalDateTime subtracted = dt.minus(Period.days(6));
      +     * LocalDateTime subtracted = dt.withFieldAdded(DurationFieldType.days(), -6);
      +     * 
      + * + * @param days the amount of days to subtract, may be negative + * @return the new LocalDateTime minus the increased days + */ + public LocalDateTime minusDays(int days) { + if (days == 0) { + return this; + } + long instant = getChronology().days().subtract(getLocalMillis(), days); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime minus the specified number of hours. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime subtracted = dt.minusHours(6);
      +     * LocalDateTime subtracted = dt.minus(Period.hours(6));
      +     * LocalDateTime subtracted = dt.withFieldAdded(DurationFieldType.hours(), -6);
      +     * 
      + * + * @param hours the amount of hours to subtract, may be negative + * @return the new LocalDateTime minus the increased hours + */ + public LocalDateTime minusHours(int hours) { + if (hours == 0) { + return this; + } + long instant = getChronology().hours().subtract(getLocalMillis(), hours); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime minus the specified number of minutes. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime subtracted = dt.minusMinutes(6);
      +     * LocalDateTime subtracted = dt.minus(Period.minutes(6));
      +     * LocalDateTime subtracted = dt.withFieldAdded(DurationFieldType.minutes(), -6);
      +     * 
      + * + * @param minutes the amount of minutes to subtract, may be negative + * @return the new LocalDateTime minus the increased minutes + */ + public LocalDateTime minusMinutes(int minutes) { + if (minutes == 0) { + return this; + } + long instant = getChronology().minutes().subtract(getLocalMillis(), minutes); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime minus the specified number of seconds. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime subtracted = dt.minusSeconds(6);
      +     * LocalDateTime subtracted = dt.minus(Period.seconds(6));
      +     * LocalDateTime subtracted = dt.withFieldAdded(DurationFieldType.seconds(), -6);
      +     * 
      + * + * @param seconds the amount of seconds to subtract, may be negative + * @return the new LocalDateTime minus the increased seconds + */ + public LocalDateTime minusSeconds(int seconds) { + if (seconds == 0) { + return this; + } + long instant = getChronology().seconds().subtract(getLocalMillis(), seconds); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this datetime minus the specified number of millis. + *

      + * This LocalDateTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalDateTime subtracted = dt.minusMillis(6);
      +     * LocalDateTime subtracted = dt.minus(Period.millis(6));
      +     * LocalDateTime subtracted = dt.withFieldAdded(DurationFieldType.millis(), -6);
      +     * 
      + * + * @param millis the amount of millis to subtract, may be negative + * @return the new LocalDateTime minus the increased millis + */ + public LocalDateTime minusMillis(int millis) { + if (millis == 0) { + return this; + } + long instant = getChronology().millis().subtract(getLocalMillis(), millis); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Gets the property object for the specified type, which contains many + * useful methods. + * + * @param fieldType the field type to get the chronology for + * @return the property object + * @throws IllegalArgumentException if the field is null or unsupported + */ + public Property property(DateTimeFieldType fieldType) { + if (fieldType == null) { + throw new IllegalArgumentException("The DateTimeFieldType must not be null"); + } + if (isSupported(fieldType) == false) { + throw new IllegalArgumentException("Field '" + fieldType + "' is not supported"); + } + return new Property(this, fieldType.getField(getChronology())); + } + + //----------------------------------------------------------------------- + /** + * Get the era field value. + * + * @return the era + */ + public int getEra() { + return getChronology().era().get(getLocalMillis()); + } + + /** + * Get the year of era field value. + * + * @return the year of era + */ + public int getCenturyOfEra() { + return getChronology().centuryOfEra().get(getLocalMillis()); + } + + /** + * Get the year of era field value. + * + * @return the year of era + */ + public int getYearOfEra() { + return getChronology().yearOfEra().get(getLocalMillis()); + } + + /** + * Get the year of century field value. + * + * @return the year of century + */ + public int getYearOfCentury() { + return getChronology().yearOfCentury().get(getLocalMillis()); + } + + /** + * Get the year field value. + * + * @return the year + */ + public int getYear() { + return getChronology().year().get(getLocalMillis()); + } + + /** + * Get the weekyear field value. + *

      + * The weekyear is the year that matches with the weekOfWeekyear field. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + * The weekyear allows you to query the effective year for that day. + * + * @return the weekyear + */ + public int getWeekyear() { + return getChronology().weekyear().get(getLocalMillis()); + } + + /** + * Get the month of year field value. + * + * @return the month of year + */ + public int getMonthOfYear() { + return getChronology().monthOfYear().get(getLocalMillis()); + } + + /** + * Get the week of weekyear field value. + *

      + * This field is associated with the "weekyear" via {@link #getWeekyear()}. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + * + * @return the week of a week based year + */ + public int getWeekOfWeekyear() { + return getChronology().weekOfWeekyear().get(getLocalMillis()); + } + + /** + * Get the day of year field value. + * + * @return the day of year + */ + public int getDayOfYear() { + return getChronology().dayOfYear().get(getLocalMillis()); + } + + /** + * Get the day of month field value. + *

      + * The values for the day of month are defined in {@link org.joda.time.DateTimeConstants}. + * + * @return the day of month + */ + public int getDayOfMonth() { + return getChronology().dayOfMonth().get(getLocalMillis()); + } + + /** + * Get the day of week field value. + *

      + * The values for the day of week are defined in {@link org.joda.time.DateTimeConstants}. + * + * @return the day of week + */ + public int getDayOfWeek() { + return getChronology().dayOfWeek().get(getLocalMillis()); + } + + //----------------------------------------------------------------------- + /** + * Get the hour of day field value. + * + * @return the hour of day + */ + public int getHourOfDay() { + return getChronology().hourOfDay().get(getLocalMillis()); + } + + /** + * Get the minute of hour field value. + * + * @return the minute of hour + */ + public int getMinuteOfHour() { + return getChronology().minuteOfHour().get(getLocalMillis()); + } + + /** + * Get the second of minute field value. + * + * @return the second of minute + */ + public int getSecondOfMinute() { + return getChronology().secondOfMinute().get(getLocalMillis()); + } + + /** + * Get the millis of second field value. + * + * @return the millis of second + */ + public int getMillisOfSecond() { + return getChronology().millisOfSecond().get(getLocalMillis()); + } + + /** + * Get the millis of day field value. + * + * @return the millis of day + */ + public int getMillisOfDay() { + return getChronology().millisOfDay().get(getLocalMillis()); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime with the era field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * era changed. + * + * @param era the era to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withEra(int era) { + return withLocalMillis(getChronology().era().set(getLocalMillis(), era)); + } + + /** + * Returns a copy of this datetime with the century of era field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * century of era changed. + * + * @param centuryOfEra the centurey of era to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withCenturyOfEra(int centuryOfEra) { + return withLocalMillis(getChronology().centuryOfEra().set(getLocalMillis(), centuryOfEra)); + } + + /** + * Returns a copy of this datetime with the year of era field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year of era changed. + * + * @param yearOfEra the year of era to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withYearOfEra(int yearOfEra) { + return withLocalMillis(getChronology().yearOfEra().set(getLocalMillis(), yearOfEra)); + } + + /** + * Returns a copy of this datetime with the year of century field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year of century changed. + * + * @param yearOfCentury the year of century to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withYearOfCentury(int yearOfCentury) { + return withLocalMillis(getChronology().yearOfCentury().set(getLocalMillis(), yearOfCentury)); + } + + /** + * Returns a copy of this datetime with the year field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year changed. + * + * @param year the year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withYear(int year) { + return withLocalMillis(getChronology().year().set(getLocalMillis(), year)); + } + + /** + * Returns a copy of this datetime with the weekyear field updated. + *

      + * The weekyear is the year that matches with the weekOfWeekyear field. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + * The weekyear allows you to query the effective year for that day. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * weekyear changed. + * + * @param weekyear the weekyear to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withWeekyear(int weekyear) { + return withLocalMillis(getChronology().weekyear().set(getLocalMillis(), weekyear)); + } + + /** + * Returns a copy of this datetime with the month of year field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * month of year changed. + * + * @param monthOfYear the month of year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withMonthOfYear(int monthOfYear) { + return withLocalMillis(getChronology().monthOfYear().set(getLocalMillis(), monthOfYear)); + } + + /** + * Returns a copy of this datetime with the week of weekyear field updated. + *

      + * This field is associated with the "weekyear" via {@link #withWeekyear(int)}. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * week of weekyear changed. + * + * @param weekOfWeekyear the week of weekyear to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withWeekOfWeekyear(int weekOfWeekyear) { + return withLocalMillis(getChronology().weekOfWeekyear().set(getLocalMillis(), weekOfWeekyear)); + } + + /** + * Returns a copy of this datetime with the day of year field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of year changed. + * + * @param dayOfYear the day of year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withDayOfYear(int dayOfYear) { + return withLocalMillis(getChronology().dayOfYear().set(getLocalMillis(), dayOfYear)); + } + + /** + * Returns a copy of this datetime with the day of month field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of month changed. + * + * @param dayOfMonth the day of month to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withDayOfMonth(int dayOfMonth) { + return withLocalMillis(getChronology().dayOfMonth().set(getLocalMillis(), dayOfMonth)); + } + + /** + * Returns a copy of this datetime with the day of week field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of week changed. + * + * @param dayOfWeek the day of week to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withDayOfWeek(int dayOfWeek) { + return withLocalMillis(getChronology().dayOfWeek().set(getLocalMillis(), dayOfWeek)); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this datetime with the hour of day field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * hour of day changed. + * + * @param hour the hour of day to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withHourOfDay(int hour) { + return withLocalMillis(getChronology().hourOfDay().set(getLocalMillis(), hour)); + } + + /** + * Returns a copy of this datetime with the minute of hour field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * minute of hour changed. + * + * @param minute the minute of hour to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withMinuteOfHour(int minute) { + return withLocalMillis(getChronology().minuteOfHour().set(getLocalMillis(), minute)); + } + + /** + * Returns a copy of this datetime with the second of minute field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * second of minute changed. + * + * @param second the second of minute to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withSecondOfMinute(int second) { + return withLocalMillis(getChronology().secondOfMinute().set(getLocalMillis(), second)); + } + + /** + * Returns a copy of this datetime with the millis of second field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * millis of second changed. + * + * @param millis the millis of second to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withMillisOfSecond(int millis) { + return withLocalMillis(getChronology().millisOfSecond().set(getLocalMillis(), millis)); + } + + /** + * Returns a copy of this datetime with the millis of day field updated. + *

      + * LocalDateTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * millis of day changed. + * + * @param millis the millis of day to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalDateTime withMillisOfDay(int millis) { + return withLocalMillis(getChronology().millisOfDay().set(getLocalMillis(), millis)); + } + + //----------------------------------------------------------------------- + /** + * Get the era property which provides access to advanced functionality. + * + * @return the era property + */ + public Property era() { + return new Property(this, getChronology().era()); + } + + /** + * Get the century of era property which provides access to advanced functionality. + * + * @return the year of era property + */ + public Property centuryOfEra() { + return new Property(this, getChronology().centuryOfEra()); + } + + /** + * Get the year of century property which provides access to advanced functionality. + * + * @return the year of era property + */ + public Property yearOfCentury() { + return new Property(this, getChronology().yearOfCentury()); + } + + /** + * Get the year of era property which provides access to advanced functionality. + * + * @return the year of era property + */ + public Property yearOfEra() { + return new Property(this, getChronology().yearOfEra()); + } + + /** + * Get the year property which provides access to advanced functionality. + * + * @return the year property + */ + public Property year() { + return new Property(this, getChronology().year()); + } + + /** + * Get the weekyear property which provides access to advanced functionality. + * + * @return the weekyear property + */ + public Property weekyear() { + return new Property(this, getChronology().weekyear()); + } + + /** + * Get the month of year property which provides access to advanced functionality. + * + * @return the month of year property + */ + public Property monthOfYear() { + return new Property(this, getChronology().monthOfYear()); + } + + /** + * Get the week of a week based year property which provides access to advanced functionality. + * + * @return the week of a week based year property + */ + public Property weekOfWeekyear() { + return new Property(this, getChronology().weekOfWeekyear()); + } + + /** + * Get the day of year property which provides access to advanced functionality. + * + * @return the day of year property + */ + public Property dayOfYear() { + return new Property(this, getChronology().dayOfYear()); + } + + /** + * Get the day of month property which provides access to advanced functionality. + * + * @return the day of month property + */ + public Property dayOfMonth() { + return new Property(this, getChronology().dayOfMonth()); + } + + /** + * Get the day of week property which provides access to advanced functionality. + * + * @return the day of week property + */ + public Property dayOfWeek() { + return new Property(this, getChronology().dayOfWeek()); + } + + //----------------------------------------------------------------------- + /** + * Get the hour of day field property which provides access to advanced functionality. + * + * @return the hour of day property + */ + public Property hourOfDay() { + return new Property(this, getChronology().hourOfDay()); + } + + /** + * Get the minute of hour field property which provides access to advanced functionality. + * + * @return the minute of hour property + */ + public Property minuteOfHour() { + return new Property(this, getChronology().minuteOfHour()); + } + + /** + * Get the second of minute field property which provides access to advanced functionality. + * + * @return the second of minute property + */ + public Property secondOfMinute() { + return new Property(this, getChronology().secondOfMinute()); + } + + /** + * Get the millis of second property which provides access to advanced functionality. + * + * @return the millis of second property + */ + public Property millisOfSecond() { + return new Property(this, getChronology().millisOfSecond()); + } + + /** + * Get the millis of day property which provides access to advanced functionality. + * + * @return the millis of day property + */ + public Property millisOfDay() { + return new Property(this, getChronology().millisOfDay()); + } + + //----------------------------------------------------------------------- + /** + * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSS). + * + * @return ISO8601 time formatted string. + */ + @ToString + public String toString() { + return ISODateTimeFormat.dateTime().print(this); + } + + /** + * Output the date using the specified format pattern. + * + * @param pattern the pattern specification, null means use toString + * @see org.joda.time.format.DateTimeFormat + */ + public String toString(String pattern) { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).print(this); + } + + /** + * Output the date using the specified format pattern. + * + * @param pattern the pattern specification, null means use toString + * @param locale Locale to use, null means default + * @see org.joda.time.format.DateTimeFormat + */ + public String toString(String pattern, Locale locale) throws IllegalArgumentException { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this); + } + + //----------------------------------------------------------------------- + /** + * LocalDateTime.Property binds a LocalDateTime to a DateTimeField allowing + * powerful datetime functionality to be easily accessed. + *

      + * The simplest use of this class is as an alternative get method, here used to + * get the year '1972' (as an int) and the month 'December' (as a String). + *

      +     * LocalDateTime dt = new LocalDateTime(1972, 12, 3, 0, 0);
      +     * int year = dt.year().get();
      +     * String monthStr = dt.month().getAsText();
      +     * 
      + *

      + * Methods are also provided that allow date modification. These return + * new instances of LocalDateTime - they do not modify the original. + * The example below yields two independent immutable date objects + * 20 years apart. + *

      +     * LocalDateTime dt = new LocalDateTime(1972, 12, 3, 0, 0);
      +     * LocalDateTime dt1920 = dt.year().setCopy(1920);
      +     * 
      + *

      + * LocalDateTime.Property itself is thread-safe and immutable, as well as the + * LocalDateTime being operated on. + * + * @author Stephen Colebourne + * @author Brian S O'Neill + * @since 1.3 + */ + public static final class Property extends AbstractReadableInstantFieldProperty { + + /** Serialization version */ + private static final long serialVersionUID = -358138762846288L; + + /** The instant this property is working against */ + private transient LocalDateTime iInstant; + /** The field this property is working against */ + private transient DateTimeField iField; + + /** + * Constructor. + * + * @param instant the instant to set + * @param field the field to use + */ + Property(LocalDateTime instant, DateTimeField field) { + super(); + iInstant = instant; + iField = field; + } + + /** + * Writes the property in a safe serialization format. + */ + private void writeObject(ObjectOutputStream oos) throws IOException { + oos.writeObject(iInstant); + oos.writeObject(iField.getType()); + } + + /** + * Reads the property from a safe serialization format. + */ + private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException { + iInstant = (LocalDateTime) oos.readObject(); + DateTimeFieldType type = (DateTimeFieldType) oos.readObject(); + iField = type.getField(iInstant.getChronology()); + } + + //----------------------------------------------------------------------- + /** + * Gets the field being used. + * + * @return the field + */ + public DateTimeField getField() { + return iField; + } + + /** + * Gets the milliseconds of the datetime that this property is linked to. + * + * @return the milliseconds + */ + protected long getMillis() { + return iInstant.getLocalMillis(); + } + + /** + * Gets the chronology of the datetime that this property is linked to. + * + * @return the chronology + * @since 1.4 + */ + protected Chronology getChronology() { + return iInstant.getChronology(); + } + + /** + * Gets the LocalDateTime object linked to this property. + * + * @return the linked LocalDateTime + */ + public LocalDateTime getLocalDateTime() { + return iInstant; + } + + //----------------------------------------------------------------------- + /** + * Adds to this field in a copy of this LocalDateTime. + *

      + * The LocalDateTime attached to this property is unchanged by this call. + * + * @param value the value to add to the field in the copy + * @return a copy of the LocalDateTime with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public LocalDateTime addToCopy(int value) { + return iInstant.withLocalMillis(iField.add(iInstant.getLocalMillis(), value)); + } + + /** + * Adds to this field in a copy of this LocalDateTime. + *

      + * The LocalDateTime attached to this property is unchanged by this call. + * + * @param value the value to add to the field in the copy + * @return a copy of the LocalDateTime with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public LocalDateTime addToCopy(long value) { + return iInstant.withLocalMillis(iField.add(iInstant.getLocalMillis(), value)); + } + + /** + * Adds to this field, possibly wrapped, in a copy of this LocalDateTime. + * A field wrapped operation only changes this field. + * Thus 31st January addWrapField one day goes to the 1st January. + *

      + * The LocalDateTime attached to this property is unchanged by this call. + * + * @param value the value to add to the field in the copy + * @return a copy of the LocalDateTime with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public LocalDateTime addWrapFieldToCopy(int value) { + return iInstant.withLocalMillis(iField.addWrapField(iInstant.getLocalMillis(), value)); + } + + //----------------------------------------------------------------------- + /** + * Sets this field in a copy of the LocalDateTime. + *

      + * The LocalDateTime attached to this property is unchanged by this call. + * + * @param value the value to set the field in the copy to + * @return a copy of the LocalDateTime with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public LocalDateTime setCopy(int value) { + return iInstant.withLocalMillis(iField.set(iInstant.getLocalMillis(), value)); + } + + /** + * Sets this field in a copy of the LocalDateTime to a parsed text value. + *

      + * The LocalDateTime attached to this property is unchanged by this call. + * + * @param text the text value to set + * @param locale optional locale to use for selecting a text symbol + * @return a copy of the LocalDateTime with the field value changed + * @throws IllegalArgumentException if the text value isn't valid + */ + public LocalDateTime setCopy(String text, Locale locale) { + return iInstant.withLocalMillis(iField.set(iInstant.getLocalMillis(), text, locale)); + } + + /** + * Sets this field in a copy of the LocalDateTime to a parsed text value. + *

      + * The LocalDateTime attached to this property is unchanged by this call. + * + * @param text the text value to set + * @return a copy of the LocalDateTime with the field value changed + * @throws IllegalArgumentException if the text value isn't valid + */ + public LocalDateTime setCopy(String text) { + return setCopy(text, null); + } + + //----------------------------------------------------------------------- + /** + * Returns a new LocalDateTime with this field set to the maximum value + * for this field. + *

      + * This operation is useful for obtaining a LocalDateTime on the last day + * of the month, as month lengths vary. + *

      +         * LocalDateTime lastDayOfMonth = dt.dayOfMonth().withMaximumValue();
      +         * 
      + *

      + * The LocalDateTime attached to this property is unchanged by this call. + * + * @return a copy of the LocalDateTime with this field set to its maximum + */ + public LocalDateTime withMaximumValue() { + return setCopy(getMaximumValue()); + } + + /** + * Returns a new LocalDateTime with this field set to the minimum value + * for this field. + *

      + * The LocalDateTime attached to this property is unchanged by this call. + * + * @return a copy of the LocalDateTime with this field set to its minimum + */ + public LocalDateTime withMinimumValue() { + return setCopy(getMinimumValue()); + } + + //----------------------------------------------------------------------- + /** + * Rounds to the lowest whole unit of this field on a copy of this + * LocalDateTime. + *

      + * For example, rounding floor on the hourOfDay field of a LocalDateTime + * where the time is 10:30 would result in new LocalDateTime with the + * time of 10:00. + * + * @return a copy of the LocalDateTime with the field value changed + */ + public LocalDateTime roundFloorCopy() { + return iInstant.withLocalMillis(iField.roundFloor(iInstant.getLocalMillis())); + } + + /** + * Rounds to the highest whole unit of this field on a copy of this + * LocalDateTime. + *

      + * For example, rounding floor on the hourOfDay field of a LocalDateTime + * where the time is 10:30 would result in new LocalDateTime with the + * time of 11:00. + * + * @return a copy of the LocalDateTime with the field value changed + */ + public LocalDateTime roundCeilingCopy() { + return iInstant.withLocalMillis(iField.roundCeiling(iInstant.getLocalMillis())); + } + + /** + * Rounds to the nearest whole unit of this field on a copy of this + * LocalDateTime, favoring the floor if halfway. + * + * @return a copy of the LocalDateTime with the field value changed + */ + public LocalDateTime roundHalfFloorCopy() { + return iInstant.withLocalMillis(iField.roundHalfFloor(iInstant.getLocalMillis())); + } + + /** + * Rounds to the nearest whole unit of this field on a copy of this + * LocalDateTime, favoring the ceiling if halfway. + * + * @return a copy of the LocalDateTime with the field value changed + */ + public LocalDateTime roundHalfCeilingCopy() { + return iInstant.withLocalMillis(iField.roundHalfCeiling(iInstant.getLocalMillis())); + } + + /** + * Rounds to the nearest whole unit of this field on a copy of this + * LocalDateTime. If halfway, the ceiling is favored over the floor + * only if it makes this field's value even. + * + * @return a copy of the LocalDateTime with the field value changed + */ + public LocalDateTime roundHalfEvenCopy() { + return iInstant.withLocalMillis(iField.roundHalfEven(iInstant.getLocalMillis())); + } + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/LocalTime.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/LocalTime.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/LocalTime.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,1623 @@ +/* + * Copyright 2001-2011 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; +import org.joda.time.base.BaseLocal; +import org.joda.time.chrono.ISOChronology; +import org.joda.time.convert.ConverterManager; +import org.joda.time.convert.PartialConverter; +import org.joda.time.field.AbstractReadableInstantFieldProperty; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; + +/** + * LocalTime is an immutable time class representing a time + * without a time zone. + *

      + * LocalTime implements the {@link ReadablePartial} interface. + * To do this, the interface methods focus on the key fields - + * HourOfDay, MinuteOfHour, SecondOfMinute and MillisOfSecond. + * However, all time fields may in fact be queried. + *

      + * Calculations on LocalTime are performed using a {@link Chronology}. + * This chronology will be set internally to be in the UTC time zone + * for all calculations. + * + *

      Each individual field can be queried in two ways: + *

        + *
      • getHourOfDay() + *
      • hourOfDay().get() + *
      + * The second technique also provides access to other useful methods on the + * field: + *
        + *
      • numeric value + *
      • text value + *
      • short text value + *
      • maximum/minimum values + *
      • add/subtract + *
      • set + *
      • rounding + *
      + * + *

      + * LocalTime is thread-safe and immutable, provided that the Chronology is as well. + * All standard Chronology classes supplied are thread-safe and immutable. + * + * @author Stephen Colebourne + * @since 1.3 + */ +public final class LocalTime + extends BaseLocal + implements ReadablePartial, Serializable { + + /** Serialization lock */ + private static final long serialVersionUID = -12873158713873L; + + /** Constant for midnight. */ + public static final LocalTime MIDNIGHT = new LocalTime(0, 0, 0, 0); + + /** The index of the hourOfDay field in the field array */ + private static final int HOUR_OF_DAY = 0; + /** The index of the minuteOfHour field in the field array */ + private static final int MINUTE_OF_HOUR = 1; + /** The index of the secondOfMinute field in the field array */ + private static final int SECOND_OF_MINUTE = 2; + /** The index of the millisOfSecond field in the field array */ + private static final int MILLIS_OF_SECOND = 3; + /** Set of known duration types. */ + private static final Set TIME_DURATION_TYPES = new HashSet(); + static { + TIME_DURATION_TYPES.add(DurationFieldType.millis()); + TIME_DURATION_TYPES.add(DurationFieldType.seconds()); + TIME_DURATION_TYPES.add(DurationFieldType.minutes()); + TIME_DURATION_TYPES.add(DurationFieldType.hours()); + } + + /** The local millis from 1970-01-01T00:00:00 */ + private final long iLocalMillis; + /** The chronology to use, in UTC */ + private final Chronology iChronology; + + //----------------------------------------------------------------------- + /** + * Obtains a {@code LocalTime} set to the current system millisecond time + * using ISOChronology in the default time zone. + * The resulting object does not use the zone. + * + * @return the current time, not null + * @since 2.0 + */ + public static LocalTime now() { + return new LocalTime(); + } + + /** + * Obtains a {@code LocalTime} set to the current system millisecond time + * using ISOChronology in the specified time zone. + * The resulting object does not use the zone. + * + * @param zone the time zone, not null + * @return the current time, not null + * @since 2.0 + */ + public static LocalTime now(DateTimeZone zone) { + if (zone == null) { + throw new NullPointerException("Zone must not be null"); + } + return new LocalTime(zone); + } + + /** + * Obtains a {@code LocalTime} set to the current system millisecond time + * using the specified chronology. + * The resulting object does not use the zone. + * + * @param chronology the chronology, not null + * @return the current time, not null + * @since 2.0 + */ + public static LocalTime now(Chronology chronology) { + if (chronology == null) { + throw new NullPointerException("Chronology must not be null"); + } + return new LocalTime(chronology); + } + + //----------------------------------------------------------------------- + /** + * Parses a {@code LocalTime} from the specified string. + *

      + * This uses {@link ISODateTimeFormat#localTimeParser()}. + * + * @param str the string to parse, not null + * @since 2.0 + */ + @FromString + public static LocalTime parse(String str) { + return parse(str, ISODateTimeFormat.localTimeParser()); + } + + /** + * Parses a {@code LocalTime} from the specified string using a formatter. + * + * @param str the string to parse, not null + * @param formatter the formatter to use, not null + * @since 2.0 + */ + public static LocalTime parse(String str, DateTimeFormatter formatter) { + return formatter.parseLocalTime(str); + } + + //----------------------------------------------------------------------- + /** + * Constructs a LocalTime from the specified millis of day using the + * ISO chronology. + *

      + * The millisOfDay value may exceed the number of millis in one day, + * but additional days will be ignored. + * This method uses the UTC time zone internally. + * + * @param millisOfDay the number of milliseconds into a day to convert + */ + public static LocalTime fromMillisOfDay(long millisOfDay) { + return fromMillisOfDay(millisOfDay, null); + } + + /** + * Constructs a LocalTime from the specified millis of day using the + * specified chronology. + *

      + * The millisOfDay value may exceed the number of millis in one day, + * but additional days will be ignored. + * This method uses the UTC time zone internally. + * + * @param millisOfDay the number of milliseconds into a day to convert + * @param chrono the chronology, null means ISO chronology + */ + public static LocalTime fromMillisOfDay(long millisOfDay, Chronology chrono) { + chrono = DateTimeUtils.getChronology(chrono).withUTC(); + return new LocalTime(millisOfDay, chrono); + } + + //----------------------------------------------------------------------- + /** + * Constructs a LocalTime from a java.util.Calendar + * using exactly the same field values. + *

      + * Each field is queried from the Calendar and assigned to the LocalTime. + * This is useful if you have been using the Calendar as a local time, + * ignoring the zone. + *

      + * One advantage of this method is that this method is unaffected if the + * version of the time zone data differs between the JDK and Joda-Time. + * That is because the local field values are transferred, calculated using + * the JDK time zone data and without using the Joda-Time time zone data. + *

      + * This factory method ignores the type of the calendar and always + * creates a LocalTime with ISO chronology. It is expected that you + * will only pass in instances of GregorianCalendar however + * this is not validated. + * + * @param calendar the Calendar to extract fields from + * @return the created LocalTime + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the date is invalid for the ISO chronology + */ + public static LocalTime fromCalendarFields(Calendar calendar) { + if (calendar == null) { + throw new IllegalArgumentException("The calendar must not be null"); + } + return new LocalTime( + calendar.get(Calendar.HOUR_OF_DAY), + calendar.get(Calendar.MINUTE), + calendar.get(Calendar.SECOND), + calendar.get(Calendar.MILLISECOND) + ); + } + + /** + * Constructs a LocalTime from a java.util.Date + * using exactly the same field values. + *

      + * Each field is queried from the Date and assigned to the LocalTime. + * This is useful if you have been using the Date as a local time, + * ignoring the zone. + *

      + * One advantage of this method is that this method is unaffected if the + * version of the time zone data differs between the JDK and Joda-Time. + * That is because the local field values are transferred, calculated using + * the JDK time zone data and without using the Joda-Time time zone data. + *

      + * This factory method always creates a LocalTime with ISO chronology. + * + * @param date the Date to extract fields from + * @return the created LocalTime + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the date is invalid for the ISO chronology + */ + @SuppressWarnings("deprecation") + public static LocalTime fromDateFields(Date date) { + if (date == null) { + throw new IllegalArgumentException("The date must not be null"); + } + return new LocalTime( + date.getHours(), + date.getMinutes(), + date.getSeconds(), + (((int) (date.getTime() % 1000)) + 1000) % 1000 + ); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance set to the current local time evaluated using + * ISO chronology in the default zone. + *

      + * Once the constructor is completed, the zone is no longer used. + * + * @see #now() + */ + public LocalTime() { + this(DateTimeUtils.currentTimeMillis(), ISOChronology.getInstance()); + } + + /** + * Constructs an instance set to the current local time evaluated using + * ISO chronology in the specified zone. + *

      + * If the specified time zone is null, the default zone is used. + * Once the constructor is completed, the zone is no longer used. + * + * @param zone the time zone, null means default zone + * @see #now(DateTimeZone) + */ + public LocalTime(DateTimeZone zone) { + this(DateTimeUtils.currentTimeMillis(), ISOChronology.getInstance(zone)); + } + + /** + * Constructs an instance set to the current local time evaluated using + * specified chronology and zone. + *

      + * If the chronology is null, ISO chronology in the default time zone is used. + * Once the constructor is completed, the zone is no longer used. + * + * @param chronology the chronology, null means ISOChronology in default zone + * @see #now(Chronology) + */ + public LocalTime(Chronology chronology) { + this(DateTimeUtils.currentTimeMillis(), chronology); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance set to the local time defined by the specified + * instant evaluated using ISO chronology in the default zone. + *

      + * Once the constructor is completed, the zone is no longer used. + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z + */ + public LocalTime(long instant) { + this(instant, ISOChronology.getInstance()); + } + + /** + * Constructs an instance set to the local time defined by the specified + * instant evaluated using ISO chronology in the specified zone. + *

      + * If the specified time zone is null, the default zone is used. + * Once the constructor is completed, the zone is no longer used. + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z + * @param zone the time zone, null means default zone + */ + public LocalTime(long instant, DateTimeZone zone) { + this(instant, ISOChronology.getInstance(zone)); + } + + /** + * Constructs an instance set to the local time defined by the specified + * instant evaluated using the specified chronology. + *

      + * If the chronology is null, ISO chronology in the default zone is used. + * Once the constructor is completed, the zone is no longer used. + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z + * @param chronology the chronology, null means ISOChronology in default zone + */ + public LocalTime(long instant, Chronology chronology) { + chronology = DateTimeUtils.getChronology(chronology); + + long localMillis = chronology.getZone().getMillisKeepLocal(DateTimeZone.UTC, instant); + chronology = chronology.withUTC(); + iLocalMillis = chronology.millisOfDay().get(localMillis); + iChronology = chronology; + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance from an Object that represents a datetime. + *

      + * If the object contains no chronology, ISOChronology is used. + * If the object contains no time zone, the default zone is used. + * Once the constructor is completed, the zone is no longer used. + *

      + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePartial, ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#localTimeParser()}. + * The default String converter ignores the zone and only parses the field values. + * + * @param instant the datetime object + * @throws IllegalArgumentException if the instant is invalid + */ + public LocalTime(Object instant) { + this(instant, (Chronology) null); + } + + /** + * Constructs an instance from an Object that represents a datetime, + * forcing the time zone to that specified. + *

      + * If the object contains no chronology, ISOChronology is used. + * If the specified time zone is null, the default zone is used. + * Once the constructor is completed, the zone is no longer used. + *

      + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePartial, ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#localTimeParser()}. + * The default String converter ignores the zone and only parses the field values. + * + * @param instant the datetime object + * @param zone the time zone + * @throws IllegalArgumentException if the instant is invalid + */ + public LocalTime(Object instant, DateTimeZone zone) { + PartialConverter converter = ConverterManager.getInstance().getPartialConverter(instant); + Chronology chronology = converter.getChronology(instant, zone); + chronology = DateTimeUtils.getChronology(chronology); + iChronology = chronology.withUTC(); + int[] values = converter.getPartialValues(this, instant, chronology, ISODateTimeFormat.localTimeParser()); + iLocalMillis = iChronology.getDateTimeMillis(0L, values[0], values[1], values[2], values[3]); + } + + /** + * Constructs an instance from an Object that represents a datetime, + * using the specified chronology. + *

      + * If the chronology is null, ISO in the default time zone is used. + * Once the constructor is completed, the zone is no longer used. + *

      + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePartial, ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#localTimeParser()}. + * The default String converter ignores the zone and only parses the field values. + * + * @param instant the datetime object + * @param chronology the chronology + * @throws IllegalArgumentException if the instant is invalid + */ + public LocalTime(Object instant, Chronology chronology) { + PartialConverter converter = ConverterManager.getInstance().getPartialConverter(instant); + chronology = converter.getChronology(instant, chronology); + chronology = DateTimeUtils.getChronology(chronology); + iChronology = chronology.withUTC(); + int[] values = converter.getPartialValues(this, instant, chronology, ISODateTimeFormat.localTimeParser()); + iLocalMillis = iChronology.getDateTimeMillis(0L, values[0], values[1], values[2], values[3]); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance set to the specified time + * using ISOChronology. + * + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + */ + public LocalTime( + int hourOfDay, + int minuteOfHour) { + this(hourOfDay, minuteOfHour, 0, 0, ISOChronology.getInstanceUTC()); + } + + /** + * Constructs an instance set to the specified time + * using ISOChronology. + * + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + * @param secondOfMinute the second of the minute + */ + public LocalTime( + int hourOfDay, + int minuteOfHour, + int secondOfMinute) { + this(hourOfDay, minuteOfHour, secondOfMinute, 0, ISOChronology.getInstanceUTC()); + } + + /** + * Constructs an instance set to the specified time + * using ISOChronology. + * + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + * @param secondOfMinute the second of the minute + * @param millisOfSecond the millisecond of the second + */ + public LocalTime( + int hourOfDay, + int minuteOfHour, + int secondOfMinute, + int millisOfSecond) { + this(hourOfDay, minuteOfHour, secondOfMinute, + millisOfSecond, ISOChronology.getInstanceUTC()); + } + + /** + * Constructs an instance set to the specified time + * using the specified chronology, whose zone is ignored. + *

      + * If the chronology is null, ISOChronology is used. + * + * @param hourOfDay the hour of the day + * @param minuteOfHour the minute of the hour + * @param secondOfMinute the second of the minute + * @param millisOfSecond the millisecond of the second + * @param chronology the chronology, null means ISOChronology in default zone + */ + public LocalTime( + int hourOfDay, + int minuteOfHour, + int secondOfMinute, + int millisOfSecond, + Chronology chronology) { + super(); + chronology = DateTimeUtils.getChronology(chronology).withUTC(); + long instant = chronology.getDateTimeMillis( + 0L, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond); + iChronology = chronology; + iLocalMillis = instant; + } + + /** + * Handle broken serialization from other tools. + * @return the resolved object, not null + */ + private Object readResolve() { + if (iChronology == null) { + return new LocalTime(iLocalMillis, ISOChronology.getInstanceUTC()); + } + if (DateTimeZone.UTC.equals(iChronology.getZone()) == false) { + return new LocalTime(iLocalMillis, iChronology.withUTC()); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets the number of fields in this partial, which is four. + * The supported fields are HourOfDay, MinuteOfHour, SecondOfMinute + * and MillisOfSecond. + * + * @return the field count, four + */ + public int size() { + return 4; + } + + /** + * Gets the field for a specific index in the chronology specified. + *

      + * This method must not use any instance variables. + * + * @param index the index to retrieve + * @param chrono the chronology to use + * @return the field + */ + protected DateTimeField getField(int index, Chronology chrono) { + switch (index) { + case HOUR_OF_DAY: + return chrono.hourOfDay(); + case MINUTE_OF_HOUR: + return chrono.minuteOfHour(); + case SECOND_OF_MINUTE: + return chrono.secondOfMinute(); + case MILLIS_OF_SECOND: + return chrono.millisOfSecond(); + default: + throw new IndexOutOfBoundsException("Invalid index: " + index); + } + } + + /** + * Gets the value of the field at the specifed index. + *

      + * This method is required to support the ReadablePartial + * interface. The supported fields are HourOfDay, MinuteOfHour, + * SecondOfMinute and MillisOfSecond. + * + * @param index the index, zero to three + * @return the value + * @throws IndexOutOfBoundsException if the index is invalid + */ + public int getValue(int index) { + switch (index) { + case HOUR_OF_DAY: + return getChronology().hourOfDay().get(getLocalMillis()); + case MINUTE_OF_HOUR: + return getChronology().minuteOfHour().get(getLocalMillis()); + case SECOND_OF_MINUTE: + return getChronology().secondOfMinute().get(getLocalMillis()); + case MILLIS_OF_SECOND: + return getChronology().millisOfSecond().get(getLocalMillis()); + default: + throw new IndexOutOfBoundsException("Invalid index: " + index); + } + } + + //----------------------------------------------------------------------- + /** + * Get the value of one of the fields of time. + *

      + * This method gets the value of the specified field. + * For example: + *

      +     * DateTime dt = new DateTime();
      +     * int hourOfDay = dt.get(DateTimeFieldType.hourOfDay());
      +     * 
      + * + * @param fieldType a field type, usually obtained from DateTimeFieldType, not null + * @return the value of that field + * @throws IllegalArgumentException if the field type is null + */ + public int get(DateTimeFieldType fieldType) { + if (fieldType == null) { + throw new IllegalArgumentException("The DateTimeFieldType must not be null"); + } + if (isSupported(fieldType) == false) { + throw new IllegalArgumentException("Field '" + fieldType + "' is not supported"); + } + return fieldType.getField(getChronology()).get(getLocalMillis()); + } + + /** + * Checks if the field type specified is supported by this + * local time and chronology. + * This can be used to avoid exceptions in {@link #get(DateTimeFieldType)}. + * + * @param type a field type, usually obtained from DateTimeFieldType + * @return true if the field type is supported + */ + public boolean isSupported(DateTimeFieldType type) { + if (type == null) { + return false; + } + if (isSupported(type.getDurationType()) == false) { + return false; + } + DurationFieldType range = type.getRangeDurationType(); + return (isSupported(range) || range == DurationFieldType.days()); + } + + /** + * Checks if the duration type specified is supported by this + * local time and chronology. + * + * @param type a duration type, usually obtained from DurationFieldType + * @return true if the field type is supported + */ + public boolean isSupported(DurationFieldType type) { + if (type == null) { + return false; + } + DurationField field = type.getField(getChronology()); + if (TIME_DURATION_TYPES.contains(type) || + field.getUnitMillis() < getChronology().days().getUnitMillis()) { + return field.isSupported(); + } + return false; + } + + //----------------------------------------------------------------------- + /** + * Gets the local milliseconds from the Java epoch + * of 1970-01-01T00:00:00 (not fixed to any specific time zone). + * + * @return the number of milliseconds since 1970-01-01T00:00:00 + * @since 1.5 (previously private) + */ + protected long getLocalMillis() { + return iLocalMillis; + } + + /** + * Gets the chronology of the time. + * + * @return the Chronology that the time is using + */ + public Chronology getChronology() { + return iChronology; + } + + //----------------------------------------------------------------------- + /** + * Compares this ReadablePartial with another returning true if the chronology, + * field types and values are equal. + * + * @param partial an object to check against + * @return true if fields and values are equal + */ + public boolean equals(Object partial) { + // override to perform faster + if (this == partial) { + return true; + } + if (partial instanceof LocalTime) { + LocalTime other = (LocalTime) partial; + if (iChronology.equals(other.iChronology)) { + return iLocalMillis == other.iLocalMillis; + } + } + return super.equals(partial); + } + + /** + * Compares this partial with another returning an integer + * indicating the order. + *

      + * The fields are compared in order, from largest to smallest. + * The first field that is non-equal is used to determine the result. + *

      + * The specified object must be a partial instance whose field types + * match those of this partial. + * + * @param partial an object to check against + * @return negative if this is less, zero if equal, positive if greater + * @throws ClassCastException if the partial is the wrong class + * or if it has field types that don't match + * @throws NullPointerException if the partial is null + */ + public int compareTo(ReadablePartial partial) { + // override to perform faster + if (this == partial) { + return 0; + } + if (partial instanceof LocalTime) { + LocalTime other = (LocalTime) partial; + if (iChronology.equals(other.iChronology)) { + return (iLocalMillis < other.iLocalMillis ? -1 : + (iLocalMillis == other.iLocalMillis ? 0 : 1)); + + } + } + return super.compareTo(partial); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this time with different local millis. + *

      + * The returned object will be a new instance of the same type. + * Only the millis will change, the chronology is kept. + * The returned object will be either be a new instance or this. + * + * @param newMillis the new millis, from 1970-01-01T00:00:00 + * @return a copy of this time with different millis + */ + LocalTime withLocalMillis(long newMillis) { + return (newMillis == getLocalMillis() ? this : new LocalTime(newMillis, getChronology())); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this time with the partial set of fields replacing + * those from this instance. + *

      + * For example, if the partial contains an hour and minute then those two + * fields will be changed in the returned instance. + * Unsupported fields are ignored. + * If the partial is null, then this is returned. + * + * @param partial the partial set of fields to apply to this time, null ignored + * @return a copy of this time with a different set of fields + * @throws IllegalArgumentException if any value is invalid + */ + public LocalTime withFields(ReadablePartial partial) { + if (partial == null) { + return this; + } + return withLocalMillis(getChronology().set(partial, getLocalMillis())); + } + + /** + * Returns a copy of this time with the specified field set + * to a new value. + *

      + * For example, if the field type is hourOfDay then the hour of day + * field would be changed in the returned instance. + * If the field type is null, then this is returned. + *

      + * These lines are equivalent: + *

      +     * LocalTime updated = dt.withHourOfDay(6);
      +     * LocalTime updated = dt.withField(DateTimeFieldType.hourOfDay(), 6);
      +     * 
      + * + * @param fieldType the field type to set, not null + * @param value the value to set + * @return a copy of this time with the field set + * @throws IllegalArgumentException if the value is null or invalid + */ + public LocalTime withField(DateTimeFieldType fieldType, int value) { + if (fieldType == null) { + throw new IllegalArgumentException("Field must not be null"); + } + if (isSupported(fieldType) == false) { + throw new IllegalArgumentException("Field '" + fieldType + "' is not supported"); + } + long instant = fieldType.getField(getChronology()).set(getLocalMillis(), value); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this time with the value of the specified + * field increased. + *

      + * If the addition is zero or the field is null, then this + * is returned. + *

      + * If the addition causes the maximum value of the field to be exceeded, + * then the value will wrap. Thus 23:59 plus two minutes yields 00:01. + *

      + * These lines are equivalent: + *

      +     * LocalTime added = dt.plusHours(6);
      +     * LocalTime added = dt.withFieldAdded(DurationFieldType.hours(), 6);
      +     * 
      + * + * @param fieldType the field type to add to, not null + * @param amount the amount to add + * @return a copy of this time with the field updated + * @throws IllegalArgumentException if the value is null or invalid + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalTime withFieldAdded(DurationFieldType fieldType, int amount) { + if (fieldType == null) { + throw new IllegalArgumentException("Field must not be null"); + } + if (isSupported(fieldType) == false) { + throw new IllegalArgumentException("Field '" + fieldType + "' is not supported"); + } + if (amount == 0) { + return this; + } + long instant = fieldType.getField(getChronology()).add(getLocalMillis(), amount); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this time with the specified period added. + *

      + * If the addition is zero, then this is returned. + *

      + * This method is typically used to add multiple copies of complex + * period instances. Adding one field is best achieved using methods + * like {@link #withFieldAdded(DurationFieldType, int)} + * or {@link #plusHours(int)}. + * + * @param period the period to add to this one, null means zero + * @param scalar the amount of times to add, such as -1 to subtract once + * @return a copy of this time with the period added + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalTime withPeriodAdded(ReadablePeriod period, int scalar) { + if (period == null || scalar == 0) { + return this; + } + long instant = getChronology().add(period, getLocalMillis(), scalar); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this time with the specified period added. + *

      + * If the amount is zero or null, then this is returned. + *

      + * This method is typically used to add complex period instances. + * Adding one field is best achieved using methods + * like {@link #plusHours(int)}. + * + * @param period the period to add to this one, null means zero + * @return a copy of this time with the period added + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalTime plus(ReadablePeriod period) { + return withPeriodAdded(period, 1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this time plus the specified number of hours. + *

      + * This LocalTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalTime added = dt.plusHours(6);
      +     * LocalTime added = dt.plus(Period.hours(6));
      +     * LocalTime added = dt.withFieldAdded(DurationFieldType.hours(), 6);
      +     * 
      + * + * @param hours the amount of hours to add, may be negative + * @return the new LocalTime plus the increased hours + */ + public LocalTime plusHours(int hours) { + if (hours == 0) { + return this; + } + long instant = getChronology().hours().add(getLocalMillis(), hours); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this time plus the specified number of minutes. + *

      + * This LocalTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalTime added = dt.plusMinutes(6);
      +     * LocalTime added = dt.plus(Period.minutes(6));
      +     * LocalTime added = dt.withFieldAdded(DurationFieldType.minutes(), 6);
      +     * 
      + * + * @param minutes the amount of minutes to add, may be negative + * @return the new LocalTime plus the increased minutes + */ + public LocalTime plusMinutes(int minutes) { + if (minutes == 0) { + return this; + } + long instant = getChronology().minutes().add(getLocalMillis(), minutes); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this time plus the specified number of seconds. + *

      + * This LocalTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalTime added = dt.plusSeconds(6);
      +     * LocalTime added = dt.plus(Period.seconds(6));
      +     * LocalTime added = dt.withFieldAdded(DurationFieldType.seconds(), 6);
      +     * 
      + * + * @param seconds the amount of seconds to add, may be negative + * @return the new LocalTime plus the increased seconds + */ + public LocalTime plusSeconds(int seconds) { + if (seconds == 0) { + return this; + } + long instant = getChronology().seconds().add(getLocalMillis(), seconds); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this time plus the specified number of millis. + *

      + * This LocalTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalTime added = dt.plusMillis(6);
      +     * LocalTime added = dt.plus(Period.millis(6));
      +     * LocalTime added = dt.withFieldAdded(DurationFieldType.millis(), 6);
      +     * 
      + * + * @param millis the amount of millis to add, may be negative + * @return the new LocalTime plus the increased millis + */ + public LocalTime plusMillis(int millis) { + if (millis == 0) { + return this; + } + long instant = getChronology().millis().add(getLocalMillis(), millis); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this time with the specified period taken away. + *

      + * If the amount is zero or null, then this is returned. + *

      + * This method is typically used to subtract complex period instances. + * Subtracting one field is best achieved using methods + * like {@link #minusHours(int)}. + * + * @param period the period to reduce this instant by + * @return a copy of this time with the period taken away + * @throws ArithmeticException if the result exceeds the internal capacity + */ + public LocalTime minus(ReadablePeriod period) { + return withPeriodAdded(period, -1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this time minus the specified number of hours. + *

      + * This LocalTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalTime subtracted = dt.minusHours(6);
      +     * LocalTime subtracted = dt.minus(Period.hours(6));
      +     * LocalTime subtracted = dt.withFieldAdded(DurationFieldType.hours(), -6);
      +     * 
      + * + * @param hours the amount of hours to subtract, may be negative + * @return the new LocalTime minus the increased hours + */ + public LocalTime minusHours(int hours) { + if (hours == 0) { + return this; + } + long instant = getChronology().hours().subtract(getLocalMillis(), hours); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this time minus the specified number of minutes. + *

      + * This LocalTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalTime subtracted = dt.minusMinutes(6);
      +     * LocalTime subtracted = dt.minus(Period.minutes(6));
      +     * LocalTime subtracted = dt.withFieldAdded(DurationFieldType.minutes(), -6);
      +     * 
      + * + * @param minutes the amount of minutes to subtract, may be negative + * @return the new LocalTime minus the increased minutes + */ + public LocalTime minusMinutes(int minutes) { + if (minutes == 0) { + return this; + } + long instant = getChronology().minutes().subtract(getLocalMillis(), minutes); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this time minus the specified number of seconds. + *

      + * This LocalTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalTime subtracted = dt.minusSeconds(6);
      +     * LocalTime subtracted = dt.minus(Period.seconds(6));
      +     * LocalTime subtracted = dt.withFieldAdded(DurationFieldType.seconds(), -6);
      +     * 
      + * + * @param seconds the amount of seconds to subtract, may be negative + * @return the new LocalTime minus the increased seconds + */ + public LocalTime minusSeconds(int seconds) { + if (seconds == 0) { + return this; + } + long instant = getChronology().seconds().subtract(getLocalMillis(), seconds); + return withLocalMillis(instant); + } + + /** + * Returns a copy of this time minus the specified number of millis. + *

      + * This LocalTime instance is immutable and unaffected by this method call. + *

      + * The following three lines are identical in effect: + *

      +     * LocalTime subtracted = dt.minusMillis(6);
      +     * LocalTime subtracted = dt.minus(Period.millis(6));
      +     * LocalTime subtracted = dt.withFieldAdded(DurationFieldType.millis(), -6);
      +     * 
      + * + * @param millis the amount of millis to subtract, may be negative + * @return the new LocalTime minus the increased millis + */ + public LocalTime minusMillis(int millis) { + if (millis == 0) { + return this; + } + long instant = getChronology().millis().subtract(getLocalMillis(), millis); + return withLocalMillis(instant); + } + + //----------------------------------------------------------------------- + /** + * Gets the property object for the specified type, which contains + * many useful methods. + * + * @param fieldType the field type to get the chronology for + * @return the property object + * @throws IllegalArgumentException if the field is null or unsupported + */ + public Property property(DateTimeFieldType fieldType) { + if (fieldType == null) { + throw new IllegalArgumentException("The DateTimeFieldType must not be null"); + } + if (isSupported(fieldType) == false) { + throw new IllegalArgumentException("Field '" + fieldType + "' is not supported"); + } + return new Property(this, fieldType.getField(getChronology())); + } + + //----------------------------------------------------------------------- + /** + * Get the hour of day field value. + * + * @return the hour of day + */ + public int getHourOfDay() { + return getChronology().hourOfDay().get(getLocalMillis()); + } + + /** + * Get the minute of hour field value. + * + * @return the minute of hour + */ + public int getMinuteOfHour() { + return getChronology().minuteOfHour().get(getLocalMillis()); + } + + /** + * Get the second of minute field value. + * + * @return the second of minute + */ + public int getSecondOfMinute() { + return getChronology().secondOfMinute().get(getLocalMillis()); + } + + /** + * Get the millis of second field value. + * + * @return the millis of second + */ + public int getMillisOfSecond() { + return getChronology().millisOfSecond().get(getLocalMillis()); + } + + /** + * Get the millis of day field value. + * + * @return the millis of day + */ + public int getMillisOfDay() { + return getChronology().millisOfDay().get(getLocalMillis()); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this time with the hour of day field updated. + *

      + * LocalTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * hour of day changed. + * + * @param hour the hour of day to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalTime withHourOfDay(int hour) { + return withLocalMillis(getChronology().hourOfDay().set(getLocalMillis(), hour)); + } + + /** + * Returns a copy of this time with the minute of hour field updated. + *

      + * LocalTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * minute of hour changed. + * + * @param minute the minute of hour to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalTime withMinuteOfHour(int minute) { + return withLocalMillis(getChronology().minuteOfHour().set(getLocalMillis(), minute)); + } + + /** + * Returns a copy of this time with the second of minute field updated. + *

      + * LocalTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * second of minute changed. + * + * @param second the second of minute to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalTime withSecondOfMinute(int second) { + return withLocalMillis(getChronology().secondOfMinute().set(getLocalMillis(), second)); + } + + /** + * Returns a copy of this time with the millis of second field updated. + *

      + * LocalTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * millis of second changed. + * + * @param millis the millis of second to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalTime withMillisOfSecond(int millis) { + return withLocalMillis(getChronology().millisOfSecond().set(getLocalMillis(), millis)); + } + + /** + * Returns a copy of this time with the millis of day field updated. + *

      + * LocalTime is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * millis of day changed. + * + * @param millis the millis of day to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + */ + public LocalTime withMillisOfDay(int millis) { + return withLocalMillis(getChronology().millisOfDay().set(getLocalMillis(), millis)); + } + + //----------------------------------------------------------------------- + /** + * Get the hour of day field property which provides access to advanced functionality. + * + * @return the hour of day property + */ + public Property hourOfDay() { + return new Property(this, getChronology().hourOfDay()); + } + + /** + * Get the minute of hour field property which provides access to advanced functionality. + * + * @return the minute of hour property + */ + public Property minuteOfHour() { + return new Property(this, getChronology().minuteOfHour()); + } + + /** + * Get the second of minute field property which provides access to advanced functionality. + * + * @return the second of minute property + */ + public Property secondOfMinute() { + return new Property(this, getChronology().secondOfMinute()); + } + + /** + * Get the millis of second property which provides access to advanced functionality. + * + * @return the millis of second property + */ + public Property millisOfSecond() { + return new Property(this, getChronology().millisOfSecond()); + } + + /** + * Get the millis of day property which provides access to advanced functionality. + * + * @return the millis of day property + */ + public Property millisOfDay() { + return new Property(this, getChronology().millisOfDay()); + } + + //----------------------------------------------------------------------- + /** + * Converts this LocalTime to a full datetime using the default time zone + * setting the time fields from this instance and the date fields from + * the current date. + * + * @return this time as a datetime using todays date + */ + public DateTime toDateTimeToday() { + return toDateTimeToday(null); + } + + /** + * Converts this LocalTime to a full datetime using the specified time zone + * setting the time fields from this instance and the date fields from + * the current time. + *

      + * This method uses the chronology from this instance plus the time zone + * specified. + * + * @param zone the zone to use, null means default + * @return this time as a datetime using todays date + */ + public DateTime toDateTimeToday(DateTimeZone zone) { + Chronology chrono = getChronology().withZone(zone); + long instantMillis = DateTimeUtils.currentTimeMillis(); + long resolved = chrono.set(this, instantMillis); + return new DateTime(resolved, chrono); + } + + //----------------------------------------------------------------------- + /** + * Output the time in ISO8601 format (HH:mm:ss.SSSZZ). + * + * @return ISO8601 time formatted string. + */ + @ToString + public String toString() { + return ISODateTimeFormat.time().print(this); + } + + /** + * Output the time using the specified format pattern. + * + * @param pattern the pattern specification, null means use toString + * @see org.joda.time.format.DateTimeFormat + */ + public String toString(String pattern) { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).print(this); + } + + /** + * Output the time using the specified format pattern. + * + * @param pattern the pattern specification, null means use toString + * @param locale Locale to use, null means default + * @see org.joda.time.format.DateTimeFormat + */ + public String toString(String pattern, Locale locale) throws IllegalArgumentException { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this); + } + + //----------------------------------------------------------------------- + /** + * LocalTime.Property binds a LocalTime to a DateTimeField allowing + * powerful datetime functionality to be easily accessed. + *

      + * The simplest use of this class is as an alternative get method, here used to + * get the minute '30'. + *

      +     * LocalTime dt = new LocalTime(12, 30);
      +     * int year = dt.minuteOfHour().get();
      +     * 
      + *

      + * Methods are also provided that allow time modification. These return + * new instances of LocalTime - they do not modify the original. The example + * below yields two independent immutable date objects 2 hours apart. + *

      +     * LocalTime dt1230 = new LocalTime(12, 30);
      +     * LocalTime dt1430 = dt1230.hourOfDay().setCopy(14);
      +     * 
      + *

      + * LocalTime.Property itself is thread-safe and immutable, as well as the + * LocalTime being operated on. + * + * @author Stephen Colebourne + * @author Brian S O'Neill + * @since 1.3 + */ + public static final class Property extends AbstractReadableInstantFieldProperty { + + /** Serialization version */ + private static final long serialVersionUID = -325842547277223L; + + /** The instant this property is working against */ + private transient LocalTime iInstant; + /** The field this property is working against */ + private transient DateTimeField iField; + + /** + * Constructor. + * + * @param instant the instant to set + * @param field the field to use + */ + Property(LocalTime instant, DateTimeField field) { + super(); + iInstant = instant; + iField = field; + } + + /** + * Writes the property in a safe serialization format. + */ + private void writeObject(ObjectOutputStream oos) throws IOException { + oos.writeObject(iInstant); + oos.writeObject(iField.getType()); + } + + /** + * Reads the property from a safe serialization format. + */ + private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException { + iInstant = (LocalTime) oos.readObject(); + DateTimeFieldType type = (DateTimeFieldType) oos.readObject(); + iField = type.getField(iInstant.getChronology()); + } + + //----------------------------------------------------------------------- + /** + * Gets the field being used. + * + * @return the field + */ + public DateTimeField getField() { + return iField; + } + + /** + * Gets the milliseconds of the time that this property is linked to. + * + * @return the milliseconds + */ + protected long getMillis() { + return iInstant.getLocalMillis(); + } + + /** + * Gets the chronology of the datetime that this property is linked to. + * + * @return the chronology + * @since 1.4 + */ + protected Chronology getChronology() { + return iInstant.getChronology(); + } + + /** + * Gets the LocalTime object linked to this property. + * + * @return the linked LocalTime + */ + public LocalTime getLocalTime() { + return iInstant; + } + + //----------------------------------------------------------------------- + /** + * Adds to this field in a copy of this LocalTime. + *

      + * The LocalTime attached to this property is unchanged by this call. + * + * @param value the value to add to the field in the copy + * @return a copy of the LocalTime with the field value changed + */ + public LocalTime addCopy(int value) { + return iInstant.withLocalMillis(iField.add(iInstant.getLocalMillis(), value)); + } + + /** + * Adds to this field in a copy of this LocalTime. + * If the addition exceeds the maximum value (eg. 23:59) it will + * wrap to the minimum value (eg. 00:00). + *

      + * The LocalTime attached to this property is unchanged by this call. + * + * @param value the value to add to the field in the copy + * @return a copy of the LocalTime with the field value changed + */ + public LocalTime addCopy(long value) { + return iInstant.withLocalMillis(iField.add(iInstant.getLocalMillis(), value)); + } + + /** + * Adds to this field in a copy of this LocalTime. + * If the addition exceeds the maximum value (eg. 23:59) then + * an exception will be thrown. + * Contrast this behaviour to {@link #addCopy(int)}. + *

      + * The LocalTime attached to this property is unchanged by this call. + * + * @param value the value to add to the field in the copy + * @return a copy of the LocalTime with the field value changed + * @throws IllegalArgumentException if the result is invalid + */ + public LocalTime addNoWrapToCopy(int value) { + long millis = iField.add(iInstant.getLocalMillis(), value); + long rounded = iInstant.getChronology().millisOfDay().get(millis); + if (rounded != millis) { + throw new IllegalArgumentException("The addition exceeded the boundaries of LocalTime"); + } + return iInstant.withLocalMillis(millis); + } + + /** + * Adds to this field, possibly wrapped, in a copy of this LocalTime. + * A field wrapped operation only changes this field. + * Thus 10:59 plusWrapField one minute goes to 10:00. + *

      + * The LocalTime attached to this property is unchanged by this call. + * + * @param value the value to add to the field in the copy + * @return a copy of the LocalTime with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public LocalTime addWrapFieldToCopy(int value) { + return iInstant.withLocalMillis(iField.addWrapField(iInstant.getLocalMillis(), value)); + } + + //----------------------------------------------------------------------- + /** + * Sets this field in a copy of the LocalTime. + *

      + * The LocalTime attached to this property is unchanged by this call. + * + * @param value the value to set the field in the copy to + * @return a copy of the LocalTime with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public LocalTime setCopy(int value) { + return iInstant.withLocalMillis(iField.set(iInstant.getLocalMillis(), value)); + } + + /** + * Sets this field in a copy of the LocalTime to a parsed text value. + *

      + * The LocalTime attached to this property is unchanged by this call. + * + * @param text the text value to set + * @param locale optional locale to use for selecting a text symbol + * @return a copy of the LocalTime with the field value changed + * @throws IllegalArgumentException if the text value isn't valid + */ + public LocalTime setCopy(String text, Locale locale) { + return iInstant.withLocalMillis(iField.set(iInstant.getLocalMillis(), text, locale)); + } + + /** + * Sets this field in a copy of the LocalTime to a parsed text value. + *

      + * The LocalTime attached to this property is unchanged by this call. + * + * @param text the text value to set + * @return a copy of the LocalTime with the field value changed + * @throws IllegalArgumentException if the text value isn't valid + */ + public LocalTime setCopy(String text) { + return setCopy(text, null); + } + + //----------------------------------------------------------------------- + /** + * Returns a new LocalTime with this field set to the maximum value + * for this field. + *

      + * The LocalTime attached to this property is unchanged by this call. + * + * @return a copy of the LocalTime with this field set to its maximum + */ + public LocalTime withMaximumValue() { + return setCopy(getMaximumValue()); + } + + /** + * Returns a new LocalTime with this field set to the minimum value + * for this field. + *

      + * The LocalTime attached to this property is unchanged by this call. + * + * @return a copy of the LocalTime with this field set to its minimum + */ + public LocalTime withMinimumValue() { + return setCopy(getMinimumValue()); + } + + //----------------------------------------------------------------------- + /** + * Rounds to the lowest whole unit of this field on a copy of this + * LocalTime. + *

      + * For example, rounding floor on the hourOfDay field of a LocalTime + * where the time is 10:30 would result in new LocalTime with the + * time of 10:00. + * + * @return a copy of the LocalTime with the field value changed + */ + public LocalTime roundFloorCopy() { + return iInstant.withLocalMillis(iField.roundFloor(iInstant.getLocalMillis())); + } + + /** + * Rounds to the highest whole unit of this field on a copy of this + * LocalTime. + *

      + * For example, rounding floor on the hourOfDay field of a LocalTime + * where the time is 10:30 would result in new LocalTime with the + * time of 11:00. + * + * @return a copy of the LocalTime with the field value changed + */ + public LocalTime roundCeilingCopy() { + return iInstant.withLocalMillis(iField.roundCeiling(iInstant.getLocalMillis())); + } + + /** + * Rounds to the nearest whole unit of this field on a copy of this + * LocalTime, favoring the floor if halfway. + * + * @return a copy of the LocalTime with the field value changed + */ + public LocalTime roundHalfFloorCopy() { + return iInstant.withLocalMillis(iField.roundHalfFloor(iInstant.getLocalMillis())); + } + + /** + * Rounds to the nearest whole unit of this field on a copy of this + * LocalTime, favoring the ceiling if halfway. + * + * @return a copy of the LocalTime with the field value changed + */ + public LocalTime roundHalfCeilingCopy() { + return iInstant.withLocalMillis(iField.roundHalfCeiling(iInstant.getLocalMillis())); + } + + /** + * Rounds to the nearest whole unit of this field on a copy of this + * LocalTime. If halfway, the ceiling is favored over the floor + * only if it makes this field's value even. + * + * @return a copy of the LocalTime with the field value changed + */ + public LocalTime roundHalfEvenCopy() { + return iInstant.withLocalMillis(iField.roundHalfEven(iInstant.getLocalMillis())); + } + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/Minutes.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/Minutes.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/Minutes.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,471 @@ +/* + * Copyright 2001-2010 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; +import org.joda.time.base.BaseSingleFieldPeriod; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.ISOPeriodFormat; +import org.joda.time.format.PeriodFormatter; + +/** + * An immutable time period representing a number of minutes. + *

      + * Minutes is an immutable period that can only store minutes. + * It does not store years, months or hours for example. As such it is a + * type-safe way of representing a number of minutes in an application. + *

      + * The number of minutes is set in the constructor, and may be queried using + * getMinutes(). Basic mathematical operations are provided - + * plus(), minus(), multipliedBy() and + * dividedBy(). + *

      + * Minutes is thread-safe and immutable. + * + * @author Stephen Colebourne + * @since 1.4 + */ +public final class Minutes extends BaseSingleFieldPeriod { + + /** Constant representing zero minutes. */ + public static final Minutes ZERO = new Minutes(0); + /** Constant representing one minute. */ + public static final Minutes ONE = new Minutes(1); + /** Constant representing two minutes. */ + public static final Minutes TWO = new Minutes(2); + /** Constant representing three minutes. */ + public static final Minutes THREE = new Minutes(3); + /** Constant representing the maximum number of minutes that can be stored in this object. */ + public static final Minutes MAX_VALUE = new Minutes(Integer.MAX_VALUE); + /** Constant representing the minimum number of minutes that can be stored in this object. */ + public static final Minutes MIN_VALUE = new Minutes(Integer.MIN_VALUE); + + /** The paser to use for this class. */ + private static final PeriodFormatter PARSER = ISOPeriodFormat.standard().withParseType(PeriodType.minutes()); + /** Serialization version. */ + private static final long serialVersionUID = 87525275727380863L; + + //----------------------------------------------------------------------- + /** + * Obtains an instance of Minutes that may be cached. + * Minutes is immutable, so instances can be cached and shared. + * This factory method provides access to shared instances. + * + * @param minutes the number of minutes to obtain an instance for + * @return the instance of Minutes + */ + public static Minutes minutes(int minutes) { + switch (minutes) { + case 0: + return ZERO; + case 1: + return ONE; + case 2: + return TWO; + case 3: + return THREE; + case Integer.MAX_VALUE: + return MAX_VALUE; + case Integer.MIN_VALUE: + return MIN_VALUE; + default: + return new Minutes(minutes); + } + } + + //----------------------------------------------------------------------- + /** + * Creates a Minutes representing the number of whole minutes + * between the two specified datetimes. + * + * @param start the start instant, must not be null + * @param end the end instant, must not be null + * @return the period in minutes + * @throws IllegalArgumentException if the instants are null or invalid + */ + public static Minutes minutesBetween(ReadableInstant start, ReadableInstant end) { + int amount = BaseSingleFieldPeriod.between(start, end, DurationFieldType.minutes()); + return Minutes.minutes(amount); + } + + /** + * Creates a Minutes representing the number of whole minutes + * between the two specified partial datetimes. + *

      + * The two partials must contain the same fields, for example you can specify + * two LocalTime objects. + * + * @param start the start partial date, must not be null + * @param end the end partial date, must not be null + * @return the period in minutes + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Minutes minutesBetween(ReadablePartial start, ReadablePartial end) { + if (start instanceof LocalTime && end instanceof LocalTime) { + Chronology chrono = DateTimeUtils.getChronology(start.getChronology()); + int minutes = chrono.minutes().getDifference( + ((LocalTime) end).getLocalMillis(), ((LocalTime) start).getLocalMillis()); + return Minutes.minutes(minutes); + } + int amount = BaseSingleFieldPeriod.between(start, end, ZERO); + return Minutes.minutes(amount); + } + + /** + * Creates a Minutes representing the number of whole minutes + * in the specified interval. + * + * @param interval the interval to extract minutes from, null returns zero + * @return the period in minutes + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Minutes minutesIn(ReadableInterval interval) { + if (interval == null) { + return Minutes.ZERO; + } + int amount = BaseSingleFieldPeriod.between(interval.getStart(), interval.getEnd(), DurationFieldType.minutes()); + return Minutes.minutes(amount); + } + + /** + * Creates a new Minutes representing the number of complete + * standard length minutes in the specified period. + *

      + * This factory method converts all fields from the period to minutes using standardised + * durations for each field. Only those fields which have a precise duration in + * the ISO UTC chronology can be converted. + *

        + *
      • One week consists of 7 days. + *
      • One day consists of 24 hours. + *
      • One hour consists of 60 minutes. + *
      • One minute consists of 60 seconds. + *
      • One second consists of 1000 milliseconds. + *
      + * Months and Years are imprecise and periods containing these values cannot be converted. + * + * @param period the period to get the number of minutes from, null returns zero + * @return the period in minutes + * @throws IllegalArgumentException if the period contains imprecise duration values + */ + public static Minutes standardMinutesIn(ReadablePeriod period) { + int amount = BaseSingleFieldPeriod.standardPeriodIn(period, DateTimeConstants.MILLIS_PER_MINUTE); + return Minutes.minutes(amount); + } + + /** + * Creates a new Minutes by parsing a string in the ISO8601 format 'PTnM'. + *

      + * The parse will accept the full ISO syntax of PnYnMnWnDTnHnMnS however only the + * minutes component may be non-zero. If any other component is non-zero, an exception + * will be thrown. + * + * @param periodStr the period string, null returns zero + * @return the period in minutes + * @throws IllegalArgumentException if the string format is invalid + */ + @FromString + public static Minutes parseMinutes(String periodStr) { + if (periodStr == null) { + return Minutes.ZERO; + } + Period p = PARSER.parsePeriod(periodStr); + return Minutes.minutes(p.getMinutes()); + } + + //----------------------------------------------------------------------- + /** + * Creates a new instance representing a number of minutes. + * You should consider using the factory method {@link #minutes(int)} + * instead of the constructor. + * + * @param minutes the number of minutes to represent + */ + private Minutes(int minutes) { + super(minutes); + } + + /** + * Resolves singletons. + * + * @return the singleton instance + */ + private Object readResolve() { + return Minutes.minutes(getValue()); + } + + //----------------------------------------------------------------------- + /** + * Gets the duration field type, which is minutes. + * + * @return the period type + */ + public DurationFieldType getFieldType() { + return DurationFieldType.minutes(); + } + + /** + * Gets the period type, which is minutes. + * + * @return the period type + */ + public PeriodType getPeriodType() { + return PeriodType.minutes(); + } + + //----------------------------------------------------------------------- + /** + * Converts this period in minutes to a period in weeks assuming a + * 7 days week, 24 hour day and 60 minute hour. + *

      + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all weeks are + * 7 days long, all days are 24 hours long and all hours are 60 minutes long. + * This is not true when daylight savings is considered and may also not + * be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of whole weeks for this number of minutes + */ + public Weeks toStandardWeeks() { + return Weeks.weeks(getValue() / DateTimeConstants.MINUTES_PER_WEEK); + } + + /** + * Converts this period in minutes to a period in days assuming a + * 24 hour day and 60 minute hour. + *

      + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all days are + * 24 hours long and all hours are 60 minutes long. + * This is not true when daylight savings is considered and may also not + * be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of whole days for this number of minutes + */ + public Days toStandardDays() { + return Days.days(getValue() / DateTimeConstants.MINUTES_PER_DAY); + } + + /** + * Converts this period in minutes to a period in hours assuming a + * 60 minute hour. + *

      + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all hours are + * 60 minutes long. + * This may not be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of hours for this number of minutes + */ + public Hours toStandardHours() { + return Hours.hours(getValue() / DateTimeConstants.MINUTES_PER_HOUR); + } + + /** + * Converts this period in minutes to a period in seconds assuming a + * 60 second minute. + *

      + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all minutes are + * 60 seconds long. + * This may not be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of seconds for this number of minutes + * @throws ArithmeticException if the number of seconds is too large to be represented + */ + public Seconds toStandardSeconds() { + return Seconds.seconds(FieldUtils.safeMultiply(getValue(), DateTimeConstants.SECONDS_PER_MINUTE)); + } + + //----------------------------------------------------------------------- + /** + * Converts this period in minutes to a duration in milliseconds assuming a + * 60 second minute. + *

      + * This method allows you to convert from a period to a duration. + * However to achieve this it makes the assumption that all minutes are + * 60 seconds long. This might not be true for an unusual chronology, + * for example one that takes leap seconds into account. + * However, the method is included as it is a useful operation for many + * applications and business rules. + * + * @return a duration equivalent to this number of minutes + */ + public Duration toStandardDuration() { + long minutes = getValue(); // assign to a long + return new Duration(minutes * DateTimeConstants.MILLIS_PER_MINUTE); + } + + //----------------------------------------------------------------------- + /** + * Gets the number of minutes that this period represents. + * + * @return the number of minutes in the period + */ + public int getMinutes() { + return getValue(); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of minutes added. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param minutes the amount of minutes to add, may be negative + * @return the new period plus the specified number of minutes + * @throws ArithmeticException if the result overflows an int + */ + public Minutes plus(int minutes) { + if (minutes == 0) { + return this; + } + return Minutes.minutes(FieldUtils.safeAdd(getValue(), minutes)); + } + + /** + * Returns a new instance with the specified number of minutes added. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param minutes the amount of minutes to add, may be negative, null means zero + * @return the new period plus the specified number of minutes + * @throws ArithmeticException if the result overflows an int + */ + public Minutes plus(Minutes minutes) { + if (minutes == null) { + return this; + } + return plus(minutes.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of minutes taken away. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param minutes the amount of minutes to take away, may be negative + * @return the new period minus the specified number of minutes + * @throws ArithmeticException if the result overflows an int + */ + public Minutes minus(int minutes) { + return plus(FieldUtils.safeNegate(minutes)); + } + + /** + * Returns a new instance with the specified number of minutes taken away. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param minutes the amount of minutes to take away, may be negative, null means zero + * @return the new period minus the specified number of minutes + * @throws ArithmeticException if the result overflows an int + */ + public Minutes minus(Minutes minutes) { + if (minutes == null) { + return this; + } + return minus(minutes.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the minutes multiplied by the specified scalar. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param scalar the amount to multiply by, may be negative + * @return the new period multiplied by the specified scalar + * @throws ArithmeticException if the result overflows an int + */ + public Minutes multipliedBy(int scalar) { + return Minutes.minutes(FieldUtils.safeMultiply(getValue(), scalar)); + } + + /** + * Returns a new instance with the minutes divided by the specified divisor. + * The calculation uses integer division, thus 3 divided by 2 is 1. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param divisor the amount to divide by, may be negative + * @return the new period divided by the specified divisor + * @throws ArithmeticException if the divisor is zero + */ + public Minutes dividedBy(int divisor) { + if (divisor == 1) { + return this; + } + return Minutes.minutes(getValue() / divisor); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the minutes value negated. + * + * @return the new period with a negated value + * @throws ArithmeticException if the result overflows an int + */ + public Minutes negated() { + return Minutes.minutes(FieldUtils.safeNegate(getValue())); + } + + //----------------------------------------------------------------------- + /** + * Is this minutes instance greater than the specified number of minutes. + * + * @param other the other period, null means zero + * @return true if this minutes instance is greater than the specified one + */ + public boolean isGreaterThan(Minutes other) { + if (other == null) { + return getValue() > 0; + } + return getValue() > other.getValue(); + } + + /** + * Is this minutes instance less than the specified number of minutes. + * + * @param other the other period, null means zero + * @return true if this minutes instance is less than the specified one + */ + public boolean isLessThan(Minutes other) { + if (other == null) { + return getValue() < 0; + } + return getValue() < other.getValue(); + } + + //----------------------------------------------------------------------- + /** + * Gets this instance as a String in the ISO8601 duration format. + *

      + * For example, "PT4M" represents 4 minutes. + * + * @return the value as an ISO8601 string + */ + @ToString + public String toString() { + return "PT" + String.valueOf(getValue()) + "M"; + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/MonthDay.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/MonthDay.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/MonthDay.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,974 @@ +/* + * Copyright 2001-2010 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; +import org.joda.time.base.BasePartial; +import org.joda.time.chrono.ISOChronology; +import org.joda.time.field.AbstractPartialFieldProperty; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.DateTimeFormatterBuilder; +import org.joda.time.format.ISODateTimeFormat; + +/** + * MonthDay is an immutable partial supporting the monthOfYear and dayOfMonth fields. + *

      + * NOTE: This class only supports the two fields listed above. + * It is impossible to query any other fields, such as dayOfWeek or centuryOfEra. + *

      + * Calculations on MonthDay are performed using a {@link Chronology}. + * This chronology is set to be in the UTC time zone for all calculations. + *

      + * One use case for this class is to store a birthday without the year (to avoid + * storing the age of the person). + * This class can be used as the gMonthDay type in XML Schema. + *

      + * Each individual field can be queried in two ways: + *

        + *
      • getMonthOfYear() + *
      • monthOfYear().get() + *
      + * The second technique also provides access to other useful methods on the + * field: + *
        + *
      • numeric value - monthOfYear().get() + *
      • text value - monthOfYear().getAsText() + *
      • short text value - monthOfYear().getAsShortText() + *
      • maximum/minimum values - monthOfYear().getMaximumValue() + *
      • add/subtract - monthOfYear().addToCopy() + *
      • set - monthOfYear().setCopy() + *
      + *

      + * MonthDay is thread-safe and immutable, provided that the Chronology is as well. + * All standard Chronology classes supplied are thread-safe and immutable. + * + * @author Chris Pheby + * @since 2.0 + */ +public final class MonthDay + extends BasePartial + implements ReadablePartial, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 2954560699050434609L; + + /** The singleton set of field types */ + private static final DateTimeFieldType[] FIELD_TYPES = new DateTimeFieldType[] { + DateTimeFieldType.monthOfYear(), + DateTimeFieldType.dayOfMonth(), }; + + /** The singleton set of field types */ + private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder() + .appendOptional(ISODateTimeFormat.localDateParser().getParser()) + .appendOptional(DateTimeFormat.forPattern("--MM-dd").getParser()).toFormatter(); + + /** The index of the monthOfYear field in the field array */ + public static final int MONTH_OF_YEAR = 0; + /** The index of the day field in the field array */ + public static final int DAY_OF_MONTH = 1; + + //----------------------------------------------------------------------- + /** + * Obtains a {@code MonthDay} set to the current system millisecond time + * using ISOChronology in the default time zone. + * The resulting object does not use the zone. + * + * @return the current month-day, not null + * @since 2.0 + */ + public static MonthDay now() { + return new MonthDay(); + } + + /** + * Obtains a {@code MonthDay} set to the current system millisecond time + * using ISOChronology in the specified time zone. + * The resulting object does not use the zone. + * + * @param zone the time zone, not null + * @return the current month-day, not null + * @since 2.0 + */ + public static MonthDay now(DateTimeZone zone) { + if (zone == null) { + throw new NullPointerException("Zone must not be null"); + } + return new MonthDay(zone); + } + + /** + * Obtains a {@code MonthDay} set to the current system millisecond time + * using the specified chronology. + * The resulting object does not use the zone. + * + * @param chronology the chronology, not null + * @return the current month-day, not null + * @since 2.0 + */ + public static MonthDay now(Chronology chronology) { + if (chronology == null) { + throw new NullPointerException("Chronology must not be null"); + } + return new MonthDay(chronology); + } + + //----------------------------------------------------------------------- + /** + * Parses a {@code MonthDay} from the specified string. + *

      + * This uses {@link ISODateTimeFormat#localDateParser()} or the format {@code --MM-dd}. + * + * @param str the string to parse, not null + * @since 2.0 + */ + @FromString + public static MonthDay parse(String str) { + return parse(str, PARSER); + } + + /** + * Parses a {@code MonthDay} from the specified string using a formatter. + * + * @param str the string to parse, not null + * @param formatter the formatter to use, not null + * @since 2.0 + */ + public static MonthDay parse(String str, DateTimeFormatter formatter) { + LocalDate date = formatter.parseLocalDate(str); + return new MonthDay(date.getMonthOfYear(), date.getDayOfMonth()); + } + + //----------------------------------------------------------------------- + /** + * Constructs a MonthDay from a java.util.Calendar + * using exactly the same field values avoiding any time zone effects. + *

      + * Each field is queried from the Calendar and assigned to the MonthDay. + *

      + * This factory method ignores the type of the calendar and always + * creates a MonthDay with ISO chronology. It is expected that you + * will only pass in instances of GregorianCalendar however + * this is not validated. + * + * @param calendar the Calendar to extract fields from + * @return the created MonthDay, never null + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the monthOfYear or dayOfMonth is invalid for the ISO chronology + */ + public static MonthDay fromCalendarFields(Calendar calendar) { + if (calendar == null) { + throw new IllegalArgumentException("The calendar must not be null"); + } + return new MonthDay(calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.DAY_OF_MONTH)); + } + + /** + * Constructs a MonthDay from a java.util.Date + * using exactly the same field values avoiding any time zone effects. + *

      + * Each field is queried from the Date and assigned to the MonthDay. + *

      + * This factory method always creates a MonthDay with ISO chronology. + * + * @param date the Date to extract fields from + * @return the created MonthDay, never null + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the monthOfYear or dayOfMonth is invalid for the ISO chronology + */ + @SuppressWarnings("deprecation") + public static MonthDay fromDateFields(Date date) { + if (date == null) { + throw new IllegalArgumentException("The date must not be null"); + } + return new MonthDay(date.getMonth() + 1, date.getDate()); + } + + //----------------------------------------------------------------------- + /** + * Constructs a MonthDay with the current monthOfYear, using ISOChronology in + * the default zone to extract the fields. + *

      + * The constructor uses the default time zone, resulting in the local time + * being initialised. Once the constructor is complete, all further calculations + * are performed without reference to a time-zone (by switching to UTC). + * + * @see #now() + */ + public MonthDay() { + super(); + } + + /** + * Constructs a MonthDay with the current month-day, using ISOChronology in + * the specified zone to extract the fields. + *

      + * The constructor uses the specified time zone to obtain the current month-day. + * Once the constructor is complete, all further calculations + * are performed without reference to a time-zone (by switching to UTC). + * + * @param zone the zone to use, null means default zone + * @see #now(DateTimeZone) + */ + public MonthDay(DateTimeZone zone) { + super(ISOChronology.getInstance(zone)); + } + + /** + * Constructs a MonthDay with the current month-day, using the specified chronology + * and zone to extract the fields. + *

      + * The constructor uses the time zone of the chronology specified. + * Once the constructor is complete, all further calculations are performed + * without reference to a time-zone (by switching to UTC). + * + * @param chronology the chronology, null means ISOChronology in the default zone + * @see #now(Chronology) + */ + public MonthDay(Chronology chronology) { + super(chronology); + } + + /** + * Constructs a MonthDay extracting the partial fields from the specified + * milliseconds using the ISOChronology in the default zone. + *

      + * The constructor uses the default time zone, resulting in the local time + * being initialised. Once the constructor is complete, all further calculations + * are performed without reference to a time-zone (by switching to UTC). + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z + */ + public MonthDay(long instant) { + super(instant); + } + + /** + * Constructs a MonthDay extracting the partial fields from the specified + * milliseconds using the chronology provided. + *

      + * The constructor uses the time zone of the chronology specified. + * Once the constructor is complete, all further calculations are performed + * without reference to a time-zone (by switching to UTC). + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z + * @param chronology the chronology, null means ISOChronology in the default zone + */ + public MonthDay(long instant, Chronology chronology) { + super(instant, chronology); + } + + /** + * Constructs a MonthDay from an Object that represents some form of time. + *

      + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#localDateParser()}. + *

      + * The chronology used will be derived from the object, defaulting to ISO. + * + * @param instant the date-time object, null means now + * @throws IllegalArgumentException if the instant is invalid + */ + public MonthDay(Object instant) { + super(instant, null, ISODateTimeFormat.localDateParser()); + } + + /** + * Constructs a MonthDay from an Object that represents some form of time, + * using the specified chronology. + *

      + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#localDateParser()}. + *

      + * The constructor uses the time zone of the chronology specified. + * Once the constructor is complete, all further calculations are performed + * without reference to a time-zone (by switching to UTC). + * The specified chronology overrides that of the object. + * + * @param instant the date-time object, null means now + * @param chronology the chronology, null means ISO default + * @throws IllegalArgumentException if the instant is invalid + */ + public MonthDay(Object instant, Chronology chronology) { + super(instant, DateTimeUtils.getChronology(chronology), ISODateTimeFormat.localDateParser()); + } + + /** + * Constructs a MonthDay with specified year and month + * using ISOChronology. + *

      + * The constructor uses the no time zone initialising the fields as provided. + * Once the constructor is complete, all further calculations + * are performed without reference to a time-zone (by switching to UTC). + * + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + */ + public MonthDay(int monthOfYear, int dayOfMonth) { + this(monthOfYear, dayOfMonth, null); + } + + /** + * Constructs an instance set to the specified monthOfYear and dayOfMonth + * using the specified chronology, whose zone is ignored. + *

      + * If the chronology is null, ISOChronology is used. + *

      + * The constructor uses the time zone of the chronology specified. + * Once the constructor is complete, all further calculations are performed + * without reference to a time-zone (by switching to UTC). + * + * @param monthOfYear the month of the year + * @param dayOfMonth the day of the month + * @param chronology the chronology, null means ISOChronology in the default zone + */ + public MonthDay(int monthOfYear, int dayOfMonth, Chronology chronology) { + super(new int[] {monthOfYear, dayOfMonth}, chronology); + } + + /** + * Constructs a MonthDay with chronology from this instance and new values. + * + * @param partial the partial to base this new instance on + * @param values the new set of values + */ + MonthDay(MonthDay partial, int[] values) { + super(partial, values); + } + + /** + * Constructs a MonthDay with values from this instance and a new chronology. + * + * @param partial the partial to base this new instance on + * @param chrono the new chronology + */ + MonthDay(MonthDay partial, Chronology chrono) { + super(partial, chrono); + } + + /** + * Handle broken serialization from other tools. + * @return the resolved object, not null + */ + private Object readResolve() { + if (DateTimeZone.UTC.equals(getChronology().getZone()) == false) { + return new MonthDay(this, getChronology().withUTC()); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets the number of fields in this partial, which is two. + * The supported fields are MonthOfYear and DayOfMonth. + * Note that only these fields may be queried. + * + * @return the field count, two + */ + public int size() { + return 2; + } + + /** + * Gets the field for a specific index in the chronology specified. + *

      + * This method must not use any instance variables. + * + * @param index the index to retrieve + * @param chrono the chronology to use + * @return the field, never null + */ + protected DateTimeField getField(int index, Chronology chrono) { + switch (index) { + case MONTH_OF_YEAR: + return chrono.monthOfYear(); + case DAY_OF_MONTH: + return chrono.dayOfMonth(); + default: + throw new IndexOutOfBoundsException("Invalid index: " + index); + } + } + + /** + * Gets the field type at the specified index. + * + * @param index the index to retrieve + * @return the field at the specified index, never null + * @throws IndexOutOfBoundsException if the index is invalid + */ + public DateTimeFieldType getFieldType(int index) { + return FIELD_TYPES[index]; + } + + /** + * Gets an array of the field type of each of the fields that this partial supports. + *

      + * The fields are returned largest to smallest, Month, Day. + * + * @return the array of field types (cloned), largest to smallest, never null + */ + public DateTimeFieldType[] getFieldTypes() { + return (DateTimeFieldType[]) FIELD_TYPES.clone(); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this month-day with the specified chronology. + * This instance is immutable and unaffected by this method call. + *

      + * This method retains the values of the fields, thus the result will + * typically refer to a different instant. + *

      + * The time zone of the specified chronology is ignored, as MonthDay + * operates without a time zone. + * + * @param newChronology the new chronology, null means ISO + * @return a copy of this month-day with a different chronology, never null + * @throws IllegalArgumentException if the values are invalid for the new chronology + */ + public MonthDay withChronologyRetainFields(Chronology newChronology) { + newChronology = DateTimeUtils.getChronology(newChronology); + newChronology = newChronology.withUTC(); + if (newChronology == getChronology()) { + return this; + } else { + MonthDay newMonthDay = new MonthDay(this, newChronology); + newChronology.validate(newMonthDay, getValues()); + return newMonthDay; + } + } + + /** + * Returns a copy of this month-day with the specified field set to a new value. + *

      + * For example, if the field type is dayOfMonth then the day + * would be changed in the returned instance. + *

      + * These three lines are equivalent: + *

      +     * MonthDay updated = md.withField(DateTimeFieldType.dayOfMonth(), 6);
      +     * MonthDay updated = md.dayOfMonth().setCopy(6);
      +     * MonthDay updated = md.property(DateTimeFieldType.dayOfMonth()).setCopy(6);
      +     * 
      + * + * @param fieldType the field type to set, not null + * @param value the value to set + * @return a copy of this instance with the field set, never null + * @throws IllegalArgumentException if the value is null or invalid + */ + public MonthDay withField(DateTimeFieldType fieldType, int value) { + int index = indexOfSupported(fieldType); + if (value == getValue(index)) { + return this; + } + int[] newValues = getValues(); + newValues = getField(index).set(this, index, newValues, value); + return new MonthDay(this, newValues); + } + + /** + * Returns a copy of this month-day with the value of the specified field increased. + *

      + * If the addition is zero, then this is returned. + *

      + * These three lines are equivalent: + *

      +     * MonthDay added = md.withFieldAdded(DurationFieldType.days(), 6);
      +     * MonthDay added = md.plusDays(6);
      +     * MonthDay added = md.dayOfMonth().addToCopy(6);
      +     * 
      + * + * @param fieldType the field type to add to, not null + * @param amount the amount to add + * @return a copy of this instance with the field updated, never null + * @throws IllegalArgumentException if the value is null or invalid + * @throws ArithmeticException if the new date-time exceeds the capacity + */ + public MonthDay withFieldAdded(DurationFieldType fieldType, int amount) { + int index = indexOfSupported(fieldType); + if (amount == 0) { + return this; + } + int[] newValues = getValues(); + newValues = getField(index).add(this, index, newValues, amount); + return new MonthDay(this, newValues); + } + + /** + * Returns a copy of this month-day with the specified period added. + *

      + * If the addition is zero, then this is returned. + * Fields in the period that aren't present in the partial are ignored. + *

      + * This method is typically used to add multiple copies of complex + * period instances. Adding one field is best achieved using methods + * like {@link #withFieldAdded(DurationFieldType, int)} + * or {@link #plusMonths(int)}. + * + * @param period the period to add to this one, null means zero + * @param scalar the amount of times to add, such as -1 to subtract once + * @return a copy of this instance with the period added, never null + * @throws ArithmeticException if the new date-time exceeds the capacity + */ + public MonthDay withPeriodAdded(ReadablePeriod period, int scalar) { + if (period == null || scalar == 0) { + return this; + } + int[] newValues = getValues(); + for (int i = 0; i < period.size(); i++) { + DurationFieldType fieldType = period.getFieldType(i); + int index = indexOf(fieldType); + if (index >= 0) { + newValues = getField(index).add(this, index, newValues, + FieldUtils.safeMultiply(period.getValue(i), scalar)); + } + } + return new MonthDay(this, newValues); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this month-day with the specified period added. + *

      + * If the amount is zero or null, then this is returned. + *

      + * This method is typically used to add complex period instances. + * Adding one field is best achieved using methods + * like {@link #plusMonths(int)}. + * + * @param period the duration to add to this one, null means zero + * @return a copy of this instance with the period added, never null + * @throws ArithmeticException if the new month-day exceeds the capacity + */ + public MonthDay plus(ReadablePeriod period) { + return withPeriodAdded(period, 1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this month-day plus the specified number of months. + *

      + * This month-day instance is immutable and unaffected by this method call. + * The month will wrap at the end of the year from December to January. + * The day will be adjusted to the last valid value if necessary. + *

      + * The following three lines are identical in effect: + *

      +     * MonthDay added = md.plusMonths(6);
      +     * MonthDay added = md.plus(Period.months(6));
      +     * MonthDay added = md.withFieldAdded(DurationFieldType.months(), 6);
      +     * 
      + * + * @param months the amount of months to add, may be negative + * @return the new month-day plus the increased months, never null + */ + public MonthDay plusMonths(int months) { + return withFieldAdded(DurationFieldType.months(), months); + } + + /** + * Returns a copy of this month-day plus the specified number of days. + *

      + * This month-day instance is immutable and unaffected by this method call. + * The month will wrap at the end of the year from December to January. + *

      + * The following three lines are identical in effect: + *

      +     * MonthDay added = md.plusDays(6);
      +     * MonthDay added = md.plus(Period.days(6));
      +     * MonthDay added = md.withFieldAdded(DurationFieldType.days(), 6);
      +     * 
      + * + * @param days the amount of days to add, may be negative + * @return the new month-day plus the increased days, never null + */ + public MonthDay plusDays(int days) { + return withFieldAdded(DurationFieldType.days(), days); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this month-day with the specified period taken away. + *

      + * If the amount is zero or null, then this is returned. + *

      + * This method is typically used to subtract complex period instances. + * Subtracting one field is best achieved using methods + * like {@link #minusMonths(int)}. + * + * @param period the period to reduce this instant by + * @return a copy of this instance with the period taken away, never null + * @throws ArithmeticException if the new month-day exceeds the capacity + */ + public MonthDay minus(ReadablePeriod period) { + return withPeriodAdded(period, -1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this month-day minus the specified number of months. + *

      + * This MonthDay instance is immutable and unaffected by this method call. + * The month will wrap at the end of the year from January to December. + * The day will be adjusted to the last valid value if necessary. + *

      + * The following three lines are identical in effect: + *

      +     * MonthDay subtracted = md.minusMonths(6);
      +     * MonthDay subtracted = md.minus(Period.months(6));
      +     * MonthDay subtracted = md.withFieldAdded(DurationFieldType.months(), -6);
      +     * 
      + * + * @param months the amount of months to subtract, may be negative + * @return the new month-day minus the increased months, never null + */ + public MonthDay minusMonths(int months) { + return withFieldAdded(DurationFieldType.months(), FieldUtils.safeNegate(months)); + } + + /** + * Returns a copy of this month-day minus the specified number of months. + *

      + * This month-day instance is immutable and unaffected by this method call. + * The month will wrap at the end of the year from January to December. + *

      + * The following three lines are identical in effect: + *

      +     * MonthDay subtracted = md.minusDays(6);
      +     * MonthDay subtracted = md.minus(Period.days(6));
      +     * MonthDay subtracted = md.withFieldAdded(DurationFieldType.days(), -6);
      +     * 
      + * + * @param days the amount of days to subtract, may be negative + * @return the new month-day minus the increased days, never null + */ + public MonthDay minusDays(int days) { + return withFieldAdded(DurationFieldType.days(), FieldUtils.safeNegate(days)); + } + + //----------------------------------------------------------------------- + /** + * Converts this object to a LocalDate with the same month-day and chronology. + * + * @param year the year to use, valid for chronology + * @return a LocalDate with the same month-day and chronology, never null + */ + public LocalDate toLocalDate(int year) { + return new LocalDate(year, getMonthOfYear(), getDayOfMonth(), getChronology()); + } + + //----------------------------------------------------------------------- + /** + * Get the month of year field value. + * + * @return the month of year + */ + public int getMonthOfYear() { + return getValue(MONTH_OF_YEAR); + } + + /** + * Get the day of month field value. + * + * @return the day of month + */ + public int getDayOfMonth() { + return getValue(DAY_OF_MONTH); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this month-day with the month of year field updated. + *

      + * MonthDay is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * month of year changed. + * + * @param monthOfYear the month of year to set + * @return a copy of this object with the field set, never null + * @throws IllegalArgumentException if the value is invalid + */ + public MonthDay withMonthOfYear(int monthOfYear) { + int[] newValues = getValues(); + newValues = getChronology().monthOfYear().set(this, MONTH_OF_YEAR, newValues, monthOfYear); + return new MonthDay(this, newValues); + } + + /** + * Returns a copy of this month-day with the day of month field updated. + *

      + * MonthDay is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of month changed. + * + * @param dayOfMonth the day of month to set + * @return a copy of this object with the field set, never null + * @throws IllegalArgumentException if the value is invalid + */ + public MonthDay withDayOfMonth(int dayOfMonth) { + int[] newValues = getValues(); + newValues = getChronology().dayOfMonth().set(this, DAY_OF_MONTH, newValues, dayOfMonth); + return new MonthDay(this, newValues); + } + + //----------------------------------------------------------------------- + /** + * Gets the property object for the specified type, which contains + * many useful methods. + * + * @param type the field type to get the property for + * @return the property object + * @throws IllegalArgumentException if the field is null or unsupported + */ + public Property property(DateTimeFieldType type) { + return new Property(this, indexOfSupported(type)); + } + + //----------------------------------------------------------------------- + /** + * Get the month of year field property which provides access to advanced functionality. + * + * @return the month of year property + */ + public Property monthOfYear() { + return new Property(this, MONTH_OF_YEAR); + } + + /** + * Get the day of month field property which provides access to advanced functionality. + * + * @return the day of month property + */ + public Property dayOfMonth() { + return new Property(this, DAY_OF_MONTH); + } + + //----------------------------------------------------------------------- + /** + * Output the month-day in ISO8601 format (--MM-dd). + * + * @return ISO8601 time formatted string. + */ + @ToString + public String toString() { + List fields = new ArrayList(); + fields.add(DateTimeFieldType.monthOfYear()); + fields.add(DateTimeFieldType.dayOfMonth()); + return ISODateTimeFormat.forFields(fields, true, true).print(this); + } + + /** + * Output the month-day using the specified format pattern. + * + * @param pattern the pattern specification, null means use toString + * @see org.joda.time.format.DateTimeFormat + */ + public String toString(String pattern) { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).print(this); + } + + /** + * Output the month-day using the specified format pattern. + * + * @param pattern the pattern specification, null means use toString + * @param locale Locale to use, null means default + * @see org.joda.time.format.DateTimeFormat + */ + public String toString(String pattern, Locale locale) throws IllegalArgumentException { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this); + } + + //----------------------------------------------------------------------- + /** + * The property class for MonthDay. + *

      + * This class binds a YearMonth to a DateTimeField. + * + * @author Chris Pheby + * @since 2.0 + */ + public static class Property extends AbstractPartialFieldProperty implements Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 5727734012190224363L; + + /** The partial */ + private final MonthDay iBase; + /** The field index */ + private final int iFieldIndex; + + /** + * Constructs a property. + * + * @param partial the partial instance + * @param fieldIndex the index in the partial + */ + Property(MonthDay partial, int fieldIndex) { + super(); + iBase = partial; + iFieldIndex = fieldIndex; + } + + /** + * Gets the field that this property uses. + * + * @return the field + */ + public DateTimeField getField() { + return iBase.getField(iFieldIndex); + } + + /** + * Gets the partial that this property belongs to. + * + * @return the partial + */ + protected ReadablePartial getReadablePartial() { + return iBase; + } + + /** + * Gets the partial that this property belongs to. + * + * @return the partial + */ + public MonthDay getMonthDay() { + return iBase; + } + + /** + * Gets the value of this field. + * + * @return the field value + */ + public int get() { + return iBase.getValue(iFieldIndex); + } + + //----------------------------------------------------------------------- + /** + * Adds to the value of this field in a copy of this MonthDay. + *

      + * The value will be added to this field. If the value is too large to be + * added solely to this field then it will affect larger fields. + * Smaller fields are unaffected. + *

      + * The MonthDay attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param valueToAdd the value to add to the field in the copy + * @return a copy of the MonthDay with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public MonthDay addToCopy(int valueToAdd) { + int[] newValues = iBase.getValues(); + newValues = getField().add(iBase, iFieldIndex, newValues, valueToAdd); + return new MonthDay(iBase, newValues); + } + + /** + * Adds to the value of this field in a copy of this MonthDay wrapping + * within this field if the maximum value is reached. + *

      + * The value will be added to this field. If the value is too large to be + * added solely to this field then it wraps within this field. + * Other fields are unaffected. + *

      + * For example, + * --12-30 addWrapField one month returns --01-30. + *

      + * The MonthDay attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param valueToAdd the value to add to the field in the copy + * @return a copy of the MonthDay with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public MonthDay addWrapFieldToCopy(int valueToAdd) { + int[] newValues = iBase.getValues(); + newValues = getField().addWrapField(iBase, iFieldIndex, newValues, valueToAdd); + return new MonthDay(iBase, newValues); + } + + //----------------------------------------------------------------------- + /** + * Sets this field in a copy of the MonthDay. + *

      + * The MonthDay attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param value the value to set the field in the copy to + * @return a copy of the MonthDay with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public MonthDay setCopy(int value) { + int[] newValues = iBase.getValues(); + newValues = getField().set(iBase, iFieldIndex, newValues, value); + return new MonthDay(iBase, newValues); + } + + /** + * Sets this field in a copy of the MonthDay to a parsed text value. + *

      + * The MonthDay attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param text the text value to set + * @param locale optional locale to use for selecting a text symbol + * @return a copy of the MonthDay with the field value changed + * @throws IllegalArgumentException if the text value isn't valid + */ + public MonthDay setCopy(String text, Locale locale) { + int[] newValues = iBase.getValues(); + newValues = getField().set(iBase, iFieldIndex, newValues, text, locale); + return new MonthDay(iBase, newValues); + } + + /** + * Sets this field in a copy of the MonthDay to a parsed text value. + *

      + * The MonthDay attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param text the text value to set + * @return a copy of the MonthDay with the field value changed + * @throws IllegalArgumentException if the text value isn't valid + */ + public MonthDay setCopy(String text) { + return setCopy(text, null); + } + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/Months.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/Months.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/Months.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,397 @@ +/* + * Copyright 2001-2010 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; +import org.joda.time.base.BaseSingleFieldPeriod; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.ISOPeriodFormat; +import org.joda.time.format.PeriodFormatter; + +/** + * An immutable time period representing a number of months. + *

      + * Months is an immutable period that can only store months. + * It does not store years, days or hours for example. As such it is a + * type-safe way of representing a number of months in an application. + *

      + * The number of months is set in the constructor, and may be queried using + * getMonths(). Basic mathematical operations are provided - + * plus(), minus(), multipliedBy() and + * dividedBy(). + *

      + * Months is thread-safe and immutable. + * + * @author Stephen Colebourne + * @since 1.4 + */ +public final class Months extends BaseSingleFieldPeriod { + + /** Constant representing zero months. */ + public static final Months ZERO = new Months(0); + /** Constant representing one month. */ + public static final Months ONE = new Months(1); + /** Constant representing two months. */ + public static final Months TWO = new Months(2); + /** Constant representing three months. */ + public static final Months THREE = new Months(3); + /** Constant representing four months. */ + public static final Months FOUR = new Months(4); + /** Constant representing five months. */ + public static final Months FIVE = new Months(5); + /** Constant representing six months. */ + public static final Months SIX = new Months(6); + /** Constant representing seven months. */ + public static final Months SEVEN = new Months(7); + /** Constant representing eight months. */ + public static final Months EIGHT = new Months(8); + /** Constant representing nine months. */ + public static final Months NINE = new Months(9); + /** Constant representing ten months. */ + public static final Months TEN = new Months(10); + /** Constant representing eleven months. */ + public static final Months ELEVEN = new Months(11); + /** Constant representing twelve months. */ + public static final Months TWELVE = new Months(12); + /** Constant representing the maximum number of months that can be stored in this object. */ + public static final Months MAX_VALUE = new Months(Integer.MAX_VALUE); + /** Constant representing the minimum number of months that can be stored in this object. */ + public static final Months MIN_VALUE = new Months(Integer.MIN_VALUE); + + /** The parser to use for this class. */ + private static final PeriodFormatter PARSER = ISOPeriodFormat.standard().withParseType(PeriodType.months()); + /** Serialization version. */ + private static final long serialVersionUID = 87525275727380867L; + + //----------------------------------------------------------------------- + /** + * Obtains an instance of Months that may be cached. + * Months is immutable, so instances can be cached and shared. + * This factory method provides access to shared instances. + * + * @param months the number of months to obtain an instance for + * @return the instance of Months + */ + public static Months months(int months) { + switch (months) { + case 0: + return ZERO; + case 1: + return ONE; + case 2: + return TWO; + case 3: + return THREE; + case 4: + return FOUR; + case 5: + return FIVE; + case 6: + return SIX; + case 7: + return SEVEN; + case 8: + return EIGHT; + case 9: + return NINE; + case 10: + return TEN; + case 11: + return ELEVEN; + case 12: + return TWELVE; + case Integer.MAX_VALUE: + return MAX_VALUE; + case Integer.MIN_VALUE: + return MIN_VALUE; + default: + return new Months(months); + } + } + + //----------------------------------------------------------------------- + /** + * Creates a Months representing the number of whole months + * between the two specified datetimes. This method corectly handles + * any daylight savings time changes that may occur during the interval. + * + * @param start the start instant, must not be null + * @param end the end instant, must not be null + * @return the period in months + * @throws IllegalArgumentException if the instants are null or invalid + */ + public static Months monthsBetween(ReadableInstant start, ReadableInstant end) { + int amount = BaseSingleFieldPeriod.between(start, end, DurationFieldType.months()); + return Months.months(amount); + } + + /** + * Creates a Months representing the number of whole months + * between the two specified partial datetimes. + *

      + * The two partials must contain the same fields, for example you can specify + * two LocalDate objects. + * + * @param start the start partial date, must not be null + * @param end the end partial date, must not be null + * @return the period in months + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Months monthsBetween(ReadablePartial start, ReadablePartial end) { + if (start instanceof LocalDate && end instanceof LocalDate) { + Chronology chrono = DateTimeUtils.getChronology(start.getChronology()); + int months = chrono.months().getDifference( + ((LocalDate) end).getLocalMillis(), ((LocalDate) start).getLocalMillis()); + return Months.months(months); + } + int amount = BaseSingleFieldPeriod.between(start, end, ZERO); + return Months.months(amount); + } + + /** + * Creates a Months representing the number of whole months + * in the specified interval. This method corectly handles any daylight + * savings time changes that may occur during the interval. + * + * @param interval the interval to extract months from, null returns zero + * @return the period in months + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Months monthsIn(ReadableInterval interval) { + if (interval == null) { + return Months.ZERO; + } + int amount = BaseSingleFieldPeriod.between(interval.getStart(), interval.getEnd(), DurationFieldType.months()); + return Months.months(amount); + } + + /** + * Creates a new Months by parsing a string in the ISO8601 format 'PnM'. + *

      + * The parse will accept the full ISO syntax of PnYnMnWnDTnHnMnS however only the + * months component may be non-zero. If any other component is non-zero, an exception + * will be thrown. + * + * @param periodStr the period string, null returns zero + * @return the period in months + * @throws IllegalArgumentException if the string format is invalid + */ + @FromString + public static Months parseMonths(String periodStr) { + if (periodStr == null) { + return Months.ZERO; + } + Period p = PARSER.parsePeriod(periodStr); + return Months.months(p.getMonths()); + } + + //----------------------------------------------------------------------- + /** + * Creates a new instance representing a number of months. + * You should consider using the factory method {@link #months(int)} + * instead of the constructor. + * + * @param months the number of months to represent + */ + private Months(int months) { + super(months); + } + + /** + * Resolves singletons. + * + * @return the singleton instance + */ + private Object readResolve() { + return Months.months(getValue()); + } + + //----------------------------------------------------------------------- + /** + * Gets the duration field type, which is months. + * + * @return the period type + */ + public DurationFieldType getFieldType() { + return DurationFieldType.months(); + } + + /** + * Gets the period type, which is months. + * + * @return the period type + */ + public PeriodType getPeriodType() { + return PeriodType.months(); + } + + //----------------------------------------------------------------------- + /** + * Gets the number of months that this period represents. + * + * @return the number of months in the period + */ + public int getMonths() { + return getValue(); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of months added. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param months the amount of months to add, may be negative + * @return the new period plus the specified number of months + * @throws ArithmeticException if the result overflows an int + */ + public Months plus(int months) { + if (months == 0) { + return this; + } + return Months.months(FieldUtils.safeAdd(getValue(), months)); + } + + /** + * Returns a new instance with the specified number of months added. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param months the amount of months to add, may be negative, null means zero + * @return the new period plus the specified number of months + * @throws ArithmeticException if the result overflows an int + */ + public Months plus(Months months) { + if (months == null) { + return this; + } + return plus(months.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of months taken away. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param months the amount of months to take away, may be negative + * @return the new period minus the specified number of months + * @throws ArithmeticException if the result overflows an int + */ + public Months minus(int months) { + return plus(FieldUtils.safeNegate(months)); + } + + /** + * Returns a new instance with the specified number of months taken away. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param months the amount of months to take away, may be negative, null means zero + * @return the new period minus the specified number of months + * @throws ArithmeticException if the result overflows an int + */ + public Months minus(Months months) { + if (months == null) { + return this; + } + return minus(months.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the months multiplied by the specified scalar. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param scalar the amount to multiply by, may be negative + * @return the new period multiplied by the specified scalar + * @throws ArithmeticException if the result overflows an int + */ + public Months multipliedBy(int scalar) { + return Months.months(FieldUtils.safeMultiply(getValue(), scalar)); + } + + /** + * Returns a new instance with the months divided by the specified divisor. + * The calculation uses integer division, thus 3 divided by 2 is 1. + *

      + * This instance is immutable and unaffected by this method call. + * + * @param divisor the amount to divide by, may be negative + * @return the new period divided by the specified divisor + * @throws ArithmeticException if the divisor is zero + */ + public Months dividedBy(int divisor) { + if (divisor == 1) { + return this; + } + return Months.months(getValue() / divisor); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the months value negated. + * + * @return the new period with a negated value + * @throws ArithmeticException if the result overflows an int + */ + public Months negated() { + return Months.months(FieldUtils.safeNegate(getValue())); + } + + //----------------------------------------------------------------------- + /** + * Is this months instance greater than the specified number of months. + * + * @param other the other period, null means zero + * @return true if this months instance is greater than the specified one + */ + public boolean isGreaterThan(Months other) { + if (other == null) { + return getValue() > 0; + } + return getValue() > other.getValue(); + } + + /** + * Is this months instance less than the specified number of months. + * + * @param other the other period, null means zero + * @return true if this months instance is less than the specified one + */ + public boolean isLessThan(Months other) { + if (other == null) { + return getValue() < 0; + } + return getValue() < other.getValue(); + } + + //----------------------------------------------------------------------- + /** + * Gets this instance as a String in the ISO8601 duration format. + *

      + * For example, "P4M" represents 4 months. + * + * @return the value as an ISO8601 string + */ + @ToString + public String toString() { + return "P" + String.valueOf(getValue()) + "M"; + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/MutableDateTime.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/MutableDateTime.java (.../MutableDateTime.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/MutableDateTime.java (.../MutableDateTime.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,65 +1,33 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2010 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Locale; +import org.joda.convert.FromString; +import org.joda.convert.ToString; import org.joda.time.base.BaseDateTime; import org.joda.time.chrono.ISOChronology; import org.joda.time.field.AbstractReadableInstantFieldProperty; import org.joda.time.field.FieldUtils; +import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; /** @@ -69,7 +37,7 @@ * This class uses a Chronology internally. The Chronology determines how the * millisecond instant value is converted into the date time fields. * The default Chronology is ISOChronology which is the agreed - * international standard and compatable with the modern Gregorian calendar. + * international standard and compatible with the modern Gregorian calendar. *

      * Each individual field can be accessed in two ways: *

        @@ -83,7 +51,7 @@ *
      • set numeric value *
      • add to numeric value *
      • add to numeric value wrapping with the field - *
      • get text vlaue + *
      • get text value *
      • get short text value *
      • set text value *
      • field maximum value @@ -97,6 +65,7 @@ * @author Guy Allard * @author Brian S O'Neill * @author Stephen Colebourne + * @author Mike Schrag * @since 1.0 * @see DateTime */ @@ -127,8 +96,77 @@ //----------------------------------------------------------------------- /** + * Obtains a {@code MutableDateTime} set to the current system millisecond time + * using ISOChronology in the default time zone. + * + * @return the current date-time, not null + * @since 2.0 + */ + public static MutableDateTime now() { + return new MutableDateTime(); + } + + /** + * Obtains a {@code MutableDateTime} set to the current system millisecond time + * using ISOChronology in the specified time zone. + * + * @param zone the time zone, not null + * @return the current date-time, not null + * @since 2.0 + */ + public static MutableDateTime now(DateTimeZone zone) { + if (zone == null) { + throw new NullPointerException("Zone must not be null"); + } + return new MutableDateTime(zone); + } + + /** + * Obtains a {@code MutableDateTime} set to the current system millisecond time + * using the specified chronology. + * + * @param chronology the chronology, not null + * @return the current date-time, not null + * @since 2.0 + */ + public static MutableDateTime now(Chronology chronology) { + if (chronology == null) { + throw new NullPointerException("Chronology must not be null"); + } + return new MutableDateTime(chronology); + } + + //----------------------------------------------------------------------- + /** + * Parses a {@code MutableDateTime} from the specified string. + *

        + * This uses {@link ISODateTimeFormat#dateTimeParser()}. + * + * @param str the string to parse, not null + * @since 2.0 + */ + @FromString + public static MutableDateTime parse(String str) { + return parse(str, ISODateTimeFormat.dateTimeParser().withOffsetParsed()); + } + + /** + * Parses a {@code MutableDateTime} from the specified string using a formatter. + * + * @param str the string to parse, not null + * @param formatter the formatter to use, not null + * @since 2.0 + */ + public static MutableDateTime parse(String str, DateTimeFormatter formatter) { + return formatter.parseDateTime(str).toMutableDateTime(); + } + + //----------------------------------------------------------------------- + /** * Constructs an instance set to the current system millisecond time * using ISOChronology in the default time zone. + * + * @see #now() */ public MutableDateTime() { super(); @@ -141,6 +179,7 @@ * If the specified time zone is null, the default zone is used. * * @param zone the time zone, null means default zone + * @see #now(DateTimeZone) */ public MutableDateTime(DateTimeZone zone) { super(zone); @@ -154,6 +193,7 @@ * in the default time zone is used. * * @param chronology the chronology, null means ISOChronology in default zone + * @see #now(Chronology) */ public MutableDateTime(Chronology chronology) { super(chronology); @@ -965,6 +1005,25 @@ //----------------------------------------------------------------------- /** + * Gets the property object for the specified type, which contains many useful methods. + * + * @param type the field type to get the chronology for + * @return the property object + * @throws IllegalArgumentException if the field is null or unsupported + * @since 1.2 + */ + public Property property(DateTimeFieldType type) { + if (type == null) { + throw new IllegalArgumentException("The DateTimeFieldType must not be null"); + } + DateTimeField field = type.getField(getChronology()); + if (field.isSupported() == false) { + throw new IllegalArgumentException("Field '" + type + "' is not supported"); + } + return new Property(this, field); + } + + /** * Get the era property. * * @return the era property @@ -1156,12 +1215,13 @@ } /** - * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZ). + * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZZ). * * @return ISO8601 time formatted string. */ + @ToString public String toString() { - return ISODateTimeFormat.getInstance().dateTime().print(this); + return ISODateTimeFormat.dateTime().print(this); } /** @@ -1190,9 +1250,9 @@ private static final long serialVersionUID = -4481126543819298617L; /** The instant this property is working against */ - private final MutableDateTime iInstant; + private MutableDateTime iInstant; /** The field this property is working against */ - private final DateTimeField iField; + private DateTimeField iField; /** * Constructor. @@ -1206,6 +1266,23 @@ iField = field; } + /** + * Writes the property in a safe serialization format. + */ + private void writeObject(ObjectOutputStream oos) throws IOException { + oos.writeObject(iInstant); + oos.writeObject(iField.getType()); + } + + /** + * Reads the property from a safe serialization format. + */ + private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException { + iInstant = (MutableDateTime) oos.readObject(); + DateTimeFieldType type = (DateTimeFieldType) oos.readObject(); + iField = type.getField(iInstant.getChronology()); + } + //----------------------------------------------------------------------- /** * Gets the field being used. @@ -1217,15 +1294,25 @@ } /** - * Gets the instant being used. + * Gets the milliseconds of the datetime that this property is linked to. * - * @return the instant + * @return the milliseconds */ - public ReadableInstant getReadableInstant() { - return iInstant; + protected long getMillis() { + return iInstant.getMillis(); } /** + * Gets the chronology of the datetime that this property is linked to. + * + * @return the chronology + * @since 1.4 + */ + protected Chronology getChronology() { + return iInstant.getChronology(); + } + + /** * Gets the mutable datetime being used. * * @return the mutable datetime Index: 3rdParty_sources/joda-time/org/joda/time/MutableInterval.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/MutableInterval.java (.../MutableInterval.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/MutableInterval.java (.../MutableInterval.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,62 +1,26 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; import java.io.Serializable; import org.joda.time.base.BaseInterval; import org.joda.time.field.FieldUtils; +import org.joda.time.format.ISODateTimeFormat; +import org.joda.time.format.ISOPeriodFormat; /** * MutableInterval is the standard implementation of a mutable time interval. @@ -94,6 +58,21 @@ //----------------------------------------------------------------------- /** + * Parses a {@code MutableInterval} from the specified string. + *

        + * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()} + * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime', + * 'datetime/period' or 'period/datetime'. + * + * @param str the string to parse, not null + * @since 2.0 + */ + public static MutableInterval parse(String str) { + return new MutableInterval(str); + } + + //----------------------------------------------------------------------- + /** * Constructs a zero length time interval from 1970-01-01 to 1970-01-01. */ public MutableInterval() { @@ -192,6 +171,13 @@ /** * Constructs a time interval by converting or copying from another object. + *

        + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadableInterval and String. + * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()} + * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime', + * 'datetime/period' or 'period/datetime'. * * @param interval the time interval to copy * @throws IllegalArgumentException if the interval is invalid @@ -203,6 +189,13 @@ /** * Constructs a time interval by converting or copying from another object, * overriding the chronology. + *

        + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadableInterval and String. + * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()} + * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime', + * 'datetime/period' or 'period/datetime'. * * @param interval the time interval to copy * @param chronology the chronology to use, null means ISO default Index: 3rdParty_sources/joda-time/org/joda/time/MutablePeriod.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/MutablePeriod.java (.../MutablePeriod.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/MutablePeriod.java (.../MutablePeriod.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,66 +1,50 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; import java.io.Serializable; +import org.joda.convert.FromString; import org.joda.time.base.BasePeriod; import org.joda.time.field.FieldUtils; +import org.joda.time.format.ISOPeriodFormat; +import org.joda.time.format.PeriodFormatter; /** * Standard mutable time period implementation. *

        + * A time period is divided into a number of fields, such as hours and seconds. + * Which fields are supported is defined by the PeriodType class. + * The default is the standard period type, which supports years, months, weeks, days, + * hours, minutes, seconds and millis. + *

        + * When this time period is added to an instant, the effect is of adding each field in turn. + * As a result, this takes into account daylight savings time. + * Adding a time period of 1 day to the day before daylight savings starts will only add + * 23 hours rather than 24 to ensure that the time remains the same. + * If this is not the behaviour you want, then see {@link Duration}. + *

        + * The definition of a period also affects the equals method. A period of 1 + * day is not equal to a period of 24 hours, nor 1 hour equal to 60 minutes. + * This is because periods represent an abstracted definition of a time period + * (eg. a day may not actually be 24 hours, it might be 23 or 25 at daylight + * savings boundary). To compare the actual duration of two periods, convert + * both to durations using toDuration, an operation that emphasises that the + * result may differ according to the date you choose. + *

        * MutablePeriod is mutable and not thread-safe, unless concurrent threads * are not invoking mutator methods. * @@ -76,7 +60,33 @@ /** Serialization version */ private static final long serialVersionUID = 3436451121567212165L; + //----------------------------------------------------------------------- /** + * Parses a {@code MutablePeriod} from the specified string. + *

        + * This uses {@link ISOPeriodFormat#standard()}. + * + * @param str the string to parse, not null + * @since 2.0 + */ + @FromString + public static MutablePeriod parse(String str) { + return parse(str, ISOPeriodFormat.standard()); + } + + /** + * Parses a {@code MutablePeriod} from the specified string using a formatter. + * + * @param str the string to parse, not null + * @param formatter the formatter to use, not null + * @since 2.0 + */ + public static MutablePeriod parse(String str, PeriodFormatter formatter) { + return formatter.parsePeriod(str).toMutablePeriod(); + } + + //----------------------------------------------------------------------- + /** * Creates a zero-length period using the standard period type. */ public MutablePeriod() { @@ -167,7 +177,7 @@ * @param duration the duration, in milliseconds */ public MutablePeriod(long duration) { - super(duration, null, null); + super(duration); } /** @@ -328,9 +338,34 @@ } /** - * Creates a period from the specified object using the - * {@link org.joda.time.convert.ConverterManager ConverterManager}. + * Creates a period from the given duration and end point. * + * @param duration the duration of the interval, null means zero-length + * @param endInstant the interval end, null means now + */ + public MutablePeriod(ReadableDuration duration, ReadableInstant endInstant) { + super(duration, endInstant, null); + } + + /** + * Creates a period from the given duration and end point. + * + * @param duration the duration of the interval, null means zero-length + * @param endInstant the interval end, null means now + * @param type which set of fields this period supports, null means standard + */ + public MutablePeriod(ReadableDuration duration, ReadableInstant endInstant, PeriodType type) { + super(duration, endInstant, type); + } + + /** + * Creates a period by converting or copying from another object. + *

        + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePeriod, ReadableInterval and String. + * The String formats are described by {@link ISOPeriodFormat#standard()}. + * * @param period period to convert * @throws IllegalArgumentException if period is invalid * @throws UnsupportedOperationException if an unsupported field's value is non-zero @@ -340,8 +375,12 @@ } /** - * Creates a period from the specified object using the - * {@link org.joda.time.convert.ConverterManager ConverterManager}. + * Creates a period by converting or copying from another object. + *

        + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePeriod, ReadableInterval and String. + * The String formats are described by {@link ISOPeriodFormat#standard()}. * * @param period period to convert * @param type which set of fields this period supports, null means use converter @@ -353,8 +392,12 @@ } /** - * Creates a period from the specified object using the - * {@link org.joda.time.convert.ConverterManager ConverterManager}. + * Creates a period by converting or copying from another object. + *

        + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePeriod, ReadableInterval and String. + * The String formats are described by {@link ISOPeriodFormat#standard()}. * * @param period period to convert * @param chrono the chronology to use, null means ISO in default zone @@ -366,8 +409,12 @@ } /** - * Creates a period from the specified object using the - * {@link org.joda.time.convert.ConverterManager ConverterManager}. + * Creates a period by converting or copying from another object. + *

        + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePeriod, ReadableInterval and String. + * The String formats are described by {@link ISOPeriodFormat#standard()}. * * @param period period to convert * @param type which set of fields this period supports, null means use converter @@ -493,7 +540,7 @@ * * @param startInstant interval start, in milliseconds * @param endInstant interval end, in milliseconds - * @param chrono the chronology to use, not null + * @param chrono the chronology to use, null means ISO chronology * @throws ArithmeticException if the set exceeds the capacity of the period */ public void setPeriod(long startInstant, long endInstant, Chronology chrono) { @@ -556,7 +603,7 @@ * available precise field. * * @param duration the duration, in milliseconds - * @param chrono the chronology to use, not null + * @param chrono the chronology to use, null means ISO chronology * @throws ArithmeticException if the set exceeds the capacity of the period */ public void setPeriod(long duration, Chronology chrono) { Index: 3rdParty_sources/joda-time/org/joda/time/Partial.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/Partial.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/Partial.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,997 @@ +/* + * Copyright 2001-2009 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import org.joda.time.base.AbstractPartial; +import org.joda.time.field.AbstractPartialFieldProperty; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; + +/** + * Partial is an immutable partial datetime supporting any set of datetime fields. + *

        + * A Partial instance can be used to hold any combination of fields. + * The instance does not contain a time zone, so any datetime is local. + *

        + * A Partial can be matched against an instant using {@link #isMatch(ReadableInstant)}. + * This method compares each field on this partial with those of the instant + * and determines if the partial matches the instant. + * Given this definition, an empty Partial instance represents any datetime + * and always matches. + *

        + * Calculations on Partial are performed using a {@link Chronology}. + * This chronology is set to be in the UTC time zone for all calculations. + *

        + * Each individual field can be queried in two ways: + *

          + *
        • get(DateTimeFieldType.monthOfYear()) + *
        • property(DateTimeFieldType.monthOfYear()).get() + *
        + * The second technique also provides access to other useful methods on the + * field: + *
          + *
        • numeric value - monthOfYear().get() + *
        • text value - monthOfYear().getAsText() + *
        • short text value - monthOfYear().getAsShortText() + *
        • maximum/minimum values - monthOfYear().getMaximumValue() + *
        • add/subtract - monthOfYear().addToCopy() + *
        • set - monthOfYear().setCopy() + *
        + *

        + * Partial is thread-safe and immutable, provided that the Chronology is as well. + * All standard Chronology classes supplied are thread-safe and immutable. + * + * @author Stephen Colebourne + * @since 1.1 + */ +public final class Partial + extends AbstractPartial + implements ReadablePartial, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 12324121189002L; + + /** The chronology in use. */ + private final Chronology iChronology; + /** The set of field types. */ + private final DateTimeFieldType[] iTypes; + /** The values of each field in this partial. */ + private final int[] iValues; + /** The formatter to use, [0] may miss some fields, [1] doesn't miss any fields. */ + private transient DateTimeFormatter[] iFormatter; + + // Constructors + //----------------------------------------------------------------------- + /** + * Constructs a Partial with no fields or values, which can be considered + * to represent any date. + *

        + * This is most useful when constructing partials, for example: + *

        +     * Partial p = new Partial()
        +     *     .with(DateTimeFieldType.dayOfWeek(), 5)
        +     *     .with(DateTimeFieldType.hourOfDay(), 12)
        +     *     .with(DateTimeFieldType.minuteOfHour(), 20);
        +     * 
        + * Note that, although this is a clean way to write code, it is fairly + * inefficient internally. + *

        + * The constructor uses the default ISO chronology. + */ + public Partial() { + this((Chronology) null); + } + + /** + * Constructs a Partial with no fields or values, which can be considered + * to represent any date. + *

        + * This is most useful when constructing partials, for example: + *

        +     * Partial p = new Partial(chrono)
        +     *     .with(DateTimeFieldType.dayOfWeek(), 5)
        +     *     .with(DateTimeFieldType.hourOfDay(), 12)
        +     *     .with(DateTimeFieldType.minuteOfHour(), 20);
        +     * 
        + * Note that, although this is a clean way to write code, it is fairly + * inefficient internally. + * + * @param chrono the chronology, null means ISO + */ + public Partial(Chronology chrono) { + super(); + iChronology = DateTimeUtils.getChronology(chrono).withUTC(); + iTypes = new DateTimeFieldType[0]; + iValues = new int[0]; + } + + /** + * Constructs a Partial with the specified field and value. + *

        + * The constructor uses the default ISO chronology. + * + * @param type the single type to create the partial from, not null + * @param value the value to store + * @throws IllegalArgumentException if the type or value is invalid + */ + public Partial(DateTimeFieldType type, int value) { + this(type, value, null); + } + + /** + * Constructs a Partial with the specified field and value. + *

        + * The constructor uses the specified chronology. + * + * @param type the single type to create the partial from, not null + * @param value the value to store + * @param chronology the chronology, null means ISO + * @throws IllegalArgumentException if the type or value is invalid + */ + public Partial(DateTimeFieldType type, int value, Chronology chronology) { + super(); + chronology = DateTimeUtils.getChronology(chronology).withUTC(); + iChronology = chronology; + if (type == null) { + throw new IllegalArgumentException("The field type must not be null"); + } + iTypes = new DateTimeFieldType[] {type}; + iValues = new int[] {value}; + chronology.validate(this, iValues); + } + + /** + * Constructs a Partial with the specified fields and values. + * The fields must be specified in the order largest to smallest. + *

        + * The constructor uses the specified chronology. + * + * @param types the types to create the partial from, not null + * @param values the values to store, not null + * @throws IllegalArgumentException if the types or values are invalid + */ + public Partial(DateTimeFieldType[] types, int[] values) { + this(types, values, null); + } + + /** + * Constructs a Partial with the specified fields and values. + * The fields must be specified in the order largest to smallest. + *

        + * The constructor uses the specified chronology. + * + * @param types the types to create the partial from, not null + * @param values the values to store, not null + * @param chronology the chronology, null means ISO + * @throws IllegalArgumentException if the types or values are invalid + */ + public Partial(DateTimeFieldType[] types, int[] values, Chronology chronology) { + super(); + chronology = DateTimeUtils.getChronology(chronology).withUTC(); + iChronology = chronology; + if (types == null) { + throw new IllegalArgumentException("Types array must not be null"); + } + if (values == null) { + throw new IllegalArgumentException("Values array must not be null"); + } + if (values.length != types.length) { + throw new IllegalArgumentException("Values array must be the same length as the types array"); + } + if (types.length == 0) { + iTypes = types; + iValues = values; + return; + } + for (int i = 0; i < types.length; i++) { + if (types[i] == null) { + throw new IllegalArgumentException("Types array must not contain null: index " + i); + } + } + DurationField lastUnitField = null; + for (int i = 0; i < types.length; i++) { + DateTimeFieldType loopType = types[i]; + DurationField loopUnitField = loopType.getDurationType().getField(iChronology); + if (i > 0) { + int compare = lastUnitField.compareTo(loopUnitField); + if (compare < 0 || (compare != 0 && loopUnitField.isSupported() == false)) { + throw new IllegalArgumentException("Types array must be in order largest-smallest: " + + types[i - 1].getName() + " < " + loopType.getName()); + } else if (compare == 0) { + if (types[i - 1].getRangeDurationType() == null) { + if (loopType.getRangeDurationType() == null) { + throw new IllegalArgumentException("Types array must not contain duplicate: " + loopType.getName()); + } + } else { + if (loopType.getRangeDurationType() == null) { + throw new IllegalArgumentException("Types array must be in order largest-smallest: " + + types[i - 1].getName() + " < " + loopType.getName()); + } + DurationField lastRangeField = types[i - 1].getRangeDurationType().getField(iChronology); + DurationField loopRangeField = loopType.getRangeDurationType().getField(iChronology); + if (lastRangeField.compareTo(loopRangeField) < 0) { + throw new IllegalArgumentException("Types array must be in order largest-smallest: " + + types[i - 1].getName() + " < " + loopType.getName()); + } + if (lastRangeField.compareTo(loopRangeField) == 0) { + throw new IllegalArgumentException("Types array must not contain duplicate: " + loopType.getName()); + } + } + } + } + lastUnitField = loopUnitField; + } + + iTypes = (DateTimeFieldType[]) types.clone(); + chronology.validate(this, values); + iValues = (int[]) values.clone(); + } + + /** + * Constructs a Partial by copying all the fields and types from + * another partial. + *

        + * This is most useful when copying from a YearMonthDay or TimeOfDay. + */ + public Partial(ReadablePartial partial) { + super(); + if (partial == null) { + throw new IllegalArgumentException("The partial must not be null"); + } + iChronology = DateTimeUtils.getChronology(partial.getChronology()).withUTC(); + iTypes = new DateTimeFieldType[partial.size()]; + iValues = new int[partial.size()]; + for (int i = 0; i < partial.size(); i++) { + iTypes[i] = partial.getFieldType(i); + iValues[i] = partial.getValue(i); + } + } + + /** + * Constructs a Partial with the specified values. + * This constructor assigns and performs no validation. + * + * @param partial the partial to copy + * @param values the values to store + * @throws IllegalArgumentException if the types or values are invalid + */ + Partial(Partial partial, int[] values) { + super(); + iChronology = partial.iChronology; + iTypes = partial.iTypes; + iValues = values; + } + + /** + * Constructs a Partial with the specified chronology, fields and values. + * This constructor assigns and performs no validation. + * + * @param chronology the chronology + * @param types the types to create the partial from + * @param values the values to store + * @throws IllegalArgumentException if the types or values are invalid + */ + Partial(Chronology chronology, DateTimeFieldType[] types, int[] values) { + super(); + iChronology = chronology; + iTypes = types; + iValues = values; + } + + //----------------------------------------------------------------------- + /** + * Gets the number of fields in this partial. + * + * @return the field count + */ + public int size() { + return iTypes.length; + } + + /** + * Gets the chronology of the partial which is never null. + *

        + * The {@link Chronology} is the calculation engine behind the partial and + * provides conversion and validation of the fields in a particular calendar system. + * + * @return the chronology, never null + */ + public Chronology getChronology() { + return iChronology; + } + + /** + * Gets the field for a specific index in the chronology specified. + * + * @param index the index to retrieve + * @param chrono the chronology to use + * @return the field + * @throws IndexOutOfBoundsException if the index is invalid + */ + protected DateTimeField getField(int index, Chronology chrono) { + return iTypes[index].getField(chrono); + } + + /** + * Gets the field type at the specified index. + * + * @param index the index to retrieve + * @return the field at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + */ + public DateTimeFieldType getFieldType(int index) { + return iTypes[index]; + } + + /** + * Gets an array of the field type of each of the fields that + * this partial supports. + *

        + * The fields are returned largest to smallest. + * + * @return the array of field types (cloned), largest to smallest + */ + public DateTimeFieldType[] getFieldTypes() { + return (DateTimeFieldType[]) iTypes.clone(); + } + + //----------------------------------------------------------------------- + /** + * Gets the value of the field at the specifed index. + * + * @param index the index + * @return the value + * @throws IndexOutOfBoundsException if the index is invalid + */ + public int getValue(int index) { + return iValues[index]; + } + + /** + * Gets an array of the value of each of the fields that + * this partial supports. + *

        + * The fields are returned largest to smallest. + * Each value corresponds to the same array index as getFieldTypes() + * + * @return the current values of each field (cloned), largest to smallest + */ + public int[] getValues() { + return (int[]) iValues.clone(); + } + + //----------------------------------------------------------------------- + /** + * Creates a new Partial instance with the specified chronology. + * This instance is immutable and unaffected by this method call. + *

        + * This method retains the values of the fields, thus the result will + * typically refer to a different instant. + *

        + * The time zone of the specified chronology is ignored, as Partial + * operates without a time zone. + * + * @param newChronology the new chronology, null means ISO + * @return a copy of this datetime with a different chronology + * @throws IllegalArgumentException if the values are invalid for the new chronology + */ + public Partial withChronologyRetainFields(Chronology newChronology) { + newChronology = DateTimeUtils.getChronology(newChronology); + newChronology = newChronology.withUTC(); + if (newChronology == getChronology()) { + return this; + } else { + Partial newPartial = new Partial(newChronology, iTypes, iValues); + newChronology.validate(newPartial, iValues); + return newPartial; + } + } + + //----------------------------------------------------------------------- + /** + * Gets a copy of this date with the specified field set to a new value. + *

        + * If this partial did not previously support the field, the new one will. + * Contrast this behaviour with {@link #withField(DateTimeFieldType, int)}. + *

        + * For example, if the field type is dayOfMonth then the day + * would be changed/added in the returned instance. + * + * @param fieldType the field type to set, not null + * @param value the value to set + * @return a copy of this instance with the field set + * @throws IllegalArgumentException if the value is null or invalid + */ + public Partial with(DateTimeFieldType fieldType, int value) { + if (fieldType == null) { + throw new IllegalArgumentException("The field type must not be null"); + } + int index = indexOf(fieldType); + if (index == -1) { + DateTimeFieldType[] newTypes = new DateTimeFieldType[iTypes.length + 1]; + int[] newValues = new int[newTypes.length]; + + // find correct insertion point to keep largest-smallest order + int i = 0; + DurationField unitField = fieldType.getDurationType().getField(iChronology); + if (unitField.isSupported()) { + for (; i < iTypes.length; i++) { + DateTimeFieldType loopType = iTypes[i]; + DurationField loopUnitField = loopType.getDurationType().getField(iChronology); + if (loopUnitField.isSupported()) { + int compare = unitField.compareTo(loopUnitField); + if (compare > 0) { + break; + } else if (compare == 0) { + DurationField rangeField = fieldType.getRangeDurationType().getField(iChronology); + DurationField loopRangeField = loopType.getRangeDurationType().getField(iChronology); + if (rangeField.compareTo(loopRangeField) > 0) { + break; + } + } + } + } + } + System.arraycopy(iTypes, 0, newTypes, 0, i); + System.arraycopy(iValues, 0, newValues, 0, i); + newTypes[i] = fieldType; + newValues[i] = value; + System.arraycopy(iTypes, i, newTypes, i + 1, newTypes.length - i - 1); + System.arraycopy(iValues, i, newValues, i + 1, newValues.length - i - 1); + + Partial newPartial = new Partial(iChronology, newTypes, newValues); + iChronology.validate(newPartial, newValues); + return newPartial; + } + if (value == getValue(index)) { + return this; + } + int[] newValues = getValues(); + newValues = getField(index).set(this, index, newValues, value); + return new Partial(this, newValues); + } + + /** + * Gets a copy of this date with the specified field removed. + *

        + * If this partial did not previously support the field, no error occurs. + * + * @param fieldType the field type to remove, may be null + * @return a copy of this instance with the field removed + */ + public Partial without(DateTimeFieldType fieldType) { + int index = indexOf(fieldType); + if (index != -1) { + DateTimeFieldType[] newTypes = new DateTimeFieldType[size() - 1]; + int[] newValues = new int[size() - 1]; + System.arraycopy(iTypes, 0, newTypes, 0, index); + System.arraycopy(iTypes, index + 1, newTypes, index, newTypes.length - index); + System.arraycopy(iValues, 0, newValues, 0, index); + System.arraycopy(iValues, index + 1, newValues, index, newValues.length - index); + Partial newPartial = new Partial(iChronology, newTypes, newValues); + iChronology.validate(newPartial, newValues); + return newPartial; + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets a copy of this Partial with the specified field set to a new value. + *

        + * If this partial does not support the field, an exception is thrown. + * Contrast this behaviour with {@link #with(DateTimeFieldType, int)}. + *

        + * For example, if the field type is dayOfMonth then the day + * would be changed in the returned instance if supported. + * + * @param fieldType the field type to set, not null + * @param value the value to set + * @return a copy of this instance with the field set + * @throws IllegalArgumentException if the value is null or invalid + */ + public Partial withField(DateTimeFieldType fieldType, int value) { + int index = indexOfSupported(fieldType); + if (value == getValue(index)) { + return this; + } + int[] newValues = getValues(); + newValues = getField(index).set(this, index, newValues, value); + return new Partial(this, newValues); + } + + /** + * Gets a copy of this Partial with the value of the specified field increased. + * If this partial does not support the field, an exception is thrown. + *

        + * If the addition is zero, then this is returned. + * The addition will overflow into larger fields (eg. minute to hour). + * However, it will not wrap around if the top maximum is reached. + * + * @param fieldType the field type to add to, not null + * @param amount the amount to add + * @return a copy of this instance with the field updated + * @throws IllegalArgumentException if the value is null or invalid + * @throws ArithmeticException if the new datetime exceeds the capacity + */ + public Partial withFieldAdded(DurationFieldType fieldType, int amount) { + int index = indexOfSupported(fieldType); + if (amount == 0) { + return this; + } + int[] newValues = getValues(); + newValues = getField(index).add(this, index, newValues, amount); + return new Partial(this, newValues); + } + + /** + * Gets a copy of this Partial with the value of the specified field increased. + * If this partial does not support the field, an exception is thrown. + *

        + * If the addition is zero, then this is returned. + * The addition will overflow into larger fields (eg. minute to hour). + * If the maximum is reached, the addition will wra. + * + * @param fieldType the field type to add to, not null + * @param amount the amount to add + * @return a copy of this instance with the field updated + * @throws IllegalArgumentException if the value is null or invalid + * @throws ArithmeticException if the new datetime exceeds the capacity + */ + public Partial withFieldAddWrapped(DurationFieldType fieldType, int amount) { + int index = indexOfSupported(fieldType); + if (amount == 0) { + return this; + } + int[] newValues = getValues(); + newValues = getField(index).addWrapPartial(this, index, newValues, amount); + return new Partial(this, newValues); + } + + /** + * Gets a copy of this Partial with the specified period added. + *

        + * If the addition is zero, then this is returned. + * Fields in the period that aren't present in the partial are ignored. + *

        + * This method is typically used to add multiple copies of complex + * period instances. Adding one field is best achieved using the method + * {@link #withFieldAdded(DurationFieldType, int)}. + * + * @param period the period to add to this one, null means zero + * @param scalar the amount of times to add, such as -1 to subtract once + * @return a copy of this instance with the period added + * @throws ArithmeticException if the new datetime exceeds the capacity + */ + public Partial withPeriodAdded(ReadablePeriod period, int scalar) { + if (period == null || scalar == 0) { + return this; + } + int[] newValues = getValues(); + for (int i = 0; i < period.size(); i++) { + DurationFieldType fieldType = period.getFieldType(i); + int index = indexOf(fieldType); + if (index >= 0) { + newValues = getField(index).add(this, index, newValues, + FieldUtils.safeMultiply(period.getValue(i), scalar)); + } + } + return new Partial(this, newValues); + } + + /** + * Gets a copy of this instance with the specified period added. + *

        + * If the amount is zero or null, then this is returned. + * + * @param period the duration to add to this one, null means zero + * @return a copy of this instance with the period added + * @throws ArithmeticException if the new datetime exceeds the capacity of a long + */ + public Partial plus(ReadablePeriod period) { + return withPeriodAdded(period, 1); + } + + /** + * Gets a copy of this instance with the specified period take away. + *

        + * If the amount is zero or null, then this is returned. + * + * @param period the period to reduce this instant by + * @return a copy of this instance with the period taken away + * @throws ArithmeticException if the new datetime exceeds the capacity of a long + */ + public Partial minus(ReadablePeriod period) { + return withPeriodAdded(period, -1); + } + + //----------------------------------------------------------------------- + /** + * Gets the property object for the specified type, which contains + * many useful methods for getting and manipulating the partial. + *

        + * See also {@link ReadablePartial#get(DateTimeFieldType)}. + * + * @param type the field type to get the property for, not null + * @return the property object + * @throws IllegalArgumentException if the field is null or unsupported + */ + public Property property(DateTimeFieldType type) { + return new Property(this, indexOfSupported(type)); + } + + //----------------------------------------------------------------------- + /** + * Does this partial match the specified instant. + *

        + * A match occurs when all the fields of this partial are the same as the + * corresponding fields on the specified instant. + * + * @param instant an instant to check against, null means now in default zone + * @return true if this partial matches the specified instant + */ + public boolean isMatch(ReadableInstant instant) { + long millis = DateTimeUtils.getInstantMillis(instant); + Chronology chrono = DateTimeUtils.getInstantChronology(instant); + for (int i = 0; i < iTypes.length; i++) { + int value = iTypes[i].getField(chrono).get(millis); + if (value != iValues[i]) { + return false; + } + } + return true; + } + + /** + * Does this partial match the specified partial. + *

        + * A match occurs when all the fields of this partial are the same as the + * corresponding fields on the specified partial. + * + * @param partial a partial to check against, must not be null + * @return true if this partial matches the specified partial + * @throws IllegalArgumentException if the partial is null + * @throws IllegalArgumentException if the fields of the two partials do not match + * @since 1.5 + */ + public boolean isMatch(ReadablePartial partial) { + if (partial == null) { + throw new IllegalArgumentException("The partial must not be null"); + } + for (int i = 0; i < iTypes.length; i++) { + int value = partial.get(iTypes[i]); + if (value != iValues[i]) { + return false; + } + } + return true; + } + + //----------------------------------------------------------------------- + /** + * Gets a formatter suitable for the fields in this partial. + *

        + * If there is no appropriate ISO format, null is returned. + * This method may return a formatter that does not display all the + * fields of the partial. This might occur when you have overlapping + * fields, such as dayOfWeek and dayOfMonth. + * + * @return a formatter suitable for the fields in this partial, null + * if none is suitable + */ + public DateTimeFormatter getFormatter() { + DateTimeFormatter[] f = iFormatter; + if (f == null) { + if (size() == 0) { + return null; + } + f = new DateTimeFormatter[2]; + try { + List list = new ArrayList(Arrays.asList(iTypes)); + f[0] = ISODateTimeFormat.forFields(list, true, false); + if (list.size() == 0) { + f[1] = f[0]; + } + } catch (IllegalArgumentException ex) { + // ignore + } + iFormatter = f; + } + return f[0]; + } + + //----------------------------------------------------------------------- + /** + * Output the date in an appropriate ISO8601 format. + *

        + * This method will output the partial in one of two ways. + * If {@link #getFormatter()} + *

        + * If there is no appropriate ISO format a dump of the fields is output + * via {@link #toStringList()}. + * + * @return ISO8601 formatted string + */ + public String toString() { + DateTimeFormatter[] f = iFormatter; + if (f == null) { + getFormatter(); + f = iFormatter; + if (f == null) { + return toStringList(); + } + } + DateTimeFormatter f1 = f[1]; + if (f1 == null) { + return toStringList(); + } + return f1.print(this); + } + + /** + * Gets a string version of the partial that lists all the fields. + *

        + * This method exists to provide a better debugging toString than + * the standard toString. This method lists all the fields and their + * values in a style similar to the collections framework. + * + * @return a toString format that lists all the fields + */ + public String toStringList() { + int size = size(); + StringBuffer buf = new StringBuffer(20 * size); + buf.append('['); + for (int i = 0; i < size; i++) { + if (i > 0) { + buf.append(',').append(' '); + } + buf.append(iTypes[i].getName()); + buf.append('='); + buf.append(iValues[i]); + } + buf.append(']'); + return buf.toString(); + } + + /** + * Output the date using the specified format pattern. + * Unsupported fields will appear as special unicode characters. + * + * @param pattern the pattern specification, null means use toString + * @see org.joda.time.format.DateTimeFormat + */ + public String toString(String pattern) { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).print(this); + } + + /** + * Output the date using the specified format pattern. + * Unsupported fields will appear as special unicode characters. + * + * @param pattern the pattern specification, null means use toString + * @param locale Locale to use, null means default + * @see org.joda.time.format.DateTimeFormat + */ + public String toString(String pattern, Locale locale) { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this); + } + + //----------------------------------------------------------------------- + /** + * The property class for Partial. + *

        + * This class binds a Partial to a DateTimeField. + * + * @author Stephen Colebourne + * @since 1.1 + */ + public static class Property extends AbstractPartialFieldProperty implements Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 53278362873888L; + + /** The partial */ + private final Partial iPartial; + /** The field index */ + private final int iFieldIndex; + + /** + * Constructs a property. + * + * @param partial the partial instance + * @param fieldIndex the index in the partial + */ + Property(Partial partial, int fieldIndex) { + super(); + iPartial = partial; + iFieldIndex = fieldIndex; + } + + /** + * Gets the field that this property uses. + * + * @return the field + */ + public DateTimeField getField() { + return iPartial.getField(iFieldIndex); + } + + /** + * Gets the partial that this property belongs to. + * + * @return the partial + */ + protected ReadablePartial getReadablePartial() { + return iPartial; + } + + /** + * Gets the partial that this property belongs to. + * + * @return the partial + */ + public Partial getPartial() { + return iPartial; + } + + /** + * Gets the value of this field. + * + * @return the field value + */ + public int get() { + return iPartial.getValue(iFieldIndex); + } + + //----------------------------------------------------------------------- + /** + * Adds to the value of this field in a copy of this Partial. + *

        + * The value will be added to this field. If the value is too large to be + * added solely to this field then it will affect larger fields. + * Smaller fields are unaffected. + *

        + * If the result would be too large, beyond the maximum year, then an + * IllegalArgumentException is thrown. + *

        + * The Partial attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param valueToAdd the value to add to the field in the copy + * @return a copy of the Partial with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public Partial addToCopy(int valueToAdd) { + int[] newValues = iPartial.getValues(); + newValues = getField().add(iPartial, iFieldIndex, newValues, valueToAdd); + return new Partial(iPartial, newValues); + } + + /** + * Adds to the value of this field in a copy of this Partial wrapping + * within this field if the maximum value is reached. + *

        + * The value will be added to this field. If the value is too large to be + * added solely to this field then it wraps within this field. + * Other fields are unaffected. + *

        + * For example, + * 2004-12-20 addWrapField one month returns 2004-01-20. + *

        + * The Partial attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param valueToAdd the value to add to the field in the copy + * @return a copy of the Partial with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public Partial addWrapFieldToCopy(int valueToAdd) { + int[] newValues = iPartial.getValues(); + newValues = getField().addWrapField(iPartial, iFieldIndex, newValues, valueToAdd); + return new Partial(iPartial, newValues); + } + + //----------------------------------------------------------------------- + /** + * Sets this field in a copy of the Partial. + *

        + * The Partial attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param value the value to set the field in the copy to + * @return a copy of the Partial with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public Partial setCopy(int value) { + int[] newValues = iPartial.getValues(); + newValues = getField().set(iPartial, iFieldIndex, newValues, value); + return new Partial(iPartial, newValues); + } + + /** + * Sets this field in a copy of the Partial to a parsed text value. + *

        + * The Partial attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param text the text value to set + * @param locale optional locale to use for selecting a text symbol + * @return a copy of the Partial with the field value changed + * @throws IllegalArgumentException if the text value isn't valid + */ + public Partial setCopy(String text, Locale locale) { + int[] newValues = iPartial.getValues(); + newValues = getField().set(iPartial, iFieldIndex, newValues, text, locale); + return new Partial(iPartial, newValues); + } + + /** + * Sets this field in a copy of the Partial to a parsed text value. + *

        + * The Partial attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param text the text value to set + * @return a copy of the Partial with the field value changed + * @throws IllegalArgumentException if the text value isn't valid + */ + public Partial setCopy(String text) { + return setCopy(text, null); + } + + //----------------------------------------------------------------------- + /** + * Returns a new Partial with this field set to the maximum value + * for this field. + *

        + * The Partial attached to this property is unchanged by this call. + * + * @return a copy of the Partial with this field set to its maximum + * @since 1.2 + */ + public Partial withMaximumValue() { + return setCopy(getMaximumValue()); + } + + /** + * Returns a new Partial with this field set to the minimum value + * for this field. + *

        + * The Partial attached to this property is unchanged by this call. + * + * @return a copy of the Partial with this field set to its minimum + * @since 1.2 + */ + public Partial withMinimumValue() { + return setCopy(getMinimumValue()); + } + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/Period.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/Period.java (.../Period.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/Period.java (.../Period.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,61 +1,28 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2010 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; import java.io.Serializable; +import org.joda.convert.FromString; import org.joda.time.base.BasePeriod; +import org.joda.time.chrono.ISOChronology; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.ISOPeriodFormat; +import org.joda.time.format.PeriodFormatter; /** * An immutable time period specifying a set of duration field values. @@ -71,6 +38,14 @@ * 23 hours rather than 24 to ensure that the time remains the same. * If this is not the behaviour you want, then see {@link Duration}. *

        + * The definition of a period also affects the equals method. A period of 1 + * day is not equal to a period of 24 hours, nor 1 hour equal to 60 minutes. + * This is because periods represent an abstracted definition of a time period + * (eg. a day may not actually be 24 hours, it might be 23 or 25 at daylight + * savings boundary). To compare the actual duration of two periods, convert + * both to durations using toDuration, an operation that emphasises that the + * result may differ according to the date you choose. + *

        * Period is thread-safe and immutable, provided that the PeriodType is as well. * All standard PeriodType classes supplied are thread-safe and immutable. * @@ -83,13 +58,50 @@ extends BasePeriod implements ReadablePeriod, Serializable { + /** + * A period of zero length and standard period type. + * @since 1.4 + */ + public static final Period ZERO = new Period(); + /** Serialization version */ private static final long serialVersionUID = 741052353876488155L; //----------------------------------------------------------------------- /** + * Parses a {@code Period} from the specified string. + *

        + * This uses {@link ISOPeriodFormat#standard()}. + * + * @param str the string to parse, not null + * @since 2.0 + */ + @FromString + public static Period parse(String str) { + return parse(str, ISOPeriodFormat.standard()); + } + + /** + * Parses a {@code Period} from the specified string using a formatter. + * + * @param str the string to parse, not null + * @param formatter the formatter to use, not null + * @since 2.0 + */ + public static Period parse(String str, PeriodFormatter formatter) { + return formatter.parsePeriod(str); + } + + //----------------------------------------------------------------------- + /** * Create a period with a specified number of years. - * The standard period type is used. + *

        + * The standard period type is used, thus you can add other fields such + * as months or days using the withXxx() methods. + * For example, Period.years(2).withMonths(6); + *

        + * If you want a year-based period that cannot have other fields added, + * then you should consider using {@link Years}. * * @param years the amount of years in this period * @return the period @@ -100,7 +112,13 @@ /** * Create a period with a specified number of months. - * The standard period type is used. + *

        + * The standard period type is used, thus you can add other fields such + * as years or days using the withXxx() methods. + * For example, Period.months(2).withDays(6); + *

        + * If you want a month-based period that cannot have other fields added, + * then you should consider using {@link Months}. * * @param months the amount of months in this period * @return the period @@ -111,7 +129,13 @@ /** * Create a period with a specified number of weeks. - * The standard period type is used. + *

        + * The standard period type is used, thus you can add other fields such + * as months or days using the withXxx() methods. + * For example, Period.weeks(2).withDays(6); + *

        + * If you want a week-based period that cannot have other fields added, + * then you should consider using {@link Weeks}. * * @param weeks the amount of weeks in this period * @return the period @@ -122,7 +146,13 @@ /** * Create a period with a specified number of days. - * The standard period type is used. + *

        + * The standard period type is used, thus you can add other fields such + * as months or weeks using the withXxx() methods. + * For example, Period.days(2).withHours(6); + *

        + * If you want a day-based period that cannot have other fields added, + * then you should consider using {@link Days}. * * @param days the amount of days in this period * @return the period @@ -133,7 +163,13 @@ /** * Create a period with a specified number of hours. - * The standard period type is used. + *

        + * The standard period type is used, thus you can add other fields such + * as months or days using the withXxx() methods. + * For example, Period.hours(2).withMinutes(30); + *

        + * If you want a hour-based period that cannot have other fields added, + * then you should consider using {@link Hours}. * * @param hours the amount of hours in this period * @return the period @@ -144,7 +180,13 @@ /** * Create a period with a specified number of minutes. - * The standard period type is used. + *

        + * The standard period type is used, thus you can add other fields such + * as days or hours using the withXxx() methods. + * For example, Period.minutes(2).withSeconds(30); + *

        + * If you want a minute-based period that cannot have other fields added, + * then you should consider using {@link Minutes}. * * @param minutes the amount of minutes in this period * @return the period @@ -155,7 +197,13 @@ /** * Create a period with a specified number of seconds. - * The standard period type is used. + *

        + * The standard period type is used, thus you can add other fields such + * as days or hours using the withXxx() methods. + * For example, Period.seconds(2).withMillis(30); + *

        + * If you want a second-based period that cannot have other fields added, + * then you should consider using {@link Seconds}. * * @param seconds the amount of seconds in this period * @return the period @@ -166,7 +214,10 @@ /** * Create a period with a specified number of millis. - * The standard period type is used. + *

        + * The standard period type is used, thus you can add other fields such + * as days or hours using the withXxx() methods. + * For example, Period.millis(20).withSeconds(30); * * @param millis the amount of millis in this period * @return the period @@ -177,6 +228,55 @@ //----------------------------------------------------------------------- /** + * Creates a period from two partially specified times, calculating + * by field difference. + *

        + * The two partials must contain the same fields, thus you can specify + * two LocalDate objects, or two LocalTime objects, + * but not one of each. Also, the partial may not contain overlapping + * fields, such as dayOfWeek and dayOfMonth. + *

        + * Calculation by field difference works by extracting the difference + * one field at a time and not wrapping into other fields. + * Thus 2005-06-09/2007-04-12 will yield P1Y-2M3D. + *

        + * For example, you have an event that always runs from the 27th of + * each month to the 2nd of the next month. If you calculate this + * period using a standard constructor, then you will get between + * P3D and P6D depending on the month. If you use this method, then + * you will get P1M-25D. This field-difference based period can + * be successfully applied to each month of the year to obtain the + * correct end date for a given start date. + * + * @param start the start of the period, must not be null + * @param end the end of the period, must not be null + * @throws IllegalArgumentException if the partials are null or invalid + * @since 1.1 + */ + public static Period fieldDifference(ReadablePartial start, ReadablePartial end) { + if (start == null || end == null) { + throw new IllegalArgumentException("ReadablePartial objects must not be null"); + } + if (start.size() != end.size()) { + throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields"); + } + DurationFieldType[] types = new DurationFieldType[start.size()]; + int[] values = new int[start.size()]; + for (int i = 0, isize = start.size(); i < isize; i++) { + if (start.getFieldType(i) != end.getFieldType(i)) { + throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields"); + } + types[i] = start.getFieldType(i).getDurationType(); + if (i > 0 && types[i - 1] == types[i]) { + throw new IllegalArgumentException("ReadablePartial objects must not have overlapping fields"); + } + values[i] = end.getValue(i) - start.getValue(i); + } + return new Period(values, PeriodType.forFields(types)); + } + + //----------------------------------------------------------------------- + /** * Creates a new empty period with the standard set of fields. *

        * One way to initialise a period is as follows: @@ -200,6 +300,8 @@ /** * Create a period from a set of field values using the standard set of fields. + * Note that the parameters specify the time fields hours, minutes, + * seconds and millis, not the date fields. * * @param hours amount of hours in this period * @param minutes amount of minutes in this period @@ -277,7 +379,7 @@ * @param duration the duration, in milliseconds */ public Period(long duration) { - super(duration, null, null); + super(duration); } /** @@ -411,6 +513,57 @@ } /** + * Creates a period from two partially specified times. + *

        + * The two partials must contain the same fields, thus you can specify + * two LocalDate objects, or two LocalTime objects, + * but not one of each. + * As these are Partial objects, time zones have no effect on the result. + *

        + * The two partials must also both be contiguous - see + * {@link DateTimeUtils#isContiguous(ReadablePartial)} for a definition. + * Both LocalDate and LocalTime are contiguous. + *

        + * An alternative way of constructing a Period from two Partials + * is {@link #fieldDifference(ReadablePartial, ReadablePartial)}. + * That method handles all kinds of partials. + * + * @param start the start of the period, must not be null + * @param end the end of the period, must not be null + * @throws IllegalArgumentException if the partials are null or invalid + * @since 1.1 + */ + public Period(ReadablePartial start, ReadablePartial end) { + super(start, end, null); + } + + /** + * Creates a period from two partially specified times. + *

        + * The two partials must contain the same fields, thus you can specify + * two LocalDate objects, or two LocalTime objects, + * but not one of each. + * As these are Partial objects, time zones have no effect on the result. + *

        + * The two partials must also both be contiguous - see + * {@link DateTimeUtils#isContiguous(ReadablePartial)} for a definition. + * Both LocalDate and LocalTime are contiguous. + *

        + * An alternative way of constructing a Period from two Partials + * is {@link #fieldDifference(ReadablePartial, ReadablePartial)}. + * That method handles all kinds of partials. + * + * @param start the start of the period, must not be null + * @param end the end of the period, must not be null + * @param type which set of fields this period supports, null means standard + * @throws IllegalArgumentException if the partials are null or invalid + * @since 1.1 + */ + public Period(ReadablePartial start, ReadablePartial end, PeriodType type) { + super(start, end, type); + } + + /** * Creates a period from the given start point and the duration. * * @param startInstant the interval start, null means now @@ -432,9 +585,34 @@ } /** - * Creates a period from the specified object using the - * {@link org.joda.time.convert.ConverterManager ConverterManager}. + * Creates a period from the given duration and end point. * + * @param duration the duration of the interval, null means zero-length + * @param endInstant the interval end, null means now + */ + public Period(ReadableDuration duration, ReadableInstant endInstant) { + super(duration, endInstant, null); + } + + /** + * Creates a period from the given duration and end point. + * + * @param duration the duration of the interval, null means zero-length + * @param endInstant the interval end, null means now + * @param type which set of fields this period supports, null means standard + */ + public Period(ReadableDuration duration, ReadableInstant endInstant, PeriodType type) { + super(duration, endInstant, type); + } + + /** + * Creates a period by converting or copying from another object. + *

        + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePeriod, ReadableInterval and String. + * The String formats are described by {@link ISOPeriodFormat#standard()}. + * * @param period period to convert * @throws IllegalArgumentException if period is invalid * @throws UnsupportedOperationException if an unsupported field's value is non-zero @@ -444,8 +622,12 @@ } /** - * Creates a period from the specified object using the - * {@link org.joda.time.convert.ConverterManager ConverterManager}. + * Creates a period by converting or copying from another object. + *

        + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePeriod, ReadableInterval and String. + * The String formats are described by {@link ISOPeriodFormat#standard()}. * * @param period period to convert * @param type which set of fields this period supports, null means use converter @@ -457,8 +639,12 @@ } /** - * Creates a period from the specified object using the - * {@link org.joda.time.convert.ConverterManager ConverterManager}. + * Creates a period by converting or copying from another object. + *

        + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePeriod, ReadableInterval and String. + * The String formats are described by {@link ISOPeriodFormat#standard()}. * * @param period period to convert * @param chrono the chronology to use, null means ISO in default zone @@ -470,8 +656,12 @@ } /** - * Creates a period from the specified object using the - * {@link org.joda.time.convert.ConverterManager ConverterManager}. + * Creates a period by converting or copying from another object. + *

        + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePeriod, ReadableInterval and String. + * The String formats are described by {@link ISOPeriodFormat#standard()}. * * @param period period to convert * @param type which set of fields this period supports, null means use converter @@ -781,6 +971,40 @@ //----------------------------------------------------------------------- /** + * Returns a new period with the specified period added. + *

        + * Each field of the period is added separately. Thus a period of + * 2 hours 30 minutes plus 3 hours 40 minutes will produce a result + * of 5 hours 70 minutes - see {@link #normalizedStandard()}. + *

        + * If the period being added contains a non-zero amount for a field that + * is not supported in this period then an exception is thrown. + *

        + * This period instance is immutable and unaffected by this method call. + * + * @param period the period to add, null adds zero and returns this + * @return the new updated period + * @throws UnsupportedOperationException if any field is not supported + * @since 1.5 + */ + public Period plus(ReadablePeriod period) { + if (period == null) { + return this; + } + int[] values = getValues(); // cloned + getPeriodType().addIndexedField(this, PeriodType.YEAR_INDEX, values, period.get(DurationFieldType.YEARS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.MONTH_INDEX, values, period.get(DurationFieldType.MONTHS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.WEEK_INDEX, values, period.get(DurationFieldType.WEEKS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.DAY_INDEX, values, period.get(DurationFieldType.DAYS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.HOUR_INDEX, values, period.get(DurationFieldType.HOURS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.MINUTE_INDEX, values, period.get(DurationFieldType.MINUTES_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.SECOND_INDEX, values, period.get(DurationFieldType.SECONDS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.MILLI_INDEX, values, period.get(DurationFieldType.MILLIS_TYPE)); + return new Period(values, getPeriodType()); + } + + //----------------------------------------------------------------------- + /** * Returns a new period with the specified number of years added. *

        * This period instance is immutable and unaffected by this method call. @@ -926,6 +1150,40 @@ //----------------------------------------------------------------------- /** + * Returns a new period with the specified period subtracted. + *

        + * Each field of the period is subtracted separately. Thus a period of + * 3 hours 30 minutes minus 2 hours 40 minutes will produce a result + * of 1 hour and -10 minutes - see {@link #normalizedStandard()}. + *

        + * If the period being added contains a non-zero amount for a field that + * is not supported in this period then an exception is thrown. + *

        + * This period instance is immutable and unaffected by this method call. + * + * @param period the period to add, null adds zero and returns this + * @return the new updated period + * @throws UnsupportedOperationException if any field is not supported + * @since 1.5 + */ + public Period minus(ReadablePeriod period) { + if (period == null) { + return this; + } + int[] values = getValues(); // cloned + getPeriodType().addIndexedField(this, PeriodType.YEAR_INDEX, values, -period.get(DurationFieldType.YEARS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.MONTH_INDEX, values, -period.get(DurationFieldType.MONTHS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.WEEK_INDEX, values, -period.get(DurationFieldType.WEEKS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.DAY_INDEX, values, -period.get(DurationFieldType.DAYS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.HOUR_INDEX, values, -period.get(DurationFieldType.HOURS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.MINUTE_INDEX, values, -period.get(DurationFieldType.MINUTES_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.SECOND_INDEX, values, -period.get(DurationFieldType.SECONDS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.MILLI_INDEX, values, -period.get(DurationFieldType.MILLIS_TYPE)); + return new Period(values, getPeriodType()); + } + + //----------------------------------------------------------------------- + /** * Returns a new period with the specified number of years taken away. *

        * This period instance is immutable and unaffected by this method call. @@ -1029,4 +1287,320 @@ return plusMillis(-millis); } + //----------------------------------------------------------------------- + /** + * Returns a new instance with each element in this period multiplied + * by the specified scalar. + * + * @param scalar the scalar to multiply by, not null + * @return a {@code Period} based on this period with the amounts multiplied by the scalar, never null + * @throws ArithmeticException if the capacity of any field is exceeded + * @since 2.1 + */ + public Period multipliedBy(int scalar) { + if (this == ZERO || scalar == 1) { + return this; + } + int[] values = getValues(); // cloned + for (int i = 0; i < values.length; i++) { + values[i] = FieldUtils.safeMultiply(values[i], scalar); + } + return new Period(values, getPeriodType()); + } + + /** + * Returns a new instance with each amount in this period negated. + * + * @return a {@code Period} based on this period with the amounts negated, never null + * @throws ArithmeticException if any field has the minimum value + * @since 2.1 + */ + public Period negated() { + return multipliedBy(-1); + } + + //----------------------------------------------------------------------- + /** + * Converts this period to a period in weeks assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *

        + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all + * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and + * all minutes are 60 seconds. This is not true when daylight savings time + * is considered, and may also not be true for some unusual chronologies. + * However, it is included as it is a useful operation for many + * applications and business rules. + *

        + * If the period contains years or months, an exception will be thrown. + * + * @return a period representing the number of standard weeks in this period + * @throws UnsupportedOperationException if the period contains years or months + * @throws ArithmeticException if the number of weeks is too large to be represented + * @since 1.5 + */ + public Weeks toStandardWeeks() { + checkYearsAndMonths("Weeks"); + long millis = getMillis(); // assign to a long + millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND; + millis += ((long) getMinutes()) * DateTimeConstants.MILLIS_PER_MINUTE; + millis += ((long) getHours()) * DateTimeConstants.MILLIS_PER_HOUR; + millis += ((long) getDays()) * DateTimeConstants.MILLIS_PER_DAY; + long weeks = ((long) getWeeks()) + millis / DateTimeConstants.MILLIS_PER_WEEK; + return Weeks.weeks(FieldUtils.safeToInt(weeks)); + } + + /** + * Converts this period to a period in days assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *

        + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all + * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and + * all minutes are 60 seconds. This is not true when daylight savings time + * is considered, and may also not be true for some unusual chronologies. + * However, it is included as it is a useful operation for many + * applications and business rules. + *

        + * If the period contains years or months, an exception will be thrown. + * + * @return a period representing the number of standard days in this period + * @throws UnsupportedOperationException if the period contains years or months + * @throws ArithmeticException if the number of days is too large to be represented + * @since 1.5 + */ + public Days toStandardDays() { + checkYearsAndMonths("Days"); + long millis = getMillis(); // assign to a long + millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND; + millis += ((long) getMinutes()) * DateTimeConstants.MILLIS_PER_MINUTE; + millis += ((long) getHours()) * DateTimeConstants.MILLIS_PER_HOUR; + long days = millis / DateTimeConstants.MILLIS_PER_DAY; + days = FieldUtils.safeAdd(days, getDays()); + days = FieldUtils.safeAdd(days, ((long) getWeeks()) * ((long) DateTimeConstants.DAYS_PER_WEEK)); + return Days.days(FieldUtils.safeToInt(days)); + } + + /** + * Converts this period to a period in hours assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *

        + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all + * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and + * all minutes are 60 seconds. This is not true when daylight savings time + * is considered, and may also not be true for some unusual chronologies. + * However, it is included as it is a useful operation for many + * applications and business rules. + *

        + * If the period contains years or months, an exception will be thrown. + * + * @return a period representing the number of standard hours in this period + * @throws UnsupportedOperationException if the period contains years or months + * @throws ArithmeticException if the number of hours is too large to be represented + * @since 1.5 + */ + public Hours toStandardHours() { + checkYearsAndMonths("Hours"); + long millis = getMillis(); // assign to a long + millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND; + millis += ((long) getMinutes()) * DateTimeConstants.MILLIS_PER_MINUTE; + long hours = millis / DateTimeConstants.MILLIS_PER_HOUR; + hours = FieldUtils.safeAdd(hours, getHours()); + hours = FieldUtils.safeAdd(hours, ((long) getDays()) * ((long) DateTimeConstants.HOURS_PER_DAY)); + hours = FieldUtils.safeAdd(hours, ((long) getWeeks()) * ((long) DateTimeConstants.HOURS_PER_WEEK)); + return Hours.hours(FieldUtils.safeToInt(hours)); + } + + /** + * Converts this period to a period in minutes assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *

        + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all + * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and + * all minutes are 60 seconds. This is not true when daylight savings time + * is considered, and may also not be true for some unusual chronologies. + * However, it is included as it is a useful operation for many + * applications and business rules. + *

        + * If the period contains years or months, an exception will be thrown. + * + * @return a period representing the number of standard minutes in this period + * @throws UnsupportedOperationException if the period contains years or months + * @throws ArithmeticException if the number of minutes is too large to be represented + * @since 1.5 + */ + public Minutes toStandardMinutes() { + checkYearsAndMonths("Minutes"); + long millis = getMillis(); // assign to a long + millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND; + long minutes = millis / DateTimeConstants.MILLIS_PER_MINUTE; + minutes = FieldUtils.safeAdd(minutes, getMinutes()); + minutes = FieldUtils.safeAdd(minutes, ((long) getHours()) * ((long) DateTimeConstants.MINUTES_PER_HOUR)); + minutes = FieldUtils.safeAdd(minutes, ((long) getDays()) * ((long) DateTimeConstants.MINUTES_PER_DAY)); + minutes = FieldUtils.safeAdd(minutes, ((long) getWeeks()) * ((long) DateTimeConstants.MINUTES_PER_WEEK)); + return Minutes.minutes(FieldUtils.safeToInt(minutes)); + } + + /** + * Converts this period to a period in seconds assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *

        + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all + * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and + * all minutes are 60 seconds. This is not true when daylight savings time + * is considered, and may also not be true for some unusual chronologies. + * However, it is included as it is a useful operation for many + * applications and business rules. + *

        + * If the period contains years or months, an exception will be thrown. + * + * @return a period representing the number of standard seconds in this period + * @throws UnsupportedOperationException if the period contains years or months + * @throws ArithmeticException if the number of seconds is too large to be represented + * @since 1.5 + */ + public Seconds toStandardSeconds() { + checkYearsAndMonths("Seconds"); + long seconds = getMillis() / DateTimeConstants.MILLIS_PER_SECOND; + seconds = FieldUtils.safeAdd(seconds, getSeconds()); + seconds = FieldUtils.safeAdd(seconds, ((long) getMinutes()) * ((long) DateTimeConstants.SECONDS_PER_MINUTE)); + seconds = FieldUtils.safeAdd(seconds, ((long) getHours()) * ((long) DateTimeConstants.SECONDS_PER_HOUR)); + seconds = FieldUtils.safeAdd(seconds, ((long) getDays()) * ((long) DateTimeConstants.SECONDS_PER_DAY)); + seconds = FieldUtils.safeAdd(seconds, ((long) getWeeks()) * ((long) DateTimeConstants.SECONDS_PER_WEEK)); + return Seconds.seconds(FieldUtils.safeToInt(seconds)); + } + + //----------------------------------------------------------------------- + /** + * Converts this period to a duration assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *

        + * This method allows you to convert from a period to a duration. + * However to achieve this it makes the assumption that all + * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and + * all minutes are 60 seconds. This is not true when daylight savings time + * is considered, and may also not be true for some unusual chronologies. + * However, it is included as it is a useful operation for many + * applications and business rules. + *

        + * If the period contains years or months, an exception will be thrown. + * + * @return a duration equivalent to this period + * @throws UnsupportedOperationException if the period contains years or months + * @since 1.5 + */ + public Duration toStandardDuration() { + checkYearsAndMonths("Duration"); + long millis = getMillis(); // no overflow can happen, even with Integer.MAX_VALUEs + millis += (((long) getSeconds()) * ((long) DateTimeConstants.MILLIS_PER_SECOND)); + millis += (((long) getMinutes()) * ((long) DateTimeConstants.MILLIS_PER_MINUTE)); + millis += (((long) getHours()) * ((long) DateTimeConstants.MILLIS_PER_HOUR)); + millis += (((long) getDays()) * ((long) DateTimeConstants.MILLIS_PER_DAY)); + millis += (((long) getWeeks()) * ((long) DateTimeConstants.MILLIS_PER_WEEK)); + return new Duration(millis); + } + + /** + * Check that there are no years or months in the period. + * + * @param destintionType the destination type, not null + * @throws UnsupportedOperationException if the period contains years or months + */ + private void checkYearsAndMonths(String destintionType) { + if (getMonths() != 0) { + throw new UnsupportedOperationException("Cannot convert to " + destintionType + " as this period contains months and months vary in length"); + } + if (getYears() != 0) { + throw new UnsupportedOperationException("Cannot convert to " + destintionType + " as this period contains years and years vary in length"); + } + } + + //----------------------------------------------------------------------- + /** + * Normalizes this period using standard rules, assuming a 12 month year, + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *

        + * This method allows you to normalize a period. + * However to achieve this it makes the assumption that all years are + * 12 months, all weeks are 7 days, all days are 24 hours, + * all hours are 60 minutes and all minutes are 60 seconds. This is not + * true when daylight savings time is considered, and may also not be true + * for some chronologies. However, it is included as it is a useful operation + * for many applications and business rules. + *

        + * If the period contains years or months, then the months will be + * normalized to be between 0 and 11. The days field and below will be + * normalized as necessary, however this will not overflow into the months + * field. Thus a period of 1 year 15 months will normalize to 2 years 3 months. + * But a period of 1 month 40 days will remain as 1 month 40 days. + *

        + * The result will always have a PeriodType of standard, thus + * days will be grouped into weeks. + * + * @return a normalized period equivalent to this period + * @throws ArithmeticException if any field is too large to be represented + * @since 1.5 + */ + public Period normalizedStandard() { + return normalizedStandard(PeriodType.standard()); + } + + //----------------------------------------------------------------------- + /** + * Normalizes this period using standard rules, assuming a 12 month year, + * 7 day week, 24 hour day, 60 minute hour and 60 second minute, + * providing control over how the result is split into fields. + *

        + * This method allows you to normalize a period. + * However to achieve this it makes the assumption that all years are + * 12 months, all weeks are 7 days, all days are 24 hours, + * all hours are 60 minutes and all minutes are 60 seconds. This is not + * true when daylight savings time is considered, and may also not be true + * for some chronologies. However, it is included as it is a useful operation + * for many applications and business rules. + *

        + * If the period contains years or months, then the months will be + * normalized to be between 0 and 11. The days field and below will be + * normalized as necessary, however this will not overflow into the months + * field. Thus a period of 1 year 15 months will normalize to 2 years 3 months. + * But a period of 1 month 40 days will remain as 1 month 40 days. + *

        + * The PeriodType parameter controls how the result is created. It allows + * you to omit certain fields from the result if desired. For example, + * you may not want the result to include weeks, in which case you pass + * in PeriodType.yearMonthDayTime(). + * + * @param type the period type of the new period, null means standard type + * @return a normalized period equivalent to this period + * @throws ArithmeticException if any field is too large to be represented + * @throws UnsupportedOperationException if this period contains non-zero + * years or months but the specified period type does not support them + * @since 1.5 + */ + public Period normalizedStandard(PeriodType type) { + long millis = getMillis(); // no overflow can happen, even with Integer.MAX_VALUEs + millis += (((long) getSeconds()) * ((long) DateTimeConstants.MILLIS_PER_SECOND)); + millis += (((long) getMinutes()) * ((long) DateTimeConstants.MILLIS_PER_MINUTE)); + millis += (((long) getHours()) * ((long) DateTimeConstants.MILLIS_PER_HOUR)); + millis += (((long) getDays()) * ((long) DateTimeConstants.MILLIS_PER_DAY)); + millis += (((long) getWeeks()) * ((long) DateTimeConstants.MILLIS_PER_WEEK)); + Period result = new Period(millis, DateTimeUtils.getPeriodType(type), ISOChronology.getInstanceUTC()); + int years = getYears(); + int months = getMonths(); + if (years != 0 || months != 0) { + years = FieldUtils.safeAdd(years, months / 12); + months = months % 12; + if (years != 0) { + result = result.withYears(years); + } + if (months != 0) { + result = result.withMonths(months); + } + } + return result; + } + } Index: 3rdParty_sources/joda-time/org/joda/time/PeriodType.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/PeriodType.java (.../PeriodType.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/PeriodType.java (.../PeriodType.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,60 +1,26 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; import java.io.Serializable; +import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.joda.time.field.FieldUtils; @@ -65,8 +31,11 @@ *

          *
        • Standard - years, months, weeks, days, hours, minutes, seconds, millis *
        • YearMonthDayTime - years, months, days, hours, minutes, seconds, millis + *
        • YearMonthDay - years, months, days *
        • YearWeekDayTime - years, weeks, days, hours, minutes, seconds, millis + *
        • YearWeekDay - years, weeks, days *
        • YearDayTime - years, days, hours, minutes, seconds, millis + *
        • YearDay - years, days, hours *
        • DayTime - days, hours, minutes, seconds, millis *
        • Time - hours, minutes, seconds, millis *
        • plus one for each single type @@ -83,6 +52,9 @@ /** Serialization version */ private static final long serialVersionUID = 2274324892792009998L; + /** Cache of all the known types. */ + private static final Map cTypes = new HashMap(32); + static int YEAR_INDEX = 0; static int MONTH_INDEX = 1; static int WEEK_INDEX = 2; @@ -94,8 +66,11 @@ private static PeriodType cStandard; private static PeriodType cYMDTime; + private static PeriodType cYMD; private static PeriodType cYWDTime; + private static PeriodType cYWD; private static PeriodType cYDTime; + private static PeriodType cYD; private static PeriodType cDTime; private static PeriodType cTime; @@ -174,6 +149,33 @@ } /** + * Gets a type that defines the year, month and day fields. + *
            + *
          • years + *
          • months + *
          • days + *
          + * + * @return the period type + * @since 1.1 + */ + public static PeriodType yearMonthDay() { + PeriodType type = cYMD; + if (type == null) { + type = new PeriodType( + "YearMonthDay", + new DurationFieldType[] { + DurationFieldType.years(), DurationFieldType.months(), + DurationFieldType.days(), + }, + new int[] { 0, 1, -1, 2, -1, -1, -1, -1, } + ); + cYMD = type; + } + return type; + } + + /** * Gets a type that defines all standard fields except months. *
            *
          • years @@ -206,6 +208,33 @@ } /** + * Gets a type that defines year, week and day fields. + *
              + *
            • years + *
            • weeks + *
            • days + *
            + * + * @return the period type + * @since 1.1 + */ + public static PeriodType yearWeekDay() { + PeriodType type = cYWD; + if (type == null) { + type = new PeriodType( + "YearWeekDay", + new DurationFieldType[] { + DurationFieldType.years(), + DurationFieldType.weeks(), DurationFieldType.days(), + }, + new int[] { 0, -1, 1, 2, -1, -1, -1, -1, } + ); + cYWD = type; + } + return type; + } + + /** * Gets a type that defines all standard fields except months and weeks. *
              *
            • years @@ -236,6 +265,31 @@ } /** + * Gets a type that defines the year and day fields. + *
                + *
              • years + *
              • days + *
              + * + * @return the period type + * @since 1.1 + */ + public static PeriodType yearDay() { + PeriodType type = cYD; + if (type == null) { + type = new PeriodType( + "YearDay", + new DurationFieldType[] { + DurationFieldType.years(), DurationFieldType.days(), + }, + new int[] { 0, -1, -1, 1, -1, -1, -1, -1, } + ); + cYD = type; + } + return type; + } + + /** * Gets a type that defines all standard fields from days downwards. *
                *
              • days @@ -435,6 +489,93 @@ return type; } + /** + * Gets a period type that contains the duration types of the array. + *

                + * Only the 8 standard duration field types are supported. + * + * @param types the types to include in the array. + * @return the period type + * @since 1.1 + */ + public static synchronized PeriodType forFields(DurationFieldType[] types) { + if (types == null || types.length == 0) { + throw new IllegalArgumentException("Types array must not be null or empty"); + } + for (int i = 0; i < types.length; i++) { + if (types[i] == null) { + throw new IllegalArgumentException("Types array must not contain null"); + } + } + Map cache = cTypes; + if (cache.isEmpty()) { + cache.put(standard(), standard()); + cache.put(yearMonthDayTime(), yearMonthDayTime()); + cache.put(yearMonthDay(), yearMonthDay()); + cache.put(yearWeekDayTime(), yearWeekDayTime()); + cache.put(yearWeekDay(), yearWeekDay()); + cache.put(yearDayTime(), yearDayTime()); + cache.put(yearDay(), yearDay()); + cache.put(dayTime(), dayTime()); + cache.put(time(), time()); + cache.put(years(), years()); + cache.put(months(), months()); + cache.put(weeks(), weeks()); + cache.put(days(), days()); + cache.put(hours(), hours()); + cache.put(minutes(), minutes()); + cache.put(seconds(), seconds()); + cache.put(millis(), millis()); + } + PeriodType inPartType = new PeriodType(null, types, null); + Object cached = cache.get(inPartType); + if (cached instanceof PeriodType) { + return (PeriodType) cached; + } + if (cached != null) { + throw new IllegalArgumentException("PeriodType does not support fields: " + cached); + } + PeriodType type = standard(); + List list = new ArrayList(Arrays.asList(types)); + if (list.remove(DurationFieldType.years()) == false) { + type = type.withYearsRemoved(); + } + if (list.remove(DurationFieldType.months()) == false) { + type = type.withMonthsRemoved(); + } + if (list.remove(DurationFieldType.weeks()) == false) { + type = type.withWeeksRemoved(); + } + if (list.remove(DurationFieldType.days()) == false) { + type = type.withDaysRemoved(); + } + if (list.remove(DurationFieldType.hours()) == false) { + type = type.withHoursRemoved(); + } + if (list.remove(DurationFieldType.minutes()) == false) { + type = type.withMinutesRemoved(); + } + if (list.remove(DurationFieldType.seconds()) == false) { + type = type.withSecondsRemoved(); + } + if (list.remove(DurationFieldType.millis()) == false) { + type = type.withMillisRemoved(); + } + if (list.size() > 0) { + cache.put(inPartType, list); + throw new IllegalArgumentException("PeriodType does not support fields: " + list); + } + // recheck cache in case initial array order was wrong + PeriodType checkPartType = new PeriodType(null, type.iTypes, null); + PeriodType checkedType = (PeriodType) cache.get(checkPartType); + if (checkedType != null) { + cache.put(checkPartType, checkedType); + return checkedType; + } + cache.put(checkPartType, type); + return type; + } + //----------------------------------------------------------------------- /** The name of the type */ private final String iName; @@ -518,7 +659,6 @@ * @return a string */ public String toString() { - String name = getName(); return "PeriodType[" + getName() + "]"; } @@ -542,12 +682,12 @@ * @param index the index to use * @param values the array to populate * @param newValue the value to set - * @throws IllegalArgumentException if not supported + * @throws UnsupportedOperationException if not supported */ boolean setIndexedField(ReadablePeriod period, int index, int[] values, int newValue) { int realIndex = iIndices[index]; if (realIndex == -1) { - throw new IllegalArgumentException("Field is not supported"); + throw new UnsupportedOperationException("Field is not supported"); } values[realIndex] = newValue; return true; @@ -560,12 +700,16 @@ * @param index the index to use * @param values the array to populate * @param valueToAdd the value to add - * @throws IllegalArgumentException if not supported + * @return true if the array is updated + * @throws UnsupportedOperationException if not supported */ boolean addIndexedField(ReadablePeriod period, int index, int[] values, int valueToAdd) { + if (valueToAdd == 0) { + return false; + } int realIndex = iIndices[index]; if (realIndex == -1) { - throw new IllegalArgumentException("Field is not supported"); + throw new UnsupportedOperationException("Field is not supported"); } values[realIndex] = FieldUtils.safeAdd(values[realIndex], valueToAdd); return true; Index: 3rdParty_sources/joda-time/org/joda/time/ReadWritableDateTime.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/ReadWritableDateTime.java (.../ReadWritableDateTime.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/ReadWritableDateTime.java (.../ReadWritableDateTime.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; @@ -64,6 +26,7 @@ * * @author Stephen Colebourne * @author Brian S O'Neill + * @since 1.0 */ public interface ReadWritableDateTime extends ReadableDateTime, ReadWritableInstant { Index: 3rdParty_sources/joda-time/org/joda/time/ReadWritableInstant.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/ReadWritableInstant.java (.../ReadWritableInstant.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/ReadWritableInstant.java (.../ReadWritableInstant.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; Index: 3rdParty_sources/joda-time/org/joda/time/ReadWritableInterval.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/ReadWritableInterval.java (.../ReadWritableInterval.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/ReadWritableInterval.java (.../ReadWritableInterval.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; Index: 3rdParty_sources/joda-time/org/joda/time/ReadWritablePeriod.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/ReadWritablePeriod.java (.../ReadWritablePeriod.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/ReadWritablePeriod.java (.../ReadWritablePeriod.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; Index: 3rdParty_sources/joda-time/org/joda/time/ReadableDateTime.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/ReadableDateTime.java (.../ReadableDateTime.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/ReadableDateTime.java (.../ReadableDateTime.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; @@ -96,13 +58,24 @@ /** * Get the week of weekyear field value. + *

                + * This field is associated with the "weekyear" via {@link #getWeekyear()}. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. * * @return the week of a week based year */ int getWeekOfWeekyear(); /** * Get the weekyear field value. + *

                + * The weekyear is the year that matches with the weekOfWeekyear field. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + * The weekyear allows you to query the effective year for that day. * * @return the year of a week based year */ Index: 3rdParty_sources/joda-time/org/joda/time/ReadableDuration.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/ReadableDuration.java (.../ReadableDuration.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/ReadableDuration.java (.../ReadableDuration.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; @@ -61,14 +23,20 @@ *

                * Methods that are passed a duration as a parameter will treat null * as a zero length duration. + *

                + * The {@code compareTo} method is no longer defined in this class in version 2.0. + * Instead, the definition is simply inherited from the {@code Comparable} interface. + * This approach is necessary to preserve binary compatibility. + * The definition of the comparison is ascending order by millisecond duration. + * Implementors are recommended to extend {@code AbstractInstant} instead of this interface. * * @see ReadableInterval * @see ReadablePeriod * @author Brian S O'Neill * @author Stephen Colebourne * @since 1.0 */ -public interface ReadableDuration extends Comparable { +public interface ReadableDuration extends Comparable { /** * Gets the total length of this duration in milliseconds. @@ -112,15 +80,16 @@ Period toPeriod(); //----------------------------------------------------------------------- - /** - * Compares this duration with the specified duration based on length. - * - * @param obj a duration to check against - * @return negative value if this is less, 0 if equal, or positive value if greater - * @throws NullPointerException if the object is null - * @throws ClassCastException if the given object is not supported - */ - int compareTo(Object obj); + // Method is no longer defined here as that would break generic backwards compatibility +// /** +// * Compares this duration with the specified duration based on length. +// * +// * @param obj a duration to check against +// * @return negative value if this is less, 0 if equal, or positive value if greater +// * @throws NullPointerException if the object is null +// * @throws ClassCastException if the given object is not supported +// */ +// int compareTo(ReadableDuration obj); /** * Is the length of this duration equal to the duration passed in. Index: 3rdParty_sources/joda-time/org/joda/time/ReadableInstant.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/ReadableInstant.java (.../ReadableInstant.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/ReadableInstant.java (.../ReadableInstant.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; @@ -63,11 +25,17 @@ * Methods in your application should be defined using ReadableInstant * as a parameter if the method only wants to read the instant without needing to know * the specific datetime fields. + *

                + * The {@code compareTo} method is no longer defined in this class in version 2.0. + * Instead, the definition is simply inherited from the {@code Comparable} interface. + * This approach is necessary to preserve binary compatibility. + * The definition of the comparison is ascending order by millisecond instant. + * Implementors are recommended to extend {@code AbstractInstant} instead of this interface. * * @author Stephen Colebourne * @since 1.0 */ -public interface ReadableInstant extends Comparable { +public interface ReadableInstant extends Comparable { /** * Get the value as the number of milliseconds since @@ -105,6 +73,14 @@ */ int get(DateTimeFieldType type); + /** + * Checks whether the field type specified is supported by this implementation. + * + * @param field the field type to check, may be null which returns false + * @return true if the field is supported + */ + boolean isSupported(DateTimeFieldType field); + //----------------------------------------------------------------------- /** * Get the value as a simple immutable Instant object. @@ -118,19 +94,20 @@ Instant toInstant(); //----------------------------------------------------------------------- - /** - * Compares this object with the specified object for ascending - * millisecond instant order. This ordering is inconsistent with - * equals, as it ignores the Chronology. - *

                - * All ReadableInstant instances are accepted. - * - * @param readableInstant a readable instant to check against - * @return negative value if this is less, 0 if equal, or positive value if greater - * @throws NullPointerException if the object is null - * @throws ClassCastException if the object type is not supported - */ - int compareTo(Object readableInstant); + // Method is no longer defined here as that would break generic backwards compatibility +// /** +// * Compares this object with the specified object for ascending +// * millisecond instant order. This ordering is inconsistent with +// * equals, as it ignores the Chronology. +// *

                +// * All ReadableInstant instances are accepted. +// * +// * @param readableInstant a readable instant to check against +// * @return negative value if this is less, 0 if equal, or positive value if greater +// * @throws NullPointerException if the object is null +// * @throws ClassCastException if the object type is not supported +// */ +// int compareTo(ReadableInstant readableInstant); //----------------------------------------------------------------------- /** Index: 3rdParty_sources/joda-time/org/joda/time/ReadableInterval.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/ReadableInterval.java (.../ReadableInterval.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/ReadableInterval.java (.../ReadableInterval.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2006 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; @@ -121,30 +83,98 @@ /** * Does this time interval contain the specified instant. *

                - * Intervals are inclusive of the start instant and exclusive of the end. + * Non-zero duration intervals are inclusive of the start instant and + * exclusive of the end. A zero duration interval cannot contain anything. + *

                + * For example: + *

                +     * [09:00 to 10:00) contains 08:59  = false (before start)
                +     * [09:00 to 10:00) contains 09:00  = true
                +     * [09:00 to 10:00) contains 09:59  = true
                +     * [09:00 to 10:00) contains 10:00  = false (equals end)
                +     * [09:00 to 10:00) contains 10:01  = false (after end)
                      * 
                +     * [14:00 to 14:00) contains 14:00  = false (zero duration contains nothing)
                +     * 
                + * * @param instant the instant, null means now * @return true if this time interval contains the instant */ boolean contains(ReadableInstant instant); /** - * Does this time interval contain the specified time interval completely. + * Does this time interval contain the specified time interval. *

                - * Intervals are inclusive of the start instant and exclusive of the end. + * Non-zero duration intervals are inclusive of the start instant and + * exclusive of the end. The other interval is contained if this interval + * wholly contains, starts, finishes or equals it. + * A zero duration interval cannot contain anything. + *

                + * When two intervals are compared the result is one of three states: + * (a) they abut, (b) there is a gap between them, (c) they overlap. + * The contains method is not related to these states. + * In particular, a zero duration interval is contained at the start of + * a larger interval, but does not overlap (it abuts instead). + *

                + * For example: + *

                +     * [09:00 to 10:00) contains [09:00 to 10:00)  = true
                +     * [09:00 to 10:00) contains [09:00 to 09:30)  = true
                +     * [09:00 to 10:00) contains [09:30 to 10:00)  = true
                +     * [09:00 to 10:00) contains [09:15 to 09:45)  = true
                +     * [09:00 to 10:00) contains [09:00 to 09:00)  = true
                      * 
                -     * @param interval  the time interval to compare to, null means now
                +     * [09:00 to 10:00) contains [08:59 to 10:00)  = false (otherStart before thisStart)
                +     * [09:00 to 10:00) contains [09:00 to 10:01)  = false (otherEnd after thisEnd)
                +     * [09:00 to 10:00) contains [10:00 to 10:00)  = false (otherStart equals thisEnd)
                +     * 
                +     * [14:00 to 14:00) contains [14:00 to 14:00)  = false (zero duration contains nothing)
                +     * 
                + * + * @param interval the time interval to compare to, null means a zero duration interval now * @return true if this time interval contains the time interval */ boolean contains(ReadableInterval interval); /** * Does this time interval overlap the specified time interval. *

                - * The intervals overlap if at least some of the time interval is in common. * Intervals are inclusive of the start instant and exclusive of the end. + * An interval overlaps another if it shares some common part of the + * datetime continuum. + *

                + * When two intervals are compared the result is one of three states: + * (a) they abut, (b) there is a gap between them, (c) they overlap. + * The abuts state takes precedence over the other two, thus a zero duration + * interval at the start of a larger interval abuts and does not overlap. + *

                + * For example: + *

                +     * [09:00 to 10:00) overlaps [08:00 to 08:30)  = false (completely before)
                +     * [09:00 to 10:00) overlaps [08:00 to 09:00)  = false (abuts before)
                +     * [09:00 to 10:00) overlaps [08:00 to 09:30)  = true
                +     * [09:00 to 10:00) overlaps [08:00 to 10:00)  = true
                +     * [09:00 to 10:00) overlaps [08:00 to 11:00)  = true
                      * 
                -     * @param interval  the time interval to compare to, null means now
                +     * [09:00 to 10:00) overlaps [09:00 to 09:00)  = false (abuts before)
                +     * [09:00 to 10:00) overlaps [09:00 to 09:30)  = true
                +     * [09:00 to 10:00) overlaps [09:00 to 10:00)  = true
                +     * [09:00 to 10:00) overlaps [09:00 to 11:00)  = true
                +     * 
                +     * [09:00 to 10:00) overlaps [09:30 to 09:30)  = true
                +     * [09:00 to 10:00) overlaps [09:30 to 10:00)  = true
                +     * [09:00 to 10:00) overlaps [09:30 to 11:00)  = true
                +     * 
                +     * [09:00 to 10:00) overlaps [10:00 to 10:00)  = false (abuts after)
                +     * [09:00 to 10:00) overlaps [10:00 to 11:00)  = false (abuts after)
                +     * 
                +     * [09:00 to 10:00) overlaps [10:30 to 11:00)  = false (completely after)
                +     * 
                +     * [14:00 to 14:00) overlaps [14:00 to 14:00)  = false (abuts before and after)
                +     * [14:00 to 14:00) overlaps [13:00 to 15:00)  = true
                +     * 
                + * + * @param interval the time interval to compare to, null means a zero length interval now * @return true if the time intervals overlap */ boolean overlaps(ReadableInterval interval); Index: 3rdParty_sources/joda-time/org/joda/time/ReadablePartial.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/ReadablePartial.java (.../ReadablePartial.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/ReadablePartial.java (.../ReadablePartial.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,74 +1,41 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; /** * Defines a partial time that does not support every datetime field, and is * thus a local time. *

                - * A ReadablePartial supports a subset of those fields on the chronology. - * It cannot be compared to a ReadableInstant, as it does not fully + * A {@code ReadablePartial} supports a subset of those fields on the chronology. + * It cannot be compared to a {@code ReadableInstant}, as it does not fully * specify an instant in time. The time it does specify is a local time, and does * not include a time zone. *

                - * A ReadablePartial can be converted to a ReadableInstant - * using one of the resolve methods. These work by providing a full base + * A {@code ReadablePartial} can be converted to a {@code ReadableInstant} + * using the {@code toDateTime} method. This works by providing a full base * instant that can be used to 'fill in the gaps' and specify a time zone. + *

                + * {@code ReadablePartial} is {@code Comparable} from v2.0. + * The comparison is based on the fields, compared in order, from largest to smallest. + * The first field that is non-equal is used to determine the result. * * @author Stephen Colebourne + * @since 1.0 */ -public interface ReadablePartial { +public interface ReadablePartial extends Comparable { /** * Gets the number of fields that this partial supports. @@ -134,23 +101,6 @@ boolean isSupported(DateTimeFieldType field); /** - * Converts this partial to a full datetime using the specified time zone and - * filing in any gaps using the current datetime. - *

                - * This method obtains the current datetime, creates a chronology from that - * on this instance plus the time zone specified, and then sets the fields - * from this instant on top. - *

                - * For example, if this partial represents a time, then the result of this - * method will be the datetime from the specified base instant plus the - * time from this partial. - * - * @param zone the zone to use, null means default - * @return the combined datetime - */ - DateTime toDateTime(DateTimeZone zone); - - /** * Converts this partial to a full datetime by resolving it against another * datetime. *

                @@ -199,6 +149,30 @@ int hashCode(); //----------------------------------------------------------------------- +// This is commented out to improve backwards compatibility +// /** +// * Compares this partial with another returning an integer +// * indicating the order. +// *

                +// * The fields are compared in order, from largest to smallest. +// * The first field that is non-equal is used to determine the result. +// * Thus a year-hour partial will first be compared on the year, and then +// * on the hour. +// *

                +// * The specified object must be a partial instance whose field types +// * match those of this partial. If the partial instance has different +// * fields then a {@code ClassCastException} is thrown. +// * +// * @param partial an object to check against +// * @return negative if this is less, zero if equal, positive if greater +// * @throws ClassCastException if the partial is the wrong class +// * or if it has field types that don't match +// * @throws NullPointerException if the partial is null +// * @since 2.0, previously on {@code AbstractPartial} +// */ +// int compareTo(ReadablePartial partial); + + //----------------------------------------------------------------------- /** * Get the value as a String in a recognisable ISO8601 format, only * displaying supported fields. Index: 3rdParty_sources/joda-time/org/joda/time/ReadablePeriod.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/ReadablePeriod.java (.../ReadablePeriod.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/ReadablePeriod.java (.../ReadablePeriod.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; @@ -156,6 +118,18 @@ * Compares this object with the specified object for equality based * on the value and type of each supported field. * All ReadablePeriod instances are accepted. + *

                + * Note that a period of 1 day is not equal to a period of 24 hours, + * nor is 1 hour equal to 60 minutes. Only periods with the same amount + * in each field are equal. + *

                + * This is because periods represent an abstracted definition of a time + * period (eg. a day may not actually be 24 hours, it might be 23 or 25 + * at daylight savings boundary). + *

                + * To compare the actual duration of two periods, convert both to + * {@link Duration}s, an operation that emphasises that the result may + * differ according to the date you choose. * * @param readablePeriod a readable period to check against * @return true if all the field values and types are equal, false if Index: 3rdParty_sources/joda-time/org/joda/time/Seconds.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/Seconds.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/Seconds.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,471 @@ +/* + * Copyright 2001-2010 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; +import org.joda.time.base.BaseSingleFieldPeriod; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.ISOPeriodFormat; +import org.joda.time.format.PeriodFormatter; + +/** + * An immutable time period representing a number of seconds. + *

                + * Seconds is an immutable period that can only store seconds. + * It does not store years, months or hours for example. As such it is a + * type-safe way of representing a number of seconds in an application. + *

                + * The number of seconds is set in the constructor, and may be queried using + * getSeconds(). Basic mathematical operations are provided - + * plus(), minus(), multipliedBy() and + * dividedBy(). + *

                + * Seconds is thread-safe and immutable. + * + * @author Stephen Colebourne + * @since 1.4 + */ +public final class Seconds extends BaseSingleFieldPeriod { + + /** Constant representing zero seconds. */ + public static final Seconds ZERO = new Seconds(0); + /** Constant representing one second. */ + public static final Seconds ONE = new Seconds(1); + /** Constant representing two seconds. */ + public static final Seconds TWO = new Seconds(2); + /** Constant representing three seconds. */ + public static final Seconds THREE = new Seconds(3); + /** Constant representing the maximum number of seconds that can be stored in this object. */ + public static final Seconds MAX_VALUE = new Seconds(Integer.MAX_VALUE); + /** Constant representing the minimum number of seconds that can be stored in this object. */ + public static final Seconds MIN_VALUE = new Seconds(Integer.MIN_VALUE); + + /** The paser to use for this class. */ + private static final PeriodFormatter PARSER = ISOPeriodFormat.standard().withParseType(PeriodType.seconds()); + /** Serialization version. */ + private static final long serialVersionUID = 87525275727380862L; + + //----------------------------------------------------------------------- + /** + * Obtains an instance of Seconds that may be cached. + * Seconds is immutable, so instances can be cached and shared. + * This factory method provides access to shared instances. + * + * @param seconds the number of seconds to obtain an instance for + * @return the instance of Seconds + */ + public static Seconds seconds(int seconds) { + switch (seconds) { + case 0: + return ZERO; + case 1: + return ONE; + case 2: + return TWO; + case 3: + return THREE; + case Integer.MAX_VALUE: + return MAX_VALUE; + case Integer.MIN_VALUE: + return MIN_VALUE; + default: + return new Seconds(seconds); + } + } + + //----------------------------------------------------------------------- + /** + * Creates a Seconds representing the number of whole seconds + * between the two specified datetimes. + * + * @param start the start instant, must not be null + * @param end the end instant, must not be null + * @return the period in seconds + * @throws IllegalArgumentException if the instants are null or invalid + */ + public static Seconds secondsBetween(ReadableInstant start, ReadableInstant end) { + int amount = BaseSingleFieldPeriod.between(start, end, DurationFieldType.seconds()); + return Seconds.seconds(amount); + } + + /** + * Creates a Seconds representing the number of whole seconds + * between the two specified partial datetimes. + *

                + * The two partials must contain the same fields, for example you can specify + * two LocalTime objects. + * + * @param start the start partial date, must not be null + * @param end the end partial date, must not be null + * @return the period in seconds + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Seconds secondsBetween(ReadablePartial start, ReadablePartial end) { + if (start instanceof LocalTime && end instanceof LocalTime) { + Chronology chrono = DateTimeUtils.getChronology(start.getChronology()); + int seconds = chrono.seconds().getDifference( + ((LocalTime) end).getLocalMillis(), ((LocalTime) start).getLocalMillis()); + return Seconds.seconds(seconds); + } + int amount = BaseSingleFieldPeriod.between(start, end, ZERO); + return Seconds.seconds(amount); + } + + /** + * Creates a Seconds representing the number of whole seconds + * in the specified interval. + * + * @param interval the interval to extract seconds from, null returns zero + * @return the period in seconds + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Seconds secondsIn(ReadableInterval interval) { + if (interval == null) { + return Seconds.ZERO; + } + int amount = BaseSingleFieldPeriod.between(interval.getStart(), interval.getEnd(), DurationFieldType.seconds()); + return Seconds.seconds(amount); + } + + /** + * Creates a new Seconds representing the number of complete + * standard length seconds in the specified period. + *

                + * This factory method converts all fields from the period to hours using standardised + * durations for each field. Only those fields which have a precise duration in + * the ISO UTC chronology can be converted. + *

                  + *
                • One week consists of 7 seconds. + *
                • One day consists of 24 hours. + *
                • One hour consists of 60 minutes. + *
                • One minute consists of 60 seconds. + *
                • One second consists of 1000 milliseconds. + *
                + * Months and Years are imprecise and periods containing these values cannot be converted. + * + * @param period the period to get the number of hours from, null returns zero + * @return the period in seconds + * @throws IllegalArgumentException if the period contains imprecise duration values + */ + public static Seconds standardSecondsIn(ReadablePeriod period) { + int amount = BaseSingleFieldPeriod.standardPeriodIn(period, DateTimeConstants.MILLIS_PER_SECOND); + return Seconds.seconds(amount); + } + + /** + * Creates a new Seconds by parsing a string in the ISO8601 format 'PTnS'. + *

                + * The parse will accept the full ISO syntax of PnYnMnWnDTnHnMnS however only the + * seconds component may be non-zero. If any other component is non-zero, an exception + * will be thrown. + * + * @param periodStr the period string, null returns zero + * @return the period in seconds + * @throws IllegalArgumentException if the string format is invalid + */ + @FromString + public static Seconds parseSeconds(String periodStr) { + if (periodStr == null) { + return Seconds.ZERO; + } + Period p = PARSER.parsePeriod(periodStr); + return Seconds.seconds(p.getSeconds()); + } + + //----------------------------------------------------------------------- + /** + * Creates a new instance representing a number of seconds. + * You should consider using the factory method {@link #seconds(int)} + * instead of the constructor. + * + * @param seconds the number of seconds to represent + */ + private Seconds(int seconds) { + super(seconds); + } + + /** + * Resolves singletons. + * + * @return the singleton instance + */ + private Object readResolve() { + return Seconds.seconds(getValue()); + } + + //----------------------------------------------------------------------- + /** + * Gets the duration field type, which is seconds. + * + * @return the period type + */ + public DurationFieldType getFieldType() { + return DurationFieldType.seconds(); + } + + /** + * Gets the period type, which is seconds. + * + * @return the period type + */ + public PeriodType getPeriodType() { + return PeriodType.seconds(); + } + + //----------------------------------------------------------------------- + /** + * Converts this period in seconds to a period in weeks assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *

                + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all weeks are 7 days + * long, all days are 24 hours long, all hours are 60 minutes long and + * all minutes are 60 seconds long. + * This is not true when daylight savings time is considered, and may also + * not be true for some unusual chronologies. However, it is included as it + * is a useful operation for many applications and business rules. + * + * @return a period representing the number of whole weeks for this number of seconds + */ + public Weeks toStandardWeeks() { + return Weeks.weeks(getValue() / DateTimeConstants.SECONDS_PER_WEEK); + } + + /** + * Converts this period in seconds to a period in days assuming a + * 24 hour day, 60 minute hour and 60 second minute. + *

                + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all days are 24 hours + * long, all hours are 60 minutes long and all minutes are 60 seconds long. + * This is not true when daylight savings is considered and may also not + * be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of days for this number of seconds + */ + public Days toStandardDays() { + return Days.days(getValue() / DateTimeConstants.SECONDS_PER_DAY); + } + + /** + * Converts this period in seconds to a period in hours assuming a + * 60 minute hour and 60 second minute. + *

                + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all hours are + * 60 minutes long and all minutes are 60 seconds long. + * This may not be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of hours for this number of seconds + */ + public Hours toStandardHours() { + return Hours.hours(getValue() / DateTimeConstants.SECONDS_PER_HOUR); + } + + /** + * Converts this period in seconds to a period in minutes assuming a + * 60 second minute. + *

                + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all minutes are + * 60 seconds long. + * This may not be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of minutes for this number of seconds + */ + public Minutes toStandardMinutes() { + return Minutes.minutes(getValue() / DateTimeConstants.SECONDS_PER_MINUTE); + } + + //----------------------------------------------------------------------- + /** + * Converts this period in seconds to a duration in milliseconds assuming a + * 24 hour day, 60 minute hour and 60 second minute. + *

                + * This method allows you to convert from a period to a duration. + * However to achieve this it makes the assumption that all seconds are 24 hours + * long, all hours are 60 minutes and all minutes are 60 seconds. + * This is not true when daylight savings time is considered, and may also + * not be true for some unusual chronologies. However, it is included as it + * is a useful operation for many applications and business rules. + * + * @return a duration equivalent to this number of seconds + */ + public Duration toStandardDuration() { + long seconds = getValue(); // assign to a long + return new Duration(seconds * DateTimeConstants.MILLIS_PER_SECOND); + } + + //----------------------------------------------------------------------- + /** + * Gets the number of seconds that this period represents. + * + * @return the number of seconds in the period + */ + public int getSeconds() { + return getValue(); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of seconds added. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param seconds the amount of seconds to add, may be negative + * @return the new period plus the specified number of seconds + * @throws ArithmeticException if the result overflows an int + */ + public Seconds plus(int seconds) { + if (seconds == 0) { + return this; + } + return Seconds.seconds(FieldUtils.safeAdd(getValue(), seconds)); + } + + /** + * Returns a new instance with the specified number of seconds added. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param seconds the amount of seconds to add, may be negative, null means zero + * @return the new period plus the specified number of seconds + * @throws ArithmeticException if the result overflows an int + */ + public Seconds plus(Seconds seconds) { + if (seconds == null) { + return this; + } + return plus(seconds.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of seconds taken away. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param seconds the amount of seconds to take away, may be negative + * @return the new period minus the specified number of seconds + * @throws ArithmeticException if the result overflows an int + */ + public Seconds minus(int seconds) { + return plus(FieldUtils.safeNegate(seconds)); + } + + /** + * Returns a new instance with the specified number of seconds taken away. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param seconds the amount of seconds to take away, may be negative, null means zero + * @return the new period minus the specified number of seconds + * @throws ArithmeticException if the result overflows an int + */ + public Seconds minus(Seconds seconds) { + if (seconds == null) { + return this; + } + return minus(seconds.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the seconds multiplied by the specified scalar. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param scalar the amount to multiply by, may be negative + * @return the new period multiplied by the specified scalar + * @throws ArithmeticException if the result overflows an int + */ + public Seconds multipliedBy(int scalar) { + return Seconds.seconds(FieldUtils.safeMultiply(getValue(), scalar)); + } + + /** + * Returns a new instance with the seconds divided by the specified divisor. + * The calculation uses integer division, thus 3 divided by 2 is 1. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param divisor the amount to divide by, may be negative + * @return the new period divided by the specified divisor + * @throws ArithmeticException if the divisor is zero + */ + public Seconds dividedBy(int divisor) { + if (divisor == 1) { + return this; + } + return Seconds.seconds(getValue() / divisor); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the seconds value negated. + * + * @return the new period with a negated value + * @throws ArithmeticException if the result overflows an int + */ + public Seconds negated() { + return Seconds.seconds(FieldUtils.safeNegate(getValue())); + } + + //----------------------------------------------------------------------- + /** + * Is this seconds instance greater than the specified number of seconds. + * + * @param other the other period, null means zero + * @return true if this seconds instance is greater than the specified one + */ + public boolean isGreaterThan(Seconds other) { + if (other == null) { + return getValue() > 0; + } + return getValue() > other.getValue(); + } + + /** + * Is this seconds instance less than the specified number of seconds. + * + * @param other the other period, null means zero + * @return true if this seconds instance is less than the specified one + */ + public boolean isLessThan(Seconds other) { + if (other == null) { + return getValue() < 0; + } + return getValue() < other.getValue(); + } + + //----------------------------------------------------------------------- + /** + * Gets this instance as a String in the ISO8601 duration format. + *

                + * For example, "PT4S" represents 4 seconds. + * + * @return the value as an ISO8601 string + */ + @ToString + public String toString() { + return "PT" + String.valueOf(getValue()) + "S"; + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/TimeOfDay.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/TimeOfDay.java (.../TimeOfDay.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/TimeOfDay.java (.../TimeOfDay.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,69 +1,39 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; import java.io.Serializable; +import java.util.Calendar; +import java.util.Date; import java.util.Locale; import org.joda.time.base.BasePartial; +import org.joda.time.chrono.ISOChronology; import org.joda.time.field.AbstractPartialFieldProperty; +import org.joda.time.field.FieldUtils; import org.joda.time.format.ISODateTimeFormat; /** * TimeOfDay is an immutable partial supporting the hour, minute, second * and millisecond fields. *

                + * NOTE: This class only supports the four fields listed above. Thus, you + * cannot query the millisOfDay or secondOfDay fields for example. + * The new LocalTime class removes this restriction. + *

                * Calculations on TimeOfDay are performed using a {@link Chronology}. * This chronology is set to be in the UTC time zone for all calculations. *

                @@ -89,7 +59,10 @@ * @author Stephen Colebourne * @author Brian S O'Neill * @since 1.0 + * @deprecated Use LocalTime which has a much better internal implementation and + * has been available since 1.3 */ +@Deprecated public final class TimeOfDay extends BasePartial implements ReadablePartial, Serializable { @@ -120,6 +93,68 @@ //----------------------------------------------------------------------- /** + * Constructs a TimeOfDay from a java.util.Calendar + * using exactly the same field values avoiding any time zone effects. + *

                + * Each field is queried from the Calendar and assigned to the TimeOfDay. + * This is useful to ensure that the field values are the same in the + * created TimeOfDay no matter what the time zone is. For example, if + * the Calendar states that the time is 04:29, then the created TimeOfDay + * will always have the time 04:29 irrespective of time zone issues. + *

                + * This factory method ignores the type of the calendar and always + * creates a TimeOfDay with ISO chronology. + * + * @param calendar the Calendar to extract fields from + * @return the created TimeOfDay + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the time is invalid for the ISO chronology + * @since 1.2 + */ + public static TimeOfDay fromCalendarFields(Calendar calendar) { + if (calendar == null) { + throw new IllegalArgumentException("The calendar must not be null"); + } + return new TimeOfDay( + calendar.get(Calendar.HOUR_OF_DAY), + calendar.get(Calendar.MINUTE), + calendar.get(Calendar.SECOND), + calendar.get(Calendar.MILLISECOND) + ); + } + + /** + * Constructs a TimeOfDay from a java.util.Date + * using exactly the same field values avoiding any time zone effects. + *

                + * Each field is queried from the Date and assigned to the TimeOfDay. + * This is useful to ensure that the field values are the same in the + * created TimeOfDay no matter what the time zone is. For example, if + * the Calendar states that the time is 04:29, then the created TimeOfDay + * will always have the time 04:29 irrespective of time zone issues. + *

                + * This factory method always creates a TimeOfDay with ISO chronology. + * + * @param date the Date to extract fields from + * @return the created TimeOfDay + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the date is invalid for the ISO chronology + * @since 1.2 + */ + public static TimeOfDay fromDateFields(Date date) { + if (date == null) { + throw new IllegalArgumentException("The date must not be null"); + } + return new TimeOfDay( + date.getHours(), + date.getMinutes(), + date.getSeconds(), + (((int) (date.getTime() % 1000)) + 1000) % 1000 + ); + } + + //----------------------------------------------------------------------- + /** * Constructs a TimeOfDay from the specified millis of day using the * ISO chronology. *

                @@ -165,6 +200,21 @@ } /** + * Constructs a TimeOfDay with the current time, using ISOChronology in + * the specified zone to extract the fields. + *

                + * The constructor uses the specified time zone to obtain the current time. + * Once the constructor is complete, all further calculations + * are performed without reference to a timezone (by switching to UTC). + * + * @param zone the zone to use, null means default zone + * @since 1.1 + */ + public TimeOfDay(DateTimeZone zone) { + super(ISOChronology.getInstance(zone)); + } + + /** * Constructs a TimeOfDay with the current time, using the specified chronology * and zone to extract the fields. *

                @@ -213,14 +263,18 @@ * The recognised object types are defined in * {@link org.joda.time.convert.ConverterManager ConverterManager} and * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#timeParser()}. *

                * The chronology used will be derived from the object, defaulting to ISO. + *

                + * NOTE: Prior to v1.3 the string format was described by + * {@link ISODateTimeFormat#dateTimeParser()}. Dates are now rejected. * * @param instant the datetime object, null means now * @throws IllegalArgumentException if the instant is invalid */ public TimeOfDay(Object instant) { - super(instant, null); + super(instant, null, ISODateTimeFormat.timeParser()); } /** @@ -230,18 +284,22 @@ * The recognised object types are defined in * {@link org.joda.time.convert.ConverterManager ConverterManager} and * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#timeParser()}. *

                * The constructor uses the time zone of the chronology specified. * Once the constructor is complete, all further calculations are performed * without reference to a timezone (by switching to UTC). * The specified chronology overrides that of the object. + *

                + * NOTE: Prior to v1.3 the string format was described by + * {@link ISODateTimeFormat#dateTimeParser()}. Dates are now rejected. * * @param instant the datetime object, null means now * @param chronology the chronology, null means ISO default * @throws IllegalArgumentException if the instant is invalid */ public TimeOfDay(Object instant, Chronology chronology) { - super(instant, DateTimeUtils.getChronology(chronology)); + super(instant, DateTimeUtils.getChronology(chronology), ISODateTimeFormat.timeParser()); } /** @@ -419,7 +477,7 @@ //----------------------------------------------------------------------- /** - * Creates a new TimeOfDay instance with the specified chronology. + * Returns a copy of this time with the specified chronology. * This instance is immutable and unaffected by this method call. *

                * This method retains the values of the fields, thus the result will @@ -430,21 +488,316 @@ * * @param newChronology the new chronology, null means ISO * @return a copy of this datetime with a different chronology + * @throws IllegalArgumentException if the values are invalid for the new chronology */ public TimeOfDay withChronologyRetainFields(Chronology newChronology) { newChronology = DateTimeUtils.getChronology(newChronology); newChronology = newChronology.withUTC(); if (newChronology == getChronology()) { return this; } else { - return new TimeOfDay(this, newChronology); + TimeOfDay newTimeOfDay = new TimeOfDay(this, newChronology); + newChronology.validate(newTimeOfDay, getValues()); + return newTimeOfDay; } } /** - * Gets the property object for the specified type, which contains many useful methods. + * Returns a copy of this time with the specified field set to a new value. + *

                + * For example, if the field type is minuteOfHour then the day + * would be changed in the returned instance. + *

                + * These three lines are equivalent: + *

                +     * TimeOfDay updated = tod.withField(DateTimeFieldType.minuteOfHour(), 6);
                +     * TimeOfDay updated = tod.minuteOfHour().setCopy(6);
                +     * TimeOfDay updated = tod.property(DateTimeFieldType.minuteOfHour()).setCopy(6);
                +     * 
                * - * @param type the field type to get the chronology for + * @param fieldType the field type to set, not null + * @param value the value to set + * @return a copy of this instance with the field set + * @throws IllegalArgumentException if the value is null or invalid + */ + public TimeOfDay withField(DateTimeFieldType fieldType, int value) { + int index = indexOfSupported(fieldType); + if (value == getValue(index)) { + return this; + } + int[] newValues = getValues(); + newValues = getField(index).set(this, index, newValues, value); + return new TimeOfDay(this, newValues); + } + + /** + * Returns a copy of this time with the value of the specified field increased, + * wrapping to what would be a new day if required. + *

                + * If the addition is zero, then this is returned. + *

                + * These three lines are equivalent: + *

                +     * TimeOfDay added = tod.withFieldAdded(DurationFieldType.minutes(), 6);
                +     * TimeOfDay added = tod.plusMinutes(6);
                +     * TimeOfDay added = tod.minuteOfHour().addToCopy(6);
                +     * 
                + * + * @param fieldType the field type to add to, not null + * @param amount the amount to add + * @return a copy of this instance with the field updated + * @throws IllegalArgumentException if the value is null or invalid + * @throws ArithmeticException if the new datetime exceeds the capacity + */ + public TimeOfDay withFieldAdded(DurationFieldType fieldType, int amount) { + int index = indexOfSupported(fieldType); + if (amount == 0) { + return this; + } + int[] newValues = getValues(); + newValues = getField(index).addWrapPartial(this, index, newValues, amount); + return new TimeOfDay(this, newValues); + } + + /** + * Returns a copy of this time with the specified period added, + * wrapping to what would be a new day if required. + *

                + * If the addition is zero, then this is returned. + * Fields in the period that aren't present in the partial are ignored. + *

                + * This method is typically used to add multiple copies of complex + * period instances. Adding one field is best achieved using methods + * like {@link #withFieldAdded(DurationFieldType, int)} + * or {@link #plusHours(int)}. + * + * @param period the period to add to this one, null means zero + * @param scalar the amount of times to add, such as -1 to subtract once + * @return a copy of this instance with the period added + * @throws ArithmeticException if the new datetime exceeds the capacity + */ + public TimeOfDay withPeriodAdded(ReadablePeriod period, int scalar) { + if (period == null || scalar == 0) { + return this; + } + int[] newValues = getValues(); + for (int i = 0; i < period.size(); i++) { + DurationFieldType fieldType = period.getFieldType(i); + int index = indexOf(fieldType); + if (index >= 0) { + newValues = getField(index).addWrapPartial(this, index, newValues, + FieldUtils.safeMultiply(period.getValue(i), scalar)); + } + } + return new TimeOfDay(this, newValues); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this time with the specified period added, + * wrapping to what would be a new day if required. + *

                + * If the amount is zero or null, then this is returned. + *

                + * This method is typically used to add complex period instances. + * Adding one field is best achieved using methods + * like {@link #plusHours(int)}. + * + * @param period the duration to add to this one, null means zero + * @return a copy of this instance with the period added + * @throws ArithmeticException if the new datetime exceeds the capacity of a long + */ + public TimeOfDay plus(ReadablePeriod period) { + return withPeriodAdded(period, 1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this time plus the specified number of hours. + *

                + * This time instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * TimeOfDay added = dt.plusHours(6);
                +     * TimeOfDay added = dt.plus(Period.hours(6));
                +     * TimeOfDay added = dt.withFieldAdded(DurationFieldType.hours(), 6);
                +     * 
                + * + * @param hours the amount of hours to add, may be negative + * @return the new time plus the increased hours + * @since 1.1 + */ + public TimeOfDay plusHours(int hours) { + return withFieldAdded(DurationFieldType.hours(), hours); + } + + /** + * Returns a copy of this time plus the specified number of minutes. + *

                + * This time instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * TimeOfDay added = dt.plusMinutes(6);
                +     * TimeOfDay added = dt.plus(Period.minutes(6));
                +     * TimeOfDay added = dt.withFieldAdded(DurationFieldType.minutes(), 6);
                +     * 
                + * + * @param minutes the amount of minutes to add, may be negative + * @return the new time plus the increased minutes + * @since 1.1 + */ + public TimeOfDay plusMinutes(int minutes) { + return withFieldAdded(DurationFieldType.minutes(), minutes); + } + + /** + * Returns a copy of this time plus the specified number of seconds. + *

                + * This time instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * TimeOfDay added = dt.plusSeconds(6);
                +     * TimeOfDay added = dt.plus(Period.seconds(6));
                +     * TimeOfDay added = dt.withFieldAdded(DurationFieldType.seconds(), 6);
                +     * 
                + * + * @param seconds the amount of seconds to add, may be negative + * @return the new time plus the increased seconds + * @since 1.1 + */ + public TimeOfDay plusSeconds(int seconds) { + return withFieldAdded(DurationFieldType.seconds(), seconds); + } + + /** + * Returns a copy of this time plus the specified number of millis. + *

                + * This time instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * TimeOfDay added = dt.plusMillis(6);
                +     * TimeOfDay added = dt.plus(Period.millis(6));
                +     * TimeOfDay added = dt.withFieldAdded(DurationFieldType.millis(), 6);
                +     * 
                + * + * @param millis the amount of millis to add, may be negative + * @return the new time plus the increased millis + * @since 1.1 + */ + public TimeOfDay plusMillis(int millis) { + return withFieldAdded(DurationFieldType.millis(), millis); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this time with the specified period taken away, + * wrapping to what would be a new day if required. + *

                + * If the amount is zero or null, then this is returned. + *

                + * This method is typically used to subtract complex period instances. + * Subtracting one field is best achieved using methods + * like {@link #minusHours(int)}. + * + * @param period the period to reduce this instant by + * @return a copy of this instance with the period taken away + * @throws ArithmeticException if the new time exceeds capacity + */ + public TimeOfDay minus(ReadablePeriod period) { + return withPeriodAdded(period, -1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this time minus the specified number of hours. + *

                + * This time instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * TimeOfDay subtracted = dt.minusHours(6);
                +     * TimeOfDay subtracted = dt.minus(Period.hours(6));
                +     * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.hours(), -6);
                +     * 
                + * + * @param hours the amount of hours to subtract, may be negative + * @return the new time minus the increased hours + * @since 1.1 + */ + public TimeOfDay minusHours(int hours) { + return withFieldAdded(DurationFieldType.hours(), FieldUtils.safeNegate(hours)); + } + + /** + * Returns a copy of this time minus the specified number of minutes. + *

                + * This time instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * TimeOfDay subtracted = dt.minusMinutes(6);
                +     * TimeOfDay subtracted = dt.minus(Period.minutes(6));
                +     * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.minutes(), -6);
                +     * 
                + * + * @param minutes the amount of minutes to subtract, may be negative + * @return the new time minus the increased minutes + * @since 1.1 + */ + public TimeOfDay minusMinutes(int minutes) { + return withFieldAdded(DurationFieldType.minutes(), FieldUtils.safeNegate(minutes)); + } + + /** + * Returns a copy of this time minus the specified number of seconds. + *

                + * This time instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * TimeOfDay subtracted = dt.minusSeconds(6);
                +     * TimeOfDay subtracted = dt.minus(Period.seconds(6));
                +     * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.seconds(), -6);
                +     * 
                + * + * @param seconds the amount of seconds to subtract, may be negative + * @return the new time minus the increased seconds + * @since 1.1 + */ + public TimeOfDay minusSeconds(int seconds) { + return withFieldAdded(DurationFieldType.seconds(), FieldUtils.safeNegate(seconds)); + } + + /** + * Returns a copy of this time minus the specified number of millis. + *

                + * This time instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * TimeOfDay subtracted = dt.minusMillis(6);
                +     * TimeOfDay subtracted = dt.minus(Period.millis(6));
                +     * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.millis(), -6);
                +     * 
                + * + * @param millis the amount of millis to subtract, may be negative + * @return the new time minus the increased millis + * @since 1.1 + */ + public TimeOfDay minusMillis(int millis) { + return withFieldAdded(DurationFieldType.millis(), FieldUtils.safeNegate(millis)); + } + + //----------------------------------------------------------------------- + /** + * Gets the property object for the specified type, which contains + * many useful methods. + * + * @param type the field type to get the property for * @return the property object * @throws IllegalArgumentException if the field is null or unsupported */ @@ -454,6 +807,48 @@ //----------------------------------------------------------------------- /** + * Converts this object to a LocalTime with the same time and chronology. + * + * @return a LocalTime with the same time and chronology + * @since 1.3 + */ + public LocalTime toLocalTime() { + return new LocalTime(getHourOfDay(), getMinuteOfHour(), + getSecondOfMinute(), getMillisOfSecond(), getChronology()); + } + + //----------------------------------------------------------------------- + /** + * Converts this partial to a full datetime using the default time zone + * setting the time fields from this instance and the date fields from + * the current time. + * + * @return this date as a datetime with the time as the current time + */ + public DateTime toDateTimeToday() { + return toDateTimeToday(null); + } + + /** + * Converts this partial to a full datetime using the specified time zone + * setting the time fields from this instance and the date fields from + * the current time. + *

                + * This method uses the chronology from this instance plus the time zone + * specified. + * + * @param zone the zone to use, null means default + * @return this date as a datetime with the time as the current time + */ + public DateTime toDateTimeToday(DateTimeZone zone) { + Chronology chrono = getChronology().withZone(zone); + long instantMillis = DateTimeUtils.currentTimeMillis(); + long resolved = chrono.set(this, instantMillis); + return new DateTime(resolved, chrono); + } + + //----------------------------------------------------------------------- + /** * Get the hour of day (0-23) field value. * * @return the hour of day @@ -491,7 +886,80 @@ //----------------------------------------------------------------------- /** - * Get the hour of day (0-23) field property + * Returns a copy of this time with the hour of day field updated. + *

                + * TimeOfDay is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * hour of day changed. + * + * @param hour the hour of day to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public TimeOfDay withHourOfDay(int hour) { + int[] newValues = getValues(); + newValues = getChronology().hourOfDay().set(this, HOUR_OF_DAY, newValues, hour); + return new TimeOfDay(this, newValues); + } + + /** + * Returns a copy of this time with the minute of hour field updated. + *

                + * TimeOfDay is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * minute of hour changed. + * + * @param minute the minute of hour to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public TimeOfDay withMinuteOfHour(int minute) { + int[] newValues = getValues(); + newValues = getChronology().minuteOfHour().set(this, MINUTE_OF_HOUR, newValues, minute); + return new TimeOfDay(this, newValues); + } + + /** + * Returns a copy of this time with the second of minute field updated. + *

                + * TimeOfDay is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * second of minute changed. + * + * @param second the second of minute to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public TimeOfDay withSecondOfMinute(int second) { + int[] newValues = getValues(); + newValues = getChronology().secondOfMinute().set(this, SECOND_OF_MINUTE, newValues, second); + return new TimeOfDay(this, newValues); + } + + /** + * Returns a copy of this time with the millis of second field updated. + *

                + * TimeOfDay is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * millis of second changed. + * + * @param millis the millis of second to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public TimeOfDay withMillisOfSecond(int millis) { + int[] newValues = getValues(); + newValues = getChronology().millisOfSecond().set(this, MILLIS_OF_SECOND, newValues, millis); + return new TimeOfDay(this, newValues); + } + + //----------------------------------------------------------------------- + /** + * Get the hour of day field property which provides access to advanced functionality. * * @return the hour of day property */ @@ -500,7 +968,7 @@ } /** - * Get the minute of hour field property + * Get the minute of hour field property which provides access to advanced functionality. * * @return the minute of hour property */ @@ -509,7 +977,7 @@ } /** - * Get the second of minute field property + * Get the second of minute field property which provides access to advanced functionality. * * @return the second of minute property */ @@ -518,7 +986,7 @@ } /** - * Get the millis of second property + * Get the millis of second property which provides access to advanced functionality. * * @return the millis of second property */ @@ -533,7 +1001,7 @@ * @return ISO8601 formatted string */ public String toString() { - return ISODateTimeFormat.getInstance().tTime().print(this); + return ISODateTimeFormat.tTime().print(this); } //----------------------------------------------------------------------- @@ -544,7 +1012,9 @@ * * @author Stephen Colebourne * @since 1.0 + * @deprecated Use LocalTime which has a much better internal implementation */ + @Deprecated public static class Property extends AbstractPartialFieldProperty implements Serializable { /** Serialization version */ @@ -581,7 +1051,7 @@ * * @return the partial */ - public ReadablePartial getReadablePartial() { + protected ReadablePartial getReadablePartial() { return iTimeOfDay; } @@ -605,14 +1075,16 @@ //----------------------------------------------------------------------- /** - * Adds to the value of this field in a copy of this TimeOfDay. + * Adds to the value of this field in a copy of this TimeOfDay, + * wrapping to what would be the next day if necessary. *

                * The value will be added to this field. If the value is too large to be * added solely to this field then it will affect larger fields. * Smaller fields are unaffected. *

                - * If the result would be too large, beyond 23:59:59:999, then an - * IllegalArgumentException is thrown. + * If the result would be too large, beyond 23:59:59:999, then the + * calculation wraps to 00:00:00.000. For the alternate strict behaviour + * with no wrapping see {@link #addNoWrapToCopy(int)}. *

                * The TimeOfDay attached to this property is unchanged by this call. * Instead, a new instance is returned. @@ -623,6 +1095,32 @@ */ public TimeOfDay addToCopy(int valueToAdd) { int[] newValues = iTimeOfDay.getValues(); + newValues = getField().addWrapPartial(iTimeOfDay, iFieldIndex, newValues, valueToAdd); + return new TimeOfDay(iTimeOfDay, newValues); + } + + /** + * Adds to the value of this field in a copy of this TimeOfDay, + * throwing an Exception if the bounds are exceeded. + *

                + * The value will be added to this field. If the value is too large to be + * added solely to this field then it will affect larger fields. + * Smaller fields are unaffected. + *

                + * If the result would be too large (beyond 23:59:59:999) or too + * small (less than 00:00:00.000) then an Execption is thrown. + * For the alternate behaviour which wraps to the next 'day', + * see {@link #addToCopy(int)}. + *

                + * The TimeOfDay attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param valueToAdd the value to add to the field in the copy + * @return a copy of the TimeOfDay with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public TimeOfDay addNoWrapToCopy(int valueToAdd) { + int[] newValues = iTimeOfDay.getValues(); newValues = getField().add(iTimeOfDay, iFieldIndex, newValues, valueToAdd); return new TimeOfDay(iTimeOfDay, newValues); } @@ -698,6 +1196,33 @@ public TimeOfDay setCopy(String text) { return setCopy(text, null); } + + //----------------------------------------------------------------------- + /** + * Returns a new TimeOfDay with this field set to the maximum value + * for this field. + *

                + * The TimeOfDay attached to this property is unchanged by this call. + * + * @return a copy of the TimeOfDay with this field set to its maximum + * @since 1.2 + */ + public TimeOfDay withMaximumValue() { + return setCopy(getMaximumValue()); + } + + /** + * Returns a new TimeOfDay with this field set to the minimum value + * for this field. + *

                + * The TimeOfDay attached to this property is unchanged by this call. + * + * @return a copy of the TimeOfDay with this field set to its minimum + * @since 1.2 + */ + public TimeOfDay withMinimumValue() { + return setCopy(getMinimumValue()); + } } } Index: 3rdParty_sources/joda-time/org/joda/time/Weeks.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/Weeks.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/Weeks.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,477 @@ +/* + * Copyright 2001-2010 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; +import org.joda.time.base.BaseSingleFieldPeriod; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.ISOPeriodFormat; +import org.joda.time.format.PeriodFormatter; + +/** + * An immutable time period representing a number of weeks. + *

                + * Weeks is an immutable period that can only store weeks. + * It does not store years, months or hours for example. As such it is a + * type-safe way of representing a number of weeks in an application. + *

                + * The number of weeks is set in the constructor, and may be queried using + * getWeeks(). Basic mathematical operations are provided - + * plus(), minus(), multipliedBy() and + * dividedBy(). + *

                + * Weeks is thread-safe and immutable. + * + * @author Stephen Colebourne + * @since 1.4 + */ +public final class Weeks extends BaseSingleFieldPeriod { + + /** Constant representing zero weeks. */ + public static final Weeks ZERO = new Weeks(0); + /** Constant representing one week. */ + public static final Weeks ONE = new Weeks(1); + /** Constant representing two weeks. */ + public static final Weeks TWO = new Weeks(2); + /** Constant representing three weeks. */ + public static final Weeks THREE = new Weeks(3); + /** Constant representing the maximum number of weeks that can be stored in this object. */ + public static final Weeks MAX_VALUE = new Weeks(Integer.MAX_VALUE); + /** Constant representing the minimum number of weeks that can be stored in this object. */ + public static final Weeks MIN_VALUE = new Weeks(Integer.MIN_VALUE); + + /** The paser to use for this class. */ + private static final PeriodFormatter PARSER = ISOPeriodFormat.standard().withParseType(PeriodType.weeks()); + /** Serialization version. */ + private static final long serialVersionUID = 87525275727380866L; + + //----------------------------------------------------------------------- + /** + * Obtains an instance of Weeks that may be cached. + * Weeks is immutable, so instances can be cached and shared. + * This factory method provides access to shared instances. + * + * @param weeks the number of weeks to obtain an instance for + * @return the instance of Weeks + */ + public static Weeks weeks(int weeks) { + switch (weeks) { + case 0: + return ZERO; + case 1: + return ONE; + case 2: + return TWO; + case 3: + return THREE; + case Integer.MAX_VALUE: + return MAX_VALUE; + case Integer.MIN_VALUE: + return MIN_VALUE; + default: + return new Weeks(weeks); + } + } + + //----------------------------------------------------------------------- + /** + * Creates a Weeks representing the number of whole weeks + * between the two specified datetimes. + * + * @param start the start instant, must not be null + * @param end the end instant, must not be null + * @return the period in weeks + * @throws IllegalArgumentException if the instants are null or invalid + */ + public static Weeks weeksBetween(ReadableInstant start, ReadableInstant end) { + int amount = BaseSingleFieldPeriod.between(start, end, DurationFieldType.weeks()); + return Weeks.weeks(amount); + } + + /** + * Creates a Weeks representing the number of whole weeks + * between the two specified partial datetimes. + *

                + * The two partials must contain the same fields, for example you can specify + * two LocalDate objects. + * + * @param start the start partial date, must not be null + * @param end the end partial date, must not be null + * @return the period in weeks + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Weeks weeksBetween(ReadablePartial start, ReadablePartial end) { + if (start instanceof LocalDate && end instanceof LocalDate) { + Chronology chrono = DateTimeUtils.getChronology(start.getChronology()); + int weeks = chrono.weeks().getDifference( + ((LocalDate) end).getLocalMillis(), ((LocalDate) start).getLocalMillis()); + return Weeks.weeks(weeks); + } + int amount = BaseSingleFieldPeriod.between(start, end, ZERO); + return Weeks.weeks(amount); + } + + /** + * Creates a Weeks representing the number of whole weeks + * in the specified interval. + * + * @param interval the interval to extract weeks from, null returns zero + * @return the period in weeks + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Weeks weeksIn(ReadableInterval interval) { + if (interval == null) { + return Weeks.ZERO; + } + int amount = BaseSingleFieldPeriod.between(interval.getStart(), interval.getEnd(), DurationFieldType.weeks()); + return Weeks.weeks(amount); + } + + /** + * Creates a new Weeks representing the number of complete + * standard length weeks in the specified period. + *

                + * This factory method converts all fields from the period to hours using standardised + * durations for each field. Only those fields which have a precise duration in + * the ISO UTC chronology can be converted. + *

                  + *
                • One week consists of 7 days. + *
                • One day consists of 24 hours. + *
                • One hour consists of 60 minutes. + *
                • One minute consists of 60 weeks. + *
                • One second consists of 1000 milliseconds. + *
                + * Months and Years are imprecise and periods containing these values cannot be converted. + * + * @param period the period to get the number of hours from, null returns zero + * @return the period in weeks + * @throws IllegalArgumentException if the period contains imprecise duration values + */ + public static Weeks standardWeeksIn(ReadablePeriod period) { + int amount = BaseSingleFieldPeriod.standardPeriodIn(period, DateTimeConstants.MILLIS_PER_WEEK); + return Weeks.weeks(amount); + } + + /** + * Creates a new Weeks by parsing a string in the ISO8601 format 'PnW'. + *

                + * The parse will accept the full ISO syntax of PnYnMnWnDTnHnMnS however only the + * weeks component may be non-zero. If any other component is non-zero, an exception + * will be thrown. + * + * @param periodStr the period string, null returns zero + * @return the period in weeks + * @throws IllegalArgumentException if the string format is invalid + */ + @FromString + public static Weeks parseWeeks(String periodStr) { + if (periodStr == null) { + return Weeks.ZERO; + } + Period p = PARSER.parsePeriod(periodStr); + return Weeks.weeks(p.getWeeks()); + } + + //----------------------------------------------------------------------- + /** + * Creates a new instance representing a number of weeks. + * You should consider using the factory method {@link #weeks(int)} + * instead of the constructor. + * + * @param weeks the number of weeks to represent + */ + private Weeks(int weeks) { + super(weeks); + } + + /** + * Resolves singletons. + * + * @return the singleton instance + */ + private Object readResolve() { + return Weeks.weeks(getValue()); + } + + //----------------------------------------------------------------------- + /** + * Gets the duration field type, which is weeks. + * + * @return the period type + */ + public DurationFieldType getFieldType() { + return DurationFieldType.weeks(); + } + + /** + * Gets the period type, which is weeks. + * + * @return the period type + */ + public PeriodType getPeriodType() { + return PeriodType.weeks(); + } + + //----------------------------------------------------------------------- + /** + * Converts this period in weeks to a period in days assuming a + * 7 day week. + *

                + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all weeks are + * 7 days long. + * This may not be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of days for this number of weeks + * @throws ArithmeticException if the number of days is too large to be represented + */ + public Days toStandardDays() { + return Days.days(FieldUtils.safeMultiply(getValue(), DateTimeConstants.DAYS_PER_WEEK)); + } + + /** + * Converts this period in weeks to a period in hours assuming a + * 7 day week and 24 hour day. + *

                + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all weeks are + * 7 days long and all days are 24 hours long. + * This is not true when daylight savings is considered and may also not + * be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of hours for this number of weeks + * @throws ArithmeticException if the number of hours is too large to be represented + */ + public Hours toStandardHours() { + return Hours.hours(FieldUtils.safeMultiply(getValue(), DateTimeConstants.HOURS_PER_WEEK)); + } + + /** + * Converts this period in weeks to a period in minutes assuming a + * 7 day week, 24 hour day and 60 minute hour. + *

                + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all weeks are + * 7 days long, all days are 24 hours long and all hours are 60 minutes long. + * This is not true when daylight savings is considered and may also not + * be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of minutes for this number of weeks + * @throws ArithmeticException if the number of minutes is too large to be represented + */ + public Minutes toStandardMinutes() { + return Minutes.minutes(FieldUtils.safeMultiply(getValue(), DateTimeConstants.MINUTES_PER_WEEK)); + } + + /** + * Converts this period in weeks to a period in seconds assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *

                + * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all weeks are + * 7 days long, all days are 24 hours long, all hours are 60 minutes long + * and all minutes are 60 seconds long. + * This is not true when daylight savings is considered and may also not + * be true for some unusual chronologies. However, it is included + * as it is a useful operation for many applications and business rules. + * + * @return a period representing the number of seconds for this number of weeks + * @throws ArithmeticException if the number of seconds is too large to be represented + */ + public Seconds toStandardSeconds() { + return Seconds.seconds(FieldUtils.safeMultiply(getValue(), DateTimeConstants.SECONDS_PER_WEEK)); + } + + //----------------------------------------------------------------------- + /** + * Converts this period in weeks to a duration in milliweeks assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *

                + * This method allows you to convert from a period to a duration. + * However to achieve this it makes the assumption that all weeks are + * 7 days long, all days are 24 hours long, all hours are 60 minutes long + * and all minutes are 60 seconds long. + * This is not true when daylight savings time is considered, and may also + * not be true for some unusual chronologies. However, it is included as it + * is a useful operation for many applications and business rules. + * + * @return a duration equivalent to this number of weeks + */ + public Duration toStandardDuration() { + long weeks = getValue(); // assign to a long + return new Duration(weeks * DateTimeConstants.MILLIS_PER_WEEK); + } + + //----------------------------------------------------------------------- + /** + * Gets the number of weeks that this period represents. + * + * @return the number of weeks in the period + */ + public int getWeeks() { + return getValue(); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of weeks added. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param weeks the amount of weeks to add, may be negative + * @return the new period plus the specified number of weeks + * @throws ArithmeticException if the result overflows an int + */ + public Weeks plus(int weeks) { + if (weeks == 0) { + return this; + } + return Weeks.weeks(FieldUtils.safeAdd(getValue(), weeks)); + } + + /** + * Returns a new instance with the specified number of weeks added. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param weeks the amount of weeks to add, may be negative, null means zero + * @return the new period plus the specified number of weeks + * @throws ArithmeticException if the result overflows an int + */ + public Weeks plus(Weeks weeks) { + if (weeks == null) { + return this; + } + return plus(weeks.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of weeks taken away. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param weeks the amount of weeks to take away, may be negative + * @return the new period minus the specified number of weeks + * @throws ArithmeticException if the result overflows an int + */ + public Weeks minus(int weeks) { + return plus(FieldUtils.safeNegate(weeks)); + } + + /** + * Returns a new instance with the specified number of weeks taken away. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param weeks the amount of weeks to take away, may be negative, null means zero + * @return the new period minus the specified number of weeks + * @throws ArithmeticException if the result overflows an int + */ + public Weeks minus(Weeks weeks) { + if (weeks == null) { + return this; + } + return minus(weeks.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the weeks multiplied by the specified scalar. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param scalar the amount to multiply by, may be negative + * @return the new period multiplied by the specified scalar + * @throws ArithmeticException if the result overflows an int + */ + public Weeks multipliedBy(int scalar) { + return Weeks.weeks(FieldUtils.safeMultiply(getValue(), scalar)); + } + + /** + * Returns a new instance with the weeks divided by the specified divisor. + * The calculation uses integer division, thus 3 divided by 2 is 1. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param divisor the amount to divide by, may be negative + * @return the new period divided by the specified divisor + * @throws ArithmeticException if the divisor is zero + */ + public Weeks dividedBy(int divisor) { + if (divisor == 1) { + return this; + } + return Weeks.weeks(getValue() / divisor); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the weeks value negated. + * + * @return the new period with a negated value + * @throws ArithmeticException if the result overflows an int + */ + public Weeks negated() { + return Weeks.weeks(FieldUtils.safeNegate(getValue())); + } + + //----------------------------------------------------------------------- + /** + * Is this weeks instance greater than the specified number of weeks. + * + * @param other the other period, null means zero + * @return true if this weeks instance is greater than the specified one + */ + public boolean isGreaterThan(Weeks other) { + if (other == null) { + return getValue() > 0; + } + return getValue() > other.getValue(); + } + + /** + * Is this weeks instance less than the specified number of weeks. + * + * @param other the other period, null means zero + * @return true if this weeks instance is less than the specified one + */ + public boolean isLessThan(Weeks other) { + if (other == null) { + return getValue() < 0; + } + return getValue() < other.getValue(); + } + + //----------------------------------------------------------------------- + /** + * Gets this instance as a String in the ISO8601 duration format. + *

                + * For example, "P4W" represents 4 weeks. + * + * @return the value as an ISO8601 string + */ + @ToString + public String toString() { + return "P" + String.valueOf(getValue()) + "W"; + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/YearMonth.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/YearMonth.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/YearMonth.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,991 @@ +/* + * Copyright 2001-2010 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import java.io.Serializable; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; +import org.joda.time.base.BasePartial; +import org.joda.time.chrono.ISOChronology; +import org.joda.time.field.AbstractPartialFieldProperty; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; + +/** + * YearMonth is an immutable partial supporting the year and monthOfYear fields. + *

                + * NOTE: This class only supports the two fields listed above. + * It is impossible to query any other fields, such as dayOfWeek or centuryOfEra. + *

                + * Calculations on YearMonth are performed using a {@link Chronology}. + * This chronology is set to be in the UTC time zone for all calculations. + *

                + * One use case for this class is to store a credit card expiry date, as that only + * references the year and month. + * This class can be used as the gYearMonth type in XML Schema. + *

                + * Each individual field can be queried in two ways: + *

                  + *
                • getMonthOfYear() + *
                • monthOfYear().get() + *
                + * The second technique also provides access to other useful methods on the + * field: + *
                  + *
                • numeric value - monthOfYear().get() + *
                • text value - monthOfYear().getAsText() + *
                • short text value - monthOfYear().getAsShortText() + *
                • maximum/minimum values - monthOfYear().getMaximumValue() + *
                • add/subtract - monthOfYear().addToCopy() + *
                • set - monthOfYear().setCopy() + *
                + *

                + * YearMonth is thread-safe and immutable, provided that the Chronology is as well. + * All standard Chronology classes supplied are thread-safe and immutable. + * + * @author Stephen Colebourne + * @since 2.0 + */ +public final class YearMonth + extends BasePartial + implements ReadablePartial, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 797544782896179L; + /** The singleton set of field types */ + private static final DateTimeFieldType[] FIELD_TYPES = new DateTimeFieldType[] { + DateTimeFieldType.year(), + DateTimeFieldType.monthOfYear(), + }; + + /** The index of the year field in the field array */ + public static final int YEAR = 0; + /** The index of the monthOfYear field in the field array */ + public static final int MONTH_OF_YEAR = 1; + + //----------------------------------------------------------------------- + /** + * Obtains a {@code YearMonth} set to the current system millisecond time + * using ISOChronology in the default time zone. + * The resulting object does not use the zone. + * + * @return the current year-month, not null + * @since 2.0 + */ + public static YearMonth now() { + return new YearMonth(); + } + + /** + * Obtains a {@code YearMonth} set to the current system millisecond time + * using ISOChronology in the specified time zone. + * The resulting object does not use the zone. + * + * @param zone the time zone, not null + * @return the current year-month, not null + * @since 2.0 + */ + public static YearMonth now(DateTimeZone zone) { + if (zone == null) { + throw new NullPointerException("Zone must not be null"); + } + return new YearMonth(zone); + } + + /** + * Obtains a {@code YearMonth} set to the current system millisecond time + * using the specified chronology. + * The resulting object does not use the zone. + * + * @param chronology the chronology, not null + * @return the current year-month, not null + * @since 2.0 + */ + public static YearMonth now(Chronology chronology) { + if (chronology == null) { + throw new NullPointerException("Chronology must not be null"); + } + return new YearMonth(chronology); + } + + //----------------------------------------------------------------------- + /** + * Parses a {@code YearMonth} from the specified string. + *

                + * This uses {@link ISODateTimeFormat#localDateParser()}. + * + * @param str the string to parse, not null + * @since 2.0 + */ + @FromString + public static YearMonth parse(String str) { + return parse(str, ISODateTimeFormat.localDateParser()); + } + + /** + * Parses a {@code YearMonth} from the specified string using a formatter. + * + * @param str the string to parse, not null + * @param formatter the formatter to use, not null + * @since 2.0 + */ + public static YearMonth parse(String str, DateTimeFormatter formatter) { + LocalDate date = formatter.parseLocalDate(str); + return new YearMonth(date.getYear(), date.getMonthOfYear()); + } + + //----------------------------------------------------------------------- + /** + * Constructs a YearMonth from a java.util.Calendar + * using exactly the same field values avoiding any time zone effects. + *

                + * Each field is queried from the Calendar and assigned to the YearMonth. + *

                + * This factory method ignores the type of the calendar and always + * creates a YearMonth with ISO chronology. It is expected that you + * will only pass in instances of GregorianCalendar however + * this is not validated. + * + * @param calendar the Calendar to extract fields from + * @return the created YearMonth, never null + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the year or month is invalid for the ISO chronology + */ + public static YearMonth fromCalendarFields(Calendar calendar) { + if (calendar == null) { + throw new IllegalArgumentException("The calendar must not be null"); + } + return new YearMonth(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1); + } + + /** + * Constructs a YearMonth from a java.util.Date + * using exactly the same field values avoiding any time zone effects. + *

                + * Each field is queried from the Date and assigned to the YearMonth. + *

                + * This factory method always creates a YearMonth with ISO chronology. + * + * @param date the Date to extract fields from + * @return the created YearMonth, never null + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the year or month is invalid for the ISO chronology + */ + @SuppressWarnings("deprecation") + public static YearMonth fromDateFields(Date date) { + if (date == null) { + throw new IllegalArgumentException("The date must not be null"); + } + return new YearMonth(date.getYear() + 1900, date.getMonth() + 1); + } + + //----------------------------------------------------------------------- + /** + * Constructs a YearMonth with the current year-month, using ISOChronology in + * the default zone to extract the fields. + *

                + * The constructor uses the default time zone, resulting in the local time + * being initialised. Once the constructor is complete, all further calculations + * are performed without reference to a time-zone (by switching to UTC). + * + * @see #now() + */ + public YearMonth() { + super(); + } + + /** + * Constructs a YearMonth with the current year-month, using ISOChronology in + * the specified zone to extract the fields. + *

                + * The constructor uses the specified time zone to obtain the current year-month. + * Once the constructor is complete, all further calculations + * are performed without reference to a time-zone (by switching to UTC). + * + * @param zone the zone to use, null means default zone + * @see #now(DateTimeZone) + */ + public YearMonth(DateTimeZone zone) { + super(ISOChronology.getInstance(zone)); + } + + /** + * Constructs a YearMonth with the current year-month, using the specified chronology + * and zone to extract the fields. + *

                + * The constructor uses the time zone of the chronology specified. + * Once the constructor is complete, all further calculations are performed + * without reference to a time-zone (by switching to UTC). + * + * @param chronology the chronology, null means ISOChronology in the default zone + * @see #now(Chronology) + */ + public YearMonth(Chronology chronology) { + super(chronology); + } + + /** + * Constructs a YearMonth extracting the partial fields from the specified + * milliseconds using the ISOChronology in the default zone. + *

                + * The constructor uses the default time zone, resulting in the local time + * being initialised. Once the constructor is complete, all further calculations + * are performed without reference to a time-zone (by switching to UTC). + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z + */ + public YearMonth(long instant) { + super(instant); + } + + /** + * Constructs a YearMonth extracting the partial fields from the specified + * milliseconds using the chronology provided. + *

                + * The constructor uses the time zone of the chronology specified. + * Once the constructor is complete, all further calculations are performed + * without reference to a time-zone (by switching to UTC). + * + * @param instant the milliseconds from 1970-01-01T00:00:00Z + * @param chronology the chronology, null means ISOChronology in the default zone + */ + public YearMonth(long instant, Chronology chronology) { + super(instant, chronology); + } + + /** + * Constructs a YearMonth from an Object that represents some form of time. + *

                + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#localDateParser()}. + *

                + * The chronology used will be derived from the object, defaulting to ISO. + * + * @param instant the date-time object, null means now + * @throws IllegalArgumentException if the instant is invalid + */ + public YearMonth(Object instant) { + super(instant, null, ISODateTimeFormat.localDateParser()); + } + + /** + * Constructs a YearMonth from an Object that represents some form of time, + * using the specified chronology. + *

                + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#localDateParser()}. + *

                + * The constructor uses the time zone of the chronology specified. + * Once the constructor is complete, all further calculations are performed + * without reference to a time-zone (by switching to UTC). + * The specified chronology overrides that of the object. + * + * @param instant the date-time object, null means now + * @param chronology the chronology, null means ISO default + * @throws IllegalArgumentException if the instant is invalid + */ + public YearMonth(Object instant, Chronology chronology) { + super(instant, DateTimeUtils.getChronology(chronology), ISODateTimeFormat.localDateParser()); + } + + /** + * Constructs a YearMonth with specified year and month + * using ISOChronology. + *

                + * The constructor uses the no time zone initialising the fields as provided. + * Once the constructor is complete, all further calculations + * are performed without reference to a time-zone (by switching to UTC). + * + * @param year the year + * @param monthOfYear the month of the year + */ + public YearMonth(int year, int monthOfYear) { + this(year, monthOfYear, null); + } + + /** + * Constructs an instance set to the specified year and month + * using the specified chronology, whose zone is ignored. + *

                + * If the chronology is null, ISOChronology is used. + *

                + * The constructor uses the time zone of the chronology specified. + * Once the constructor is complete, all further calculations are performed + * without reference to a time-zone (by switching to UTC). + * + * @param year the year + * @param monthOfYear the month of the year + * @param chronology the chronology, null means ISOChronology in the default zone + */ + public YearMonth(int year, int monthOfYear, Chronology chronology) { + super(new int[] {year, monthOfYear}, chronology); + } + + /** + * Constructs a YearMonth with chronology from this instance and new values. + * + * @param partial the partial to base this new instance on + * @param values the new set of values + */ + YearMonth(YearMonth partial, int[] values) { + super(partial, values); + } + + /** + * Constructs a YearMonth with values from this instance and a new chronology. + * + * @param partial the partial to base this new instance on + * @param chrono the new chronology + */ + YearMonth(YearMonth partial, Chronology chrono) { + super(partial, chrono); + } + + /** + * Handle broken serialization from other tools. + * @return the resolved object, not null + */ + private Object readResolve() { + if (DateTimeZone.UTC.equals(getChronology().getZone()) == false) { + return new YearMonth(this, getChronology().withUTC()); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets the number of fields in this partial, which is two. + * The supported fields are Year and MonthOfYear. + * Note that only these fields may be queried. + * + * @return the field count, two + */ + public int size() { + return 2; + } + + /** + * Gets the field for a specific index in the chronology specified. + *

                + * This method must not use any instance variables. + * + * @param index the index to retrieve + * @param chrono the chronology to use + * @return the field, never null + */ + protected DateTimeField getField(int index, Chronology chrono) { + switch (index) { + case YEAR: + return chrono.year(); + case MONTH_OF_YEAR: + return chrono.monthOfYear(); + default: + throw new IndexOutOfBoundsException("Invalid index: " + index); + } + } + + /** + * Gets the field type at the specified index. + * + * @param index the index to retrieve + * @return the field at the specified index, never null + * @throws IndexOutOfBoundsException if the index is invalid + */ + public DateTimeFieldType getFieldType(int index) { + return FIELD_TYPES[index]; + } + + /** + * Gets an array of the field type of each of the fields that this partial supports. + *

                + * The fields are returned largest to smallest, Year, Month. + * + * @return the array of field types (cloned), largest to smallest, never null + */ + public DateTimeFieldType[] getFieldTypes() { + return (DateTimeFieldType[]) FIELD_TYPES.clone(); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this year-month with the specified chronology. + * This instance is immutable and unaffected by this method call. + *

                + * This method retains the values of the fields, thus the result will + * typically refer to a different instant. + *

                + * The time zone of the specified chronology is ignored, as YearMonth + * operates without a time zone. + * + * @param newChronology the new chronology, null means ISO + * @return a copy of this year-month with a different chronology, never null + * @throws IllegalArgumentException if the values are invalid for the new chronology + */ + public YearMonth withChronologyRetainFields(Chronology newChronology) { + newChronology = DateTimeUtils.getChronology(newChronology); + newChronology = newChronology.withUTC(); + if (newChronology == getChronology()) { + return this; + } else { + YearMonth newYearMonth = new YearMonth(this, newChronology); + newChronology.validate(newYearMonth, getValues()); + return newYearMonth; + } + } + + /** + * Returns a copy of this year-month with the specified field set to a new value. + *

                + * For example, if the field type is monthOfYear then the month + * would be changed in the returned instance. + *

                + * These three lines are equivalent: + *

                +     * YearMonth updated = ym.withField(DateTimeFieldType.monthOfYear(), 6);
                +     * YearMonth updated = ym.monthOfYear().setCopy(6);
                +     * YearMonth updated = ym.property(DateTimeFieldType.monthOfYear()).setCopy(6);
                +     * 
                + * + * @param fieldType the field type to set, not null + * @param value the value to set + * @return a copy of this instance with the field set, never null + * @throws IllegalArgumentException if the value is null or invalid + */ + public YearMonth withField(DateTimeFieldType fieldType, int value) { + int index = indexOfSupported(fieldType); + if (value == getValue(index)) { + return this; + } + int[] newValues = getValues(); + newValues = getField(index).set(this, index, newValues, value); + return new YearMonth(this, newValues); + } + + /** + * Returns a copy of this year-month with the value of the specified field increased. + *

                + * If the addition is zero, then this is returned. + *

                + * These three lines are equivalent: + *

                +     * YearMonth added = ym.withFieldAdded(DurationFieldType.months(), 6);
                +     * YearMonth added = ym.plusMonths(6);
                +     * YearMonth added = ym.monthOfYear().addToCopy(6);
                +     * 
                + * + * @param fieldType the field type to add to, not null + * @param amount the amount to add + * @return a copy of this instance with the field updated, never null + * @throws IllegalArgumentException if the value is null or invalid + * @throws ArithmeticException if the new date-time exceeds the capacity + */ + public YearMonth withFieldAdded(DurationFieldType fieldType, int amount) { + int index = indexOfSupported(fieldType); + if (amount == 0) { + return this; + } + int[] newValues = getValues(); + newValues = getField(index).add(this, index, newValues, amount); + return new YearMonth(this, newValues); + } + + /** + * Returns a copy of this year-month with the specified period added. + *

                + * If the addition is zero, then this is returned. + * Fields in the period that aren't present in the partial are ignored. + *

                + * This method is typically used to add multiple copies of complex + * period instances. Adding one field is best achieved using methods + * like {@link #withFieldAdded(DurationFieldType, int)} + * or {@link #plusYears(int)}. + * + * @param period the period to add to this one, null means zero + * @param scalar the amount of times to add, such as -1 to subtract once + * @return a copy of this instance with the period added, never null + * @throws ArithmeticException if the new date-time exceeds the capacity + */ + public YearMonth withPeriodAdded(ReadablePeriod period, int scalar) { + if (period == null || scalar == 0) { + return this; + } + int[] newValues = getValues(); + for (int i = 0; i < period.size(); i++) { + DurationFieldType fieldType = period.getFieldType(i); + int index = indexOf(fieldType); + if (index >= 0) { + newValues = getField(index).add(this, index, newValues, + FieldUtils.safeMultiply(period.getValue(i), scalar)); + } + } + return new YearMonth(this, newValues); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this year-month with the specified period added. + *

                + * If the amount is zero or null, then this is returned. + *

                + * This method is typically used to add complex period instances. + * Adding one field is best achieved using methods + * like {@link #plusYears(int)}. + * + * @param period the duration to add to this one, null means zero + * @return a copy of this instance with the period added, never null + * @throws ArithmeticException if the new year-month exceeds the capacity + */ + public YearMonth plus(ReadablePeriod period) { + return withPeriodAdded(period, 1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this year-month plus the specified number of years. + *

                + * This year-month instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * YearMonth added = ym.plusYears(6);
                +     * YearMonth added = ym.plus(Period.years(6));
                +     * YearMonth added = ym.withFieldAdded(DurationFieldType.years(), 6);
                +     * 
                + * + * @param years the amount of years to add, may be negative + * @return the new year-month plus the increased years, never null + */ + public YearMonth plusYears(int years) { + return withFieldAdded(DurationFieldType.years(), years); + } + + /** + * Returns a copy of this year-month plus the specified number of months. + *

                + * This year-month instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * YearMonth added = ym.plusMonths(6);
                +     * YearMonth added = ym.plus(Period.months(6));
                +     * YearMonth added = ym.withFieldAdded(DurationFieldType.months(), 6);
                +     * 
                + * + * @param months the amount of months to add, may be negative + * @return the new year-month plus the increased months, never null + */ + public YearMonth plusMonths(int months) { + return withFieldAdded(DurationFieldType.months(), months); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this year-month with the specified period taken away. + *

                + * If the amount is zero or null, then this is returned. + *

                + * This method is typically used to subtract complex period instances. + * Subtracting one field is best achieved using methods + * like {@link #minusYears(int)}. + * + * @param period the period to reduce this instant by + * @return a copy of this instance with the period taken away, never null + * @throws ArithmeticException if the new year-month exceeds the capacity + */ + public YearMonth minus(ReadablePeriod period) { + return withPeriodAdded(period, -1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this year-month minus the specified number of years. + *

                + * This year-month instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * YearMonth subtracted = ym.minusYears(6);
                +     * YearMonth subtracted = ym.minus(Period.years(6));
                +     * YearMonth subtracted = ym.withFieldAdded(DurationFieldType.years(), -6);
                +     * 
                + * + * @param years the amount of years to subtract, may be negative + * @return the new year-month minus the increased years, never null + */ + public YearMonth minusYears(int years) { + return withFieldAdded(DurationFieldType.years(), FieldUtils.safeNegate(years)); + } + + /** + * Returns a copy of this year-month minus the specified number of months. + *

                + * This year-month instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * YearMonth subtracted = ym.minusMonths(6);
                +     * YearMonth subtracted = ym.minus(Period.months(6));
                +     * YearMonth subtracted = ym.withFieldAdded(DurationFieldType.months(), -6);
                +     * 
                + * + * @param months the amount of months to subtract, may be negative + * @return the new year-month minus the increased months, never null + */ + public YearMonth minusMonths(int months) { + return withFieldAdded(DurationFieldType.months(), FieldUtils.safeNegate(months)); + } + + //----------------------------------------------------------------------- + /** + * Converts this object to a LocalDate with the same year-month and chronology. + * + * @param dayOfMonth the day of month to use, valid for chronology, such as 1-31 for ISO + * @return a LocalDate with the same year-month and chronology, never null + */ + public LocalDate toLocalDate(int dayOfMonth) { + return new LocalDate(getYear(), getMonthOfYear(), dayOfMonth, getChronology()); + } + + //----------------------------------------------------------------------- + /** + * Converts this object to an Interval representing the whole month. + *

                + * The interval will use the chronology of the year-month in the default zone. + *

                + * This instance is immutable and unaffected by this method call. + * + * @return an interval over the month, never null + */ + public Interval toInterval() { + return toInterval(null); + } + + /** + * Converts this object to an Interval representing the whole month. + *

                + * The interval will use the chronology of the year-month in the specified zone. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param zone the zone to get the Interval in, null means default + * @return an interval over the month, never null + */ + public Interval toInterval(DateTimeZone zone) { + zone = DateTimeUtils.getZone(zone); + DateTime start = toLocalDate(1).toDateTimeAtStartOfDay(zone); + DateTime end = plusMonths(1).toLocalDate(1).toDateTimeAtStartOfDay(zone); + return new Interval(start, end); + } + + //----------------------------------------------------------------------- + /** + * Get the year field value. + * + * @return the year + */ + public int getYear() { + return getValue(YEAR); + } + + /** + * Get the month of year field value. + * + * @return the month of year + */ + public int getMonthOfYear() { + return getValue(MONTH_OF_YEAR); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this year-month with the year field updated. + *

                + * YearMonth is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year changed. + * + * @param year the year to set + * @return a copy of this object with the field set, never null + * @throws IllegalArgumentException if the value is invalid + */ + public YearMonth withYear(int year) { + int[] newValues = getValues(); + newValues = getChronology().year().set(this, YEAR, newValues, year); + return new YearMonth(this, newValues); + } + + /** + * Returns a copy of this year-month with the month of year field updated. + *

                + * YearMonth is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * month of year changed. + * + * @param monthOfYear the month of year to set + * @return a copy of this object with the field set, never null + * @throws IllegalArgumentException if the value is invalid + */ + public YearMonth withMonthOfYear(int monthOfYear) { + int[] newValues = getValues(); + newValues = getChronology().monthOfYear().set(this, MONTH_OF_YEAR, newValues, monthOfYear); + return new YearMonth(this, newValues); + } + + //----------------------------------------------------------------------- + /** + * Gets the property object for the specified type, which contains + * many useful methods. + * + * @param type the field type to get the property for + * @return the property object + * @throws IllegalArgumentException if the field is null or unsupported + */ + public Property property(DateTimeFieldType type) { + return new Property(this, indexOfSupported(type)); + } + + //----------------------------------------------------------------------- + /** + * Get the year field property which provides access to advanced functionality. + * + * @return the year property + */ + public Property year() { + return new Property(this, YEAR); + } + + /** + * Get the month of year field property which provides access to advanced functionality. + * + * @return the month of year property + */ + public Property monthOfYear() { + return new Property(this, MONTH_OF_YEAR); + } + + //----------------------------------------------------------------------- + /** + * Output the year-month in ISO8601 format (yyyy-MM). + * + * @return ISO8601 time formatted string. + */ + @ToString + public String toString() { + return ISODateTimeFormat.yearMonth().print(this); + } + + /** + * Output the year-month using the specified format pattern. + * + * @param pattern the pattern specification, null means use toString + * @see org.joda.time.format.DateTimeFormat + */ + public String toString(String pattern) { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).print(this); + } + + /** + * Output the year-month using the specified format pattern. + * + * @param pattern the pattern specification, null means use toString + * @param locale Locale to use, null means default + * @see org.joda.time.format.DateTimeFormat + */ + public String toString(String pattern, Locale locale) throws IllegalArgumentException { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this); + } + + //----------------------------------------------------------------------- + /** + * The property class for YearMonth. + *

                + * This class binds a YearMonth to a DateTimeField. + * + * @author Stephen Colebourne + * @since 2.0 + */ + public static class Property extends AbstractPartialFieldProperty implements Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 5727734012190224363L; + + /** The partial */ + private final YearMonth iBase; + /** The field index */ + private final int iFieldIndex; + + /** + * Constructs a property. + * + * @param partial the partial instance + * @param fieldIndex the index in the partial + */ + Property(YearMonth partial, int fieldIndex) { + super(); + iBase = partial; + iFieldIndex = fieldIndex; + } + + /** + * Gets the field that this property uses. + * + * @return the field + */ + public DateTimeField getField() { + return iBase.getField(iFieldIndex); + } + + /** + * Gets the partial that this property belongs to. + * + * @return the partial + */ + protected ReadablePartial getReadablePartial() { + return iBase; + } + + /** + * Gets the partial that this property belongs to. + * + * @return the partial + */ + public YearMonth getYearMonth() { + return iBase; + } + + /** + * Gets the value of this field. + * + * @return the field value + */ + public int get() { + return iBase.getValue(iFieldIndex); + } + + //----------------------------------------------------------------------- + /** + * Adds to the value of this field in a copy of this YearMonth. + *

                + * The value will be added to this field. If the value is too large to be + * added solely to this field then it will affect larger fields. + * Smaller fields are unaffected. + *

                + * If the result would be too large, beyond the maximum year, then an + * IllegalArgumentException is thrown. + *

                + * The YearMonth attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param valueToAdd the value to add to the field in the copy + * @return a copy of the YearMonth with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public YearMonth addToCopy(int valueToAdd) { + int[] newValues = iBase.getValues(); + newValues = getField().add(iBase, iFieldIndex, newValues, valueToAdd); + return new YearMonth(iBase, newValues); + } + + /** + * Adds to the value of this field in a copy of this YearMonth wrapping + * within this field if the maximum value is reached. + *

                + * The value will be added to this field. If the value is too large to be + * added solely to this field then it wraps within this field. + * Other fields are unaffected. + *

                + * For example, + * 2004-12 addWrapField one month returns 2004-01. + *

                + * The YearMonth attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param valueToAdd the value to add to the field in the copy + * @return a copy of the YearMonth with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public YearMonth addWrapFieldToCopy(int valueToAdd) { + int[] newValues = iBase.getValues(); + newValues = getField().addWrapField(iBase, iFieldIndex, newValues, valueToAdd); + return new YearMonth(iBase, newValues); + } + + //----------------------------------------------------------------------- + /** + * Sets this field in a copy of the YearMonth. + *

                + * The YearMonth attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param value the value to set the field in the copy to + * @return a copy of the YearMonth with the field value changed + * @throws IllegalArgumentException if the value isn't valid + */ + public YearMonth setCopy(int value) { + int[] newValues = iBase.getValues(); + newValues = getField().set(iBase, iFieldIndex, newValues, value); + return new YearMonth(iBase, newValues); + } + + /** + * Sets this field in a copy of the YearMonth to a parsed text value. + *

                + * The YearMonth attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param text the text value to set + * @param locale optional locale to use for selecting a text symbol + * @return a copy of the YearMonth with the field value changed + * @throws IllegalArgumentException if the text value isn't valid + */ + public YearMonth setCopy(String text, Locale locale) { + int[] newValues = iBase.getValues(); + newValues = getField().set(iBase, iFieldIndex, newValues, text, locale); + return new YearMonth(iBase, newValues); + } + + /** + * Sets this field in a copy of the YearMonth to a parsed text value. + *

                + * The YearMonth attached to this property is unchanged by this call. + * Instead, a new instance is returned. + * + * @param text the text value to set + * @return a copy of the YearMonth with the field value changed + * @throws IllegalArgumentException if the text value isn't valid + */ + public YearMonth setCopy(String text) { + return setCopy(text, null); + } + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/YearMonthDay.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/YearMonthDay.java (.../YearMonthDay.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/YearMonthDay.java (.../YearMonthDay.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,69 +1,39 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time; import java.io.Serializable; +import java.util.Calendar; +import java.util.Date; import java.util.Locale; import org.joda.time.base.BasePartial; +import org.joda.time.chrono.ISOChronology; import org.joda.time.field.AbstractPartialFieldProperty; +import org.joda.time.field.FieldUtils; import org.joda.time.format.ISODateTimeFormat; /** * YearMonthDay is an immutable partial supporting the year, monthOfYear * and dayOfMonth fields. *

                + * NOTE: This class only supports the three fields listed above. Thus, you + * cannot query the dayOfWeek or centuryOfEra fields for example. + * The new LocalDate class removes this restriction. + *

                * Calculations on YearMonthDay are performed using a {@link Chronology}. * This chronology is set to be in the UTC time zone for all calculations. *

                @@ -88,7 +58,10 @@ * * @author Stephen Colebourne * @since 1.0 + * @deprecated Use LocalDate which has a much better internal implementation and + * has been available since 1.3 */ +@Deprecated public final class YearMonthDay extends BasePartial implements ReadablePartial, Serializable { @@ -109,10 +82,67 @@ /** The index of the dayOfMonth field in the field array */ public static final int DAY_OF_MONTH = 2; - // Constructors //----------------------------------------------------------------------- /** - * Constructs a YearMonthDay with the current time, using ISOChronology in + * Constructs a YearMonthDay from a java.util.Calendar + * using exactly the same field values avoiding any time zone effects. + *

                + * Each field is queried from the Calendar and assigned to the YearMonthDay. + * This is useful if you have been using the Calendar as a local date, + * ignoing the zone. + *

                + * This factory method ignores the type of the calendar and always + * creates a YearMonthDay with ISO chronology. It is expected that you + * will only pass in instances of GregorianCalendar however + * this is not validated. + * + * @param calendar the Calendar to extract fields from + * @return the created YearMonthDay + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the date is invalid for the ISO chronology + * @since 1.2 + */ + public static YearMonthDay fromCalendarFields(Calendar calendar) { + if (calendar == null) { + throw new IllegalArgumentException("The calendar must not be null"); + } + return new YearMonthDay( + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH) + 1, + calendar.get(Calendar.DAY_OF_MONTH) + ); + } + + /** + * Constructs a YearMonthDay from a java.util.Date + * using exactly the same field values avoiding any time zone effects. + *

                + * Each field is queried from the Date and assigned to the YearMonthDay. + * This is useful if you have been using the Date as a local date, + * ignoing the zone. + *

                + * This factory method always creates a YearMonthDay with ISO chronology. + * + * @param date the Date to extract fields from + * @return the created YearMonthDay + * @throws IllegalArgumentException if the calendar is null + * @throws IllegalArgumentException if the date is invalid for the ISO chronology + * @since 1.2 + */ + public static YearMonthDay fromDateFields(Date date) { + if (date == null) { + throw new IllegalArgumentException("The date must not be null"); + } + return new YearMonthDay( + date.getYear() + 1900, + date.getMonth() + 1, + date.getDate() + ); + } + + //----------------------------------------------------------------------- + /** + * Constructs a YearMonthDay with the current date, using ISOChronology in * the default zone to extract the fields. *

                * The constructor uses the default time zone, resulting in the local time @@ -124,7 +154,22 @@ } /** - * Constructs a YearMonthDay with the current time, using the specified chronology + * Constructs a YearMonthDay with the current date, using ISOChronology in + * the specified zone to extract the fields. + *

                + * The constructor uses the specified time zone to obtain the current date. + * Once the constructor is complete, all further calculations + * are performed without reference to a timezone (by switching to UTC). + * + * @param zone the zone to use, null means default zone + * @since 1.1 + */ + public YearMonthDay(DateTimeZone zone) { + super(ISOChronology.getInstance(zone)); + } + + /** + * Constructs a YearMonthDay with the current date, using the specified chronology * and zone to extract the fields. *

                * The constructor uses the time zone of the chronology specified. @@ -172,14 +217,18 @@ * The recognised object types are defined in * {@link org.joda.time.convert.ConverterManager ConverterManager} and * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#dateOptionalTimeParser()}. *

                * The chronology used will be derived from the object, defaulting to ISO. + *

                + * NOTE: Prior to v1.3 the string format was described by + * {@link ISODateTimeFormat#dateTimeParser()}. Time ony strings are now rejected. * * @param instant the datetime object, null means now * @throws IllegalArgumentException if the instant is invalid */ public YearMonthDay(Object instant) { - super(instant, null); + super(instant, null, ISODateTimeFormat.dateOptionalTimeParser()); } /** @@ -189,18 +238,22 @@ * The recognised object types are defined in * {@link org.joda.time.convert.ConverterManager ConverterManager} and * include ReadableInstant, String, Calendar and Date. + * The String formats are described by {@link ISODateTimeFormat#dateOptionalTimeParser()}. *

                * The constructor uses the time zone of the chronology specified. * Once the constructor is complete, all further calculations are performed * without reference to a timezone (by switching to UTC). * The specified chronology overrides that of the object. + *

                + * NOTE: Prior to v1.3 the string format was described by + * {@link ISODateTimeFormat#dateTimeParser()}. Time only strings are now rejected. * * @param instant the datetime object, null means now * @param chronology the chronology, null means ISO default * @throws IllegalArgumentException if the instant is invalid */ public YearMonthDay(Object instant, Chronology chronology) { - super(instant, DateTimeUtils.getChronology(chronology)); + super(instant, DateTimeUtils.getChronology(chronology), ISODateTimeFormat.dateOptionalTimeParser()); } /** @@ -311,32 +364,283 @@ //----------------------------------------------------------------------- /** - * Creates a new YearMonthDay instance with the specified chronology. + * Returns a copy of this date with the specified chronology. * This instance is immutable and unaffected by this method call. *

                * This method retains the values of the fields, thus the result will * typically refer to a different instant. *

                - * The time zone of the specified chronology is ignored, as TimeOfDay + * The time zone of the specified chronology is ignored, as YearMonthDay * operates without a time zone. * * @param newChronology the new chronology, null means ISO * @return a copy of this datetime with a different chronology + * @throws IllegalArgumentException if the values are invalid for the new chronology */ public YearMonthDay withChronologyRetainFields(Chronology newChronology) { newChronology = DateTimeUtils.getChronology(newChronology); newChronology = newChronology.withUTC(); if (newChronology == getChronology()) { return this; } else { - return new YearMonthDay(this, newChronology); + YearMonthDay newYearMonthDay = new YearMonthDay(this, newChronology); + newChronology.validate(newYearMonthDay, getValues()); + return newYearMonthDay; } } /** - * Gets the property object for the specified type, which contains many useful methods. + * Returns a copy of this date with the specified field set to a new value. + *

                + * For example, if the field type is dayOfMonth then the day + * would be changed in the returned instance. + *

                + * These three lines are equivalent: + *

                +     * YearMonthDay updated = ymd.withField(DateTimeFieldType.dayOfMonth(), 6);
                +     * YearMonthDay updated = ymd.dayOfMonth().setCopy(6);
                +     * YearMonthDay updated = ymd.property(DateTimeFieldType.dayOfMonth()).setCopy(6);
                +     * 
                * - * @param type the field type to get the chronology for + * @param fieldType the field type to set, not null + * @param value the value to set + * @return a copy of this instance with the field set + * @throws IllegalArgumentException if the value is null or invalid + */ + public YearMonthDay withField(DateTimeFieldType fieldType, int value) { + int index = indexOfSupported(fieldType); + if (value == getValue(index)) { + return this; + } + int[] newValues = getValues(); + newValues = getField(index).set(this, index, newValues, value); + return new YearMonthDay(this, newValues); + } + + /** + * Returns a copy of this date with the value of the specified field increased. + *

                + * If the addition is zero, then this is returned. + *

                + * These three lines are equivalent: + *

                +     * YearMonthDay added = ymd.withFieldAdded(DurationFieldType.days(), 6);
                +     * YearMonthDay added = ymd.plusDays(6);
                +     * YearMonthDay added = ymd.dayOfMonth().addToCopy(6);
                +     * 
                + * + * @param fieldType the field type to add to, not null + * @param amount the amount to add + * @return a copy of this instance with the field updated + * @throws IllegalArgumentException if the value is null or invalid + * @throws ArithmeticException if the new datetime exceeds the capacity + */ + public YearMonthDay withFieldAdded(DurationFieldType fieldType, int amount) { + int index = indexOfSupported(fieldType); + if (amount == 0) { + return this; + } + int[] newValues = getValues(); + newValues = getField(index).add(this, index, newValues, amount); + return new YearMonthDay(this, newValues); + } + + /** + * Returns a copy of this date with the specified period added. + *

                + * If the addition is zero, then this is returned. + * Fields in the period that aren't present in the partial are ignored. + *

                + * This method is typically used to add multiple copies of complex + * period instances. Adding one field is best achieved using methods + * like {@link #withFieldAdded(DurationFieldType, int)} + * or {@link #plusYears(int)}. + * + * @param period the period to add to this one, null means zero + * @param scalar the amount of times to add, such as -1 to subtract once + * @return a copy of this instance with the period added + * @throws ArithmeticException if the new datetime exceeds the capacity + */ + public YearMonthDay withPeriodAdded(ReadablePeriod period, int scalar) { + if (period == null || scalar == 0) { + return this; + } + int[] newValues = getValues(); + for (int i = 0; i < period.size(); i++) { + DurationFieldType fieldType = period.getFieldType(i); + int index = indexOf(fieldType); + if (index >= 0) { + newValues = getField(index).add(this, index, newValues, + FieldUtils.safeMultiply(period.getValue(i), scalar)); + } + } + return new YearMonthDay(this, newValues); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the specified period added. + *

                + * If the amount is zero or null, then this is returned. + *

                + * This method is typically used to add complex period instances. + * Adding one field is best achieved using methods + * like {@link #plusYears(int)}. + * + * @param period the duration to add to this one, null means zero + * @return a copy of this instance with the period added + * @throws ArithmeticException if the new datetime exceeds the capacity of a long + */ + public YearMonthDay plus(ReadablePeriod period) { + return withPeriodAdded(period, 1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date plus the specified number of years. + *

                + * This date instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * YearMonthDay added = dt.plusYears(6);
                +     * YearMonthDay added = dt.plus(Period.years(6));
                +     * YearMonthDay added = dt.withFieldAdded(DurationFieldType.years(), 6);
                +     * 
                + * + * @param years the amount of years to add, may be negative + * @return the new date plus the increased years + * @since 1.1 + */ + public YearMonthDay plusYears(int years) { + return withFieldAdded(DurationFieldType.years(), years); + } + + /** + * Returns a copy of this date plus the specified number of months. + *

                + * This date instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * YearMonthDay added = dt.plusMonths(6);
                +     * YearMonthDay added = dt.plus(Period.months(6));
                +     * YearMonthDay added = dt.withFieldAdded(DurationFieldType.months(), 6);
                +     * 
                + * + * @param months the amount of months to add, may be negative + * @return the new date plus the increased months + * @since 1.1 + */ + public YearMonthDay plusMonths(int months) { + return withFieldAdded(DurationFieldType.months(), months); + } + + /** + * Returns a copy of this date plus the specified number of days. + *

                + * This date instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * YearMonthDay added = dt.plusDays(6);
                +     * YearMonthDay added = dt.plus(Period.days(6));
                +     * YearMonthDay added = dt.withFieldAdded(DurationFieldType.days(), 6);
                +     * 
                + * + * @param days the amount of days to add, may be negative + * @return the new date plus the increased days + * @since 1.1 + */ + public YearMonthDay plusDays(int days) { + return withFieldAdded(DurationFieldType.days(), days); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the specified period taken away. + *

                + * If the amount is zero or null, then this is returned. + *

                + * This method is typically used to subtract complex period instances. + * Subtracting one field is best achieved using methods + * like {@link #minusYears(int)}. + * + * @param period the period to reduce this instant by + * @return a copy of this instance with the period taken away + * @throws ArithmeticException if the new datetime exceeds the capacity of a long + */ + public YearMonthDay minus(ReadablePeriod period) { + return withPeriodAdded(period, -1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date minus the specified number of years. + *

                + * This datetime instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * YearMonthDay subtracted = dt.minusYears(6);
                +     * YearMonthDay subtracted = dt.minus(Period.years(6));
                +     * YearMonthDay subtracted = dt.withFieldAdded(DurationFieldType.years(), -6);
                +     * 
                + * + * @param years the amount of years to subtract, may be negative + * @return the new datetime minus the increased years + * @since 1.1 + */ + public YearMonthDay minusYears(int years) { + return withFieldAdded(DurationFieldType.years(), FieldUtils.safeNegate(years)); + } + + /** + * Returns a copy of this date minus the specified number of months. + *

                + * This datetime instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * YearMonthDay subtracted = dt.minusMonths(6);
                +     * YearMonthDay subtracted = dt.minus(Period.months(6));
                +     * YearMonthDay subtracted = dt.withFieldAdded(DurationFieldType.months(), -6);
                +     * 
                + * + * @param months the amount of months to subtract, may be negative + * @return the new datetime minus the increased months + * @since 1.1 + */ + public YearMonthDay minusMonths(int months) { + return withFieldAdded(DurationFieldType.months(), FieldUtils.safeNegate(months)); + } + + /** + * Returns a copy of this date minus the specified number of days. + *

                + * This datetime instance is immutable and unaffected by this method call. + *

                + * The following three lines are identical in effect: + *

                +     * YearMonthDay subtracted = dt.minusDays(6);
                +     * YearMonthDay subtracted = dt.minus(Period.days(6));
                +     * YearMonthDay subtracted = dt.withFieldAdded(DurationFieldType.days(), -6);
                +     * 
                + * + * @param days the amount of days to subtract, may be negative + * @return the new datetime minus the increased days + * @since 1.1 + */ + public YearMonthDay minusDays(int days) { + return withFieldAdded(DurationFieldType.days(), FieldUtils.safeNegate(days)); + } + + //----------------------------------------------------------------------- + /** + * Gets the property object for the specified type, which contains + * many useful methods. + * + * @param type the field type to get the property for * @return the property object * @throws IllegalArgumentException if the field is null or unsupported */ @@ -346,6 +650,73 @@ //----------------------------------------------------------------------- /** + * Converts this object to a LocalDate with the same date and chronology. + * + * @return a LocalDate with the same date and chronology + * @since 1.3 + */ + public LocalDate toLocalDate() { + return new LocalDate(getYear(), getMonthOfYear(), getDayOfMonth(), getChronology()); + } + + //----------------------------------------------------------------------- + /** + * Converts this YearMonthDay to a full datetime at midnight using the + * default time zone. + * + * @return this date as a datetime at midnight + */ + public DateTime toDateTimeAtMidnight() { + return toDateTimeAtMidnight(null); + } + + /** + * Converts this YearMonthDay to a full datetime at midnight using the + * specified time zone. + *

                + * This method uses the chronology from this instance plus the time zone + * specified. + * + * @param zone the zone to use, null means default + * @return this date as a datetime at midnight + */ + public DateTime toDateTimeAtMidnight(DateTimeZone zone) { + Chronology chrono = getChronology().withZone(zone); + return new DateTime(getYear(), getMonthOfYear(), getDayOfMonth(), 0, 0, 0, 0, chrono); + } + + //----------------------------------------------------------------------- + /** + * Converts this partial to a full datetime using the default time zone + * setting the date fields from this instance and the time fields from + * the current time. + * + * @return this date as a datetime with the time as the current time + */ + public DateTime toDateTimeAtCurrentTime() { + return toDateTimeAtCurrentTime(null); + } + + /** + * Converts this partial to a full datetime using the specified time zone + * setting the date fields from this instance and the time fields from + * the current time. + *

                + * This method uses the chronology from this instance plus the time zone + * specified. + * + * @param zone the zone to use, null means default + * @return this date as a datetime with the time as the current time + */ + public DateTime toDateTimeAtCurrentTime(DateTimeZone zone) { + Chronology chrono = getChronology().withZone(zone); + long instantMillis = DateTimeUtils.currentTimeMillis(); + long resolved = chrono.set(this, instantMillis); + return new DateTime(resolved, chrono); + } + + //----------------------------------------------------------------------- + /** * Converts this object to a DateMidnight in the default time zone. * * @return the DateMidnight instance in the default zone @@ -410,7 +781,7 @@ * Converts this object to an Interval representing the whole day * in the default time zone. * - * @return the DateMidnight instance in the default zone + * @return a interval over the day */ public Interval toInterval() { return toInterval(null); @@ -420,7 +791,7 @@ * Converts this object to an Interval representing the whole day. * * @param zone the zone to get the Interval in, null means default - * @return the DateMidnight instance + * @return a interval over the day */ public Interval toInterval(DateTimeZone zone) { zone = DateTimeUtils.getZone(zone); @@ -457,7 +828,62 @@ //----------------------------------------------------------------------- /** - * Get the year field property + * Returns a copy of this date with the year field updated. + *

                + * YearMonthDay is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * year changed. + * + * @param year the year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public YearMonthDay withYear(int year) { + int[] newValues = getValues(); + newValues = getChronology().year().set(this, YEAR, newValues, year); + return new YearMonthDay(this, newValues); + } + + /** + * Returns a copy of this date with the month of year field updated. + *

                + * YearMonthDay is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * month of year changed. + * + * @param monthOfYear the month of year to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public YearMonthDay withMonthOfYear(int monthOfYear) { + int[] newValues = getValues(); + newValues = getChronology().monthOfYear().set(this, MONTH_OF_YEAR, newValues, monthOfYear); + return new YearMonthDay(this, newValues); + } + + /** + * Returns a copy of this date with the day of month field updated. + *

                + * YearMonthDay is immutable, so there are no set methods. + * Instead, this method returns a new instance with the value of + * day of month changed. + * + * @param dayOfMonth the day of month to set + * @return a copy of this object with the field set + * @throws IllegalArgumentException if the value is invalid + * @since 1.3 + */ + public YearMonthDay withDayOfMonth(int dayOfMonth) { + int[] newValues = getValues(); + newValues = getChronology().dayOfMonth().set(this, DAY_OF_MONTH, newValues, dayOfMonth); + return new YearMonthDay(this, newValues); + } + + //----------------------------------------------------------------------- + /** + * Get the year field property which provides access to advanced functionality. * * @return the year property */ @@ -466,7 +892,7 @@ } /** - * Get the month of year field property + * Get the month of year field property which provides access to advanced functionality. * * @return the month of year property */ @@ -475,7 +901,7 @@ } /** - * Get the day of month field property + * Get the day of month field property which provides access to advanced functionality. * * @return the day of month property */ @@ -485,12 +911,12 @@ //----------------------------------------------------------------------- /** - * Output the time in the ISO8601 format YYYY-MM-DD. + * Output the date in the ISO8601 format YYYY-MM-DD. * * @return ISO8601 formatted string */ public String toString() { - return ISODateTimeFormat.getInstance().yearMonthDay().print(this); + return ISODateTimeFormat.yearMonthDay().print(this); } //----------------------------------------------------------------------- @@ -501,7 +927,9 @@ * * @author Stephen Colebourne * @since 1.0 + * @deprecated Use LocalDate which has a much better internal implementation */ + @Deprecated public static class Property extends AbstractPartialFieldProperty implements Serializable { /** Serialization version */ @@ -538,7 +966,7 @@ * * @return the partial */ - public ReadablePartial getReadablePartial() { + protected ReadablePartial getReadablePartial() { return iYearMonthDay; } @@ -655,6 +1083,39 @@ public YearMonthDay setCopy(String text) { return setCopy(text, null); } + + //----------------------------------------------------------------------- + /** + * Returns a new YearMonthDay with this field set to the maximum value + * for this field. + *

                + * This operation is useful for obtaining a DateTime on the last day + * of the month, as month lengths vary. + *

                +         * YearMonthDay lastDayOfMonth = dt.dayOfMonth().withMaximumValue();
                +         * 
                + *

                + * The YearMonthDay attached to this property is unchanged by this call. + * + * @return a copy of the YearMonthDay with this field set to its maximum + * @since 1.2 + */ + public YearMonthDay withMaximumValue() { + return setCopy(getMaximumValue()); + } + + /** + * Returns a new YearMonthDay with this field set to the minimum value + * for this field. + *

                + * The YearMonthDay attached to this property is unchanged by this call. + * + * @return a copy of the YearMonthDay with this field set to its minimum + * @since 1.2 + */ + public YearMonthDay withMinimumValue() { + return setCopy(getMinimumValue()); + } } } Index: 3rdParty_sources/joda-time/org/joda/time/Years.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/Years.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/Years.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,361 @@ +/* + * Copyright 2001-2010 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; +import org.joda.time.base.BaseSingleFieldPeriod; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.ISOPeriodFormat; +import org.joda.time.format.PeriodFormatter; + +/** + * An immutable time period representing a number of years. + *

                + * Years is an immutable period that can only store years. + * It does not store years, days or hours for example. As such it is a + * type-safe way of representing a number of years in an application. + *

                + * The number of years is set in the constructor, and may be queried using + * getYears(). Basic mathematical operations are provided - + * plus(), minus(), multipliedBy() and + * dividedBy(). + *

                + * Years is thread-safe and immutable. + * + * @author Stephen Colebourne + * @since 1.4 + */ +public final class Years extends BaseSingleFieldPeriod { + + /** Constant representing zero years. */ + public static final Years ZERO = new Years(0); + /** Constant representing one year. */ + public static final Years ONE = new Years(1); + /** Constant representing two years. */ + public static final Years TWO = new Years(2); + /** Constant representing three years. */ + public static final Years THREE = new Years(3); + /** Constant representing the maximum number of years that can be stored in this object. */ + public static final Years MAX_VALUE = new Years(Integer.MAX_VALUE); + /** Constant representing the minimum number of years that can be stored in this object. */ + public static final Years MIN_VALUE = new Years(Integer.MIN_VALUE); + + /** The paser to use for this class. */ + private static final PeriodFormatter PARSER = ISOPeriodFormat.standard().withParseType(PeriodType.years()); + /** Serialization version. */ + private static final long serialVersionUID = 87525275727380868L; + + //----------------------------------------------------------------------- + /** + * Obtains an instance of Years that may be cached. + * Years is immutable, so instances can be cached and shared. + * This factory method provides access to shared instances. + * + * @param years the number of years to obtain an instance for + * @return the instance of Years + */ + public static Years years(int years) { + switch (years) { + case 0: + return ZERO; + case 1: + return ONE; + case 2: + return TWO; + case 3: + return THREE; + case Integer.MAX_VALUE: + return MAX_VALUE; + case Integer.MIN_VALUE: + return MIN_VALUE; + default: + return new Years(years); + } + } + + //----------------------------------------------------------------------- + /** + * Creates a Years representing the number of whole years + * between the two specified datetimes. This method corectly handles + * any daylight savings time changes that may occur during the interval. + * + * @param start the start instant, must not be null + * @param end the end instant, must not be null + * @return the period in years + * @throws IllegalArgumentException if the instants are null or invalid + */ + public static Years yearsBetween(ReadableInstant start, ReadableInstant end) { + int amount = BaseSingleFieldPeriod.between(start, end, DurationFieldType.years()); + return Years.years(amount); + } + + /** + * Creates a Years representing the number of whole years + * between the two specified partial datetimes. + *

                + * The two partials must contain the same fields, for example you can specify + * two LocalDate objects. + * + * @param start the start partial date, must not be null + * @param end the end partial date, must not be null + * @return the period in years + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Years yearsBetween(ReadablePartial start, ReadablePartial end) { + if (start instanceof LocalDate && end instanceof LocalDate) { + Chronology chrono = DateTimeUtils.getChronology(start.getChronology()); + int years = chrono.years().getDifference( + ((LocalDate) end).getLocalMillis(), ((LocalDate) start).getLocalMillis()); + return Years.years(years); + } + int amount = BaseSingleFieldPeriod.between(start, end, ZERO); + return Years.years(amount); + } + + /** + * Creates a Years representing the number of whole years + * in the specified interval. This method corectly handles any daylight + * savings time changes that may occur during the interval. + * + * @param interval the interval to extract years from, null returns zero + * @return the period in years + * @throws IllegalArgumentException if the partials are null or invalid + */ + public static Years yearsIn(ReadableInterval interval) { + if (interval == null) { + return Years.ZERO; + } + int amount = BaseSingleFieldPeriod.between(interval.getStart(), interval.getEnd(), DurationFieldType.years()); + return Years.years(amount); + } + + /** + * Creates a new Years by parsing a string in the ISO8601 format 'PnY'. + *

                + * The parse will accept the full ISO syntax of PnYnMnWnDTnHnMnS however only the + * years component may be non-zero. If any other component is non-zero, an exception + * will be thrown. + * + * @param periodStr the period string, null returns zero + * @return the period in years + * @throws IllegalArgumentException if the string format is invalid + */ + @FromString + public static Years parseYears(String periodStr) { + if (periodStr == null) { + return Years.ZERO; + } + Period p = PARSER.parsePeriod(periodStr); + return Years.years(p.getYears()); + } + + //----------------------------------------------------------------------- + /** + * Creates a new instance representing a number of years. + * You should consider using the factory method {@link #years(int)} + * instead of the constructor. + * + * @param years the number of years to represent + */ + private Years(int years) { + super(years); + } + + /** + * Resolves singletons. + * + * @return the singleton instance + */ + private Object readResolve() { + return Years.years(getValue()); + } + + //----------------------------------------------------------------------- + /** + * Gets the duration field type, which is years. + * + * @return the period type + */ + public DurationFieldType getFieldType() { + return DurationFieldType.years(); + } + + /** + * Gets the period type, which is years. + * + * @return the period type + */ + public PeriodType getPeriodType() { + return PeriodType.years(); + } + + //----------------------------------------------------------------------- + /** + * Gets the number of years that this period represents. + * + * @return the number of years in the period + */ + public int getYears() { + return getValue(); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of years added. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param years the amount of years to add, may be negative + * @return the new period plus the specified number of years + * @throws ArithmeticException if the result overflows an int + */ + public Years plus(int years) { + if (years == 0) { + return this; + } + return Years.years(FieldUtils.safeAdd(getValue(), years)); + } + + /** + * Returns a new instance with the specified number of years added. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param years the amount of years to add, may be negative, null means zero + * @return the new period plus the specified number of years + * @throws ArithmeticException if the result overflows an int + */ + public Years plus(Years years) { + if (years == null) { + return this; + } + return plus(years.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified number of years taken away. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param years the amount of years to take away, may be negative + * @return the new period minus the specified number of years + * @throws ArithmeticException if the result overflows an int + */ + public Years minus(int years) { + return plus(FieldUtils.safeNegate(years)); + } + + /** + * Returns a new instance with the specified number of years taken away. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param years the amount of years to take away, may be negative, null means zero + * @return the new period minus the specified number of years + * @throws ArithmeticException if the result overflows an int + */ + public Years minus(Years years) { + if (years == null) { + return this; + } + return minus(years.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the years multiplied by the specified scalar. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param scalar the amount to multiply by, may be negative + * @return the new period multiplied by the specified scalar + * @throws ArithmeticException if the result overflows an int + */ + public Years multipliedBy(int scalar) { + return Years.years(FieldUtils.safeMultiply(getValue(), scalar)); + } + + /** + * Returns a new instance with the years divided by the specified divisor. + * The calculation uses integer division, thus 3 divided by 2 is 1. + *

                + * This instance is immutable and unaffected by this method call. + * + * @param divisor the amount to divide by, may be negative + * @return the new period divided by the specified divisor + * @throws ArithmeticException if the divisor is zero + */ + public Years dividedBy(int divisor) { + if (divisor == 1) { + return this; + } + return Years.years(getValue() / divisor); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the years value negated. + * + * @return the new period with a negated value + * @throws ArithmeticException if the result overflows an int + */ + public Years negated() { + return Years.years(FieldUtils.safeNegate(getValue())); + } + + //----------------------------------------------------------------------- + /** + * Is this years instance greater than the specified number of years. + * + * @param other the other period, null means zero + * @return true if this years instance is greater than the specified one + */ + public boolean isGreaterThan(Years other) { + if (other == null) { + return getValue() > 0; + } + return getValue() > other.getValue(); + } + + /** + * Is this years instance less than the specified number of years. + * + * @param other the other period, null means zero + * @return true if this years instance is less than the specified one + */ + public boolean isLessThan(Years other) { + if (other == null) { + return getValue() < 0; + } + return getValue() < other.getValue(); + } + + //----------------------------------------------------------------------- + /** + * Gets this instance as a String in the ISO8601 duration format. + *

                + * For example, "P4Y" represents 4 years. + * + * @return the value as an ISO8601 string + */ + @ToString + public String toString() { + return "P" + String.valueOf(getValue()) + "Y"; + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/base/AbstractDateTime.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/base/AbstractDateTime.java (.../AbstractDateTime.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/base/AbstractDateTime.java (.../AbstractDateTime.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.base; @@ -82,7 +44,6 @@ extends AbstractInstant implements ReadableDateTime { - //----------------------------------------------------------------------- /** * Constructor. */ @@ -156,6 +117,12 @@ /** * Get the weekyear field value. + *

                + * The weekyear is the year that matches with the weekOfWeekyear field. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. + * The weekyear allows you to query the effective year for that day. * * @return the year of a week based year */ @@ -174,6 +141,11 @@ /** * Get the week of weekyear field value. + *

                + * This field is associated with the "weekyear" via {@link #getWeekyear()}. + * In the standard ISO8601 week algorithm, the first week of the year + * is that in which at least 4 days are in the year. As a result of this + * definition, day 1 of the first week may be in the previous year. * * @return the week of a week based year */ @@ -278,10 +250,19 @@ //----------------------------------------------------------------------- /** - * Get the date time as a java.util.Calendar. + * Get the date time as a java.util.Calendar, assigning + * exactly the same millisecond instant. * The locale is passed in, enabling Calendar to select the correct * localized subclass. - * + *

                + * The JDK and Joda-Time both have time zone implementations and these + * differ in accuracy. Joda-Time's implementation is generally more up to + * date and thus more accurate - for example JDK1.3 has no historical data. + * The effect of this is that the field values of the Calendar + * may differ from those of this object, even though the milliseond value + * is the same. Most of the time this just means that the JDK field values + * are wrong, as our time zone information is more up to date. + * * @param locale the locale to get the Calendar for, or default if null * @return a localized Calendar initialised with this datetime */ @@ -296,8 +277,17 @@ } /** - * Get the date time as a java.util.GregorianCalendar. - * + * Get the date time as a java.util.GregorianCalendar, + * assigning exactly the same millisecond instant. + *

                + * The JDK and Joda-Time both have time zone implementations and these + * differ in accuracy. Joda-Time's implementation is generally more up to + * date and thus more accurate - for example JDK1.3 has no historical data. + * The effect of this is that the field values of the Calendar + * may differ from those of this object, even though the milliseond value + * is the same. Most of the time this just means that the JDK field values + * are wrong, as our time zone information is more up to date. + * * @return a GregorianCalendar initialised with this datetime */ public GregorianCalendar toGregorianCalendar() { @@ -318,7 +308,7 @@ if (pattern == null) { return toString(); } - return DateTimeFormat.getInstance().forPattern(pattern).print(this); + return DateTimeFormat.forPattern(pattern).print(this); } /** @@ -332,7 +322,7 @@ if (pattern == null) { return toString(); } - return DateTimeFormat.getInstance(locale).forPattern(pattern).print(this); + return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this); } } Index: 3rdParty_sources/joda-time/org/joda/time/base/AbstractDuration.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/base/AbstractDuration.java (.../AbstractDuration.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/base/AbstractDuration.java (.../AbstractDuration.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,61 +1,25 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2010 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.base; +import org.joda.convert.ToString; import org.joda.time.Duration; import org.joda.time.Period; import org.joda.time.ReadableDuration; +import org.joda.time.ReadableInstant; import org.joda.time.format.FormatUtils; /** @@ -120,19 +84,15 @@ /** * Compares this duration with the specified duration based on length. * - * @param obj a duration to check against + * @param other a duration to check against * @return negative value if this is less, 0 if equal, or positive value if greater * @throws NullPointerException if the object is null * @throws ClassCastException if the given object is not supported */ - public int compareTo(Object obj) { - // Comparable contract means we cannot handle null or other types gracefully - ReadableDuration thisDuration = (ReadableDuration) this; - ReadableDuration otherDuration = (ReadableDuration) obj; + public int compareTo(ReadableDuration other) { + long thisMillis = this.getMillis(); + long otherMillis = other.getMillis(); - long thisMillis = thisDuration.getMillis(); - long otherMillis = otherDuration.getMillis(); - // cannot do (thisMillis - otherMillis) as it can overflow if (thisMillis < otherMillis) { return -1; @@ -224,16 +184,21 @@ * * @return the value as an ISO8601 string */ + @ToString public String toString() { long millis = getMillis(); StringBuffer buf = new StringBuffer(); buf.append("PT"); - FormatUtils.appendUnpaddedInteger(buf, millis / 1000); - long part = Math.abs(millis % 1000); - if (part > 0) { - buf.append('.'); - FormatUtils.appendPaddedInteger(buf, part, 3); + boolean negative = (millis < 0); + FormatUtils.appendUnpaddedInteger(buf, millis); + while (buf.length() < (negative ? 7 : 6)) { + buf.insert(negative ? 3 : 2, "0"); } + if ((millis / 1000) * 1000 == millis) { + buf.setLength(buf.length() - 3); + } else { + buf.insert(buf.length() - 3, "."); + } buf.append('S'); return buf.toString(); } Index: 3rdParty_sources/joda-time/org/joda/time/base/AbstractInstant.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/base/AbstractInstant.java (.../AbstractInstant.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/base/AbstractInstant.java (.../AbstractInstant.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,60 +1,23 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2010 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.base; import java.util.Date; +import org.joda.convert.ToString; import org.joda.time.Chronology; import org.joda.time.DateTime; import org.joda.time.DateTimeField; @@ -65,6 +28,8 @@ import org.joda.time.MutableDateTime; import org.joda.time.ReadableInstant; import org.joda.time.chrono.ISOChronology; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; /** @@ -128,6 +93,20 @@ } /** + * Checks if the field type specified is supported by this instant and chronology. + * This can be used to avoid exceptions in {@link #get(DateTimeFieldType)}. + * + * @param type a field type, usually obtained from DateTimeFieldType + * @return true if the field type is supported + */ + public boolean isSupported(DateTimeFieldType type) { + if (type == null) { + return false; + } + return type.getField(getChronology()).isSupported(); + } + + /** * Get the value of one of the fields of a datetime. *

                * This could be used to get a field using a different Chronology. @@ -159,21 +138,21 @@ } /** - * Get this object as a DateTime. - * + * Get this object as a DateTime in the same zone. + * * @return a DateTime using the same millis */ public DateTime toDateTime() { - return new DateTime(getMillis()); + return new DateTime(getMillis(), getZone()); } /** - * Get this object as a DateTime using ISOChronology in the default zone. - * - * @return a DateTime using the same millis with ISOChronology in the default zone. + * Get this object as a DateTime using ISOChronology in the same zone. + * + * @return a DateTime using the same millis with ISOChronology */ public DateTime toDateTimeISO() { - return new DateTime(getMillis(), ISOChronology.getInstance()); + return new DateTime(getMillis(), ISOChronology.getInstance(getZone())); } /** @@ -189,7 +168,7 @@ } /** - * Get this object as a DateTime. + * Get this object as a DateTime using the given chronology and its zone. * * @param chronology chronology to apply, or ISOChronology if null * @return a DateTime using the same millis @@ -204,21 +183,21 @@ // returning a copy prevents this. /** - * Get this object as a MutableDateTime. - * + * Get this object as a MutableDateTime in the same zone. + * * @return a MutableDateTime using the same millis */ public MutableDateTime toMutableDateTime() { - return new MutableDateTime(getMillis()); + return new MutableDateTime(getMillis(), getZone()); } /** - * Get this object as a MutableDateTime using ISOChronology in the default zone. - * - * @return a MutableDateTime using the same millis with ISOChronology in the default zone. + * Get this object as a MutableDateTime using ISOChronology in the same zone. + * + * @return a MutableDateTime using the same millis with ISOChronology */ public MutableDateTime toMutableDateTimeISO() { - return new MutableDateTime(getMillis(), ISOChronology.getInstance()); + return new MutableDateTime(getMillis(), ISOChronology.getInstance(getZone())); } /** @@ -234,7 +213,7 @@ } /** - * Get this object as a MutableDateTime. + * Get this object as a MutableDateTime using the given chronology and its zone. * * @param chronology chronology to apply, or ISOChronology if null * @return a MutableDateTime using the same millis @@ -246,7 +225,10 @@ //----------------------------------------------------------------------- /** * Get the date time as a java.util.Date. - * + *

                + * The Date object created has exactly the same millisecond + * instant as this object. + * * @return a Date initialised with this datetime */ public Date toDate() { @@ -256,12 +238,17 @@ //----------------------------------------------------------------------- /** * Compares this object with the specified object for equality based - * on the millisecond instant and the Chronology. + * on the millisecond instant, chronology and time zone. *

                - * All ReadableInstant instances are accepted. + * Two objects which represent the same instant in time, but are in + * different time zones (based on time zone id), will be considered to + * be different. Only two objects with the same {@link DateTimeZone}, + * {@link Chronology} and instant are equal. *

                * See {@link #isEqual(ReadableInstant)} for an equals method that - * ignores the Chronology. + * ignores the Chronology and time zone. + *

                + * All ReadableInstant instances are accepted. * * @param readableInstant a readable instant to check against * @return true if millisecond and chronology are equal, false if @@ -272,19 +259,13 @@ if (this == readableInstant) { return true; } - if (readableInstant instanceof ReadableInstant) { - ReadableInstant otherInstant = (ReadableInstant) readableInstant; - if (getMillis() == otherInstant.getMillis()) { - Chronology chrono = getChronology(); - if (chrono == otherInstant.getChronology()) { - return true; - } - if (chrono != null && chrono.equals(otherInstant.getChronology())) { - return true; - } - } + if (readableInstant instanceof ReadableInstant == false) { + return false; } - return false; + ReadableInstant otherInstant = (ReadableInstant) readableInstant; + return + getMillis() == otherInstant.getMillis() && + FieldUtils.equals(getChronology(), otherInstant.getChronology()); } /** @@ -306,19 +287,17 @@ *

                * All ReadableInstant instances are accepted. * - * @param instant a readable instant to check against + * @param other a readable instant to check against * @return negative value if this is less, 0 if equal, or positive value if greater * @throws NullPointerException if the object is null * @throws ClassCastException if the object type is not supported */ - public int compareTo(Object instant) { - if (this == instant) { + public int compareTo(ReadableInstant other) { + if (this == other) { return 0; } - ReadableInstant otherInstant = (ReadableInstant) instant; - - long otherMillis = otherInstant.getMillis(); + long otherMillis = other.getMillis(); long thisMillis = getMillis(); // cannot do (thisMillis - otherMillis) as can overflow @@ -436,12 +415,28 @@ //----------------------------------------------------------------------- /** - * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZ). + * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZZ). * * @return ISO8601 time formatted string. */ + @ToString public String toString() { - return ISODateTimeFormat.getInstance().dateTime().print(this); + return ISODateTimeFormat.dateTime().print(this); } + //----------------------------------------------------------------------- + /** + * Uses the specified formatter to convert this partial to a String. + * + * @param formatter the formatter to use, null means use toString(). + * @return the formatted string + * @since 1.1 + */ + public String toString(DateTimeFormatter formatter) { + if (formatter == null) { + return toString(); + } + return formatter.print(this); + } + } Index: 3rdParty_sources/joda-time/org/joda/time/base/AbstractInterval.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/base/AbstractInterval.java (.../AbstractInterval.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/base/AbstractInterval.java (.../AbstractInterval.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.base; @@ -63,7 +25,7 @@ import org.joda.time.ReadableInstant; import org.joda.time.ReadableInterval; import org.joda.time.field.FieldUtils; -import org.joda.time.format.DateTimePrinter; +import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; /** @@ -125,8 +87,9 @@ /** * Does this time interval contain the specified millisecond instant. *

                - * Intervals are inclusive of the start instant and exclusive of the end. - * + * Non-zero duration intervals are inclusive of the start instant and + * exclusive of the end. A zero duration interval cannot contain anything. + * * @param millisInstant the instant to compare to, * millisecond instant from 1970-01-01T00:00:00Z * @return true if this time interval contains the millisecond @@ -140,8 +103,9 @@ /** * Does this time interval contain the current instant. *

                - * Intervals are inclusive of the start instant and exclusive of the end. - * + * Non-zero duration intervals are inclusive of the start instant and + * exclusive of the end. A zero duration interval cannot contain anything. + * * @return true if this time interval contains the current instant */ public boolean containsNow() { @@ -151,8 +115,22 @@ /** * Does this time interval contain the specified instant. *

                - * Intervals are inclusive of the start instant and exclusive of the end. + * Non-zero duration intervals are inclusive of the start instant and + * exclusive of the end. A zero duration interval cannot contain anything. + *

                + * For example: + *

                +     * [09:00 to 10:00) contains 08:59  = false (before start)
                +     * [09:00 to 10:00) contains 09:00  = true
                +     * [09:00 to 10:00) contains 09:59  = true
                +     * [09:00 to 10:00) contains 10:00  = false (equals end)
                +     * [09:00 to 10:00) contains 10:01  = false (after end)
                      * 
                +     * [14:00 to 14:00) contains 14:00  = false (zero duration contains nothing)
                +     * 
                + * Passing in a null parameter will have the same effect as + * calling {@link #containsNow()}. + * * @param instant the instant, null means now * @return true if this time interval contains the instant */ @@ -164,11 +142,37 @@ } /** - * Does this time interval contain the specified time interval completely. + * Does this time interval contain the specified time interval. *

                - * Intervals are inclusive of the start instant and exclusive of the end. + * Non-zero duration intervals are inclusive of the start instant and + * exclusive of the end. The other interval is contained if this interval + * wholly contains, starts, finishes or equals it. + * A zero duration interval cannot contain anything. + *

                + * When two intervals are compared the result is one of three states: + * (a) they abut, (b) there is a gap between them, (c) they overlap. + * The contains method is not related to these states. + * In particular, a zero duration interval is contained at the start of + * a larger interval, but does not overlap (it abuts instead). + *

                + * For example: + *

                +     * [09:00 to 10:00) contains [09:00 to 10:00)  = true
                +     * [09:00 to 10:00) contains [09:00 to 09:30)  = true
                +     * [09:00 to 10:00) contains [09:30 to 10:00)  = true
                +     * [09:00 to 10:00) contains [09:15 to 09:45)  = true
                +     * [09:00 to 10:00) contains [09:00 to 09:00)  = true
                      * 
                -     * @param interval  the time interval to compare to, null means now
                +     * [09:00 to 10:00) contains [08:59 to 10:00)  = false (otherStart before thisStart)
                +     * [09:00 to 10:00) contains [09:00 to 10:01)  = false (otherEnd after thisEnd)
                +     * [09:00 to 10:00) contains [10:00 to 10:00)  = false (otherStart equals thisEnd)
                +     * 
                +     * [14:00 to 14:00) contains [14:00 to 14:00)  = false (zero duration contains nothing)
                +     * 
                + * Passing in a null parameter will have the same effect as + * calling {@link #containsNow()}. + * + * @param interval the time interval to compare to, null means a zero duration interval now * @return true if this time interval contains the time interval */ public boolean contains(ReadableInterval interval) { @@ -179,27 +183,61 @@ long otherEnd = interval.getEndMillis(); long thisStart = getStartMillis(); long thisEnd = getEndMillis(); - return (otherStart >= thisStart && otherStart < thisEnd && otherEnd <= thisEnd); + return (thisStart <= otherStart && otherStart < thisEnd && otherEnd <= thisEnd); } /** * Does this time interval overlap the specified time interval. *

                - * The intervals overlap if at least some of the time interval is in common. * Intervals are inclusive of the start instant and exclusive of the end. + * An interval overlaps another if it shares some common part of the + * datetime continuum. + *

                + * When two intervals are compared the result is one of three states: + * (a) they abut, (b) there is a gap between them, (c) they overlap. + * The abuts state takes precedence over the other two, thus a zero duration + * interval at the start of a larger interval abuts and does not overlap. + *

                + * For example: + *

                +     * [09:00 to 10:00) overlaps [08:00 to 08:30)  = false (completely before)
                +     * [09:00 to 10:00) overlaps [08:00 to 09:00)  = false (abuts before)
                +     * [09:00 to 10:00) overlaps [08:00 to 09:30)  = true
                +     * [09:00 to 10:00) overlaps [08:00 to 10:00)  = true
                +     * [09:00 to 10:00) overlaps [08:00 to 11:00)  = true
                      * 
                -     * @param interval  the time interval to compare to, null means now
                +     * [09:00 to 10:00) overlaps [09:00 to 09:00)  = false (abuts before)
                +     * [09:00 to 10:00) overlaps [09:00 to 09:30)  = true
                +     * [09:00 to 10:00) overlaps [09:00 to 10:00)  = true
                +     * [09:00 to 10:00) overlaps [09:00 to 11:00)  = true
                +     * 
                +     * [09:00 to 10:00) overlaps [09:30 to 09:30)  = true
                +     * [09:00 to 10:00) overlaps [09:30 to 10:00)  = true
                +     * [09:00 to 10:00) overlaps [09:30 to 11:00)  = true
                +     * 
                +     * [09:00 to 10:00) overlaps [10:00 to 10:00)  = false (abuts after)
                +     * [09:00 to 10:00) overlaps [10:00 to 11:00)  = false (abuts after)
                +     * 
                +     * [09:00 to 10:00) overlaps [10:30 to 11:00)  = false (completely after)
                +     * 
                +     * [14:00 to 14:00) overlaps [14:00 to 14:00)  = false (abuts before and after)
                +     * [14:00 to 14:00) overlaps [13:00 to 15:00)  = true
                +     * 
                + * + * @param interval the time interval to compare to, null means a zero length interval now * @return true if the time intervals overlap */ public boolean overlaps(ReadableInterval interval) { - if (interval == null) { - return containsNow(); - } - long otherStart = interval.getStartMillis(); - long otherEnd = interval.getEndMillis(); long thisStart = getStartMillis(); long thisEnd = getEndMillis(); - return (thisStart < otherEnd && otherStart < thisEnd); + if (interval == null) { + long now = DateTimeUtils.currentTimeMillis(); + return (thisStart < now && now < thisEnd); + } else { + long otherStart = interval.getStartMillis(); + long otherEnd = interval.getEndMillis(); + return (thisStart < otherEnd && otherStart < thisEnd); + } } //----------------------------------------------------------------------- @@ -301,15 +339,19 @@ * Is this time interval entirely after the specified interval. *

                * Intervals are inclusive of the start instant and exclusive of the end. + * Only the end time of the specified interval is used in the comparison. * * @param interval the interval to compare to, null means now * @return true if this time interval is after the interval specified */ public boolean isAfter(ReadableInterval interval) { + long endMillis; if (interval == null) { - return isAfterNow(); + endMillis = DateTimeUtils.currentTimeMillis(); + } else { + endMillis = interval.getEndMillis(); } - return isAfter(interval.getEndMillis()); + return (getStartMillis() >= endMillis); } //----------------------------------------------------------------------- @@ -411,9 +453,10 @@ return false; } ReadableInterval other = (ReadableInterval) readableInterval; - return (getStartMillis() == other.getStartMillis() && - getEndMillis() == other.getEndMillis() && - getChronology() == other.getChronology()); + return + getStartMillis() == other.getStartMillis() && + getEndMillis() == other.getEndMillis() && + FieldUtils.equals(getChronology(), other.getChronology()); } /** @@ -433,15 +476,18 @@ /** * Output a string in ISO8601 interval format. + *

                + * From version 2.1, the string includes the time zone offset. * - * @return re-parsable string + * @return re-parsable string (in the default zone) */ public String toString() { - DateTimePrinter printer = ISODateTimeFormat.getInstance().dateHourMinuteSecondFraction(); + DateTimeFormatter printer = ISODateTimeFormat.dateTime(); + printer = printer.withChronology(getChronology()); StringBuffer buf = new StringBuffer(48); - printer.printTo(buf, getStartMillis(), getChronology()); + printer.printTo(buf, getStartMillis()); buf.append('/'); - printer.printTo(buf, getEndMillis(), getChronology()); + printer.printTo(buf, getEndMillis()); return buf.toString(); } Index: 3rdParty_sources/joda-time/org/joda/time/base/AbstractPartial.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/base/AbstractPartial.java (.../AbstractPartial.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/base/AbstractPartial.java (.../AbstractPartial.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.base; @@ -58,9 +20,11 @@ import org.joda.time.DateTimeField; import org.joda.time.DateTimeFieldType; import org.joda.time.DateTimeUtils; -import org.joda.time.DateTimeZone; +import org.joda.time.DurationFieldType; import org.joda.time.ReadableInstant; import org.joda.time.ReadablePartial; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.DateTimeFormatter; /** * AbstractPartial provides a standard base implementation of most methods @@ -69,16 +33,18 @@ * Calculations on are performed using a {@link Chronology}. * This chronology is set to be in the UTC time zone for all calculations. *

                - * The methods on this class uses {@link ReadablePartial#size()}, - * {@link ReadablePartial#getField(int)} and {@link ReadablePartial#getValue(int)} - * to calculate their results. Subclasses may have a better implementation. + * The methods on this class use {@link ReadablePartial#size()}, + * {@link AbstractPartial#getField(int, Chronology)} and + * {@link ReadablePartial#getValue(int)} to calculate their results. + * Subclasses may have a better implementation. *

                * AbstractPartial allows subclasses may be mutable and not thread-safe. * * @author Stephen Colebourne * @since 1.0 */ -public abstract class AbstractPartial implements ReadablePartial { +public abstract class AbstractPartial + implements ReadablePartial, Comparable { //----------------------------------------------------------------------- /** @@ -213,8 +179,8 @@ * Gets the index of the specified field, throwing an exception if the * field is unsupported. * - * @param type the type to check, may be null which returns -1 - * @return the index of the field, -1 if unsupported + * @param type the type to check, not null + * @return the index of the field * @throws IllegalArgumentException if the field is null or not supported */ protected int indexOfSupported(DateTimeFieldType type) { @@ -225,30 +191,40 @@ return index; } - //----------------------------------------------------------------------- /** - * Converts this partial to a full datetime using the specified time zone and - * filing in any gaps using the current datetime. - *

                - * This method obtains the current datetime, creates a chronology from that - * on this instance plus the time zone specified, and then sets the fields - * from this instant on top. - *

                - * For example, if this partial represents a time, then the result of this - * method will be the datetime from the specified base instant plus the - * time from this partial. + * Gets the index of the first fields to have the specified duration, + * or -1 if the field is unsupported. * - * @param zone the zone to use, null means default - * @return the combined datetime + * @param type the type to check, may be null which returns -1 + * @return the index of the field, -1 if unsupported */ - public DateTime toDateTime(DateTimeZone zone) { - Chronology chrono = getChronology().withZone(zone); - long instantMillis = DateTimeUtils.currentTimeMillis(); - long resolved = chrono.set(this, instantMillis); - return new DateTime(resolved, chrono); + protected int indexOf(DurationFieldType type) { + for (int i = 0, isize = size(); i < isize; i++) { + if (getFieldType(i).getDurationType() == type) { + return i; + } + } + return -1; } /** + * Gets the index of the first fields to have the specified duration, + * throwing an exception if the field is unsupported. + * + * @param type the type to check, not null + * @return the index of the field + * @throws IllegalArgumentException if the field is null or not supported + */ + protected int indexOfSupported(DurationFieldType type) { + int index = indexOf(type); + if (index == -1) { + throw new IllegalArgumentException("Field '" + type + "' is not supported"); + } + return index; + } + + //----------------------------------------------------------------------- + /** * Resolves this partial against another complete instant to create a new * full instant. The combination is performed using the chronology of the * specified instant. @@ -291,7 +267,7 @@ return false; } } - return (getChronology() == other.getChronology()); + return FieldUtils.equals(getChronology(), other.getChronology()); } /** @@ -310,4 +286,130 @@ return total; } + //----------------------------------------------------------------------- + /** + * Compares this partial with another returning an integer + * indicating the order. + *

                + * The fields are compared in order, from largest to smallest. + * The first field that is non-equal is used to determine the result. + *

                + * The specified object must be a partial instance whose field types + * match those of this partial. + *

                + * NOTE: Prior to v2.0, the {@code Comparable} interface was only implemented + * in this class and not in the {@code ReadablePartial} interface. + * + * @param other an object to check against + * @return negative if this is less, zero if equal, positive if greater + * @throws ClassCastException if the partial is the wrong class + * or if it has field types that don't match + * @throws NullPointerException if the partial is null + * @since 1.1 + */ + public int compareTo(ReadablePartial other) { + if (this == other) { + return 0; + } + if (size() != other.size()) { + throw new ClassCastException("ReadablePartial objects must have matching field types"); + } + for (int i = 0, isize = size(); i < isize; i++) { + if (getFieldType(i) != other.getFieldType(i)) { + throw new ClassCastException("ReadablePartial objects must have matching field types"); + } + } + // fields are ordered largest first + for (int i = 0, isize = size(); i < isize; i++) { + if (getValue(i) > other.getValue(i)) { + return 1; + } + if (getValue(i) < other.getValue(i)) { + return -1; + } + } + return 0; + } + + /** + * Is this partial later than the specified partial. + *

                + * The fields are compared in order, from largest to smallest. + * The first field that is non-equal is used to determine the result. + *

                + * You may not pass null into this method. This is because you need + * a time zone to accurately determine the current date. + * + * @param partial a partial to check against, must not be null + * @return true if this date is after the date passed in + * @throws IllegalArgumentException if the specified partial is null + * @throws ClassCastException if the partial has field types that don't match + * @since 1.1 + */ + public boolean isAfter(ReadablePartial partial) { + if (partial == null) { + throw new IllegalArgumentException("Partial cannot be null"); + } + return compareTo(partial) > 0; + } + + /** + * Is this partial earlier than the specified partial. + *

                + * The fields are compared in order, from largest to smallest. + * The first field that is non-equal is used to determine the result. + *

                + * You may not pass null into this method. This is because you need + * a time zone to accurately determine the current date. + * + * @param partial a partial to check against, must not be null + * @return true if this date is before the date passed in + * @throws IllegalArgumentException if the specified partial is null + * @throws ClassCastException if the partial has field types that don't match + * @since 1.1 + */ + public boolean isBefore(ReadablePartial partial) { + if (partial == null) { + throw new IllegalArgumentException("Partial cannot be null"); + } + return compareTo(partial) < 0; + } + + /** + * Is this partial the same as the specified partial. + *

                + * The fields are compared in order, from largest to smallest. + * If all fields are equal, the result is true. + *

                + * You may not pass null into this method. This is because you need + * a time zone to accurately determine the current date. + * + * @param partial a partial to check against, must not be null + * @return true if this date is the same as the date passed in + * @throws IllegalArgumentException if the specified partial is null + * @throws ClassCastException if the partial has field types that don't match + * @since 1.1 + */ + public boolean isEqual(ReadablePartial partial) { + if (partial == null) { + throw new IllegalArgumentException("Partial cannot be null"); + } + return compareTo(partial) == 0; + } + + //----------------------------------------------------------------------- + /** + * Uses the specified formatter to convert this partial to a String. + * + * @param formatter the formatter to use, null means use toString(). + * @return the formatted string + * @since 1.1 + */ + public String toString(DateTimeFormatter formatter) { + if (formatter == null) { + return toString(); + } + return formatter.print(this); + } + } Index: 3rdParty_sources/joda-time/org/joda/time/base/AbstractPeriod.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/base/AbstractPeriod.java (.../AbstractPeriod.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/base/AbstractPeriod.java (.../AbstractPeriod.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,63 +1,27 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2010 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.base; +import org.joda.convert.ToString; import org.joda.time.DurationFieldType; import org.joda.time.MutablePeriod; import org.joda.time.Period; import org.joda.time.ReadablePeriod; import org.joda.time.format.ISOPeriodFormat; +import org.joda.time.format.PeriodFormatter; /** * AbstractPeriod provides the common behaviour for period classes. @@ -83,6 +47,28 @@ //----------------------------------------------------------------------- /** + * Gets the number of fields that this period supports. + * + * @return the number of fields supported + * @since 2.0 (previously on BasePeriod) + */ + public int size() { + return getPeriodType().size(); + } + + /** + * Gets the field type at the specified index. + * + * @param index the index to retrieve + * @return the field at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + * @since 2.0 (previously on BasePeriod) + */ + public DurationFieldType getFieldType(int index) { + return getPeriodType().getFieldType(index); + } + + /** * Gets an array of the field types that this period supports. *

                * The fields are returned largest to smallest, for example Hours, Minutes, Seconds. @@ -176,6 +162,18 @@ /** * Compares this object with the specified object for equality based * on the value of each field. All ReadablePeriod instances are accepted. + *

                + * Note that a period of 1 day is not equal to a period of 24 hours, + * nor is 1 hour equal to 60 minutes. Only periods with the same amount + * in each field are equal. + *

                + * This is because periods represent an abstracted definition of a time + * period (eg. a day may not actually be 24 hours, it might be 23 or 25 + * at daylight savings boundary). + *

                + * To compare the actual duration of two periods, convert both to + * {@link org.joda.time.Duration Duration}s, an operation that emphasises + * that the result may differ according to the date you choose. * * @param period a readable period to check against * @return true if all the field values are equal, false if @@ -225,8 +223,24 @@ * * @return the value as an ISO8601 string */ + @ToString public String toString() { - return ISOPeriodFormat.getInstance().standard().print(this); + return ISOPeriodFormat.standard().print(this); } + //----------------------------------------------------------------------- + /** + * Uses the specified formatter to convert this period to a String. + * + * @param formatter the formatter to use, null means use toString(). + * @return the formatted string + * @since 1.5 + */ + public String toString(PeriodFormatter formatter) { + if (formatter == null) { + return toString(); + } + return formatter.print(this); + } + } Index: 3rdParty_sources/joda-time/org/joda/time/base/BaseDateTime.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/base/BaseDateTime.java (.../BaseDateTime.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/base/BaseDateTime.java (.../BaseDateTime.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.base; @@ -86,9 +48,9 @@ private static final long serialVersionUID = -6728882245981L; /** The millis from 1970-01-01T00:00:00Z */ - private long iMillis; + private volatile long iMillis; /** The chronology to use */ - private Chronology iChronology; + private volatile Chronology iChronology; //----------------------------------------------------------------------- /** Index: 3rdParty_sources/joda-time/org/joda/time/base/BaseDuration.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/base/BaseDuration.java (.../BaseDuration.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/base/BaseDuration.java (.../BaseDuration.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.base; @@ -88,7 +50,7 @@ private static final long serialVersionUID = 2581698638990L; /** The duration length */ - private long iMillis; + private volatile long iMillis; /** * Creates a duration from the given millisecond duration. @@ -192,7 +154,8 @@ * However, ISO UTC also has precise days and weeks. *

                * For more control over the conversion process, you must pair the duration with - * an instant, see {@link #toPeriodFrom(ReadableInstant)}. + * an instant, see {@link #toPeriodFrom(ReadableInstant)} and + * {@link #toPeriodTo(ReadableInstant)} * * @param chrono the chronology to use, null means ISO default * @return a Period created using the millisecond duration from this instance @@ -211,7 +174,8 @@ * However, ISO UTC also has precise days and weeks. *

                * For more control over the conversion process, you must pair the duration with - * an instant, see {@link #toPeriodFrom(ReadableInstant, PeriodType)}. + * an instant, see {@link #toPeriodFrom(ReadableInstant, PeriodType)} and + * {@link #toPeriodTo(ReadableInstant, PeriodType)} * * @param type the period type to use, null means standard * @param chrono the chronology to use, null means ISO default @@ -253,13 +217,56 @@ } /** + * Converts this duration to a Period instance by subtracting the duration + * from an end instant to obtain an interval using the standard period + * type. + *

                + * This conversion will determine the fields of a period accurately. + * The results are based on the instant millis, the chronology of the instant, + * the standard period type and the length of this duration. + * + * @param endInstant the instant to calculate the period to, null means now + * @return a Period created using the millisecond duration from this instance + */ + public Period toPeriodTo(ReadableInstant endInstant) { + return new Period(this, endInstant); + } + + /** + * Converts this duration to a Period instance by subtracting the duration + * from an end instant to obtain an interval using the standard period + * type. + *

                + * This conversion will determine the fields of a period accurately. + * The results are based on the instant millis, the chronology of the instant, + * the period type and the length of this duration. + * + * @param endInstant the instant to calculate the period to, null means now + * @param type the period type determining how to split the duration into fields, null means All type + * @return a Period created using the millisecond duration from this instance + */ + public Period toPeriodTo(ReadableInstant endInstant, PeriodType type) { + return new Period(this, endInstant, type); + } + + /** * Converts this duration to an Interval starting at the specified instant. * - * @param startInstant the instant to start the instant from, null means now + * @param startInstant the instant to start the interval at, null means now * @return an Interval starting at the specified instant */ public Interval toIntervalFrom(ReadableInstant startInstant) { return new Interval(startInstant, this); } + /** + * Converts this duration to an Interval ending at the specified instant. + * + * @param endInstant the instant to end the interval at, null means now + * @return an Interval ending at the specified instant + */ + public Interval toIntervalTo(ReadableInstant endInstant) { + return new Interval(this, endInstant); + } + } Index: 3rdParty_sources/joda-time/org/joda/time/base/BaseInterval.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/base/BaseInterval.java (.../BaseInterval.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/base/BaseInterval.java (.../BaseInterval.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.base; @@ -63,6 +25,7 @@ import org.joda.time.ReadableInstant; import org.joda.time.ReadableInterval; import org.joda.time.ReadablePeriod; +import org.joda.time.chrono.ISOChronology; import org.joda.time.convert.ConverterManager; import org.joda.time.convert.IntervalConverter; import org.joda.time.field.FieldUtils; @@ -90,11 +53,11 @@ private static final long serialVersionUID = 576586928732749278L; /** The chronology of the interval */ - private Chronology iChronology; + private volatile Chronology iChronology; /** The start of the interval */ - private long iStartMillis; + private volatile long iStartMillis; /** The end of the interval */ - private long iEndMillis; + private volatile long iEndMillis; /** * Constructs an interval from a start and end instant. @@ -123,7 +86,7 @@ super(); if (start == null && end == null) { iStartMillis = iEndMillis = DateTimeUtils.currentTimeMillis(); - iChronology = Chronology.getISO(); + iChronology = ISOChronology.getInstance(); } else { iChronology = DateTimeUtils.getInstantChronology(start); iStartMillis = DateTimeUtils.getInstantMillis(start); Index: 3rdParty_sources/joda-time/org/joda/time/base/BaseLocal.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/base/BaseLocal.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/base/BaseLocal.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,62 @@ +/* + * Copyright 2001-2007 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.base; + +/** + * BaseLocal is an abstract implementation of ReadablePartial that + * use a local milliseconds internal representation. + *

                + * This class should generally not be used directly by API users. + * The {@link org.joda.time.ReadablePartial} interface should be used when different + * kinds of partial objects are to be referenced. + *

                + * BasePartial subclasses may be mutable and not thread-safe. + * + * @author Stephen Colebourne + * @since 1.5 + */ +public abstract class BaseLocal + extends AbstractPartial { + + /** Serialization version */ + private static final long serialVersionUID = 276453175381783L; + + //----------------------------------------------------------------------- + /** + * Constructs a partial with the current time, using ISOChronology in + * the default zone to extract the fields. + *

                + * The constructor uses the default time zone, resulting in the local time + * being initialised. Once the constructor is complete, all further calculations + * are performed without reference to a timezone (by switching to UTC). + */ + protected BaseLocal() { + super(); + } + + //----------------------------------------------------------------------- + /** + * Gets the local milliseconds from the Java epoch + * of 1970-01-01T00:00:00 (not fixed to any specific time zone). + *

                + * This method is useful in certain circustances for high performance + * access to the datetime fields. + * + * @return the number of milliseconds since 1970-01-01T00:00:00 + */ + protected abstract long getLocalMillis(); + +} Index: 3rdParty_sources/joda-time/org/joda/time/base/BasePartial.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/base/BasePartial.java (.../BasePartial.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/base/BasePartial.java (.../BasePartial.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,75 +1,38 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.base; import java.io.Serializable; +import java.util.Locale; import org.joda.time.Chronology; -import org.joda.time.DateTime; import org.joda.time.DateTimeField; import org.joda.time.DateTimeUtils; -import org.joda.time.DateTimeZone; import org.joda.time.ReadablePartial; import org.joda.time.convert.ConverterManager; import org.joda.time.convert.PartialConverter; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; /** * BasePartial is an abstract implementation of ReadablePartial that stores * data in array and Chronology fields. *

                * This class should generally not be used directly by API users. - * The {@link org.joda.time.ReadablePeriod} interface should be used when different + * The {@link org.joda.time.ReadablePartial} interface should be used when different * kinds of partial objects are to be referenced. *

                * BasePartial subclasses may be mutable and not thread-safe. @@ -85,9 +48,9 @@ private static final long serialVersionUID = 2353678632973660L; /** The chronology in use */ - private Chronology iChronology; + private final Chronology iChronology; /** The values of each field in this partial */ - private int[] iValues; + private final int[] iValues; //----------------------------------------------------------------------- /** @@ -174,6 +137,33 @@ } /** + * Constructs a partial from an Object that represents a time, using the + * specified chronology. + *

                + * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadableInstant, String, Calendar and Date. + *

                + * The constructor uses the time zone of the chronology specified. + * Once the constructor is complete, all further calculations are performed + * without reference to a timezone (by switching to UTC). + * + * @param instant the datetime object + * @param chronology the chronology, null means use converter + * @param parser if converting from a String, the given parser is preferred + * @throws IllegalArgumentException if the date is invalid + * @since 1.3 + */ + protected BasePartial(Object instant, Chronology chronology, DateTimeFormatter parser) { + super(); + PartialConverter converter = ConverterManager.getInstance().getPartialConverter(instant); + chronology = converter.getChronology(instant, chronology); + chronology = DateTimeUtils.getChronology(chronology); + iChronology = chronology.withUTC(); + iValues = converter.getPartialValues(this, instant, chronology, parser); + } + + /** * Constructs a partial with specified time field values and chronology. *

                * The constructor uses the time zone of the chronology specified. @@ -261,36 +251,62 @@ //----------------------------------------------------------------------- /** - * Sets the value of the field at the specifed index. + * Sets the value of the field at the specified index. + *

                + * In version 2.0 and later, this method copies the array into the original. + * This is because the instance variable has been changed to be final to satisfy the Java Memory Model. + * This only impacts subclasses that are mutable. * * @param index the index * @param value the value to set * @throws IndexOutOfBoundsException if the index is invalid */ protected void setValue(int index, int value) { DateTimeField field = getField(index); - iValues = field.set(this, index, iValues, value); + int[] values = field.set(this, index, iValues, value); + System.arraycopy(values, 0, iValues, 0, iValues.length); } /** * Sets the values of all fields. + *

                + * In version 2.0 and later, this method copies the array into the original. + * This is because the instance variable has been changed to be final to satisfy the Java Memory Model. + * This only impacts subclasses that are mutable. * * @param values the array of values */ protected void setValues(int[] values) { getChronology().validate(this, values); - iValues = values; + System.arraycopy(values, 0, iValues, 0, iValues.length); } //----------------------------------------------------------------------- /** - * Converts this object to a DateTime using the current date to fill in the - * missing fields and using the default time zone. + * Output the date using the specified format pattern. * - * @return the DateTime instance + * @param pattern the pattern specification, null means use toString + * @see org.joda.time.format.DateTimeFormat */ - public DateTime toDateTime() { - return toDateTime((DateTimeZone) null); + public String toString(String pattern) { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).print(this); } + /** + * Output the date using the specified format pattern. + * + * @param pattern the pattern specification, null means use toString + * @param locale Locale to use, null means default + * @see org.joda.time.format.DateTimeFormat + */ + public String toString(String pattern, Locale locale) throws IllegalArgumentException { + if (pattern == null) { + return toString(); + } + return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this); + } + } Index: 3rdParty_sources/joda-time/org/joda/time/base/BasePeriod.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/base/BasePeriod.java (.../BasePeriod.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/base/BasePeriod.java (.../BasePeriod.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.base; @@ -64,7 +26,9 @@ import org.joda.time.ReadWritablePeriod; import org.joda.time.ReadableDuration; import org.joda.time.ReadableInstant; +import org.joda.time.ReadablePartial; import org.joda.time.ReadablePeriod; +import org.joda.time.chrono.ISOChronology; import org.joda.time.convert.ConverterManager; import org.joda.time.convert.PeriodConverter; import org.joda.time.field.FieldUtils; @@ -89,11 +53,20 @@ /** Serialization version */ private static final long serialVersionUID = -2110953284060001145L; + /** Serialization version */ + private static final ReadablePeriod DUMMY_PERIOD = new AbstractPeriod() { + public int getValue(int index) { + return 0; + } + public PeriodType getPeriodType() { + return PeriodType.time(); + } + }; /** The type of period */ - private PeriodType iType; + private final PeriodType iType; /** The values */ - private int[] iValues; + private final int[] iValues; //----------------------------------------------------------------------- /** @@ -112,12 +85,12 @@ * @throws IllegalArgumentException if an unsupported field's value is non-zero */ protected BasePeriod(int years, int months, int weeks, int days, - int hours, int minutes, int seconds, int millis, - PeriodType type) { + int hours, int minutes, int seconds, int millis, + PeriodType type) { super(); type = checkPeriodType(type); iType = type; - setPeriodInternal(years, months, weeks, days, hours, minutes, seconds, millis); // internal method + iValues = setPeriodInternal(years, months, weeks, days, hours, minutes, seconds, millis); // internal method } /** @@ -155,9 +128,58 @@ long startMillis = DateTimeUtils.getInstantMillis(startInstant); long endMillis = DateTimeUtils.getInstantMillis(endInstant); Chronology chrono = DateTimeUtils.getIntervalChronology(startInstant, endInstant); + iType = type; + iValues = chrono.get(this, startMillis, endMillis); + } + } + + /** + * Creates a period from the given duration and end point. + *

                + * The two partials must contain the same fields, thus you can + * specify two LocalDate objects, or two LocalTime + * objects, but not one of each. + * As these are Partial objects, time zones have no effect on the result. + *

                + * The two partials must also both be contiguous - see + * {@link DateTimeUtils#isContiguous(ReadablePartial)} for a + * definition. Both LocalDate and LocalTime are contiguous. + * + * @param start the start of the period, must not be null + * @param end the end of the period, must not be null + * @param type which set of fields this period supports, null means standard + * @throws IllegalArgumentException if the partials are null or invalid + * @since 1.1 + */ + protected BasePeriod(ReadablePartial start, ReadablePartial end, PeriodType type) { + super(); + if (start == null || end == null) { + throw new IllegalArgumentException("ReadablePartial objects must not be null"); + } + if (start instanceof BaseLocal && end instanceof BaseLocal && start.getClass() == end.getClass()) { + // for performance + type = checkPeriodType(type); + long startMillis = ((BaseLocal) start).getLocalMillis(); + long endMillis = ((BaseLocal) end).getLocalMillis(); + Chronology chrono = start.getChronology(); chrono = DateTimeUtils.getChronology(chrono); iType = type; iValues = chrono.get(this, startMillis, endMillis); + } else { + if (start.size() != end.size()) { + throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields"); + } + for (int i = 0, isize = start.size(); i < isize; i++) { + if (start.getFieldType(i) != end.getFieldType(i)) { + throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields"); + } + } + if (DateTimeUtils.isContiguous(start) == false) { + throw new IllegalArgumentException("ReadablePartial objects must be contiguous"); + } + iType = checkPeriodType(type); + Chronology chrono = DateTimeUtils.getChronology(start.getChronology()).withUTC(); + iValues = chrono.get(this, chrono.set(start, 0L), chrono.set(end, 0L)); } } @@ -180,6 +202,43 @@ } /** + * Creates a period from the given duration and end point. + * + * @param duration the duration of the interval, null means zero-length + * @param endInstant the interval end, null means now + * @param type which set of fields this period supports, null means standard + */ + protected BasePeriod(ReadableDuration duration, ReadableInstant endInstant, PeriodType type) { + super(); + type = checkPeriodType(type); + long durationMillis = DateTimeUtils.getDurationMillis(duration); + long endMillis = DateTimeUtils.getInstantMillis(endInstant); + long startMillis = FieldUtils.safeSubtract(endMillis, durationMillis); + Chronology chrono = DateTimeUtils.getInstantChronology(endInstant); + iType = type; + iValues = chrono.get(this, startMillis, endMillis); + } + + /** + * Creates a period from the given millisecond duration with the standard period type + * and ISO rules, ensuring that the calculation is performed with the time-only period type. + *

                + * The calculation uses the hour, minute, second and millisecond fields. + * + * @param duration the duration, in milliseconds + */ + protected BasePeriod(long duration) { + super(); + // bug [3264409] + // calculation uses period type from a period object (bad design) + // thus we use a dummy period object with the time type + iType = PeriodType.standard(); + int[] values = ISOChronology.getInstanceUTC().get(DUMMY_PERIOD, duration); + iValues = new int[8]; + System.arraycopy(values, 0, iValues, 4, 4); + } + + /** * Creates a period from the given millisecond duration, which is only really * suitable for durations less than one day. *

                @@ -259,28 +318,7 @@ return iType; } - //----------------------------------------------------------------------- /** - * Gets the number of fields that this period supports. - * - * @return the number of fields supported - */ - public int size() { - return iType.size(); - } - - /** - * Gets the field type at the specified index. - * - * @param index the index to retrieve - * @return the field at the specified index - * @throws IndexOutOfBoundsException if the index is invalid - */ - public DurationFieldType getFieldType(int index) { - return iType.getFieldType(index); - } - - /** * Gets the value at the specified index. * * @param index the index to retrieve @@ -295,8 +333,14 @@ /** * Gets the total millisecond duration of this period relative to a start instant. *

                - * This method adds the period to the specifed instant. - * The difference between the start instant and the result of the add is the duration + * This method adds the period to the specified instant in order to + * calculate the duration. + *

                + * An instant must be supplied as the duration of a period varies. + * For example, a period of 1 month could vary between the equivalent of + * 28 and 31 days in milliseconds due to different length months. + * Similarly, a day can vary at Daylight Savings cutover, typically between + * 23 and 25 hours. * * @param startInstant the instant to add the period to, thus obtaining the duration * @return the total length of the period as a duration relative to the start instant @@ -309,10 +353,34 @@ return new Duration(startMillis, endMillis); } + /** + * Gets the total millisecond duration of this period relative to an + * end instant. + *

                + * This method subtracts the period from the specified instant in order + * to calculate the duration. + *

                + * An instant must be supplied as the duration of a period varies. + * For example, a period of 1 month could vary between the equivalent of + * 28 and 31 days in milliseconds due to different length months. + * Similarly, a day can vary at Daylight Savings cutover, typically between + * 23 and 25 hours. + * + * @param endInstant the instant to subtract the period from, thus obtaining the duration + * @return the total length of the period as a duration relative to the end instant + * @throws ArithmeticException if the millis exceeds the capacity of the duration + */ + public Duration toDurationTo(ReadableInstant endInstant) { + long endMillis = DateTimeUtils.getInstantMillis(endInstant); + Chronology chrono = DateTimeUtils.getInstantChronology(endInstant); + long startMillis = chrono.add(this, endMillis, -1); + return new Duration(startMillis, endMillis); + } + //----------------------------------------------------------------------- /** * Checks whether a field type is supported, and if so adds the new value - * to the relevent index in the specified array. + * to the relevant index in the specified array. * * @param type the field type * @param values the array to update @@ -355,7 +423,7 @@ int value = period.getValue(i); checkAndUpdate(type, newValues, value); } - iValues = newValues; + setValues(newValues); } /** @@ -373,13 +441,14 @@ */ protected void setPeriod(int years, int months, int weeks, int days, int hours, int minutes, int seconds, int millis) { - setPeriodInternal(years, months, weeks, days, hours, minutes, seconds, millis); + int[] newValues = setPeriodInternal(years, months, weeks, days, hours, minutes, seconds, millis); + setValues(newValues); } /** * Private method called from constructor. */ - private void setPeriodInternal(int years, int months, int weeks, int days, + private int[] setPeriodInternal(int years, int months, int weeks, int days, int hours, int minutes, int seconds, int millis) { int[] newValues = new int[size()]; checkAndUpdate(DurationFieldType.years(), newValues, years); @@ -390,7 +459,7 @@ checkAndUpdate(DurationFieldType.minutes(), newValues, minutes); checkAndUpdate(DurationFieldType.seconds(), newValues, seconds); checkAndUpdate(DurationFieldType.millis(), newValues, millis); - iValues = newValues; + return newValues; } //----------------------------------------------------------------------- @@ -464,7 +533,7 @@ */ protected void mergePeriod(ReadablePeriod period) { if (period != null) { - iValues = mergePeriodInto(getValues(), period); + setValues(mergePeriodInto(getValues(), period)); } } @@ -477,12 +546,12 @@ * @throws IllegalArgumentException if an unsupported field's value is non-zero */ protected int[] mergePeriodInto(int[] values, ReadablePeriod period) { - for (int i = 0, isize = period.size(); i < isize; i++) { - DurationFieldType type = period.getFieldType(i); - int value = period.getValue(i); - checkAndUpdate(type, values, value); - } - return values; + for (int i = 0, isize = period.size(); i < isize; i++) { + DurationFieldType type = period.getFieldType(i); + int value = period.getValue(i); + checkAndUpdate(type, values, value); + } + return values; } /** @@ -493,7 +562,7 @@ */ protected void addPeriod(ReadablePeriod period) { if (period != null) { - iValues = addPeriodInto(getValues(), period); + setValues(addPeriodInto(getValues(), period)); } } @@ -506,25 +575,25 @@ * @throws IllegalArgumentException if an unsupported field's value is non-zero */ protected int[] addPeriodInto(int[] values, ReadablePeriod period) { - for (int i = 0, isize = period.size(); i < isize; i++) { - DurationFieldType type = period.getFieldType(i); - int value = period.getValue(i); - if (value != 0) { - int index = indexOf(type); - if (index == -1) { - throw new IllegalArgumentException( - "Period does not support field '" + type.getName() + "'"); - } else { - values[index] = FieldUtils.safeAdd(getValue(index), value); - } - } - } - return values; + for (int i = 0, isize = period.size(); i < isize; i++) { + DurationFieldType type = period.getFieldType(i); + int value = period.getValue(i); + if (value != 0) { + int index = indexOf(type); + if (index == -1) { + throw new IllegalArgumentException( + "Period does not support field '" + type.getName() + "'"); + } else { + values[index] = FieldUtils.safeAdd(getValue(index), value); + } + } + } + return values; } //----------------------------------------------------------------------- /** - * Sets the value of the field at the specifed index. + * Sets the value of the field at the specified index. * * @param index the index * @param value the value to set @@ -536,11 +605,15 @@ /** * Sets the values of all fields. + *

                + * In version 2.0 and later, this method copies the array into the original. + * This is because the instance variable has been changed to be final to satisfy the Java Memory Model. + * This only impacts subclasses that are mutable. * * @param values the array of values */ protected void setValues(int[] values) { - iValues = values; + System.arraycopy(values, 0, iValues, 0, iValues.length); } } Index: 3rdParty_sources/joda-time/org/joda/time/base/BaseSingleFieldPeriod.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/base/BaseSingleFieldPeriod.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/base/BaseSingleFieldPeriod.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,344 @@ +/* + * Copyright 2001-2011 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.base; + +import java.io.Serializable; + +import org.joda.time.Chronology; +import org.joda.time.DateTimeUtils; +import org.joda.time.DurationField; +import org.joda.time.DurationFieldType; +import org.joda.time.MutablePeriod; +import org.joda.time.Period; +import org.joda.time.PeriodType; +import org.joda.time.ReadableInstant; +import org.joda.time.ReadablePartial; +import org.joda.time.ReadablePeriod; +import org.joda.time.chrono.ISOChronology; +import org.joda.time.field.FieldUtils; + +/** + * BaseSingleFieldPeriod is an abstract implementation of ReadablePeriod that + * manages a single duration field, such as days or minutes. + *

                + * This class should generally not be used directly by API users. + * The {@link ReadablePeriod} interface should be used when different + * kinds of period objects are to be referenced. + *

                + * BaseSingleFieldPeriod subclasses may be mutable and not thread-safe. + * + * @author Stephen Colebourne + * @since 1.4 + */ +public abstract class BaseSingleFieldPeriod + implements ReadablePeriod, Comparable, Serializable { + + /** Serialization version. */ + private static final long serialVersionUID = 9386874258972L; + + /** The period in the units of this period. */ + private volatile int iPeriod; + + //----------------------------------------------------------------------- + /** + * Calculates the number of whole units between the two specified datetimes. + * + * @param start the start instant, validated to not be null + * @param end the end instant, validated to not be null + * @param field the field type to use, must not be null + * @return the period + * @throws IllegalArgumentException if the instants are null or invalid + */ + protected static int between(ReadableInstant start, ReadableInstant end, DurationFieldType field) { + if (start == null || end == null) { + throw new IllegalArgumentException("ReadableInstant objects must not be null"); + } + Chronology chrono = DateTimeUtils.getInstantChronology(start); + int amount = field.getField(chrono).getDifference(end.getMillis(), start.getMillis()); + return amount; + } + + //----------------------------------------------------------------------- + /** + * Calculates the number of whole units between the two specified partial datetimes. + *

                + * The two partials must contain the same fields, for example you can specify + * two LocalDate objects. + * + * @param start the start partial date, validated to not be null + * @param end the end partial date, validated to not be null + * @param zeroInstance the zero instance constant, must not be null + * @return the period + * @throws IllegalArgumentException if the partials are null or invalid + */ + protected static int between(ReadablePartial start, ReadablePartial end, ReadablePeriod zeroInstance) { + if (start == null || end == null) { + throw new IllegalArgumentException("ReadablePartial objects must not be null"); + } + if (start.size() != end.size()) { + throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields"); + } + for (int i = 0, isize = start.size(); i < isize; i++) { + if (start.getFieldType(i) != end.getFieldType(i)) { + throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields"); + } + } + if (DateTimeUtils.isContiguous(start) == false) { + throw new IllegalArgumentException("ReadablePartial objects must be contiguous"); + } + Chronology chrono = DateTimeUtils.getChronology(start.getChronology()).withUTC(); + int[] values = chrono.get(zeroInstance, chrono.set(start, 0L), chrono.set(end, 0L)); + return values[0]; + } + + /** + * Creates a new instance representing the number of complete standard length units + * in the specified period. + *

                + * This factory method converts all fields from the period to hours using standardised + * durations for each field. Only those fields which have a precise duration in + * the ISO UTC chronology can be converted. + *

                  + *
                • One week consists of 7 days. + *
                • One day consists of 24 hours. + *
                • One hour consists of 60 minutes. + *
                • One minute consists of 60 seconds. + *
                • One second consists of 1000 milliseconds. + *
                + * Months and Years are imprecise and periods containing these values cannot be converted. + * + * @param period the period to get the number of hours from, must not be null + * @param millisPerUnit the number of milliseconds in one standard unit of this period + * @throws IllegalArgumentException if the period contains imprecise duration values + */ + protected static int standardPeriodIn(ReadablePeriod period, long millisPerUnit) { + if (period == null) { + return 0; + } + Chronology iso = ISOChronology.getInstanceUTC(); + long duration = 0L; + for (int i = 0; i < period.size(); i++) { + int value = period.getValue(i); + if (value != 0) { + DurationField field = period.getFieldType(i).getField(iso); + if (field.isPrecise() == false) { + throw new IllegalArgumentException( + "Cannot convert period to duration as " + field.getName() + + " is not precise in the period " + period); + } + duration = FieldUtils.safeAdd(duration, FieldUtils.safeMultiply(field.getUnitMillis(), value)); + } + } + return FieldUtils.safeToInt(duration / millisPerUnit); + } + + //----------------------------------------------------------------------- + /** + * Creates a new instance representing the specified period. + * + * @param period the period to represent + */ + protected BaseSingleFieldPeriod(int period) { + super(); + iPeriod = period; + } + + //----------------------------------------------------------------------- + /** + * Gets the amount of this period. + * + * @return the period value + */ + protected int getValue() { + return iPeriod; + } + + /** + * Sets the amount of this period. + * To make a subclass immutable you must declare it final, or block this method. + * + * @param value the period value + */ + protected void setValue(int value) { + iPeriod = value; + } + + //----------------------------------------------------------------------- + /** + * Gets the single duration field type. + * + * @return the duration field type, not null + */ + public abstract DurationFieldType getFieldType(); + + /** + * Gets the period type which matches the duration field type. + * + * @return the period type, not null + */ + public abstract PeriodType getPeriodType(); + + //----------------------------------------------------------------------- + /** + * Gets the number of fields that this period supports, which is one. + * + * @return the number of fields supported, which is one + */ + public int size() { + return 1; + } + + /** + * Gets the field type at the specified index. + *

                + * The only index supported by this period is zero which returns the + * field type of this class. + * + * @param index the index to retrieve, which must be zero + * @return the field at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + */ + public DurationFieldType getFieldType(int index) { + if (index != 0) { + throw new IndexOutOfBoundsException(String.valueOf(index)); + } + return getFieldType(); + } + + /** + * Gets the value at the specified index. + *

                + * The only index supported by this period is zero. + * + * @param index the index to retrieve, which must be zero + * @return the value of the field at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + */ + public int getValue(int index) { + if (index != 0) { + throw new IndexOutOfBoundsException(String.valueOf(index)); + } + return getValue(); + } + + /** + * Gets the value of a duration field represented by this period. + *

                + * If the field type specified does not match the type used by this class + * then zero is returned. + * + * @param type the field type to query, null returns zero + * @return the value of that field, zero if field not supported + */ + public int get(DurationFieldType type) { + if (type == getFieldType()) { + return getValue(); + } + return 0; + } + + /** + * Checks whether the duration field specified is supported by this period. + * + * @param type the type to check, may be null which returns false + * @return true if the field is supported + */ + public boolean isSupported(DurationFieldType type) { + return (type == getFieldType()); + } + + //----------------------------------------------------------------------- + /** + * Get this period as an immutable Period object. + * The period will use PeriodType.standard(). + * + * @return a Period representing the same number of days + */ + public Period toPeriod() { + return Period.ZERO.withFields(this); + } + + /** + * Get this object as a MutablePeriod. + *

                + * This will always return a new MutablePeriod with the same fields. + * The period will use PeriodType.standard(). + * + * @return a MutablePeriod using the same field set and values + */ + public MutablePeriod toMutablePeriod() { + MutablePeriod period = new MutablePeriod(); + period.add(this); + return period; + } + + //----------------------------------------------------------------------- + /** + * Compares this object with the specified object for equality based on the + * value of each field. All ReadablePeriod instances are accepted, but only + * those with a matching PeriodType can return true. + * + * @param period a readable period to check against + * @return true if all the field values are equal, false if + * not or the period is null or of an incorrect type + */ + public boolean equals(Object period) { + if (this == period) { + return true; + } + if (period instanceof ReadablePeriod == false) { + return false; + } + ReadablePeriod other = (ReadablePeriod) period; + return (other.getPeriodType() == getPeriodType() && other.getValue(0) == getValue()); + } + + /** + * Gets a hash code for the period as defined by ReadablePeriod. + * + * @return a hash code + */ + public int hashCode() { + int total = 17; + total = 27 * total + getValue(); + total = 27 * total + getFieldType().hashCode(); + return total; + } + + /** + * Compares this period to another object of the same class. + * + * @param other the other period, must not be null + * @return zero if equal, positive if greater, negative if less + * @throws NullPointerException if the other period is null + * @throws ClassCastException if the other period is of a different type + */ + public int compareTo(BaseSingleFieldPeriod other) { + if (other.getClass() != getClass()) { + throw new ClassCastException(getClass() + " cannot be compared to " + other.getClass()); + } + int otherValue = other.getValue(); + int thisValue = getValue(); + if (thisValue > otherValue) { + return 1; + } + if (thisValue < otherValue) { + return -1; + } + return 0; + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/base/package.html =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/base/package.html (.../package.html) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/base/package.html (.../package.html) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -4,57 +4,19 @@ org.joda.time.chrono package Index: 3rdParty_sources/joda-time/org/joda/time/chrono/AssembledChronology.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/AssembledChronology.java (.../AssembledChronology.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/AssembledChronology.java (.../AssembledChronology.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; Index: 3rdParty_sources/joda-time/org/joda/time/chrono/BaseChronology.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/BaseChronology.java (.../BaseChronology.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/BaseChronology.java (.../BaseChronology.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -61,17 +23,18 @@ import org.joda.time.DateTimeZone; import org.joda.time.DurationField; import org.joda.time.DurationFieldType; +import org.joda.time.IllegalFieldValueException; import org.joda.time.ReadablePartial; import org.joda.time.ReadablePeriod; import org.joda.time.field.FieldUtils; import org.joda.time.field.UnsupportedDateTimeField; import org.joda.time.field.UnsupportedDurationField; /** - * AbstractChronology provides a skeleton implementation for chronology + * BaseChronology provides a skeleton implementation for chronology * classes. Many utility methods are defined, but all fields are unsupported. *

                - * AbstractChronology is thread-safe and immutable, and all subclasses must be + * BaseChronology is thread-safe and immutable, and all subclasses must be * as well. * * @author Brian S O'Neill @@ -222,25 +185,29 @@ int value = values[i]; DateTimeField field = partial.getField(i); if (value < field.getMinimumValue()) { - throw new IllegalArgumentException("Value " + value + - " for " + field.getName() + " is less than minimum"); + throw new IllegalFieldValueException + (field.getType(), Integer.valueOf(value), + Integer.valueOf(field.getMinimumValue()), null); } if (value > field.getMaximumValue()) { - throw new IllegalArgumentException("Value " + value + - " for " + field.getName() + " is greater than maximum"); + throw new IllegalFieldValueException + (field.getType(), Integer.valueOf(value), + null, Integer.valueOf(field.getMaximumValue())); } } // check values in specific range, catching really odd cases like 30th Feb for (int i = 0; i < size; i++) { int value = values[i]; DateTimeField field = partial.getField(i); if (value < field.getMinimumValue(partial, values)) { - throw new IllegalArgumentException("Value " + value + - " for " + field.getName() + " is less than minimum"); + throw new IllegalFieldValueException + (field.getType(), Integer.valueOf(value), + Integer.valueOf(field.getMinimumValue(partial, values)), null); } if (value > field.getMaximumValue(partial, values)) { - throw new IllegalArgumentException("Value " + value + - " for " + field.getName() + " is greater than maximum"); + throw new IllegalFieldValueException + (field.getType(), Integer.valueOf(value), + null, Integer.valueOf(field.getMaximumValue(partial, values))); } } } Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/chrono/BaseGJChronology.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/joda-time/org/joda/time/chrono/BasicChronology.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/chrono/BasicChronology.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/BasicChronology.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,776 @@ +/* + * Copyright 2001-2005 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.chrono; + +import java.util.Locale; + +import org.joda.time.Chronology; +import org.joda.time.DateTimeConstants; +import org.joda.time.DateTimeField; +import org.joda.time.DateTimeFieldType; +import org.joda.time.DateTimeZone; +import org.joda.time.DurationField; +import org.joda.time.DurationFieldType; +import org.joda.time.field.DividedDateTimeField; +import org.joda.time.field.FieldUtils; +import org.joda.time.field.MillisDurationField; +import org.joda.time.field.OffsetDateTimeField; +import org.joda.time.field.PreciseDateTimeField; +import org.joda.time.field.PreciseDurationField; +import org.joda.time.field.RemainderDateTimeField; +import org.joda.time.field.ZeroIsMaxDateTimeField; + +/** + * Abstract implementation for calendar systems that use a typical + * day/month/year/leapYear model. + * Most of the utility methods required by subclasses are package-private, + * reflecting the intention that they be defined in the same package. + *

                + * BasicChronology is thread-safe and immutable, and all subclasses must + * be as well. + * + * @author Stephen Colebourne + * @author Brian S O'Neill + * @author Guy Allard + * @since 1.2, renamed from BaseGJChronology + */ +abstract class BasicChronology extends AssembledChronology { + + /** Serialization lock */ + private static final long serialVersionUID = 8283225332206808863L; + + private static final DurationField cMillisField; + private static final DurationField cSecondsField; + private static final DurationField cMinutesField; + private static final DurationField cHoursField; + private static final DurationField cHalfdaysField; + private static final DurationField cDaysField; + private static final DurationField cWeeksField; + + private static final DateTimeField cMillisOfSecondField; + private static final DateTimeField cMillisOfDayField; + private static final DateTimeField cSecondOfMinuteField; + private static final DateTimeField cSecondOfDayField; + private static final DateTimeField cMinuteOfHourField; + private static final DateTimeField cMinuteOfDayField; + private static final DateTimeField cHourOfDayField; + private static final DateTimeField cHourOfHalfdayField; + private static final DateTimeField cClockhourOfDayField; + private static final DateTimeField cClockhourOfHalfdayField; + private static final DateTimeField cHalfdayOfDayField; + + static { + cMillisField = MillisDurationField.INSTANCE; + cSecondsField = new PreciseDurationField + (DurationFieldType.seconds(), DateTimeConstants.MILLIS_PER_SECOND); + cMinutesField = new PreciseDurationField + (DurationFieldType.minutes(), DateTimeConstants.MILLIS_PER_MINUTE); + cHoursField = new PreciseDurationField + (DurationFieldType.hours(), DateTimeConstants.MILLIS_PER_HOUR); + cHalfdaysField = new PreciseDurationField + (DurationFieldType.halfdays(), DateTimeConstants.MILLIS_PER_DAY / 2); + cDaysField = new PreciseDurationField + (DurationFieldType.days(), DateTimeConstants.MILLIS_PER_DAY); + cWeeksField = new PreciseDurationField + (DurationFieldType.weeks(), DateTimeConstants.MILLIS_PER_WEEK); + + cMillisOfSecondField = new PreciseDateTimeField + (DateTimeFieldType.millisOfSecond(), cMillisField, cSecondsField); + + cMillisOfDayField = new PreciseDateTimeField + (DateTimeFieldType.millisOfDay(), cMillisField, cDaysField); + + cSecondOfMinuteField = new PreciseDateTimeField + (DateTimeFieldType.secondOfMinute(), cSecondsField, cMinutesField); + + cSecondOfDayField = new PreciseDateTimeField + (DateTimeFieldType.secondOfDay(), cSecondsField, cDaysField); + + cMinuteOfHourField = new PreciseDateTimeField + (DateTimeFieldType.minuteOfHour(), cMinutesField, cHoursField); + + cMinuteOfDayField = new PreciseDateTimeField + (DateTimeFieldType.minuteOfDay(), cMinutesField, cDaysField); + + cHourOfDayField = new PreciseDateTimeField + (DateTimeFieldType.hourOfDay(), cHoursField, cDaysField); + + cHourOfHalfdayField = new PreciseDateTimeField + (DateTimeFieldType.hourOfHalfday(), cHoursField, cHalfdaysField); + + cClockhourOfDayField = new ZeroIsMaxDateTimeField + (cHourOfDayField, DateTimeFieldType.clockhourOfDay()); + + cClockhourOfHalfdayField = new ZeroIsMaxDateTimeField + (cHourOfHalfdayField, DateTimeFieldType.clockhourOfHalfday()); + + cHalfdayOfDayField = new HalfdayField(); + } + + private static final int CACHE_SIZE = 1 << 10; + private static final int CACHE_MASK = CACHE_SIZE - 1; + + private transient final YearInfo[] iYearInfoCache = new YearInfo[CACHE_SIZE]; + + private final int iMinDaysInFirstWeek; + + BasicChronology(Chronology base, Object param, int minDaysInFirstWeek) { + super(base, param); + + if (minDaysInFirstWeek < 1 || minDaysInFirstWeek > 7) { + throw new IllegalArgumentException + ("Invalid min days in first week: " + minDaysInFirstWeek); + } + + iMinDaysInFirstWeek = minDaysInFirstWeek; + } + + public DateTimeZone getZone() { + Chronology base; + if ((base = getBase()) != null) { + return base.getZone(); + } + return DateTimeZone.UTC; + } + + public long getDateTimeMillis( + int year, int monthOfYear, int dayOfMonth, int millisOfDay) + throws IllegalArgumentException { + Chronology base; + if ((base = getBase()) != null) { + return base.getDateTimeMillis(year, monthOfYear, dayOfMonth, millisOfDay); + } + + FieldUtils.verifyValueBounds + (DateTimeFieldType.millisOfDay(), millisOfDay, 0, DateTimeConstants.MILLIS_PER_DAY - 1); + return getDateMidnightMillis(year, monthOfYear, dayOfMonth) + millisOfDay; + } + + public long getDateTimeMillis( + int year, int monthOfYear, int dayOfMonth, + int hourOfDay, int minuteOfHour, int secondOfMinute, int millisOfSecond) + throws IllegalArgumentException { + Chronology base; + if ((base = getBase()) != null) { + return base.getDateTimeMillis(year, monthOfYear, dayOfMonth, + hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond); + } + + FieldUtils.verifyValueBounds(DateTimeFieldType.hourOfDay(), hourOfDay, 0, 23); + FieldUtils.verifyValueBounds(DateTimeFieldType.minuteOfHour(), minuteOfHour, 0, 59); + FieldUtils.verifyValueBounds(DateTimeFieldType.secondOfMinute(), secondOfMinute, 0, 59); + FieldUtils.verifyValueBounds(DateTimeFieldType.millisOfSecond(), millisOfSecond, 0, 999); + + return getDateMidnightMillis(year, monthOfYear, dayOfMonth) + + hourOfDay * DateTimeConstants.MILLIS_PER_HOUR + + minuteOfHour * DateTimeConstants.MILLIS_PER_MINUTE + + secondOfMinute * DateTimeConstants.MILLIS_PER_SECOND + + millisOfSecond; + } + + public int getMinimumDaysInFirstWeek() { + return iMinDaysInFirstWeek; + } + + /** + * Checks if this chronology instance equals another. + * + * @param obj the object to compare to + * @return true if equal + * @since 1.6 + */ + public boolean equals(Object obj) { + return super.equals(obj); + } + + /** + * A suitable hash code for the chronology. + * + * @return the hash code + * @since 1.6 + */ + public int hashCode() { + return getClass().getName().hashCode() * 11 + getZone().hashCode() + getMinimumDaysInFirstWeek(); + } + + // Output + //----------------------------------------------------------------------- + /** + * Gets a debugging toString. + * + * @return a debugging string + */ + public String toString() { + StringBuffer sb = new StringBuffer(60); + String name = getClass().getName(); + int index = name.lastIndexOf('.'); + if (index >= 0) { + name = name.substring(index + 1); + } + sb.append(name); + sb.append('['); + DateTimeZone zone = getZone(); + if (zone != null) { + sb.append(zone.getID()); + } + if (getMinimumDaysInFirstWeek() != 4) { + sb.append(",mdfw="); + sb.append(getMinimumDaysInFirstWeek()); + } + sb.append(']'); + return sb.toString(); + } + + protected void assemble(Fields fields) { + // First copy fields that are the same for all Gregorian and Julian + // chronologies. + + fields.millis = cMillisField; + fields.seconds = cSecondsField; + fields.minutes = cMinutesField; + fields.hours = cHoursField; + fields.halfdays = cHalfdaysField; + fields.days = cDaysField; + fields.weeks = cWeeksField; + + fields.millisOfSecond = cMillisOfSecondField; + fields.millisOfDay = cMillisOfDayField; + fields.secondOfMinute = cSecondOfMinuteField; + fields.secondOfDay = cSecondOfDayField; + fields.minuteOfHour = cMinuteOfHourField; + fields.minuteOfDay = cMinuteOfDayField; + fields.hourOfDay = cHourOfDayField; + fields.hourOfHalfday = cHourOfHalfdayField; + fields.clockhourOfDay = cClockhourOfDayField; + fields.clockhourOfHalfday = cClockhourOfHalfdayField; + fields.halfdayOfDay = cHalfdayOfDayField; + + // Now create fields that have unique behavior for Gregorian and Julian + // chronologies. + + fields.year = new BasicYearDateTimeField(this); + fields.yearOfEra = new GJYearOfEraDateTimeField(fields.year, this); + + // Define one-based centuryOfEra and yearOfCentury. + DateTimeField field = new OffsetDateTimeField( + fields.yearOfEra, 99); + fields.centuryOfEra = new DividedDateTimeField( + field, DateTimeFieldType.centuryOfEra(), 100); + + field = new RemainderDateTimeField( + (DividedDateTimeField) fields.centuryOfEra); + fields.yearOfCentury = new OffsetDateTimeField( + field, DateTimeFieldType.yearOfCentury(), 1); + + fields.era = new GJEraDateTimeField(this); + fields.dayOfWeek = new GJDayOfWeekDateTimeField(this, fields.days); + fields.dayOfMonth = new BasicDayOfMonthDateTimeField(this, fields.days); + fields.dayOfYear = new BasicDayOfYearDateTimeField(this, fields.days); + fields.monthOfYear = new GJMonthOfYearDateTimeField(this); + fields.weekyear = new BasicWeekyearDateTimeField(this); + fields.weekOfWeekyear = new BasicWeekOfWeekyearDateTimeField(this, fields.weeks); + + field = new RemainderDateTimeField( + fields.weekyear, DateTimeFieldType.weekyearOfCentury(), 100); + fields.weekyearOfCentury = new OffsetDateTimeField( + field, DateTimeFieldType.weekyearOfCentury(), 1); + + // The remaining (imprecise) durations are available from the newly + // created datetime fields. + + fields.years = fields.year.getDurationField(); + fields.centuries = fields.centuryOfEra.getDurationField(); + fields.months = fields.monthOfYear.getDurationField(); + fields.weekyears = fields.weekyear.getDurationField(); + } + + //----------------------------------------------------------------------- + /** + * Get the number of days in the year. + * + * @return 366 + */ + int getDaysInYearMax() { + return 366; + } + + /** + * Get the number of days in the year. + * + * @param year the year to use + * @return 366 if a leap year, otherwise 365 + */ + int getDaysInYear(int year) { + return isLeapYear(year) ? 366 : 365; + } + + /** + * Get the number of weeks in the year. + * + * @param year the year to use + * @return number of weeks in the year + */ + int getWeeksInYear(int year) { + long firstWeekMillis1 = getFirstWeekOfYearMillis(year); + long firstWeekMillis2 = getFirstWeekOfYearMillis(year + 1); + return (int) ((firstWeekMillis2 - firstWeekMillis1) / DateTimeConstants.MILLIS_PER_WEEK); + } + + /** + * Get the millis for the first week of a year. + * + * @param year the year to use + * @return millis + */ + long getFirstWeekOfYearMillis(int year) { + long jan1millis = getYearMillis(year); + int jan1dayOfWeek = getDayOfWeek(jan1millis); + + if (jan1dayOfWeek > (8 - iMinDaysInFirstWeek)) { + // First week is end of previous year because it doesn't have enough days. + return jan1millis + (8 - jan1dayOfWeek) + * (long)DateTimeConstants.MILLIS_PER_DAY; + } else { + // First week is start of this year because it has enough days. + return jan1millis - (jan1dayOfWeek - 1) + * (long)DateTimeConstants.MILLIS_PER_DAY; + } + } + + /** + * Get the milliseconds for the start of a year. + * + * @param year The year to use. + * @return millis from 1970-01-01T00:00:00Z + */ + long getYearMillis(int year) { + return getYearInfo(year).iFirstDayMillis; + } + + /** + * Get the milliseconds for the start of a month. + * + * @param year The year to use. + * @param month The month to use + * @return millis from 1970-01-01T00:00:00Z + */ + long getYearMonthMillis(int year, int month) { + long millis = getYearMillis(year); + millis += getTotalMillisByYearMonth(year, month); + return millis; + } + + /** + * Get the milliseconds for a particular date. + * + * @param year The year to use. + * @param month The month to use + * @param dayOfMonth The day of the month to use + * @return millis from 1970-01-01T00:00:00Z + */ + long getYearMonthDayMillis(int year, int month, int dayOfMonth) { + long millis = getYearMillis(year); + millis += getTotalMillisByYearMonth(year, month); + return millis + (dayOfMonth - 1) * (long)DateTimeConstants.MILLIS_PER_DAY; + } + + /** + * @param instant millis from 1970-01-01T00:00:00Z + */ + int getYear(long instant) { + // Get an initial estimate of the year, and the millis value that + // represents the start of that year. Then verify estimate and fix if + // necessary. + + // Initial estimate uses values divided by two to avoid overflow. + long unitMillis = getAverageMillisPerYearDividedByTwo(); + long i2 = (instant >> 1) + getApproxMillisAtEpochDividedByTwo(); + if (i2 < 0) { + i2 = i2 - unitMillis + 1; + } + int year = (int) (i2 / unitMillis); + + long yearStart = getYearMillis(year); + long diff = instant - yearStart; + + if (diff < 0) { + year--; + } else if (diff >= DateTimeConstants.MILLIS_PER_DAY * 365L) { + // One year may need to be added to fix estimate. + long oneYear; + if (isLeapYear(year)) { + oneYear = DateTimeConstants.MILLIS_PER_DAY * 366L; + } else { + oneYear = DateTimeConstants.MILLIS_PER_DAY * 365L; + } + + yearStart += oneYear; + + if (yearStart <= instant) { + // Didn't go too far, so actually add one year. + year++; + } + } + + return year; + } + + /** + * @param millis from 1970-01-01T00:00:00Z + */ + int getMonthOfYear(long millis) { + return getMonthOfYear(millis, getYear(millis)); + } + + /** + * @param millis from 1970-01-01T00:00:00Z + * @param year precalculated year of millis + */ + abstract int getMonthOfYear(long millis, int year); + + /** + * @param millis from 1970-01-01T00:00:00Z + */ + int getDayOfMonth(long millis) { + int year = getYear(millis); + int month = getMonthOfYear(millis, year); + return getDayOfMonth(millis, year, month); + } + + /** + * @param millis from 1970-01-01T00:00:00Z + * @param year precalculated year of millis + */ + int getDayOfMonth(long millis, int year) { + int month = getMonthOfYear(millis, year); + return getDayOfMonth(millis, year, month); + } + + /** + * @param millis from 1970-01-01T00:00:00Z + * @param year precalculated year of millis + * @param month precalculated month of millis + */ + int getDayOfMonth(long millis, int year, int month) { + long dateMillis = getYearMillis(year); + dateMillis += getTotalMillisByYearMonth(year, month); + return (int) ((millis - dateMillis) / DateTimeConstants.MILLIS_PER_DAY) + 1; + } + + /** + * @param instant millis from 1970-01-01T00:00:00Z + */ + int getDayOfYear(long instant) { + return getDayOfYear(instant, getYear(instant)); + } + + /** + * @param instant millis from 1970-01-01T00:00:00Z + * @param year precalculated year of millis + */ + int getDayOfYear(long instant, int year) { + long yearStart = getYearMillis(year); + return (int) ((instant - yearStart) / DateTimeConstants.MILLIS_PER_DAY) + 1; + } + + /** + * @param instant millis from 1970-01-01T00:00:00Z + */ + int getWeekyear(long instant) { + int year = getYear(instant); + int week = getWeekOfWeekyear(instant, year); + if (week == 1) { + return getYear(instant + DateTimeConstants.MILLIS_PER_WEEK); + } else if (week > 51) { + return getYear(instant - (2 * DateTimeConstants.MILLIS_PER_WEEK)); + } else { + return year; + } + } + + /** + * @param instant millis from 1970-01-01T00:00:00Z + */ + int getWeekOfWeekyear(long instant) { + return getWeekOfWeekyear(instant, getYear(instant)); + } + + /** + * @param instant millis from 1970-01-01T00:00:00Z + * @param year precalculated year of millis + */ + int getWeekOfWeekyear(long instant, int year) { + long firstWeekMillis1 = getFirstWeekOfYearMillis(year); + if (instant < firstWeekMillis1) { + return getWeeksInYear(year - 1); + } + long firstWeekMillis2 = getFirstWeekOfYearMillis(year + 1); + if (instant >= firstWeekMillis2) { + return 1; + } + return (int) ((instant - firstWeekMillis1) / DateTimeConstants.MILLIS_PER_WEEK) + 1; + } + + /** + * @param instant millis from 1970-01-01T00:00:00Z + */ + int getDayOfWeek(long instant) { + // 1970-01-01 is day of week 4, Thursday. + + long daysSince19700101; + if (instant >= 0) { + daysSince19700101 = instant / DateTimeConstants.MILLIS_PER_DAY; + } else { + daysSince19700101 = (instant - (DateTimeConstants.MILLIS_PER_DAY - 1)) + / DateTimeConstants.MILLIS_PER_DAY; + if (daysSince19700101 < -3) { + return 7 + (int) ((daysSince19700101 + 4) % 7); + } + } + + return 1 + (int) ((daysSince19700101 + 3) % 7); + } + + /** + * @param instant millis from 1970-01-01T00:00:00Z + */ + int getMillisOfDay(long instant) { + if (instant >= 0) { + return (int) (instant % DateTimeConstants.MILLIS_PER_DAY); + } else { + return (DateTimeConstants.MILLIS_PER_DAY - 1) + + (int) ((instant + 1) % DateTimeConstants.MILLIS_PER_DAY); + } + } + + /** + * Gets the maximum number of days in any month. + * + * @return 31 + */ + int getDaysInMonthMax() { + return 31; + } + + /** + * Gets the maximum number of days in the month specified by the instant. + * + * @param instant millis from 1970-01-01T00:00:00Z + * @return the maximum number of days in the month + */ + int getDaysInMonthMax(long instant) { + int thisYear = getYear(instant); + int thisMonth = getMonthOfYear(instant, thisYear); + return getDaysInYearMonth(thisYear, thisMonth); + } + + /** + * Gets the maximum number of days in the month specified by the instant. + * The value represents what the user is trying to set, and can be + * used to optimise this method. + * + * @param instant millis from 1970-01-01T00:00:00Z + * @param value the value being set + * @return the maximum number of days in the month + */ + int getDaysInMonthMaxForSet(long instant, int value) { + return getDaysInMonthMax(instant); + } + + //----------------------------------------------------------------------- + /** + * Gets the milliseconds for a date at midnight. + * + * @param year the year + * @param monthOfYear the month + * @param dayOfMonth the day + * @return the milliseconds + */ + long getDateMidnightMillis(int year, int monthOfYear, int dayOfMonth) { + FieldUtils.verifyValueBounds(DateTimeFieldType.year(), year, getMinYear(), getMaxYear()); + FieldUtils.verifyValueBounds(DateTimeFieldType.monthOfYear(), monthOfYear, 1, getMaxMonth(year)); + FieldUtils.verifyValueBounds(DateTimeFieldType.dayOfMonth(), dayOfMonth, 1, getDaysInYearMonth(year, monthOfYear)); + return getYearMonthDayMillis(year, monthOfYear, dayOfMonth); + } + + /** + * Gets the difference between the two instants in years. + * + * @param minuendInstant the first instant + * @param subtrahendInstant the second instant + * @return the difference + */ + abstract long getYearDifference(long minuendInstant, long subtrahendInstant); + + /** + * Is the specified year a leap year? + * + * @param year the year to test + * @return true if leap + */ + abstract boolean isLeapYear(int year); + + /** + * Gets the number of days in the specified month and year. + * + * @param year the year + * @param month the month + * @return the number of days + */ + abstract int getDaysInYearMonth(int year, int month); + + /** + * Gets the maximum days in the specified month. + * + * @param month the month + * @return the max days + */ + abstract int getDaysInMonthMax(int month); + + /** + * Gets the total number of millis elapsed in this year at the start + * of the specified month, such as zero for month 1. + * + * @param year the year + * @param month the month + * @return the elapsed millis at the start of the month + */ + abstract long getTotalMillisByYearMonth(int year, int month); + + /** + * Gets the millisecond value of the first day of the year. + * + * @return the milliseconds for the first of the year + */ + abstract long calculateFirstDayOfYearMillis(int year); + + /** + * Gets the minimum supported year. + * + * @return the year + */ + abstract int getMinYear(); + + /** + * Gets the maximum supported year. + * + * @return the year + */ + abstract int getMaxYear(); + + /** + * Gets the maximum month for the specified year. + * This implementation calls getMaxMonth(). + * + * @param year the year + * @return the maximum month value + */ + int getMaxMonth(int year) { + return getMaxMonth(); + } + + /** + * Gets the maximum number of months. + * + * @return 12 + */ + int getMaxMonth() { + return 12; + } + + /** + * Gets an average value for the milliseconds per year. + * + * @return the millis per year + */ + abstract long getAverageMillisPerYear(); + + /** + * Gets an average value for the milliseconds per year, divided by two. + * + * @return the millis per year divided by two + */ + abstract long getAverageMillisPerYearDividedByTwo(); + + /** + * Gets an average value for the milliseconds per month. + * + * @return the millis per month + */ + abstract long getAverageMillisPerMonth(); + + /** + * Returns a constant representing the approximate number of milliseconds + * elapsed from year 0 of this chronology, divided by two. This constant + * must be defined as: + *

                +     *    (yearAtEpoch * averageMillisPerYear + millisOfYearAtEpoch) / 2
                +     * 
                + * where epoch is 1970-01-01 (Gregorian). + */ + abstract long getApproxMillisAtEpochDividedByTwo(); + + /** + * Sets the year from an instant and year. + * + * @param instant millis from 1970-01-01T00:00:00Z + * @param year the year to set + * @return the updated millis + */ + abstract long setYear(long instant, int year); + + //----------------------------------------------------------------------- + // Although accessed by multiple threads, this method doesn't need to be synchronized. + private YearInfo getYearInfo(int year) { + YearInfo info = iYearInfoCache[year & CACHE_MASK]; + if (info == null || info.iYear != year) { + info = new YearInfo(year, calculateFirstDayOfYearMillis(year)); + iYearInfoCache[year & CACHE_MASK] = info; + } + return info; + } + + private static class HalfdayField extends PreciseDateTimeField { + private static final long serialVersionUID = 581601443656929254L; + + HalfdayField() { + super(DateTimeFieldType.halfdayOfDay(), cHalfdaysField, cDaysField); + } + + public String getAsText(int fieldValue, Locale locale) { + return GJLocaleSymbols.forLocale(locale).halfdayValueToText(fieldValue); + } + + public long set(long millis, String text, Locale locale) { + return set(millis, GJLocaleSymbols.forLocale(locale).halfdayTextToValue(text)); + } + + public int getMaximumTextLength(Locale locale) { + return GJLocaleSymbols.forLocale(locale).getHalfdayMaxTextLength(); + } + } + + private static class YearInfo { + public final int iYear; + public final long iFirstDayMillis; + + YearInfo(int year, long firstDayMillis) { + iYear = year; + iFirstDayMillis = firstDayMillis; + } + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/chrono/BasicDayOfMonthDateTimeField.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/chrono/BasicDayOfMonthDateTimeField.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/BasicDayOfMonthDateTimeField.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,105 @@ +/* + * Copyright 2001-2005 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.chrono; + +import org.joda.time.DateTimeFieldType; +import org.joda.time.DurationField; +import org.joda.time.ReadablePartial; +import org.joda.time.field.PreciseDurationDateTimeField; + +/** + * Provides time calculations for the day of the month component of time. + * + * @author Guy Allard + * @author Stephen Colebourne + * @author Brian S O'Neill + * @since 1.1, refactored from GJDayOfMonthDateTimeField + */ +final class BasicDayOfMonthDateTimeField extends PreciseDurationDateTimeField { + + private static final long serialVersionUID = -4677223814028011723L; + + private final BasicChronology iChronology; + + /** + * Restricted constructor. + */ + BasicDayOfMonthDateTimeField(BasicChronology chronology, DurationField days) { + super(DateTimeFieldType.dayOfMonth(), days); + iChronology = chronology; + } + + //----------------------------------------------------------------------- + public int get(long instant) { + return iChronology.getDayOfMonth(instant); + } + + public DurationField getRangeDurationField() { + return iChronology.months(); + } + + public int getMinimumValue() { + return 1; + } + + public int getMaximumValue() { + return iChronology.getDaysInMonthMax(); + } + + public int getMaximumValue(long instant) { + return iChronology.getDaysInMonthMax(instant); + } + + public int getMaximumValue(ReadablePartial partial) { + if (partial.isSupported(DateTimeFieldType.monthOfYear())) { + int month = partial.get(DateTimeFieldType.monthOfYear()); + if (partial.isSupported(DateTimeFieldType.year())) { + int year = partial.get(DateTimeFieldType.year()); + return iChronology.getDaysInYearMonth(year, month); + } + return iChronology.getDaysInMonthMax(month); + } + return getMaximumValue(); + } + + public int getMaximumValue(ReadablePartial partial, int[] values) { + int size = partial.size(); + for (int i = 0; i < size; i++) { + if (partial.getFieldType(i) == DateTimeFieldType.monthOfYear()) { + int month = values[i]; + for (int j = 0; j < size; j++) { + if (partial.getFieldType(j) == DateTimeFieldType.year()) { + int year = values[j]; + return iChronology.getDaysInYearMonth(year, month); + } + } + return iChronology.getDaysInMonthMax(month); + } + } + return getMaximumValue(); + } + + protected int getMaximumValueForSet(long instant, int value) { + return iChronology.getDaysInMonthMaxForSet(instant, value); + } + + /** + * Serialization singleton + */ + private Object readResolve() { + return iChronology.dayOfMonth(); + } +} Index: 3rdParty_sources/joda-time/org/joda/time/chrono/BasicDayOfYearDateTimeField.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/chrono/BasicDayOfYearDateTimeField.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/BasicDayOfYearDateTimeField.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,102 @@ +/* + * Copyright 2001-2005 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.chrono; + +import org.joda.time.DateTimeFieldType; +import org.joda.time.DurationField; +import org.joda.time.ReadablePartial; +import org.joda.time.field.PreciseDurationDateTimeField; + +/** + * Provides time calculations for the day of the year component of time. + * + * @author Guy Allard + * @author Stephen Colebourne + * @author Brian S O'Neill + * @since 1.1, refactored from GJDayOfYearDateTimeField + */ +final class BasicDayOfYearDateTimeField extends PreciseDurationDateTimeField { + + private static final long serialVersionUID = -6821236822336841037L; + + private final BasicChronology iChronology; + + /** + * Restricted constructor + */ + BasicDayOfYearDateTimeField(BasicChronology chronology, DurationField days) { + super(DateTimeFieldType.dayOfYear(), days); + iChronology = chronology; + } + + /** + * Get the day of the year component of the specified time instant. + * + * @param instant the time instant in millis to query. + * @return the day of the year extracted from the input. + */ + public int get(long instant) { + return iChronology.getDayOfYear(instant); + } + + public DurationField getRangeDurationField() { + return iChronology.years(); + } + + public int getMinimumValue() { + return 1; + } + + public int getMaximumValue() { + return iChronology.getDaysInYearMax(); + } + + public int getMaximumValue(long instant) { + int year = iChronology.getYear(instant); + return iChronology.getDaysInYear(year); + } + + public int getMaximumValue(ReadablePartial partial) { + if (partial.isSupported(DateTimeFieldType.year())) { + int year = partial.get(DateTimeFieldType.year()); + return iChronology.getDaysInYear(year); + } + return iChronology.getDaysInYearMax(); + } + + public int getMaximumValue(ReadablePartial partial, int[] values) { + int size = partial.size(); + for (int i = 0; i < size; i++) { + if (partial.getFieldType(i) == DateTimeFieldType.year()) { + int year = values[i]; + return iChronology.getDaysInYear(year); + } + } + return iChronology.getDaysInYearMax(); + } + + protected int getMaximumValueForSet(long instant, int value) { + int maxLessOne = iChronology.getDaysInYearMax() - 1; + return (value > maxLessOne || value < 1) ? getMaximumValue(instant) : maxLessOne; + } + + /** + * Serialization singleton + */ + private Object readResolve() { + return iChronology.dayOfYear(); + } +} Index: 3rdParty_sources/joda-time/org/joda/time/chrono/BasicFixedMonthChronology.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/chrono/BasicFixedMonthChronology.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/BasicFixedMonthChronology.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,161 @@ +/* + * Copyright 2001-2005 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.chrono; + +import org.joda.time.Chronology; +import org.joda.time.DateTimeConstants; + +/** + * Abstract implementation of a calendar system based around fixed length months. + *

                + * As the month length is fixed various calculations can be optimised. + * This implementation assumes any additional days after twelve + * months fall into a thirteenth month. + *

                + * BasicFixedMonthChronology is thread-safe and immutable, and all + * subclasses must be as well. + * + * @author Brian S O'Neill + * @author Stephen Colebourne + * @since 1.2, refactored from CopticChronology + */ +abstract class BasicFixedMonthChronology extends BasicChronology { + + /** Serialization lock */ + private static final long serialVersionUID = 261387371998L; + + /** The length of the month. */ + static final int MONTH_LENGTH = 30; + + /** The typical millis per year. */ + static final long MILLIS_PER_YEAR = + (long) (365.25 * DateTimeConstants.MILLIS_PER_DAY); + + /** The length of the month in millis. */ + static final long MILLIS_PER_MONTH = ((long) MONTH_LENGTH) * DateTimeConstants.MILLIS_PER_DAY; + + //----------------------------------------------------------------------- + /** + * Restricted constructor. + * + * @param base the base chronology + * @param param the init parameter + * @param minDaysInFirstWeek the minimum days in the first week + */ + BasicFixedMonthChronology(Chronology base, Object param, int minDaysInFirstWeek) { + super(base, param, minDaysInFirstWeek); + } + + //----------------------------------------------------------------------- + long setYear(long instant, int year) { + // optimsed implementation of set, due to fixed months + int thisYear = getYear(instant); + int dayOfYear = getDayOfYear(instant, thisYear); + int millisOfDay = getMillisOfDay(instant); + + if (dayOfYear > 365) { + // Current year is leap, and day is leap. + if (!isLeapYear(year)) { + // Moving to a non-leap year, leap day doesn't exist. + dayOfYear--; + } + } + + instant = getYearMonthDayMillis(year, 1, dayOfYear); + instant += millisOfDay; + return instant; + } + + //----------------------------------------------------------------------- + long getYearDifference(long minuendInstant, long subtrahendInstant) { + // optimsed implementation of getDifference, due to fixed months + int minuendYear = getYear(minuendInstant); + int subtrahendYear = getYear(subtrahendInstant); + + // Inlined remainder method to avoid duplicate calls to get. + long minuendRem = minuendInstant - getYearMillis(minuendYear); + long subtrahendRem = subtrahendInstant - getYearMillis(subtrahendYear); + + int difference = minuendYear - subtrahendYear; + if (minuendRem < subtrahendRem) { + difference--; + } + return difference; + } + + //----------------------------------------------------------------------- + long getTotalMillisByYearMonth(int year, int month) { + return ((month - 1) * MILLIS_PER_MONTH); + } + + //----------------------------------------------------------------------- + int getDayOfMonth(long millis) { + // optimised for fixed months + return (getDayOfYear(millis) - 1) % MONTH_LENGTH + 1; + } + + //----------------------------------------------------------------------- + boolean isLeapYear(int year) { + return (year & 3) == 3; + } + + //----------------------------------------------------------------------- + int getDaysInYearMonth(int year, int month) { + return (month != 13) ? MONTH_LENGTH : (isLeapYear(year) ? 6 : 5); + } + + //----------------------------------------------------------------------- + int getDaysInMonthMax() { + return MONTH_LENGTH; + } + + //----------------------------------------------------------------------- + int getDaysInMonthMax(int month) { + return (month != 13 ? MONTH_LENGTH : 6); + } + + //----------------------------------------------------------------------- + int getMonthOfYear(long millis) { + return (getDayOfYear(millis) - 1) / MONTH_LENGTH + 1; + } + + //----------------------------------------------------------------------- + int getMonthOfYear(long millis, int year) { + long monthZeroBased = (millis - getYearMillis(year)) / MILLIS_PER_MONTH; + return ((int) monthZeroBased) + 1; + } + + //----------------------------------------------------------------------- + int getMaxMonth() { + return 13; + } + + //----------------------------------------------------------------------- + long getAverageMillisPerYear() { + return MILLIS_PER_YEAR; + } + + //----------------------------------------------------------------------- + long getAverageMillisPerYearDividedByTwo() { + return MILLIS_PER_YEAR / 2; + } + + //----------------------------------------------------------------------- + long getAverageMillisPerMonth() { + return MILLIS_PER_MONTH; + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/chrono/BasicGJChronology.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/chrono/BasicGJChronology.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/BasicGJChronology.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,201 @@ +/* + * Copyright 2001-2005 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.chrono; + +import org.joda.time.Chronology; +import org.joda.time.DateTimeConstants; + +/** + * Abstract Chronology for implementing chronologies based on Gregorian/Julian formulae. + * Most of the utility methods required by subclasses are package-private, + * reflecting the intention that they be defined in the same package. + *

                + * BasicGJChronology is thread-safe and immutable, and all subclasses must + * be as well. + * + * @author Stephen Colebourne + * @author Brian S O'Neill + * @author Guy Allard + * @since 1.2, refactored from CommonGJChronology + */ +abstract class BasicGJChronology extends BasicChronology { + + /** Serialization lock */ + private static final long serialVersionUID = 538276888268L; + + // These arrays are NOT public. We trust ourselves not to alter the array. + // They use zero-based array indexes so the that valid range of months is + // automatically checked. + private static final int[] MIN_DAYS_PER_MONTH_ARRAY = { + 31,28,31,30,31,30,31,31,30,31,30,31 + }; + private static final int[] MAX_DAYS_PER_MONTH_ARRAY = { + 31,29,31,30,31,30,31,31,30,31,30,31 + }; + private static final long[] MIN_TOTAL_MILLIS_BY_MONTH_ARRAY; + private static final long[] MAX_TOTAL_MILLIS_BY_MONTH_ARRAY; + private static final long FEB_29 = (31L + 29 - 1) * DateTimeConstants.MILLIS_PER_DAY; + + static { + MIN_TOTAL_MILLIS_BY_MONTH_ARRAY = new long[12]; + MAX_TOTAL_MILLIS_BY_MONTH_ARRAY = new long[12]; + + long minSum = 0; + long maxSum = 0; + for (int i = 0; i < 11; i++) { + long millis = MIN_DAYS_PER_MONTH_ARRAY[i] + * (long)DateTimeConstants.MILLIS_PER_DAY; + minSum += millis; + MIN_TOTAL_MILLIS_BY_MONTH_ARRAY[i + 1] = minSum; + + millis = MAX_DAYS_PER_MONTH_ARRAY[i] + * (long)DateTimeConstants.MILLIS_PER_DAY; + maxSum += millis; + MAX_TOTAL_MILLIS_BY_MONTH_ARRAY[i + 1] = maxSum; + } + } + + /** + * Constructor. + */ + BasicGJChronology(Chronology base, Object param, int minDaysInFirstWeek) { + super(base, param, minDaysInFirstWeek); + } + + //----------------------------------------------------------------------- + int getMonthOfYear(long millis, int year) { + // Perform a binary search to get the month. To make it go even faster, + // compare using ints instead of longs. The number of milliseconds per + // year exceeds the limit of a 32-bit int's capacity, so divide by + // 1024. No precision is lost (except time of day) since the number of + // milliseconds per day contains 1024 as a factor. After the division, + // the instant isn't measured in milliseconds, but in units of + // (128/125)seconds. + + int i = (int)((millis - getYearMillis(year)) >> 10); + + // There are 86400000 milliseconds per day, but divided by 1024 is + // 84375. There are 84375 (128/125)seconds per day. + + return + (isLeapYear(year)) + ? ((i < 182 * 84375) + ? ((i < 91 * 84375) + ? ((i < 31 * 84375) ? 1 : (i < 60 * 84375) ? 2 : 3) + : ((i < 121 * 84375) ? 4 : (i < 152 * 84375) ? 5 : 6)) + : ((i < 274 * 84375) + ? ((i < 213 * 84375) ? 7 : (i < 244 * 84375) ? 8 : 9) + : ((i < 305 * 84375) ? 10 : (i < 335 * 84375) ? 11 : 12))) + : ((i < 181 * 84375) + ? ((i < 90 * 84375) + ? ((i < 31 * 84375) ? 1 : (i < 59 * 84375) ? 2 : 3) + : ((i < 120 * 84375) ? 4 : (i < 151 * 84375) ? 5 : 6)) + : ((i < 273 * 84375) + ? ((i < 212 * 84375) ? 7 : (i < 243 * 84375) ? 8 : 9) + : ((i < 304 * 84375) ? 10 : (i < 334 * 84375) ? 11 : 12))); + } + + //----------------------------------------------------------------------- + /** + * Gets the number of days in the specified month and year. + * + * @param year the year + * @param month the month + * @return the number of days + */ + int getDaysInYearMonth(int year, int month) { + if (isLeapYear(year)) { + return MAX_DAYS_PER_MONTH_ARRAY[month - 1]; + } else { + return MIN_DAYS_PER_MONTH_ARRAY[month - 1]; + } + } + + //----------------------------------------------------------------------- + int getDaysInMonthMax(int month) { + return MAX_DAYS_PER_MONTH_ARRAY[month - 1]; + } + + //----------------------------------------------------------------------- + int getDaysInMonthMaxForSet(long instant, int value) { + return (value > 28 ? getDaysInMonthMax(instant) : 28); + } + + //----------------------------------------------------------------------- + long getTotalMillisByYearMonth(int year, int month) { + if (isLeapYear(year)) { + return MAX_TOTAL_MILLIS_BY_MONTH_ARRAY[month - 1]; + } else { + return MIN_TOTAL_MILLIS_BY_MONTH_ARRAY[month - 1]; + } + } + + //----------------------------------------------------------------------- + long getYearDifference(long minuendInstant, long subtrahendInstant) { + int minuendYear = getYear(minuendInstant); + int subtrahendYear = getYear(subtrahendInstant); + + // Inlined remainder method to avoid duplicate calls to get. + long minuendRem = minuendInstant - getYearMillis(minuendYear); + long subtrahendRem = subtrahendInstant - getYearMillis(subtrahendYear); + + // Balance leap year differences on remainders. + if (subtrahendRem >= FEB_29) { + if (isLeapYear(subtrahendYear)) { + if (!isLeapYear(minuendYear)) { + subtrahendRem -= DateTimeConstants.MILLIS_PER_DAY; + } + } else if (minuendRem >= FEB_29 && isLeapYear(minuendYear)) { + minuendRem -= DateTimeConstants.MILLIS_PER_DAY; + } + } + + int difference = minuendYear - subtrahendYear; + if (minuendRem < subtrahendRem) { + difference--; + } + return difference; + } + + //----------------------------------------------------------------------- + long setYear(long instant, int year) { + int thisYear = getYear(instant); + int dayOfYear = getDayOfYear(instant, thisYear); + int millisOfDay = getMillisOfDay(instant); + + if (dayOfYear > (31 + 28)) { // after Feb 28 + if (isLeapYear(thisYear)) { + // Current date is Feb 29 or later. + if (!isLeapYear(year)) { + // Moving to a non-leap year, Feb 29 does not exist. + dayOfYear--; + } + } else { + // Current date is Mar 01 or later. + if (isLeapYear(year)) { + // Moving to a leap year, account for Feb 29. + dayOfYear++; + } + } + } + + instant = getYearMonthDayMillis(year, 1, dayOfYear); + instant += millisOfDay; + + return instant; + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/chrono/BasicMonthOfYearDateTimeField.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/chrono/BasicMonthOfYearDateTimeField.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/BasicMonthOfYearDateTimeField.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,360 @@ +/* + * Copyright 2001-2005 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.chrono; + +import org.joda.time.DateTimeConstants; +import org.joda.time.DateTimeFieldType; +import org.joda.time.DateTimeUtils; +import org.joda.time.DurationField; +import org.joda.time.ReadablePartial; +import org.joda.time.field.FieldUtils; +import org.joda.time.field.ImpreciseDateTimeField; + +/** + * Provides time calculations for the month of the year component of time. + * + * @author Guy Allard + * @author Stephen Colebourne + * @author Brian S O'Neill + * @since 1.2, refactored from GJMonthOfYearDateTimeField + */ +class BasicMonthOfYearDateTimeField extends ImpreciseDateTimeField { + + /** Serialization version */ + private static final long serialVersionUID = -8258715387168736L; + + private static final int MIN = DateTimeConstants.JANUARY; + + private final BasicChronology iChronology; + private final int iMax; + private final int iLeapMonth; + + /** + * Restricted constructor. + * + * @param leapMonth the month of year that leaps + */ + BasicMonthOfYearDateTimeField(BasicChronology chronology, int leapMonth) { + super(DateTimeFieldType.monthOfYear(), chronology.getAverageMillisPerMonth()); + iChronology = chronology; + iMax = iChronology.getMaxMonth(); + iLeapMonth = leapMonth; + } + + //----------------------------------------------------------------------- + public boolean isLenient() { + return false; + } + + //----------------------------------------------------------------------- + /** + * Get the Month component of the specified time instant. + * + * @see org.joda.time.DateTimeField#get(long) + * @see org.joda.time.ReadableDateTime#getMonthOfYear() + * @param instant the time instant in millis to query. + * @return the month extracted from the input. + */ + public int get(long instant) { + return iChronology.getMonthOfYear(instant); + } + + //----------------------------------------------------------------------- + /** + * Add the specified month to the specified time instant. + * The amount added may be negative.

                + * If the new month has less total days than the specified + * day of the month, this value is coerced to the nearest + * sane value. e.g.

                + * 07-31 - (1 month) = 06-30

                + * 03-31 - (1 month) = 02-28 or 02-29 depending

                + * + * @see org.joda.time.DateTimeField#add + * @see org.joda.time.ReadWritableDateTime#addMonths(int) + * @param instant the time instant in millis to update. + * @param months the months to add (can be negative). + * @return the updated time instant. + */ + public long add(long instant, int months) { + if (months == 0) { + return instant; // the easy case + } + // + // Save time part first. + // + long timePart = iChronology.getMillisOfDay(instant); + // + // + // Get this year and month. + // + int thisYear = iChronology.getYear(instant); + int thisMonth = iChronology.getMonthOfYear(instant, thisYear); + // ---------------------------------------------------------- + // + // Do not refactor without careful consideration. + // Order of calculation is important. + // + int yearToUse; + // Initially, monthToUse is zero-based + int monthToUse = thisMonth - 1 + months; + if (monthToUse >= 0) { + yearToUse = thisYear + (monthToUse / iMax); + monthToUse = (monthToUse % iMax) + 1; + } else { + yearToUse = thisYear + (monthToUse / iMax) - 1; + monthToUse = Math.abs(monthToUse); + int remMonthToUse = monthToUse % iMax; + // Take care of the boundary condition + if (remMonthToUse == 0) { + remMonthToUse = iMax; + } + monthToUse = iMax - remMonthToUse + 1; + // Take care of the boundary condition + if (monthToUse == 1) { + yearToUse += 1; + } + } + // End of do not refactor. + // ---------------------------------------------------------- + + // + // Quietly force DOM to nearest sane value. + // + int dayToUse = iChronology.getDayOfMonth(instant, thisYear, thisMonth); + int maxDay = iChronology.getDaysInYearMonth(yearToUse, monthToUse); + if (dayToUse > maxDay) { + dayToUse = maxDay; + } + // + // get proper date part, and return result + // + long datePart = + iChronology.getYearMonthDayMillis(yearToUse, monthToUse, dayToUse); + return datePart + timePart; + } + + //----------------------------------------------------------------------- + public long add(long instant, long months) { + int i_months = (int)months; + if (i_months == months) { + return add(instant, i_months); + } + + // Copied from add(long, int) and modified slightly: + + long timePart = iChronology.getMillisOfDay(instant); + + int thisYear = iChronology.getYear(instant); + int thisMonth = iChronology.getMonthOfYear(instant, thisYear); + + long yearToUse; + long monthToUse = thisMonth - 1 + months; + if (monthToUse >= 0) { + yearToUse = thisYear + (monthToUse / iMax); + monthToUse = (monthToUse % iMax) + 1; + } else { + yearToUse = thisYear + (monthToUse / iMax) - 1; + monthToUse = Math.abs(monthToUse); + int remMonthToUse = (int)(monthToUse % iMax); + if (remMonthToUse == 0) { + remMonthToUse = iMax; + } + monthToUse = iMax - remMonthToUse + 1; + if (monthToUse == 1) { + yearToUse += 1; + } + } + + if (yearToUse < iChronology.getMinYear() || + yearToUse > iChronology.getMaxYear()) { + + throw new IllegalArgumentException + ("Magnitude of add amount is too large: " + months); + } + + int i_yearToUse = (int)yearToUse; + int i_monthToUse = (int)monthToUse; + + int dayToUse = iChronology.getDayOfMonth(instant, thisYear, thisMonth); + int maxDay = iChronology.getDaysInYearMonth(i_yearToUse, i_monthToUse); + if (dayToUse > maxDay) { + dayToUse = maxDay; + } + + long datePart = + iChronology.getYearMonthDayMillis(i_yearToUse, i_monthToUse, dayToUse); + return datePart + timePart; + } + + //----------------------------------------------------------------------- + public int[] add(ReadablePartial partial, int fieldIndex, int[] values, int valueToAdd) { + // overridden as superclass algorithm can't handle + // 2004-02-29 + 48 months -> 2008-02-29 type dates + if (valueToAdd == 0) { + return values; + } + if (DateTimeUtils.isContiguous(partial)) { + long instant = 0L; + for (int i = 0, isize = partial.size(); i < isize; i++) { + instant = partial.getFieldType(i).getField(iChronology).set(instant, values[i]); + } + instant = add(instant, valueToAdd); + return iChronology.get(partial, instant); + } else { + return super.add(partial, fieldIndex, values, valueToAdd); + } + } + + //----------------------------------------------------------------------- + /** + * Add to the Month component of the specified time instant + * wrapping around within that component if necessary. + * + * @see org.joda.time.DateTimeField#addWrapField + * @param instant the time instant in millis to update. + * @param months the months to add (can be negative). + * @return the updated time instant. + */ + public long addWrapField(long instant, int months) { + return set(instant, FieldUtils.getWrappedValue(get(instant), months, MIN, iMax)); + } + + //----------------------------------------------------------------------- + public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) { + if (minuendInstant < subtrahendInstant) { + return -getDifference(subtrahendInstant, minuendInstant); + } + + int minuendYear = iChronology.getYear(minuendInstant); + int minuendMonth = iChronology.getMonthOfYear(minuendInstant, minuendYear); + int subtrahendYear = iChronology.getYear(subtrahendInstant); + int subtrahendMonth = iChronology.getMonthOfYear(subtrahendInstant, subtrahendYear); + + long difference = (minuendYear - subtrahendYear) * ((long) iMax) + minuendMonth - subtrahendMonth; + + // Before adjusting for remainder, account for special case of add + // where the day-of-month is forced to the nearest sane value. + int minuendDom = iChronology.getDayOfMonth + (minuendInstant, minuendYear, minuendMonth); + if (minuendDom == iChronology.getDaysInYearMonth(minuendYear, minuendMonth)) { + // Last day of the minuend month... + int subtrahendDom = iChronology.getDayOfMonth + (subtrahendInstant, subtrahendYear, subtrahendMonth); + if (subtrahendDom > minuendDom) { + // ...and day of subtrahend month is larger. + // Note: This works fine, but it ideally shouldn't invoke other + // fields from within a field. + subtrahendInstant = iChronology.dayOfMonth().set(subtrahendInstant, minuendDom); + } + } + + // Inlined remainder method to avoid duplicate calls. + long minuendRem = minuendInstant + - iChronology.getYearMonthMillis(minuendYear, minuendMonth); + long subtrahendRem = subtrahendInstant + - iChronology.getYearMonthMillis(subtrahendYear, subtrahendMonth); + + if (minuendRem < subtrahendRem) { + difference--; + } + + return difference; + } + + //----------------------------------------------------------------------- + /** + * Set the Month component of the specified time instant.

                + * If the new month has less total days than the specified + * day of the month, this value is coerced to the nearest + * sane value. e.g.

                + * 07-31 to month 6 = 06-30

                + * 03-31 to month 2 = 02-28 or 02-29 depending

                + * + * @param instant the time instant in millis to update. + * @param month the month (1,12) to update the time to. + * @return the updated time instant. + * @throws IllegalArgumentException if month is invalid + */ + public long set(long instant, int month) { + FieldUtils.verifyValueBounds(this, month, MIN, iMax); + // + int thisYear = iChronology.getYear(instant); + // + int thisDom = iChronology.getDayOfMonth(instant, thisYear); + int maxDom = iChronology.getDaysInYearMonth(thisYear, month); + if (thisDom > maxDom) { + // Quietly force DOM to nearest sane value. + thisDom = maxDom; + } + // Return newly calculated millis value + return iChronology.getYearMonthDayMillis(thisYear, month, thisDom) + + iChronology.getMillisOfDay(instant); + } + + //----------------------------------------------------------------------- + public DurationField getRangeDurationField() { + return iChronology.years(); + } + + //----------------------------------------------------------------------- + public boolean isLeap(long instant) { + int thisYear = iChronology.getYear(instant); + if (iChronology.isLeapYear(thisYear)) { + return (iChronology.getMonthOfYear(instant, thisYear) == iLeapMonth); + } + return false; + } + + //----------------------------------------------------------------------- + public int getLeapAmount(long instant) { + return isLeap(instant) ? 1 : 0; + } + + //----------------------------------------------------------------------- + public DurationField getLeapDurationField() { + return iChronology.days(); + } + + //----------------------------------------------------------------------- + public int getMinimumValue() { + return MIN; + } + + //----------------------------------------------------------------------- + public int getMaximumValue() { + return iMax; + } + + //----------------------------------------------------------------------- + public long roundFloor(long instant) { + int year = iChronology.getYear(instant); + int month = iChronology.getMonthOfYear(instant, year); + return iChronology.getYearMonthMillis(year, month); + } + + //----------------------------------------------------------------------- + public long remainder(long instant) { + return instant - roundFloor(instant); + } + + //----------------------------------------------------------------------- + /** + * Serialization singleton + */ + private Object readResolve() { + return iChronology.monthOfYear(); + } +} Index: 3rdParty_sources/joda-time/org/joda/time/chrono/BasicSingleEraDateTimeField.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/chrono/BasicSingleEraDateTimeField.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/BasicSingleEraDateTimeField.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,134 @@ +/* + * Copyright 2001-2005 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.chrono; + +import java.util.Locale; + +import org.joda.time.DateTimeConstants; +import org.joda.time.DateTimeFieldType; +import org.joda.time.DurationField; +import org.joda.time.DurationFieldType; +import org.joda.time.IllegalFieldValueException; +import org.joda.time.field.BaseDateTimeField; +import org.joda.time.field.FieldUtils; +import org.joda.time.field.UnsupportedDurationField; + +/** + * Provides time calculations for the coptic era component of time. + * + * @author Brian S O'Neill + * @author Stephen Colebourne + * @since 1.2, refactored from CopticEraDateTimeField + */ +final class BasicSingleEraDateTimeField extends BaseDateTimeField { + + /** + * Value of the era, which will be the same as DateTimeConstants.CE. + */ + private static final int ERA_VALUE = DateTimeConstants.CE; + /** + * Text value of the era. + */ + private final String iEraText; + + /** + * Restricted constructor. + */ + BasicSingleEraDateTimeField(String text) { + super(DateTimeFieldType.era()); + iEraText = text; + } + + /** @inheritDoc */ + public boolean isLenient() { + return false; + } + + /** @inheritDoc */ + public int get(long instant) { + return ERA_VALUE; + } + + /** @inheritDoc */ + public long set(long instant, int era) { + FieldUtils.verifyValueBounds(this, era, ERA_VALUE, ERA_VALUE); + return instant; + } + + /** @inheritDoc */ + public long set(long instant, String text, Locale locale) { + if (iEraText.equals(text) == false && "1".equals(text) == false) { + throw new IllegalFieldValueException(DateTimeFieldType.era(), text); + } + return instant; + } + + /** @inheritDoc */ + public long roundFloor(long instant) { + return Long.MIN_VALUE; + } + + /** @inheritDoc */ + public long roundCeiling(long instant) { + return Long.MAX_VALUE; + } + + /** @inheritDoc */ + public long roundHalfFloor(long instant) { + return Long.MIN_VALUE; + } + + /** @inheritDoc */ + public long roundHalfCeiling(long instant) { + return Long.MIN_VALUE; + } + + /** @inheritDoc */ + public long roundHalfEven(long instant) { + return Long.MIN_VALUE; + } + + /** @inheritDoc */ + public DurationField getDurationField() { + return UnsupportedDurationField.getInstance(DurationFieldType.eras()); + } + + /** @inheritDoc */ + public DurationField getRangeDurationField() { + return null; + } + + /** @inheritDoc */ + public int getMinimumValue() { + return ERA_VALUE; + } + + /** @inheritDoc */ + public int getMaximumValue() { + return ERA_VALUE; + } + + /** @inheritDoc */ + public String getAsText(int fieldValue, Locale locale) { + return iEraText; + } + + /** @inheritDoc */ + public int getMaximumTextLength(Locale locale) { + return iEraText.length(); + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/chrono/BasicWeekOfWeekyearDateTimeField.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/chrono/BasicWeekOfWeekyearDateTimeField.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/BasicWeekOfWeekyearDateTimeField.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,120 @@ +/* + * Copyright 2001-2005 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.chrono; + +import org.joda.time.DateTimeConstants; +import org.joda.time.DateTimeFieldType; +import org.joda.time.DurationField; +import org.joda.time.ReadablePartial; +import org.joda.time.field.PreciseDurationDateTimeField; + +/** + * Provides time calculations for the week of a week based year component of time. + * + * @author Guy Allard + * @author Stephen Colebourne + * @author Brian S O'Neill + * @since 1.1, refactored from GJWeekOfWeekyearDateTimeField + */ +final class BasicWeekOfWeekyearDateTimeField extends PreciseDurationDateTimeField { + + private static final long serialVersionUID = -1587436826395135328L; + + private final BasicChronology iChronology; + + /** + * Restricted constructor + */ + BasicWeekOfWeekyearDateTimeField(BasicChronology chronology, DurationField weeks) { + super(DateTimeFieldType.weekOfWeekyear(), weeks); + iChronology = chronology; + } + + /** + * Get the week of a week based year component of the specified time instant. + * + * @see org.joda.time.DateTimeField#get(long) + * @param instant the time instant in millis to query. + * @return the week of the year extracted from the input. + */ + public int get(long instant) { + return iChronology.getWeekOfWeekyear(instant); + } + + public DurationField getRangeDurationField() { + return iChronology.weekyears(); + } + + // 1970-01-01 is day of week 4, Thursday. The rounding methods need to + // apply a corrective alignment since weeks begin on day of week 1, Monday. + + public long roundFloor(long instant) { + return super.roundFloor(instant + 3 * DateTimeConstants.MILLIS_PER_DAY) + - 3 * DateTimeConstants.MILLIS_PER_DAY; + } + + public long roundCeiling(long instant) { + return super.roundCeiling(instant + 3 * DateTimeConstants.MILLIS_PER_DAY) + - 3 * DateTimeConstants.MILLIS_PER_DAY; + } + + public long remainder(long instant) { + return super.remainder(instant + 3 * DateTimeConstants.MILLIS_PER_DAY); + } + + public int getMinimumValue() { + return 1; + } + + public int getMaximumValue() { + return 53; + } + + public int getMaximumValue(long instant) { + int weekyear = iChronology.getWeekyear(instant); + return iChronology.getWeeksInYear(weekyear); + } + + public int getMaximumValue(ReadablePartial partial) { + if (partial.isSupported(DateTimeFieldType.weekyear())) { + int weekyear = partial.get(DateTimeFieldType.weekyear()); + return iChronology.getWeeksInYear(weekyear); + } + return 53; + } + + public int getMaximumValue(ReadablePartial partial, int[] values) { + int size = partial.size(); + for (int i = 0; i < size; i++) { + if (partial.getFieldType(i) == DateTimeFieldType.weekyear()) { + int weekyear = values[i]; + return iChronology.getWeeksInYear(weekyear); + } + } + return 53; + } + + protected int getMaximumValueForSet(long instant, int value) { + return value > 52 ? getMaximumValue(instant) : 52; + } + + /** + * Serialization singleton + */ + private Object readResolve() { + return iChronology.weekOfWeekyear(); + } +} Index: 3rdParty_sources/joda-time/org/joda/time/chrono/BasicWeekyearDateTimeField.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/chrono/BasicWeekyearDateTimeField.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/BasicWeekyearDateTimeField.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,252 @@ +/* + * Copyright 2001-2005 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.chrono; + +import org.joda.time.DateTimeConstants; +import org.joda.time.DateTimeFieldType; +import org.joda.time.DurationField; +import org.joda.time.field.FieldUtils; +import org.joda.time.field.ImpreciseDateTimeField; + +/** + * Provides time calculations for the week of the weekyear component of time. + * + * @author Guy Allard + * @author Stephen Colebourne + * @author Brian S O'Neill + * @since 1.1, refactored from GJWeekyearDateTimeField + */ +final class BasicWeekyearDateTimeField extends ImpreciseDateTimeField { + + private static final long serialVersionUID = 6215066916806820644L; + + private static final long WEEK_53 = (53L - 1) * DateTimeConstants.MILLIS_PER_WEEK; + + private final BasicChronology iChronology; + + /** + * Restricted constructor + */ + BasicWeekyearDateTimeField(BasicChronology chronology) { + super(DateTimeFieldType.weekyear(), chronology.getAverageMillisPerYear()); + iChronology = chronology; + } + + public boolean isLenient() { + return false; + } + + /** + * Get the Year of a week based year component of the specified time instant. + * + * @see org.joda.time.DateTimeField#get + * @param instant the time instant in millis to query. + * @return the year extracted from the input. + */ + public int get(long instant) { + return iChronology.getWeekyear(instant); + } + + /** + * Add the specified years to the specified time instant. + * + * @see org.joda.time.DateTimeField#add + * @param instant the time instant in millis to update. + * @param years the years to add (can be negative). + * @return the updated time instant. + */ + public long add(long instant, int years) { + if (years == 0) { + return instant; + } + return set(instant, get(instant) + years); + } + + public long add(long instant, long value) { + return add(instant, FieldUtils.safeToInt(value)); + } + + /** + * Add to the year component of the specified time instant + * wrapping around within that component if necessary. + * + * @see org.joda.time.DateTimeField#addWrapField + * @param instant the time instant in millis to update. + * @param years the years to add (can be negative). + * @return the updated time instant. + */ + public long addWrapField(long instant, int years) { + return add(instant, years); + } + + public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) { + if (minuendInstant < subtrahendInstant) { + return -getDifference(subtrahendInstant, minuendInstant); + } + + int minuendWeekyear = get(minuendInstant); + int subtrahendWeekyear = get(subtrahendInstant); + + long minuendRem = remainder(minuendInstant); + long subtrahendRem = remainder(subtrahendInstant); + + // Balance leap weekyear differences on remainders. + if (subtrahendRem >= WEEK_53 && iChronology.getWeeksInYear(minuendWeekyear) <= 52) { + subtrahendRem -= DateTimeConstants.MILLIS_PER_WEEK; + } + + int difference = minuendWeekyear - subtrahendWeekyear; + if (minuendRem < subtrahendRem) { + difference--; + } + return difference; + } + + /** + * Set the Year of a week based year component of the specified time instant. + * + * @see org.joda.time.DateTimeField#set + * @param instant the time instant in millis to update. + * @param year the year (-9999,9999) to set the date to. + * @return the updated DateTime. + * @throws IllegalArgumentException if year is invalid. + */ + public long set(long instant, int year) { + FieldUtils.verifyValueBounds(this, Math.abs(year), + iChronology.getMinYear(), iChronology.getMaxYear()); + // + // Do nothing if no real change is requested. + // + int thisWeekyear = get( instant ); + if ( thisWeekyear == year ) { + return instant; + } + // + // Calculate the DayOfWeek (to be preserved). + // + int thisDow = iChronology.getDayOfWeek(instant); + // + // Calculate the maximum weeks in the target year. + // + int weeksInFromYear = iChronology.getWeeksInYear( thisWeekyear ); + int weeksInToYear = iChronology.getWeeksInYear( year ); + int maxOutWeeks = (weeksInToYear < weeksInFromYear) ? + weeksInToYear : weeksInFromYear; + // + // Get the current week of the year. This will be preserved in + // the output unless it is greater than the maximum possible + // for the target weekyear. In that case it is adjusted + // to the maximum possible. + // + int setToWeek = iChronology.getWeekOfWeekyear(instant); + if ( setToWeek > maxOutWeeks ) { + setToWeek = maxOutWeeks; + } + // + // Get a wroking copy of the current date-time. + // This can be a convenience for debugging. + // + long workInstant = instant; // Get a copy + // + // Attempt to get close to the proper weekyear. + // Note - we cannot currently call ourself, so we just call + // set for the year. This at least gets us close. + // + workInstant = iChronology.setYear( workInstant, year ); + // + // Calculate the weekyear number for the get close to value + // (which might not be equal to the year just set). + // + int workWoyYear = get( workInstant ); + + // + // At most we are off by one year, which can be "fixed" by + // adding/subtracting a week. + // + if ( workWoyYear < year ) { + workInstant += DateTimeConstants.MILLIS_PER_WEEK; + } else if ( workWoyYear > year ) { + workInstant -= DateTimeConstants.MILLIS_PER_WEEK; + } + // + // Set the proper week in the current weekyear. + // + + // BEGIN: possible set WeekOfWeekyear logic. + int currentWoyWeek = iChronology.getWeekOfWeekyear(workInstant); + // No range check required (we already know it is OK). + workInstant = workInstant + (setToWeek - currentWoyWeek) + * (long)DateTimeConstants.MILLIS_PER_WEEK; + // END: possible set WeekOfWeekyear logic. + + // + // Reset DayOfWeek to previous value. + // + // Note: This works fine, but it ideally shouldn't invoke other + // fields from within a field. + workInstant = iChronology.dayOfWeek().set( workInstant, thisDow ); + // + // Return result. + // + return workInstant; + } + + public DurationField getRangeDurationField() { + return null; + } + + public boolean isLeap(long instant) { + return iChronology.getWeeksInYear(iChronology.getWeekyear(instant)) > 52; + } + + public int getLeapAmount(long instant) { + return iChronology.getWeeksInYear(iChronology.getWeekyear(instant)) - 52; + } + + public DurationField getLeapDurationField() { + return iChronology.weeks(); + } + + public int getMinimumValue() { + return iChronology.getMinYear(); + } + + public int getMaximumValue() { + return iChronology.getMaxYear(); + } + + public long roundFloor(long instant) { + // Note: This works fine, but it ideally shouldn't invoke other + // fields from within a field. + instant = iChronology.weekOfWeekyear().roundFloor(instant); + int wow = iChronology.getWeekOfWeekyear(instant); + if (wow > 1) { + instant -= ((long) DateTimeConstants.MILLIS_PER_WEEK) * (wow - 1); + } + return instant; + } + + public long remainder(long instant) { + return instant - roundFloor(instant); + } + + /** + * Serialization singleton + */ + private Object readResolve() { + return iChronology.weekyear(); + } +} Index: 3rdParty_sources/joda-time/org/joda/time/chrono/BasicYearDateTimeField.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/chrono/BasicYearDateTimeField.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/BasicYearDateTimeField.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,146 @@ +/* + * Copyright 2001-2005 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.chrono; + +import org.joda.time.DateTimeFieldType; +import org.joda.time.DurationField; +import org.joda.time.field.FieldUtils; +import org.joda.time.field.ImpreciseDateTimeField; + +/** + * A year field suitable for many calendars. + * + * @author Guy Allard + * @author Stephen Colebourne + * @author Brian S O'Neill + * @since 1.1, refactored from GJYearDateTimeField + */ +class BasicYearDateTimeField extends ImpreciseDateTimeField { + + /** Serialization version. */ + private static final long serialVersionUID = -98628754872287L; + + /** The underlying basic chronology. */ + protected final BasicChronology iChronology; + + /** + * Restricted constructor. + * + * @param chronology the chronology this field belogs to + */ + BasicYearDateTimeField(BasicChronology chronology) { + super(DateTimeFieldType.year(), chronology.getAverageMillisPerYear()); + iChronology = chronology; + } + + public boolean isLenient() { + return false; + } + + public int get(long instant) { + return iChronology.getYear(instant); + } + + public long add(long instant, int years) { + if (years == 0) { + return instant; + } + int thisYear = get(instant); + int newYear = FieldUtils.safeAdd(thisYear, years); + return set(instant, newYear); + } + + public long add(long instant, long years) { + return add(instant, FieldUtils.safeToInt(years)); + } + + public long addWrapField(long instant, int years) { + if (years == 0) { + return instant; + } + // Return newly calculated millis value + int thisYear = iChronology.getYear(instant); + int wrappedYear = FieldUtils.getWrappedValue + (thisYear, years, iChronology.getMinYear(), iChronology.getMaxYear()); + return set(instant, wrappedYear); + } + + public long set(long instant, int year) { + FieldUtils.verifyValueBounds + (this, year, iChronology.getMinYear(), iChronology.getMaxYear()); + return iChronology.setYear(instant, year); + } + + public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) { + if (minuendInstant < subtrahendInstant) { + return -iChronology.getYearDifference(subtrahendInstant, minuendInstant); + } + return iChronology.getYearDifference(minuendInstant, subtrahendInstant); + } + + public DurationField getRangeDurationField() { + return null; + } + + public boolean isLeap(long instant) { + return iChronology.isLeapYear(get(instant)); + } + + public int getLeapAmount(long instant) { + if (iChronology.isLeapYear(get(instant))) { + return 1; + } else { + return 0; + } + } + + public DurationField getLeapDurationField() { + return iChronology.days(); + } + + public int getMinimumValue() { + return iChronology.getMinYear(); + } + + public int getMaximumValue() { + return iChronology.getMaxYear(); + } + + public long roundFloor(long instant) { + return iChronology.getYearMillis(get(instant)); + } + + public long roundCeiling(long instant) { + int year = get(instant); + long yearStartMillis = iChronology.getYearMillis(year); + if (instant != yearStartMillis) { + // Bump up to start of next year. + instant = iChronology.getYearMillis(year + 1); + } + return instant; + } + + public long remainder(long instant) { + return instant - roundFloor(instant); + } + + /** + * Serialization singleton + */ + private Object readResolve() { + return iChronology.year(); + } +} Index: 3rdParty_sources/joda-time/org/joda/time/chrono/BuddhistChronology.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/BuddhistChronology.java (.../BuddhistChronology.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/BuddhistChronology.java (.../BuddhistChronology.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -62,18 +24,26 @@ import org.joda.time.DateTimeField; import org.joda.time.DateTimeFieldType; import org.joda.time.DateTimeZone; +import org.joda.time.field.DelegatedDateTimeField; import org.joda.time.field.DividedDateTimeField; import org.joda.time.field.OffsetDateTimeField; import org.joda.time.field.RemainderDateTimeField; +import org.joda.time.field.SkipUndoDateTimeField; /** - * Implements the Buddhist calendar system, which is similar to Gregorian/Julian, - * except with the year offset by 543. + * A chronology that matches the BuddhistCalendar class supplied by Sun. *

                - * The Buddhist calendar differs from the Gregorian/Julian calendar only - * in the year. This class is compatable with the BuddhistCalendar class - * supplied by Sun. + * The chronology is identical to the Gregorian/Julian, except that the + * year is offset by +543 and the era is named 'BE' for Buddhist Era. *

                + * This class was intended by Sun to model the calendar used in Thailand. + * However, the actual rules for Thailand are much more involved than + * this class covers. (This class is accurate after 1941-01-01 ISO). + *

                + * This chronlogy is being retained for those who want a same effect + * replacement for the Sun class. It is hoped that community support will + * enable a more accurate chronology for Thailand, to be developed. + *

                * BuddhistChronology is thread-safe and immutable. * * @author Stephen Colebourne @@ -87,15 +57,18 @@ /** * Constant value for 'Buddhist Era', equivalent to the value returned - * for AD/CE. + * for AD/CE. Note that this differs from the constant in BuddhistCalendar. */ public static final int BE = DateTimeConstants.CE; + /** A singleton era field. */ + private static final DateTimeField ERA_FIELD = new BasicSingleEraDateTimeField("BE"); + /** Number of years difference in calendars. */ private static final int BUDDHIST_OFFSET = 543; /** Cache of zone to chronology */ - private static final Map cCache = new HashMap(); + private static final Map cCache = new HashMap(); /** UTC instance of the chronology */ private static final BuddhistChronology INSTANCE_UTC = getInstance(DateTimeZone.UTC); @@ -131,7 +104,7 @@ if (zone == null) { zone = DateTimeZone.getDefault(); } - BuddhistChronology chrono = (BuddhistChronology) cCache.get(zone); + BuddhistChronology chrono = cCache.get(zone); if (chrono == null) { // First create without a lower limit. chrono = new BuddhistChronology(GJChronology.getInstance(zone, null), null); @@ -190,6 +163,27 @@ return getInstance(zone); } + /** + * Checks if this chronology instance equals another. + * + * @param obj the object to compare to + * @return true if equal + * @since 1.6 + */ + public boolean equals(Object obj) { + return super.equals(obj); + } + + /** + * A suitable hash code for the chronology. + * + * @return the hash code + * @since 1.6 + */ + public int hashCode() { + return "Buddhist".hashCode() * 11 + getZone().hashCode(); + } + // Output //----------------------------------------------------------------------- /** @@ -208,15 +202,20 @@ protected void assemble(Fields fields) { if (getParam() == null) { + // julian chrono removed zero, but we need to put it back DateTimeField field = fields.year; - fields.year = new OffsetDateTimeField(field, BUDDHIST_OFFSET); + fields.year = new OffsetDateTimeField( + new SkipUndoDateTimeField(this, field), BUDDHIST_OFFSET); + // one era, so yearOfEra is the same field = fields.yearOfEra; - fields.yearOfEra = new OffsetDateTimeField( - fields.year, DateTimeFieldType.yearOfEra(), BUDDHIST_OFFSET); + fields.yearOfEra = new DelegatedDateTimeField( + fields.year, DateTimeFieldType.yearOfEra()); + // julian chrono removed zero, but we need to put it back field = fields.weekyear; - fields.weekyear = new OffsetDateTimeField(field, BUDDHIST_OFFSET); + fields.weekyear = new OffsetDateTimeField( + new SkipUndoDateTimeField(this, field), BUDDHIST_OFFSET); field = new OffsetDateTimeField(fields.yearOfEra, 99); fields.centuryOfEra = new DividedDateTimeField( @@ -232,7 +231,7 @@ fields.weekyearOfCentury = new OffsetDateTimeField( field, DateTimeFieldType.weekyearOfCentury(), 1); - fields.era = BuddhistEraDateTimeField.INSTANCE; + fields.era = ERA_FIELD; } } Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/chrono/BuddhistEraDateTimeField.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/joda-time/org/joda/time/chrono/CopticChronology.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/CopticChronology.java (.../CopticChronology.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/CopticChronology.java (.../CopticChronology.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -59,11 +21,9 @@ import org.joda.time.Chronology; import org.joda.time.DateTime; import org.joda.time.DateTimeConstants; +import org.joda.time.DateTimeField; import org.joda.time.DateTimeZone; -import org.joda.time.DurationField; -import org.joda.time.DurationFieldType; -import org.joda.time.field.FieldUtils; -import org.joda.time.field.PreciseDurationField; +import org.joda.time.field.SkipDateTimeField; /** * Implements the Coptic calendar system, which defines every fourth year as @@ -75,6 +35,11 @@ * Coptic years do not begin at the same time as Julian years. This chronology * is not proleptic, as it does not allow dates before the first Coptic year. *

                + * This implementation defines a day as midnight to midnight exactly as per + * the ISO chronology. Some references indicate that a coptic day starts at + * sunset on the previous ISO day, but this has not been confirmed and is not + * implemented. + *

                * CopticChronology is thread-safe and immutable. * * @see Wikipedia @@ -83,7 +48,7 @@ * @author Brian S O'Neill * @since 1.0 */ -public final class CopticChronology extends BaseGJChronology { +public final class CopticChronology extends BasicFixedMonthChronology { /** Serialization lock */ private static final long serialVersionUID = -5972804258688333942L; @@ -94,26 +59,26 @@ */ public static final int AM = DateTimeConstants.CE; - private static final long MILLIS_PER_YEAR = - (long) (365.25 * DateTimeConstants.MILLIS_PER_DAY); + /** A singleton era field. */ + private static final DateTimeField ERA_FIELD = new BasicSingleEraDateTimeField("AM"); - private static final long MILLIS_PER_MONTH = - (long) (365.25 * DateTimeConstants.MILLIS_PER_DAY / 12); + /** The lowest year that can be fully supported. */ + private static final int MIN_YEAR = -292269337; - private static final DurationField cMonthsField; + /** The highest year that can be fully supported. */ + private static final int MAX_YEAR = 292272708; - /** Singleton instance of a UTC CopticChronology */ - private static final CopticChronology INSTANCE_UTC; - /** Cache of zone to chronology arrays */ - private static final Map cCache = new HashMap(); + private static final Map cCache = new HashMap(); + /** Singleton instance of a UTC CopticChronology */ + private static final CopticChronology INSTANCE_UTC; static { - cMonthsField = new PreciseDurationField - (DurationFieldType.months(), 30L * DateTimeConstants.MILLIS_PER_DAY); + // init after static fields INSTANCE_UTC = getInstance(DateTimeZone.UTC); } + //----------------------------------------------------------------------- /** * Gets an instance of the CopticChronology. * The time zone of the returned instance is UTC. @@ -156,7 +121,7 @@ } CopticChronology chrono; synchronized (cCache) { - CopticChronology[] chronos = (CopticChronology[]) cCache.get(zone); + CopticChronology[] chronos = cCache.get(zone); if (chronos == null) { chronos = new CopticChronology[7]; cCache.put(zone, chronos); @@ -189,20 +154,23 @@ // Constructors and instance variables //----------------------------------------------------------------------- - /** - * Restricted constructor + * Restricted constructor. */ CopticChronology(Chronology base, Object param, int minDaysInFirstWeek) { super(base, param, minDaysInFirstWeek); } /** - * Serialization singleton + * Serialization singleton. */ private Object readResolve() { Chronology base = getBase(); - return base == null ? getInstanceUTC() : getInstance(base.getZone()); + int minDays = getMinimumDaysInFirstWeek(); + minDays = (minDays == 0 ? 4 : minDays); // handle rename of BaseGJChronology + return base == null ? + getInstance(DateTimeZone.UTC, minDays) : + getInstance(base.getZone(), minDays); } // Conversion @@ -232,32 +200,7 @@ return getInstance(zone); } - long getDateMidnightMillis(int year, int monthOfYear, int dayOfMonth) - throws IllegalArgumentException - { - FieldUtils.verifyValueBounds("year", year, getMinYear(), getMaxYear()); - FieldUtils.verifyValueBounds("monthOfYear", monthOfYear, 1, 13); - - int dayLimit = (monthOfYear != 13) ? 30 : (isLeapYear(year) ? 6 : 5); - FieldUtils.verifyValueBounds("dayOfMonth", dayOfMonth, 1, dayLimit); - - long instant = getYearMillis(year); - - if (monthOfYear > 1) { - instant += (monthOfYear - 1) * 30L * DateTimeConstants.MILLIS_PER_DAY; - } - - if (dayOfMonth != 1) { - instant += (dayOfMonth - 1) * (long)DateTimeConstants.MILLIS_PER_DAY; - } - - return instant; - } - - boolean isLeapYear(int year) { - return (year & 3) == 3; - } - + //----------------------------------------------------------------------- long calculateFirstDayOfYearMillis(int year) { // Java epoch is 1970-01-01 Gregorian which is 1686-04-23 Coptic. // Calculate relative to the nearest leap year and account for the @@ -285,43 +228,33 @@ return millis + (365L - 112) * DateTimeConstants.MILLIS_PER_DAY; } + //----------------------------------------------------------------------- int getMinYear() { - // The lowest year that can be fully supported. - return -292269337; + return MIN_YEAR; } + //----------------------------------------------------------------------- int getMaxYear() { - // The highest year that can be fully supported. - return 292271022; + return MAX_YEAR; } - long getAverageMillisPerYear() { - return MILLIS_PER_YEAR; + //----------------------------------------------------------------------- + long getApproxMillisAtEpochDividedByTwo() { + return (1686L * MILLIS_PER_YEAR + 112L * DateTimeConstants.MILLIS_PER_DAY) / 2; } - long getAverageMillisPerMonth() { - return MILLIS_PER_MONTH; - } - - long getApproxMillisAtEpoch() { - return 1686L * MILLIS_PER_YEAR + 112L * DateTimeConstants.MILLIS_PER_DAY; - } - + //----------------------------------------------------------------------- protected void assemble(Fields fields) { if (getBase() == null) { super.assemble(fields); - fields.year = new CopticYearDateTimeField(this); - fields.years = fields.year.getDurationField(); - // Coptic, like Julian, has no year zero. - fields.year = new JulianChronology.NoYearZeroField(this, fields.year); - fields.weekyear = new JulianChronology.NoWeekyearZeroField(this, fields.weekyear); + fields.year = new SkipDateTimeField(this, fields.year); + fields.weekyear = new SkipDateTimeField(this, fields.weekyear); - fields.era = CopticEraDateTimeField.INSTANCE; - fields.months = cMonthsField; - fields.monthOfYear = new CopticMonthOfYearDateTimeField(this, cMonthsField); - fields.dayOfMonth = new CopticDayOfMonthDateTimeField(this, fields.days); + fields.era = ERA_FIELD; + fields.monthOfYear = new BasicMonthOfYearDateTimeField(this, 13); + fields.months = fields.monthOfYear.getDurationField(); } } Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/chrono/CopticDayOfMonthDateTimeField.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/chrono/CopticEraDateTimeField.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/chrono/CopticMonthOfYearDateTimeField.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/chrono/CopticYearDateTimeField.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/joda-time/org/joda/time/chrono/EthiopicChronology.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/chrono/EthiopicChronology.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/EthiopicChronology.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,259 @@ +/* + * Copyright 2001-2009 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.chrono; + +import java.util.HashMap; +import java.util.Map; + +import org.joda.time.Chronology; +import org.joda.time.DateTime; +import org.joda.time.DateTimeConstants; +import org.joda.time.DateTimeField; +import org.joda.time.DateTimeZone; +import org.joda.time.field.SkipDateTimeField; + +/** + * Implements the Ethiopic calendar system, which defines every fourth year as + * leap, much like the Julian calendar. The year is broken down into 12 months, + * each 30 days in length. An extra period at the end of the year is either 5 + * or 6 days in length. In this implementation, it is considered a 13th month. + *

                + * Year 1 in the Ethiopic calendar began on August 29, 8 CE (Julian), thus + * Ethiopic years do not begin at the same time as Julian years. This chronology + * is not proleptic, as it does not allow dates before the first Ethiopic year. + *

                + * This implementation defines a day as midnight to midnight exactly as per + * the ISO chronology. Some references indicate that a coptic day starts at + * sunset on the previous ISO day, but this has not been confirmed and is not + * implemented. + *

                + * EthiopicChronology is thread-safe and immutable. + * + * @see Wikipedia + * + * @author Brian S O'Neill + * @author Stephen Colebourne + * @since 1.2 + */ +public final class EthiopicChronology extends BasicFixedMonthChronology { + + /** Serialization lock */ + private static final long serialVersionUID = -5972804258688333942L; + + /** + * Constant value for 'Ethiopean Era', equivalent + * to the value returned for AD/CE. + */ + public static final int EE = DateTimeConstants.CE; + + /** A singleton era field. */ + private static final DateTimeField ERA_FIELD = new BasicSingleEraDateTimeField("EE"); + + /** The lowest year that can be fully supported. */ + private static final int MIN_YEAR = -292269337; + + /** The highest year that can be fully supported. */ + private static final int MAX_YEAR = 292272984; + + /** Cache of zone to chronology arrays */ + private static final Map cCache = new HashMap(); + + /** Singleton instance of a UTC EthiopicChronology */ + private static final EthiopicChronology INSTANCE_UTC; + static { + // init after static fields + INSTANCE_UTC = getInstance(DateTimeZone.UTC); + } + + //----------------------------------------------------------------------- + /** + * Gets an instance of the EthiopicChronology. + * The time zone of the returned instance is UTC. + * + * @return a singleton UTC instance of the chronology + */ + public static EthiopicChronology getInstanceUTC() { + return INSTANCE_UTC; + } + + /** + * Gets an instance of the EthiopicChronology in the default time zone. + * + * @return a chronology in the default time zone + */ + public static EthiopicChronology getInstance() { + return getInstance(DateTimeZone.getDefault(), 4); + } + + /** + * Gets an instance of the EthiopicChronology in the given time zone. + * + * @param zone the time zone to get the chronology in, null is default + * @return a chronology in the specified time zone + */ + public static EthiopicChronology getInstance(DateTimeZone zone) { + return getInstance(zone, 4); + } + + /** + * Gets an instance of the EthiopicChronology in the given time zone. + * + * @param zone the time zone to get the chronology in, null is default + * @param minDaysInFirstWeek minimum number of days in first week of the year; default is 4 + * @return a chronology in the specified time zone + */ + public static EthiopicChronology getInstance(DateTimeZone zone, int minDaysInFirstWeek) { + if (zone == null) { + zone = DateTimeZone.getDefault(); + } + EthiopicChronology chrono; + synchronized (cCache) { + EthiopicChronology[] chronos = cCache.get(zone); + if (chronos == null) { + chronos = new EthiopicChronology[7]; + cCache.put(zone, chronos); + } + try { + chrono = chronos[minDaysInFirstWeek - 1]; + } catch (ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException + ("Invalid min days in first week: " + minDaysInFirstWeek); + } + if (chrono == null) { + if (zone == DateTimeZone.UTC) { + // First create without a lower limit. + chrono = new EthiopicChronology(null, null, minDaysInFirstWeek); + // Impose lower limit and make another EthiopicChronology. + DateTime lowerLimit = new DateTime(1, 1, 1, 0, 0, 0, 0, chrono); + chrono = new EthiopicChronology + (LimitChronology.getInstance(chrono, lowerLimit, null), + null, minDaysInFirstWeek); + } else { + chrono = getInstance(DateTimeZone.UTC, minDaysInFirstWeek); + chrono = new EthiopicChronology + (ZonedChronology.getInstance(chrono, zone), null, minDaysInFirstWeek); + } + chronos[minDaysInFirstWeek - 1] = chrono; + } + } + return chrono; + } + + // Constructors and instance variables + //----------------------------------------------------------------------- + /** + * Restricted constructor. + */ + EthiopicChronology(Chronology base, Object param, int minDaysInFirstWeek) { + super(base, param, minDaysInFirstWeek); + } + + /** + * Serialization singleton. + */ + private Object readResolve() { + Chronology base = getBase(); + return base == null ? + getInstance(DateTimeZone.UTC, getMinimumDaysInFirstWeek()) : + getInstance(base.getZone(), getMinimumDaysInFirstWeek()); + } + + // Conversion + //----------------------------------------------------------------------- + /** + * Gets the Chronology in the UTC time zone. + * + * @return the chronology in UTC + */ + public Chronology withUTC() { + return INSTANCE_UTC; + } + + /** + * Gets the Chronology in a specific time zone. + * + * @param zone the zone to get the chronology in, null is default + * @return the chronology + */ + public Chronology withZone(DateTimeZone zone) { + if (zone == null) { + zone = DateTimeZone.getDefault(); + } + if (zone == getZone()) { + return this; + } + return getInstance(zone); + } + + //----------------------------------------------------------------------- + long calculateFirstDayOfYearMillis(int year) { + // Java epoch is 1970-01-01 Gregorian which is 1962-04-23 Ethiopic. + // Calculate relative to the nearest leap year and account for the + // difference later. + + int relativeYear = year - 1963; + int leapYears; + if (relativeYear <= 0) { + // Add 3 before shifting right since /4 and >>2 behave differently + // on negative numbers. + leapYears = (relativeYear + 3) >> 2; + } else { + leapYears = relativeYear >> 2; + // For post 1963 an adjustment is needed as jan1st is before leap day + if (!isLeapYear(year)) { + leapYears++; + } + } + + long millis = (relativeYear * 365L + leapYears) + * (long)DateTimeConstants.MILLIS_PER_DAY; + + // Adjust to account for difference between 1963-01-01 and 1962-04-23. + + return millis + (365L - 112) * DateTimeConstants.MILLIS_PER_DAY; + } + + //----------------------------------------------------------------------- + int getMinYear() { + return MIN_YEAR; + } + + //----------------------------------------------------------------------- + int getMaxYear() { + return MAX_YEAR; + } + + //----------------------------------------------------------------------- + long getApproxMillisAtEpochDividedByTwo() { + return (1962L * MILLIS_PER_YEAR + 112L * DateTimeConstants.MILLIS_PER_DAY) / 2; + } + + //----------------------------------------------------------------------- + protected void assemble(Fields fields) { + if (getBase() == null) { + super.assemble(fields); + + // Ethiopic, like Julian, has no year zero. + fields.year = new SkipDateTimeField(this, fields.year); + fields.weekyear = new SkipDateTimeField(this, fields.weekyear); + + fields.era = ERA_FIELD; + fields.monthOfYear = new BasicMonthOfYearDateTimeField(this, 13); + fields.months = fields.monthOfYear.getDurationField(); + } + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/chrono/GJChronology.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/GJChronology.java (.../GJChronology.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/GJChronology.java (.../GJChronology.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -63,11 +25,13 @@ import org.joda.time.DateTimeUtils; import org.joda.time.DateTimeZone; import org.joda.time.DurationField; +import org.joda.time.IllegalFieldValueException; import org.joda.time.Instant; import org.joda.time.ReadableInstant; +import org.joda.time.ReadablePartial; import org.joda.time.field.BaseDateTimeField; import org.joda.time.field.DecoratedDurationField; -import org.joda.time.format.DateTimePrinter; +import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; /** @@ -141,7 +105,7 @@ static final Instant DEFAULT_CUTOVER = new Instant(-12219292800000L); /** Cache of zone to chronology list */ - private static final Map cCache = new HashMap(); + private static final Map> cCache = new HashMap>(); /** * Factory method returns instances of the default GJ cutover @@ -232,13 +196,13 @@ GJChronology chrono; - ArrayList chronos = (ArrayList)cCache.get(zone); + ArrayList chronos = cCache.get(zone); if (chronos == null) { - chronos = new ArrayList(2); + chronos = new ArrayList(2); cCache.put(zone, chronos); } else { for (int i=chronos.size(); --i>=0; ) { - chrono = (GJChronology)chronos.get(i); + chrono = chronos.get(i); if (minDaysInFirstWeek == chrono.getMinimumDaysInFirstWeek() && cutoverInstant.equals(chrono.getGregorianCutover())) { @@ -396,9 +360,22 @@ } // Assume date is Gregorian. - long instant = iGregorianChronology.getDateTimeMillis - (year, monthOfYear, dayOfMonth, - hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond); + long instant; + try { + instant = iGregorianChronology.getDateTimeMillis + (year, monthOfYear, dayOfMonth, + hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond); + } catch (IllegalFieldValueException ex) { + if (monthOfYear != 2 || dayOfMonth != 29) { + throw ex; + } + instant = iGregorianChronology.getDateTimeMillis + (year, monthOfYear, 28, + hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond); + if (instant >= iCutoverMillis) { + throw ex; + } + } if (instant < iCutoverMillis) { // Maybe it's Julian. instant = iJulianChronology.getDateTimeMillis @@ -429,6 +406,28 @@ return iGregorianChronology.getMinimumDaysInFirstWeek(); } + /** + * Checks if this chronology instance equals another. + * + * @param obj the object to compare to + * @return true if equal + * @since 1.6 + */ + public boolean equals(Object obj) { + return super.equals(obj); + } + + /** + * A suitable hash code for the chronology. + * + * @return the hash code + * @since 1.6 + */ + public int hashCode() { + return "GJ".hashCode() * 11 + iJulianChronology.hashCode() + + iGregorianChronology.hashCode() + iCutoverInstant.hashCode(); + } + // Output //----------------------------------------------------------------------- /** @@ -444,13 +443,13 @@ if (iCutoverMillis != DEFAULT_CUTOVER.getMillis()) { sb.append(",cutover="); - DateTimePrinter printer; + DateTimeFormatter printer; if (withUTC().dayOfYear().remainder(iCutoverMillis) == 0) { - printer = ISODateTimeFormat.getInstance().date(); + printer = ISODateTimeFormat.date(); } else { - printer = ISODateTimeFormat.getInstance().dateTime(); + printer = ISODateTimeFormat.dateTime(); } - printer.printTo(sb, iCutoverMillis, withUTC()); + printer.withChronology(withUTC()).printTo(sb, iCutoverMillis); } if (getMinimumDaysInFirstWeek() != 4) { @@ -516,7 +515,6 @@ // These fields just require basic cutover support. { fields.era = new CutoverField(julian.era(), fields.era, iCutoverMillis); - fields.dayOfMonth = new CutoverField(julian.dayOfMonth(), fields.dayOfMonth, iCutoverMillis); } // DayOfYear and weekOfWeekyear require special handling since cutover @@ -562,6 +560,15 @@ julian.weekyearOfCentury(), fields.weekyearOfCentury, fields.weekyears, iCutoverMillis); fields.weekyears = fields.weekyear.getDurationField(); } + + // These fields require basic cutover support, except they must link to + // imprecise durations. + { + CutoverField cf = new CutoverField + (julian.dayOfMonth(), fields.dayOfMonth, iCutoverMillis); + cf.iRangeDurationField = fields.months; + fields.dayOfMonth = cf; + } } long julianToGregorianByYear(long instant) { @@ -594,6 +601,7 @@ final boolean iConvertByWeekyear; protected DurationField iDurationField; + protected DurationField iRangeDurationField; /** * @param julianField field from the chronology used before the cutover instant @@ -620,6 +628,12 @@ // Although average length of Julian and Gregorian years differ, // use the Gregorian duration field because it is more accurate. iDurationField = gregorianField.getDurationField(); + + DurationField rangeField = gregorianField.getRangeDurationField(); + if (rangeField == null) { + rangeField = julianField.getRangeDurationField(); + } + iRangeDurationField = rangeField; } public boolean isLenient() { @@ -642,6 +656,10 @@ } } + public String getAsText(int fieldValue, Locale locale) { + return iGregorianField.getAsText(fieldValue, locale); + } + public String getAsShortText(long instant, Locale locale) { if (instant >= iCutover) { return iGregorianField.getAsShortText(instant, locale); @@ -650,6 +668,10 @@ } } + public String getAsShortText(int fieldValue, Locale locale) { + return iGregorianField.getAsShortText(fieldValue, locale); + } + public long add(long instant, int value) { return iGregorianField.add(instant, value); } @@ -658,6 +680,24 @@ return iGregorianField.add(instant, value); } + public int[] add(ReadablePartial partial, int fieldIndex, int[] values, int valueToAdd) { + // overridden as superclass algorithm can't handle + // 2004-02-29 + 48 months -> 2008-02-29 type dates + if (valueToAdd == 0) { + return values; + } + if (DateTimeUtils.isContiguous(partial)) { + long instant = 0L; + for (int i = 0, isize = partial.size(); i < isize; i++) { + instant = partial.getFieldType(i).getField(GJChronology.this).set(instant, values[i]); + } + instant = add(instant, valueToAdd); + return GJChronology.this.get(partial, instant); + } else { + return super.add(partial, fieldIndex, values, valueToAdd); + } + } + public int getDifference(long minuendInstant, long subtrahendInstant) { return iGregorianField.getDifference(minuendInstant, subtrahendInstant); } @@ -676,8 +716,8 @@ } // Verify that new value stuck. if (get(instant) != value) { - throw new IllegalArgumentException - ("Illegal value for " + iGregorianField.getName() + ": " + value); + throw new IllegalFieldValueException + (iGregorianField.getType(), Integer.valueOf(value), null, null); } } } else { @@ -689,8 +729,8 @@ } // Verify that new value stuck. if (get(instant) != value) { - throw new IllegalArgumentException - ("Illegal value for " + iJulianField.getName() + ": " + value); + throw new IllegalFieldValueException + (iJulianField.getType(), Integer.valueOf(value), null, null); } } } @@ -725,11 +765,7 @@ } public DurationField getRangeDurationField() { - DurationField rangeField = iGregorianField.getRangeDurationField(); - if (rangeField == null) { - rangeField = iJulianField.getRangeDurationField(); - } - return rangeField; + return iRangeDurationField; } public boolean isLeap(long instant) { @@ -758,7 +794,15 @@ // identical. Choose Julian to tighten up the year limits. return iJulianField.getMinimumValue(); } - + + public int getMinimumValue(ReadablePartial partial) { + return iJulianField.getMinimumValue(partial); + } + + public int getMinimumValue(ReadablePartial partial, int[] values) { + return iJulianField.getMinimumValue(partial, values); + } + public int getMinimumValue(long instant) { if (instant < iCutover) { return iJulianField.getMinimumValue(instant); @@ -799,6 +843,23 @@ return max; } + public int getMaximumValue(ReadablePartial partial) { + long instant = GJChronology.getInstanceUTC().set(partial, 0L); + return getMaximumValue(instant); + } + + public int getMaximumValue(ReadablePartial partial, int[] values) { + Chronology chrono = GJChronology.getInstanceUTC(); + long instant = 0L; + for (int i = 0, isize = partial.size(); i < isize; i++) { + DateTimeField field = partial.getFieldType(i).getField(chrono); + if (values[i] <= field.getMaximumValue(instant)) { + instant = field.set(instant, values[i]); + } + } + return getMaximumValue(instant); + } + public long roundFloor(long instant) { if (instant >= iCutover) { instant = iGregorianField.roundFloor(instant); Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/chrono/GJDayOfMonthDateTimeField.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/joda-time/org/joda/time/chrono/GJDayOfWeekDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/GJDayOfWeekDateTimeField.java (.../GJDayOfWeekDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/GJDayOfWeekDateTimeField.java (.../GJDayOfWeekDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -74,12 +36,12 @@ /** Serialization version */ private static final long serialVersionUID = -3857947176719041436L; - private final BaseGJChronology iChronology; + private final BasicChronology iChronology; /** * Restricted constructor. */ - GJDayOfWeekDateTimeField(BaseGJChronology chronology, DurationField days) { + GJDayOfWeekDateTimeField(BasicChronology chronology, DurationField days) { super(DateTimeFieldType.dayOfWeek(), days); iChronology = chronology; } @@ -101,7 +63,7 @@ * @param locale the locale to use * @return the day of the week, such as 'Monday' */ - protected String getAsText(int fieldValue, Locale locale) { + public String getAsText(int fieldValue, Locale locale) { return GJLocaleSymbols.forLocale(locale).dayOfWeekValueToText(fieldValue); } @@ -112,7 +74,7 @@ * @param locale the locale to use * @return the day of the week, such as 'Mon' */ - protected String getAsShortText(int fieldValue, Locale locale) { + public String getAsShortText(int fieldValue, Locale locale) { return GJLocaleSymbols.forLocale(locale).dayOfWeekValueToShortText(fieldValue); } Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/chrono/GJDayOfYearDateTimeField.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/joda-time/org/joda/time/chrono/GJEraDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/GJEraDateTimeField.java (.../GJEraDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/GJEraDateTimeField.java (.../GJEraDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -68,20 +30,19 @@ * * @author Stephen Colebourne * @author Brian S O'Neill - * @version 1.0 * @since 1.0 */ final class GJEraDateTimeField extends BaseDateTimeField { /** Serialization version */ private static final long serialVersionUID = 4240986525305515528L; - private final BaseGJChronology iChronology; + private final BasicChronology iChronology; /** * Restricted constructor */ - GJEraDateTimeField(BaseGJChronology chronology) { + GJEraDateTimeField(BasicChronology chronology) { super(DateTimeFieldType.era()); iChronology = chronology; } @@ -103,7 +64,7 @@ } } - protected String getAsText(int fieldValue, Locale locale) { + public String getAsText(int fieldValue, Locale locale) { return GJLocaleSymbols.forLocale(locale).eraValueToText(fieldValue); } Index: 3rdParty_sources/joda-time/org/joda/time/chrono/GJLocaleSymbols.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/GJLocaleSymbols.java (.../GJLocaleSymbols.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/GJLocaleSymbols.java (.../GJLocaleSymbols.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,83 +1,54 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; import java.lang.ref.WeakReference; import java.text.DateFormatSymbols; -import java.util.WeakHashMap; import java.util.Locale; +import java.util.TreeMap; +import java.util.WeakHashMap; +import org.joda.time.DateTimeFieldType; +import org.joda.time.DateTimeUtils; +import org.joda.time.IllegalFieldValueException; + /** * Utility class used by a few of the GJDateTimeFields. * * @author Brian S O'Neill + * @since 1.0 */ class GJLocaleSymbols { private static final int FAST_CACHE_SIZE = 64; private static final GJLocaleSymbols[] cFastCache = new GJLocaleSymbols[FAST_CACHE_SIZE]; - private static WeakHashMap cCache = new WeakHashMap(); + private static WeakHashMap cCache = new WeakHashMap(); public static GJLocaleSymbols forLocale(Locale locale) { + if (locale == null) { + locale = Locale.getDefault(); + } int index = System.identityHashCode(locale) & (FAST_CACHE_SIZE - 1); GJLocaleSymbols symbols = cFastCache[index]; if (symbols != null && symbols.iLocale.get() == locale) { return symbols; } synchronized (cCache) { - symbols = (GJLocaleSymbols) cCache.get(locale); + symbols = cCache.get(locale); if (symbols == null) { symbols = new GJLocaleSymbols(locale); cCache.put(locale, symbols); @@ -103,6 +74,21 @@ return a; } + private static void addSymbols(TreeMap map, String[] symbols, Integer[] integers) { + for (int i=symbols.length; --i>=0; ) { + String symbol = symbols[i]; + if (symbol != null) { + map.put(symbol, integers[i]); + } + } + } + + private static void addNumerals(TreeMap map, int start, int end, Integer[] integers) { + for (int i=start; i<=end; i++) { + map.put(String.valueOf(i).intern(), integers[i]); + } + } + private static int maxLength(String[] a) { int max = 0; for (int i=a.length; --i>=0; ) { @@ -117,7 +103,7 @@ return max; } - private final WeakReference iLocale; + private final WeakReference iLocale; private final String[] iEras; private final String[] iDaysOfWeek; @@ -126,29 +112,57 @@ private final String[] iShortMonths; private final String[] iHalfday; + private final TreeMap iParseEras; + private final TreeMap iParseDaysOfWeek; + private final TreeMap iParseMonths; + private final int iMaxEraLength; private final int iMaxDayOfWeekLength; private final int iMaxShortDayOfWeekLength; private final int iMaxMonthLength; private final int iMaxShortMonthLength; private final int iMaxHalfdayLength; + /** + * @param locale must not be null + */ private GJLocaleSymbols(Locale locale) { - if (locale == null) { - locale = Locale.getDefault(); - } - - iLocale = new WeakReference(locale); - - DateFormatSymbols dfs = new DateFormatSymbols(locale); - + iLocale = new WeakReference(locale); + + DateFormatSymbols dfs = DateTimeUtils.getDateFormatSymbols(locale); + iEras = dfs.getEras(); iDaysOfWeek = realignDaysOfWeek(dfs.getWeekdays()); iShortDaysOfWeek = realignDaysOfWeek(dfs.getShortWeekdays()); iMonths = realignMonths(dfs.getMonths()); iShortMonths = realignMonths(dfs.getShortMonths()); iHalfday = dfs.getAmPmStrings(); + Integer[] integers = new Integer[13]; + for (int i=0; i<13; i++) { + integers[i] = Integer.valueOf(i); + } + + iParseEras = new TreeMap(String.CASE_INSENSITIVE_ORDER); + addSymbols(iParseEras, iEras, integers); + if ("en".equals(locale.getLanguage())) { + // Include support for parsing "BCE" and "CE" if the language is + // English. At some point Joda-Time will need an independent set of + // localized symbols and not depend on java.text.DateFormatSymbols. + iParseEras.put("BCE", integers[0]); + iParseEras.put("CE", integers[1]); + } + + iParseDaysOfWeek = new TreeMap(String.CASE_INSENSITIVE_ORDER); + addSymbols(iParseDaysOfWeek, iDaysOfWeek, integers); + addSymbols(iParseDaysOfWeek, iShortDaysOfWeek, integers); + addNumerals(iParseDaysOfWeek, 1, 7, integers); + + iParseMonths = new TreeMap(String.CASE_INSENSITIVE_ORDER); + addSymbols(iParseMonths, iMonths, integers); + addSymbols(iParseMonths, iShortMonths, integers); + addNumerals(iParseMonths, 1, 12, integers); + iMaxEraLength = maxLength(iEras); iMaxDayOfWeekLength = maxLength(iDaysOfWeek); iMaxShortDayOfWeekLength = maxLength(iShortDaysOfWeek); @@ -162,13 +176,11 @@ } public int eraTextToValue(String text) { - String[] eras = iEras; - for (int i=eras.length; --i>=0; ) { - if (eras[i].equalsIgnoreCase(text)) { - return i; - } + Integer era = iParseEras.get(text); + if (era != null) { + return era.intValue(); } - throw new IllegalArgumentException("Illegal era text: " + text); + throw new IllegalFieldValueException(DateTimeFieldType.era(), text); } public int getEraMaxTextLength() { @@ -184,27 +196,11 @@ } public int monthOfYearTextToValue(String text) { - String[] months = iMonths; - for (int i=months.length; --i>=1; ) { - if (months[i].equalsIgnoreCase(text)) { - return i; - } + Integer month = iParseMonths.get(text); + if (month != null) { + return month.intValue(); } - months = iShortMonths; - for (int i=months.length; --i>=1; ) { - if (months[i].equalsIgnoreCase(text)) { - return i; - } - } - try { - int month = Integer.parseInt(text); - if (month >= 1 && month <= 12) { - return month; - } - } catch (NumberFormatException ex) { - // ignore - } - throw new IllegalArgumentException("Illegal monthOfYear text: " + text); + throw new IllegalFieldValueException(DateTimeFieldType.monthOfYear(), text); } public int getMonthMaxTextLength() { @@ -224,27 +220,11 @@ } public int dayOfWeekTextToValue(String text) { - String[] daysOfWeek = iDaysOfWeek; - for (int i=daysOfWeek.length; --i>=1; ) { - if (daysOfWeek[i].equalsIgnoreCase(text)) { - return i; - } + Integer day = iParseDaysOfWeek.get(text); + if (day != null) { + return day.intValue(); } - daysOfWeek = iShortDaysOfWeek; - for (int i=daysOfWeek.length; --i>=1; ) { - if (daysOfWeek[i].equalsIgnoreCase(text)) { - return i; - } - } - try { - int day = Integer.parseInt(text); - if (day >= 1 && day <= 7) { - return day; - } - } catch (NumberFormatException ex) { - // ignore - } - throw new IllegalArgumentException("Illegal dayOfWeek text: " + text); + throw new IllegalFieldValueException(DateTimeFieldType.dayOfWeek(), text); } public int getDayOfWeekMaxTextLength() { @@ -266,7 +246,7 @@ return i; } } - throw new IllegalArgumentException("Illegal halfday text: " + text); + throw new IllegalFieldValueException(DateTimeFieldType.halfdayOfDay(), text); } public int getHalfdayMaxTextLength() { Index: 3rdParty_sources/joda-time/org/joda/time/chrono/GJMonthOfYearDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/GJMonthOfYearDateTimeField.java (.../GJMonthOfYearDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/GJMonthOfYearDateTimeField.java (.../GJMonthOfYearDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,389 +1,65 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; import java.util.Locale; -import org.joda.time.DateTimeConstants; -import org.joda.time.DateTimeFieldType; -import org.joda.time.DurationField; -import org.joda.time.field.FieldUtils; -import org.joda.time.field.ImpreciseDateTimeField; - /** * Provides time calculations for the month of the year component of time. * * @author Guy Allard * @author Stephen Colebourne * @author Brian S O'Neill - * @version 1.0 * @since 1.0 */ -final class GJMonthOfYearDateTimeField extends ImpreciseDateTimeField { +final class GJMonthOfYearDateTimeField extends BasicMonthOfYearDateTimeField { /** Serialization version */ private static final long serialVersionUID = -4748157875845286249L; - private static final int MIN = DateTimeConstants.JANUARY; - private static final int MAX = DateTimeConstants.DECEMBER; - - private final BaseGJChronology iChronology; - /** * Restricted constructor */ - GJMonthOfYearDateTimeField(BaseGJChronology chronology) { - super(DateTimeFieldType.monthOfYear(), chronology.getAverageMillisPerMonth()); - iChronology = chronology; + GJMonthOfYearDateTimeField(BasicChronology chronology) { + super(chronology, 2); } - public boolean isLenient() { - return false; - } - - /** - * Get the Month component of the specified time instant. - * - * @see org.joda.time.DateTimeField#get(long) - * @see org.joda.time.ReadableDateTime#getMonthOfYear() - * @param instant the time instant in millis to query. - * @return the month extracted from the input. - */ - public int get(long instant) { - return iChronology.getMonthOfYear(instant); - } - - protected String getAsText(int fieldValue, Locale locale) { + //----------------------------------------------------------------------- + public String getAsText(int fieldValue, Locale locale) { return GJLocaleSymbols.forLocale(locale).monthOfYearValueToText(fieldValue); } - protected String getAsShortText(int fieldValue, Locale locale) { + //----------------------------------------------------------------------- + public String getAsShortText(int fieldValue, Locale locale) { return GJLocaleSymbols.forLocale(locale).monthOfYearValueToShortText(fieldValue); } - /** - * Add the specified month to the specified time instant. - * The amount added may be negative.

                - * If the new month has less total days than the specified - * day of the month, this value is coerced to the nearest - * sane value. e.g.

                - * 07-31 - (1 month) = 06-30

                - * 03-31 - (1 month) = 02-28 or 02-29 depending

                - * - * @see org.joda.time.DateTimeField#add - * @see org.joda.time.ReadWritableDateTime#addMonths(int) - * @param instant the time instant in millis to update. - * @param months the months to add (can be negative). - * @return the updated time instant. - */ - public long add(long instant, int months) { - if (months == 0) { - return instant; // the easy case - } - // - // Save time part first. - // - long timePart = iChronology.getMillisOfDay(instant); - // - // - // Get this year and month. - // - int thisYear = iChronology.getYear(instant); - int thisMonth = iChronology.getMonthOfYear(instant, thisYear); - // ---------------------------------------------------------- - // - // Do not refactor without careful consideration. - // Order of calculation is important. - // - int yearToUse; - // Initially, monthToUse is zero-based - int monthToUse = thisMonth - 1 + months; - if (monthToUse >= 0) { - yearToUse = thisYear + (monthToUse / MAX); - monthToUse = (monthToUse % MAX) + 1; - } else { - yearToUse = thisYear + (monthToUse / MAX) - 1; - monthToUse = Math.abs(monthToUse); - int remMonthToUse = monthToUse % MAX; - // Take care of the boundary condition - if (remMonthToUse == 0) { - remMonthToUse = MAX; - } - monthToUse = MAX - remMonthToUse + 1; - // Take care of the boundary condition - if (monthToUse == 1) { - yearToUse += 1; - } - } - // End of do not refactor. - // ---------------------------------------------------------- - - // - // Quietly force DOM to nearest sane value. - // - int dayToUse = iChronology.getDayOfMonth(instant, thisYear, thisMonth); - int maxDay = iChronology.getDaysInYearMonth(yearToUse, monthToUse); - if (dayToUse > maxDay) { - dayToUse = maxDay; - } - // - // get proper date part, and return result - // - long datePart = - iChronology.getYearMonthDayMillis(yearToUse, monthToUse, dayToUse); - return datePart + timePart; - } - - public long add(long instant, long months) { - int i_months = (int)months; - if (i_months == months) { - return add(instant, i_months); - } - - // Copied from add(long, int) and modified slightly: - - long timePart = iChronology.getMillisOfDay(instant); - - int thisYear = iChronology.getYear(instant); - int thisMonth = iChronology.getMonthOfYear(instant, thisYear); - - long yearToUse; - long monthToUse = thisMonth - 1 + months; - if (monthToUse >= 0) { - yearToUse = thisYear + (monthToUse / MAX); - monthToUse = (monthToUse % MAX) + 1; - } else { - yearToUse = thisYear + (monthToUse / MAX) - 1; - monthToUse = Math.abs(monthToUse); - int remMonthToUse = (int)(monthToUse % MAX); - if (remMonthToUse == 0) { - remMonthToUse = MAX; - } - monthToUse = MAX - remMonthToUse + 1; - if (monthToUse == 1) { - yearToUse += 1; - } - } - - if (yearToUse < iChronology.getMinYear() || - yearToUse > iChronology.getMaxYear()) { - - throw new IllegalArgumentException - ("Magnitude of add amount is too large: " + months); - } - - int i_yearToUse = (int)yearToUse; - int i_monthToUse = (int)monthToUse; - - int dayToUse = iChronology.getDayOfMonth(instant, thisYear, thisMonth); - int maxDay = iChronology.getDaysInYearMonth(i_yearToUse, i_monthToUse); - if (dayToUse > maxDay) { - dayToUse = maxDay; - } - - long datePart = - iChronology.getYearMonthDayMillis(i_yearToUse, i_monthToUse, dayToUse); - return datePart + timePart; - } - - /** - * Add to the Month component of the specified time instant - * wrapping around within that component if necessary. - * - * @see org.joda.time.DateTimeField#addWrapField - * @param instant the time instant in millis to update. - * @param months the months to add (can be negative). - * @return the updated time instant. - */ - public long addWrapField(long instant, int months) { - return set(instant, FieldUtils.getWrappedValue(get(instant), months, MIN, MAX)); - } - - public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) { - if (minuendInstant < subtrahendInstant) { - return -getDifference(subtrahendInstant, minuendInstant); - } - - int minuendYear = iChronology.getYear(minuendInstant); - int minuendMonth = iChronology.getMonthOfYear(minuendInstant, minuendYear); - int subtrahendYear = iChronology.getYear(subtrahendInstant); - int subtrahendMonth = iChronology.getMonthOfYear(subtrahendInstant, subtrahendYear); - - long difference = (minuendYear - subtrahendYear) * 12L + minuendMonth - subtrahendMonth; - - // Before adjusting for remainder, account for special case of add - // where the day-of-month is forced to the nearest sane value. - int minuendDom = iChronology.getDayOfMonth - (minuendInstant, minuendYear, minuendMonth); - if (minuendDom == iChronology.getDaysInYearMonth(minuendYear, minuendMonth)) { - // Last day of the minuend month... - int subtrahendDom = iChronology.getDayOfMonth - (subtrahendInstant, subtrahendYear, subtrahendMonth); - if (subtrahendDom > minuendDom) { - // ...and day of subtrahend month is larger. - // Note: This works fine, but it ideally shouldn't invoke other - // fields from within a field. - subtrahendInstant = iChronology.dayOfMonth().set(subtrahendInstant, minuendDom); - } - } - - // Inlined remainder method to avoid duplicate calls. - long minuendRem = minuendInstant - - iChronology.getYearMonthMillis(minuendYear, minuendMonth); - long subtrahendRem = subtrahendInstant - - iChronology.getYearMonthMillis(subtrahendYear, subtrahendMonth); - - if (minuendRem < subtrahendRem) { - difference--; - } - - return difference; - } - - /** - * Set the Month component of the specified time instant.

                - * If the new month has less total days than the specified - * day of the month, this value is coerced to the nearest - * sane value. e.g.

                - * 07-31 to month 6 = 06-30

                - * 03-31 to month 2 = 02-28 or 02-29 depending

                - * - * @param instant the time instant in millis to update. - * @param month the month (1,12) to update the time to. - * @return the updated time instant. - * @throws IllegalArgumentException if month is invalid - */ - public long set(long instant, int month) { - FieldUtils.verifyValueBounds(this, month, MIN, MAX); - // - int thisYear = iChronology.getYear(instant); - // - int thisDom = iChronology.getDayOfMonth(instant, thisYear); - int maxDom = iChronology.getDaysInYearMonth(thisYear, month); - if (thisDom > maxDom) { - // Quietly force DOM to nearest sane value. - thisDom = maxDom; - } - // Return newly calculated millis value - return iChronology.getYearMonthDayMillis(thisYear, month, thisDom) + - iChronology.getMillisOfDay(instant); - } - - /** - * Convert the specified text and locale into a value. - * - * @param text the text to convert - * @param locale the locale to convert using - * @return the value extracted from the text - * @throws IllegalArgumentException if the text is invalid - */ + //----------------------------------------------------------------------- protected int convertText(String text, Locale locale) { return GJLocaleSymbols.forLocale(locale).monthOfYearTextToValue(text); } - public DurationField getRangeDurationField() { - return iChronology.years(); - } - - public boolean isLeap(long instant) { - int thisYear = iChronology.getYear(instant); - int thisMonth = iChronology.getMonthOfYear(instant, thisYear); - if (thisMonth != 2) { - return false; - } else { - return 29 == iChronology.getDaysInYearMonth(thisYear, thisMonth); - } - } - - public int getLeapAmount(long instant) { - return isLeap(instant) ? 1 : 0; - } - - public DurationField getLeapDurationField() { - return iChronology.days(); - } - - public int getMinimumValue() { - return MIN; - } - - public int getMaximumValue() { - return MAX; - } - + //----------------------------------------------------------------------- public int getMaximumTextLength(Locale locale) { return GJLocaleSymbols.forLocale(locale).getMonthMaxTextLength(); } + //----------------------------------------------------------------------- public int getMaximumShortTextLength(Locale locale) { return GJLocaleSymbols.forLocale(locale).getMonthMaxShortTextLength(); } - public long roundFloor(long instant) { - int year = iChronology.getYear(instant); - int month = iChronology.getMonthOfYear(instant, year); - return iChronology.getYearMonthMillis(year, month); - } - - public long remainder(long instant) { - return instant - roundFloor(instant); - } - - /** - * Serialization singleton - */ - private Object readResolve() { - return iChronology.monthOfYear(); - } } Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/chrono/GJWeekOfWeekyearDateTimeField.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/chrono/GJWeekyearDateTimeField.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/chrono/GJYearDateTimeField.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/joda-time/org/joda/time/chrono/GJYearOfEraDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/GJYearOfEraDateTimeField.java (.../GJYearOfEraDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/GJYearOfEraDateTimeField.java (.../GJYearOfEraDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -63,17 +25,18 @@ * Provides time calculations for the year of era component of time. * * @author Brian S O'Neill + * @since 1.0 */ final class GJYearOfEraDateTimeField extends DecoratedDateTimeField { private static final long serialVersionUID = -5961050944769862059L; - private final BaseGJChronology iChronology; + private final BasicChronology iChronology; /** * Restricted constructor. */ - GJYearOfEraDateTimeField(DateTimeField yearField, BaseGJChronology chronology) { + GJYearOfEraDateTimeField(DateTimeField yearField, BasicChronology chronology) { super(yearField, DateTimeFieldType.yearOfEra()); iChronology = chronology; } Index: 3rdParty_sources/joda-time/org/joda/time/chrono/GregorianChronology.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/GregorianChronology.java (.../GregorianChronology.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/GregorianChronology.java (.../GregorianChronology.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -80,7 +42,7 @@ * @author Brian S O'Neill * @since 1.0 */ -public final class GregorianChronology extends BaseGJChronology { +public final class GregorianChronology extends BasicGJChronology { /** Serialization lock */ private static final long serialVersionUID = -861407383323710522L; @@ -91,11 +53,19 @@ private static final long MILLIS_PER_MONTH = (long) (365.2425 * DateTimeConstants.MILLIS_PER_DAY / 12); + private static final int DAYS_0000_TO_1970 = 719527; + + /** The lowest year that can be fully supported. */ + private static final int MIN_YEAR = -292275054; + + /** The highest year that can be fully supported. */ + private static final int MAX_YEAR = 292278993; + /** Singleton instance of a UTC GregorianChronology */ private static final GregorianChronology INSTANCE_UTC; /** Cache of zone to chronology arrays */ - private static final Map cCache = new HashMap(); + private static final Map cCache = new HashMap(); static { INSTANCE_UTC = getInstance(DateTimeZone.UTC); @@ -143,7 +113,7 @@ } GregorianChronology chrono; synchronized (cCache) { - GregorianChronology[] chronos = (GregorianChronology[]) cCache.get(zone); + GregorianChronology[] chronos = cCache.get(zone); if (chronos == null) { chronos = new GregorianChronology[7]; cCache.put(zone, chronos); @@ -183,7 +153,11 @@ */ private Object readResolve() { Chronology base = getBase(); - return base == null ? getInstanceUTC() : getInstance(base.getZone()); + int minDays = getMinimumDaysInFirstWeek(); + minDays = (minDays == 0 ? 4 : minDays); // handle rename of BaseGJChronology + return base == null ? + getInstance(DateTimeZone.UTC, minDays) : + getInstance(base.getZone(), minDays); } // Conversion @@ -224,56 +198,47 @@ } long calculateFirstDayOfYearMillis(int year) { - // Calculate relative to 2000 as that is on a 400 year boundary - // and that makes the sum easier - int relativeYear = year - 2000; // Initial value is just temporary. - int leapYears = relativeYear / 100; - if (relativeYear <= 0) { + int leapYears = year / 100; + if (year < 0) { // Add 3 before shifting right since /4 and >>2 behave differently // on negative numbers. When the expression is written as - // (relativeYear / 4) - (relativeYear / 100) + (relativeYear / 400), + // (year / 4) - (year / 100) + (year / 400), // it works for both positive and negative values, except this optimization // eliminates two divisions. - leapYears = ((relativeYear + 3) >> 2) - leapYears + ((leapYears + 3) >> 2); + leapYears = ((year + 3) >> 2) - leapYears + ((leapYears + 3) >> 2) - 1; } else { - leapYears = (relativeYear >> 2) - leapYears + (leapYears >> 2); - // For post 2000 an adjustment is needed as jan1st is before leap day - if (!isLeapYear(year)) { - leapYears++; + leapYears = (year >> 2) - leapYears + (leapYears >> 2); + if (isLeapYear(year)) { + leapYears--; } } - - long millis = (relativeYear * 365L + leapYears) - * (long)DateTimeConstants.MILLIS_PER_DAY; - - // Previous line was reduced from this to eliminate a multiplication. - // millis = ((relativeYear - leapYears) * 365L + leapYears * 366) * MILLIS_PER_DAY; - // (x - y)*c + y*(c + 1) => x*c - y*c + y*c + y => x*c + y - - return millis + MILLIS_1970_TO_2000; + + return (year * 365L + (leapYears - DAYS_0000_TO_1970)) * DateTimeConstants.MILLIS_PER_DAY; } int getMinYear() { - // The lowest year that can be fully supported. - return -292275054; + return MIN_YEAR; } int getMaxYear() { - // The highest year that can be fully supported. - return 292277023; + return MAX_YEAR; } long getAverageMillisPerYear() { return MILLIS_PER_YEAR; } + long getAverageMillisPerYearDividedByTwo() { + return MILLIS_PER_YEAR / 2; + } + long getAverageMillisPerMonth() { return MILLIS_PER_MONTH; } - long getApproxMillisAtEpoch() { - return 1970L * MILLIS_PER_YEAR; + long getApproxMillisAtEpochDividedByTwo() { + return (1970L * MILLIS_PER_YEAR) / 2; } } Index: 3rdParty_sources/joda-time/org/joda/time/chrono/ISOChronology.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/ISOChronology.java (.../ISOChronology.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/ISOChronology.java (.../ISOChronology.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -98,7 +60,7 @@ private static final ISOChronology[] cFastCache; /** Cache of zone to chronology */ - private static final Map cCache = new HashMap(); + private static final Map cCache = new HashMap(); static { cFastCache = new ISOChronology[FAST_CACHE_SIZE]; INSTANCE_UTC = new ISOChronology(GregorianChronology.getInstanceUTC()); @@ -140,7 +102,7 @@ return chrono; } synchronized (cCache) { - chrono = (ISOChronology) cCache.get(zone); + chrono = cCache.get(zone); if (chrono == null) { chrono = new ISOChronology(ZonedChronology.getInstance(INSTANCE_UTC, zone)); cCache.put(zone, chrono); @@ -218,6 +180,27 @@ } /** + * Checks if this chronology instance equals another. + * + * @param obj the object to compare to + * @return true if equal + * @since 1.6 + */ + public boolean equals(Object obj) { + return super.equals(obj); + } + + /** + * A suitable hash code for the chronology. + * + * @return the hash code + * @since 1.6 + */ + public int hashCode() { + return "ISO".hashCode() * 11 + getZone().hashCode(); + } + + /** * Serialize ISOChronology instances using a small stub. This reduces the * serialized size, and deserialized instances come from the cache. */ Index: 3rdParty_sources/joda-time/org/joda/time/chrono/ISOYearOfEraDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/ISOYearOfEraDateTimeField.java (.../ISOYearOfEraDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/ISOYearOfEraDateTimeField.java (.../ISOYearOfEraDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -66,6 +28,7 @@ * * @author Brian S O'Neill * @see GJYearOfEraDateTimeField + * @since 1.0 */ class ISOYearOfEraDateTimeField extends DecoratedDateTimeField { Index: 3rdParty_sources/joda-time/org/joda/time/chrono/IslamicChronology.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/chrono/IslamicChronology.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/IslamicChronology.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,543 @@ +/* + * Copyright 2001-2009 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.chrono; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.joda.time.Chronology; +import org.joda.time.DateTime; +import org.joda.time.DateTimeConstants; +import org.joda.time.DateTimeField; +import org.joda.time.DateTimeZone; + +/** + * Implements the Islamic, or Hijri, calendar system using arithmetic rules. + *

                + * This calendar is a lunar calendar with a shorter year than ISO. + * Year 1 in the Islamic calendar began on July 16, 622 CE (Julian), thus + * Islamic years do not begin at the same time as Julian years. This chronology + * is not proleptic, as it does not allow dates before the first Islamic year. + *

                + * There are two basic forms of the Islamic calendar, the tabular and the + * observed. The observed form cannot easily be used by computers as it + * relies on human observation of the new moon. + * The tabular calendar, implemented here, is an arithmetical approximation + * of the observed form that follows relatively simple rules. + *

                + * The tabular form of the calendar defines 12 months of alternately + * 30 and 29 days. The last month is extended to 30 days in a leap year. + * Leap years occur according to a 30 year cycle. There are four recognised + * patterns of leap years in the 30 year cycle: + *

                + * Years 2, 5, 7, 10, 13, 15, 18, 21, 24, 26 & 29 - 15-based, used by Microsoft
                + * Years 2, 5, 7, 10, 13, 16, 18, 21, 24, 26 & 29 - 16-based, most commonly used
                + * Years 2, 5, 8, 10, 13, 16, 19, 21, 24, 27 & 29 - Indian
                + * Years 2, 5, 8, 11, 13, 16, 19, 21, 24, 27 & 30 - Habash al-Hasib
                + * 
                + * You can select which pattern to use via the factory methods, or use the + * default (16-based). + *

                + * This implementation defines a day as midnight to midnight exactly as per + * the ISO chronology. This correct start of day is at sunset on the previous + * day, however this cannot readily be modelled and has been ignored. + *

                + * IslamicChronology is thread-safe and immutable. + * + * @see Wikipedia + * + * @author Stephen Colebourne + * @since 1.2 + */ +public final class IslamicChronology extends BasicChronology { + + /** Serialization lock */ + private static final long serialVersionUID = -3663823829888L; + + /** + * Constant value for 'Anno Hegirae', equivalent + * to the value returned for AD/CE. + */ + public static final int AH = DateTimeConstants.CE; + + /** A singleton era field. */ + private static final DateTimeField ERA_FIELD = new BasicSingleEraDateTimeField("AH"); + + /** Leap year 15-based pattern. */ + public static final LeapYearPatternType LEAP_YEAR_15_BASED = new LeapYearPatternType(0, 623158436); + /** Leap year 16-based pattern. */ + public static final LeapYearPatternType LEAP_YEAR_16_BASED = new LeapYearPatternType(1, 623191204); + /** Leap year Indian pattern. */ + public static final LeapYearPatternType LEAP_YEAR_INDIAN = new LeapYearPatternType(2, 690562340); + /** Leap year Habash al-Hasib pattern. */ + public static final LeapYearPatternType LEAP_YEAR_HABASH_AL_HASIB = new LeapYearPatternType(3, 153692453); + + /** The lowest year that can be fully supported. */ + private static final int MIN_YEAR = -292269337; + + /** + * The highest year that can be fully supported. + * Although calculateFirstDayOfYearMillis can go higher without + * overflowing, the getYear method overflows when it adds the + * approximate millis at the epoch. + */ + private static final int MAX_YEAR = 292271022; + + /** The days in a pair of months. */ + private static final int MONTH_PAIR_LENGTH = 59; + + /** The length of the long month. */ + private static final int LONG_MONTH_LENGTH = 30; + + /** The length of the short month. */ + private static final int SHORT_MONTH_LENGTH = 29; + + /** The length of the long month in millis. */ + private static final long MILLIS_PER_MONTH_PAIR = 59L * DateTimeConstants.MILLIS_PER_DAY; + + /** The length of the long month in millis. */ + private static final long MILLIS_PER_MONTH = (long) (29.53056 * DateTimeConstants.MILLIS_PER_DAY); + + /** The length of the long month in millis. */ + private static final long MILLIS_PER_LONG_MONTH = 30L * DateTimeConstants.MILLIS_PER_DAY; + + /** The typical millis per year. */ + private static final long MILLIS_PER_YEAR = (long) (354.36667 * DateTimeConstants.MILLIS_PER_DAY); + + /** The typical millis per year. */ + private static final long MILLIS_PER_SHORT_YEAR = 354L * DateTimeConstants.MILLIS_PER_DAY; + + /** The typical millis per year. */ + private static final long MILLIS_PER_LONG_YEAR = 355L * DateTimeConstants.MILLIS_PER_DAY; + + /** The millis of 0001-01-01. */ + private static final long MILLIS_YEAR_1 = -42521587200000L; + // -42520809600000L; +// long start = 0L - 278L * DateTimeConstants.MILLIS_PER_DAY; +// long cy = 46L * MILLIS_PER_CYCLE; // 1381-01-01 +// long rem = 5L * MILLIS_PER_SHORT_YEAR + +// 3L * MILLIS_PER_LONG_YEAR; // 1389-01-01 + + /** The length of the cycle of leap years. */ + private static final int CYCLE = 30; + + /** The millis of a 30 year cycle. */ + private static final long MILLIS_PER_CYCLE = ((19L * 354L + 11L * 355L) * DateTimeConstants.MILLIS_PER_DAY); + + /** Cache of zone to chronology arrays */ + private static final Map cCache = new HashMap(); + + /** Singleton instance of a UTC IslamicChronology */ + private static final IslamicChronology INSTANCE_UTC; + static { + // init after static fields + INSTANCE_UTC = getInstance(DateTimeZone.UTC); + } + + /** The leap years to use. */ + private final LeapYearPatternType iLeapYears; + + //----------------------------------------------------------------------- + /** + * Gets an instance of the IslamicChronology. + * The time zone of the returned instance is UTC. + * + * @return a singleton UTC instance of the chronology + */ + public static IslamicChronology getInstanceUTC() { + return INSTANCE_UTC; + } + + /** + * Gets an instance of the IslamicChronology in the default time zone. + * + * @return a chronology in the default time zone + */ + public static IslamicChronology getInstance() { + return getInstance(DateTimeZone.getDefault(), LEAP_YEAR_16_BASED); + } + + /** + * Gets an instance of the IslamicChronology in the given time zone. + * + * @param zone the time zone to get the chronology in, null is default + * @return a chronology in the specified time zone + */ + public static IslamicChronology getInstance(DateTimeZone zone) { + return getInstance(zone, LEAP_YEAR_16_BASED); + } + + /** + * Gets an instance of the IslamicChronology in the given time zone. + * + * @param zone the time zone to get the chronology in, null is default + * @param leapYears the type defining the leap year pattern + * @return a chronology in the specified time zone + */ + public static IslamicChronology getInstance(DateTimeZone zone, LeapYearPatternType leapYears) { + if (zone == null) { + zone = DateTimeZone.getDefault(); + } + IslamicChronology chrono; + synchronized (cCache) { + IslamicChronology[] chronos = cCache.get(zone); + if (chronos == null) { + chronos = new IslamicChronology[4]; + cCache.put(zone, chronos); + } + chrono = chronos[leapYears.index]; + if (chrono == null) { + if (zone == DateTimeZone.UTC) { + // First create without a lower limit. + chrono = new IslamicChronology(null, null, leapYears); + // Impose lower limit and make another IslamicChronology. + DateTime lowerLimit = new DateTime(1, 1, 1, 0, 0, 0, 0, chrono); + chrono = new IslamicChronology( + LimitChronology.getInstance(chrono, lowerLimit, null), + null, leapYears); + } else { + chrono = getInstance(DateTimeZone.UTC, leapYears); + chrono = new IslamicChronology + (ZonedChronology.getInstance(chrono, zone), null, leapYears); + } + chronos[leapYears.index] = chrono; + } + } + return chrono; + } + + // Constructors and instance variables + //----------------------------------------------------------------------- + /** + * Restricted constructor. + */ + IslamicChronology(Chronology base, Object param, LeapYearPatternType leapYears) { + super(base, param, 4); + this.iLeapYears = leapYears; + } + + /** + * Serialization singleton. + */ + private Object readResolve() { + Chronology base = getBase(); + return base == null ? getInstanceUTC() : getInstance(base.getZone()); + } + + //----------------------------------------------------------------------- + /** + * Gets the leap year pattern type. + * + * @return the pattern type + */ + public LeapYearPatternType getLeapYearPatternType() { + return iLeapYears; + } + + // Conversion + //----------------------------------------------------------------------- + /** + * Gets the Chronology in the UTC time zone. + * + * @return the chronology in UTC + */ + public Chronology withUTC() { + return INSTANCE_UTC; + } + + /** + * Gets the Chronology in a specific time zone. + * + * @param zone the zone to get the chronology in, null is default + * @return the chronology + */ + public Chronology withZone(DateTimeZone zone) { + if (zone == null) { + zone = DateTimeZone.getDefault(); + } + if (zone == getZone()) { + return this; + } + return getInstance(zone); + } + + /** + * A suitable hash code for the chronology. + * + * @return the hash code + * @since 1.6 + */ + public int hashCode() { + return super.hashCode() * 13 + getLeapYearPatternType().hashCode(); + } + + //----------------------------------------------------------------------- + int getYear(long instant) { + long millisIslamic = instant - MILLIS_YEAR_1; + long cycles = millisIslamic / MILLIS_PER_CYCLE; + long cycleRemainder = millisIslamic % MILLIS_PER_CYCLE; + + int year = (int) ((cycles * CYCLE) + 1L); + long yearMillis = (isLeapYear(year) ? MILLIS_PER_LONG_YEAR : MILLIS_PER_SHORT_YEAR); + while (cycleRemainder >= yearMillis) { + cycleRemainder -= yearMillis; + yearMillis = (isLeapYear(++year) ? MILLIS_PER_LONG_YEAR : MILLIS_PER_SHORT_YEAR); + } + return year; + } + + long setYear(long instant, int year) { + // optimsed implementation of set, due to fixed months + int thisYear = getYear(instant); + int dayOfYear = getDayOfYear(instant, thisYear); + int millisOfDay = getMillisOfDay(instant); + + if (dayOfYear > 354) { + // Current year is leap, and day is leap. + if (!isLeapYear(year)) { + // Moving to a non-leap year, leap day doesn't exist. + dayOfYear--; + } + } + + instant = getYearMonthDayMillis(year, 1, dayOfYear); + instant += millisOfDay; + return instant; + } + + //----------------------------------------------------------------------- + long getYearDifference(long minuendInstant, long subtrahendInstant) { + // optimsed implementation of getDifference, due to fixed months + int minuendYear = getYear(minuendInstant); + int subtrahendYear = getYear(subtrahendInstant); + + // Inlined remainder method to avoid duplicate calls to get. + long minuendRem = minuendInstant - getYearMillis(minuendYear); + long subtrahendRem = subtrahendInstant - getYearMillis(subtrahendYear); + + int difference = minuendYear - subtrahendYear; + if (minuendRem < subtrahendRem) { + difference--; + } + return difference; + } + + //----------------------------------------------------------------------- + long getTotalMillisByYearMonth(int year, int month) { + if (--month % 2 == 1) { + month /= 2; + return month * MILLIS_PER_MONTH_PAIR + MILLIS_PER_LONG_MONTH; + } else { + month /= 2; + return month * MILLIS_PER_MONTH_PAIR; + } + } + + //----------------------------------------------------------------------- + int getDayOfMonth(long millis) { + // optimised for simple months + int doy = getDayOfYear(millis) - 1; + if (doy == 354) { + return 30; + } + return (doy % MONTH_PAIR_LENGTH) % LONG_MONTH_LENGTH + 1; + } + + //----------------------------------------------------------------------- + boolean isLeapYear(int year) { + return iLeapYears.isLeapYear(year); + } + + //----------------------------------------------------------------------- + int getDaysInYearMax() { + return 355; + } + + //----------------------------------------------------------------------- + int getDaysInYear(int year) { + return isLeapYear(year) ? 355 : 354; + } + + //----------------------------------------------------------------------- + int getDaysInYearMonth(int year, int month) { + if (month == 12 && isLeapYear(year)) { + return LONG_MONTH_LENGTH; + } + return (--month % 2 == 0 ? LONG_MONTH_LENGTH : SHORT_MONTH_LENGTH); + } + + //----------------------------------------------------------------------- + int getDaysInMonthMax() { + return LONG_MONTH_LENGTH; + } + + //----------------------------------------------------------------------- + int getDaysInMonthMax(int month) { + if (month == 12) { + return LONG_MONTH_LENGTH; + } + return (--month % 2 == 0 ? LONG_MONTH_LENGTH : SHORT_MONTH_LENGTH); + } + + //----------------------------------------------------------------------- + int getMonthOfYear(long millis, int year) { + int doyZeroBased = (int) ((millis - getYearMillis(year)) / DateTimeConstants.MILLIS_PER_DAY); + if (doyZeroBased == 354) { + return 12; + } + return ((doyZeroBased * 2) / MONTH_PAIR_LENGTH) + 1; +// return (int) (doyZeroBased / 29.9f) + 1; +// +// int monthPairZeroBased = doyZeroBased / MONTH_PAIR_LENGTH; +// int monthPairRemainder = doyZeroBased % MONTH_PAIR_LENGTH; +// return (monthPairZeroBased * 2) + 1 + (monthPairRemainder >= LONG_MONTH_LENGTH ? 1 : 0); + } + + //----------------------------------------------------------------------- + long getAverageMillisPerYear() { + return MILLIS_PER_YEAR; + } + + //----------------------------------------------------------------------- + long getAverageMillisPerYearDividedByTwo() { + return MILLIS_PER_YEAR / 2; + } + + //----------------------------------------------------------------------- + long getAverageMillisPerMonth() { + return MILLIS_PER_MONTH; + } + + //----------------------------------------------------------------------- + long calculateFirstDayOfYearMillis(int year) { + if (year > MAX_YEAR) { + throw new ArithmeticException("Year is too large: " + year + " > " + MAX_YEAR); + } + if (year < MIN_YEAR) { + throw new ArithmeticException("Year is too small: " + year + " < " + MIN_YEAR); + } + + // Java epoch is 1970-01-01 Gregorian which is 0622-07-16 Islamic. + // 0001-01-01 Islamic is -42520809600000L + // would prefer to calculate against year zero, but leap year + // can be in that year so it doesn't work + year--; + long cycle = year / CYCLE; + long millis = MILLIS_YEAR_1 + cycle * MILLIS_PER_CYCLE; + int cycleRemainder = (year % CYCLE) + 1; + + for (int i = 1; i < cycleRemainder; i++) { + millis += (isLeapYear(i) ? MILLIS_PER_LONG_YEAR : MILLIS_PER_SHORT_YEAR); + } + + return millis; + } + + //----------------------------------------------------------------------- + int getMinYear() { + return 1; //MIN_YEAR; + } + + //----------------------------------------------------------------------- + int getMaxYear() { + return MAX_YEAR; + } + + //----------------------------------------------------------------------- + long getApproxMillisAtEpochDividedByTwo() { + // Epoch 1970-01-01 ISO = 1389-10-22 Islamic + return (-MILLIS_YEAR_1) / 2; + } + + //----------------------------------------------------------------------- + protected void assemble(Fields fields) { + if (getBase() == null) { + super.assemble(fields); + + fields.era = ERA_FIELD; + fields.monthOfYear = new BasicMonthOfYearDateTimeField(this, 12); + fields.months = fields.monthOfYear.getDurationField(); + } + } + + //----------------------------------------------------------------------- + /** + * Opaque object describing a leap year pattern for the Islamic Chronology. + * + * @since 1.2 + */ + public static class LeapYearPatternType implements Serializable { + /** Serialization lock */ + private static final long serialVersionUID = 26581275372698L; +// /** Leap year raw data encoded into bits. */ +// private static final int[][] LEAP_YEARS = { +// {2, 5, 7, 10, 13, 15, 18, 21, 24, 26, 29}, // 623158436 +// {2, 5, 7, 10, 13, 16, 18, 21, 24, 26, 29}, // 623191204 +// {2, 5, 8, 10, 13, 16, 19, 21, 24, 27, 29}, // 690562340 +// {0, 2, 5, 8, 11, 13, 16, 19, 21, 24, 27}, // 153692453 +// }; + + /** The index. */ + final byte index; + /** The leap year pattern, a bit-based 1=true pattern. */ + final int pattern; + + /** + * Constructor. + * This constructor takes a bit pattern where bits 0-29 correspond + * to years 0-29 in the 30 year Islamic cycle of years. This allows + * a highly efficient lookup by bit-matching. + * + * @param index the index + * @param pattern the bit pattern + */ + LeapYearPatternType(int index, int pattern) { + super(); + this.index = (byte) index; + this.pattern = pattern; + } + + /** + * Is the year a leap year. + * @param year the year to query + * @return true if leap + */ + boolean isLeapYear(int year) { + int key = 1 << (year % 30); + return ((pattern & key) > 0); + } + + /** + * Ensure a singleton is returned if possible. + * @return the singleton instance + */ + private Object readResolve() { + switch (index) { + case 0: + return LEAP_YEAR_15_BASED; + case 1: + return LEAP_YEAR_16_BASED; + case 2: + return LEAP_YEAR_INDIAN; + case 3: + return LEAP_YEAR_HABASH_AL_HASIB; + default: + return this; + } + } + } +} Index: 3rdParty_sources/joda-time/org/joda/time/chrono/JulianChronology.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/JulianChronology.java (.../JulianChronology.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/JulianChronology.java (.../JulianChronology.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -58,10 +20,10 @@ import org.joda.time.Chronology; import org.joda.time.DateTimeConstants; -import org.joda.time.DateTimeField; +import org.joda.time.DateTimeFieldType; import org.joda.time.DateTimeZone; -import org.joda.time.field.DelegatedDateTimeField; -import org.joda.time.field.FieldUtils; +import org.joda.time.IllegalFieldValueException; +import org.joda.time.field.SkipDateTimeField; /** * Implements a pure proleptic Julian calendar system, which defines every @@ -85,7 +47,7 @@ * @author Stephen Colebourne * @since 1.0 */ -public final class JulianChronology extends BaseGJChronology { +public final class JulianChronology extends BasicGJChronology { /** Serialization lock */ private static final long serialVersionUID = -8731039522547897247L; @@ -96,11 +58,17 @@ private static final long MILLIS_PER_MONTH = (long) (365.25 * DateTimeConstants.MILLIS_PER_DAY / 12); + /** The lowest year that can be fully supported. */ + private static final int MIN_YEAR = -292269054; + + /** The highest year that can be fully supported. */ + private static final int MAX_YEAR = 292272992; + /** Singleton instance of a UTC JulianChronology */ private static final JulianChronology INSTANCE_UTC; /** Cache of zone to chronology arrays */ - private static final Map cCache = new HashMap(); + private static final Map cCache = new HashMap(); static { INSTANCE_UTC = getInstance(DateTimeZone.UTC); @@ -109,7 +77,8 @@ static int adjustYearForSet(int year) { if (year <= 0) { if (year == 0) { - throw new IllegalArgumentException("Invalid year: " + year); + throw new IllegalFieldValueException + (DateTimeFieldType.year(), Integer.valueOf(year), null, null); } year++; } @@ -158,7 +127,7 @@ } JulianChronology chrono; synchronized (cCache) { - JulianChronology[] chronos = (JulianChronology[]) cCache.get(zone); + JulianChronology[] chronos = cCache.get(zone); if (chronos == null) { chronos = new JulianChronology[7]; cCache.put(zone, chronos); @@ -198,7 +167,11 @@ */ private Object readResolve() { Chronology base = getBase(); - return base == null ? getInstanceUTC() : getInstance(base.getZone()); + int minDays = getMinimumDaysInFirstWeek(); + minDays = (minDays == 0 ? 4 : minDays); // handle rename of BaseGJChronology + return base == null ? + getInstance(DateTimeZone.UTC, minDays) : + getInstance(base.getZone(), minDays); } // Conversion @@ -257,96 +230,44 @@ } } - long millis = (relativeYear * 365L + leapYears) - * (long)DateTimeConstants.MILLIS_PER_DAY; + long millis = (relativeYear * 365L + leapYears) * (long)DateTimeConstants.MILLIS_PER_DAY; // Adjust to account for difference between 1968-01-01 and 1969-12-19. return millis - (366L + 352) * DateTimeConstants.MILLIS_PER_DAY; } int getMinYear() { - // The lowest year that can be fully supported. - return -292269054; + return MIN_YEAR; } int getMaxYear() { - // The highest year that can be fully supported. - return 292271022; + return MAX_YEAR; } long getAverageMillisPerYear() { return MILLIS_PER_YEAR; } + long getAverageMillisPerYearDividedByTwo() { + return MILLIS_PER_YEAR / 2; + } + long getAverageMillisPerMonth() { return MILLIS_PER_MONTH; } - long getApproxMillisAtEpoch() { - return 1969L * MILLIS_PER_YEAR + 352L * DateTimeConstants.MILLIS_PER_DAY; + long getApproxMillisAtEpochDividedByTwo() { + return (1969L * MILLIS_PER_YEAR + 352L * DateTimeConstants.MILLIS_PER_DAY) / 2; } protected void assemble(Fields fields) { if (getBase() == null) { super.assemble(fields); // Julian chronology has no year zero. - fields.year = new NoYearZeroField(this, fields.year); - fields.weekyear = new NoWeekyearZeroField(this, fields.weekyear); + fields.year = new SkipDateTimeField(this, fields.year); + fields.weekyear = new SkipDateTimeField(this, fields.weekyear); } } - static class NoYearZeroField extends DelegatedDateTimeField { - private static final long serialVersionUID = -8869148464118507846L; - - final BaseGJChronology iChronology; - private transient int iMinYear; - - NoYearZeroField(BaseGJChronology chronology, DateTimeField field) { - super(field); - iChronology = chronology; - int min = super.getMinimumValue(); - if (min < 0) { - iMinYear = min - 1; - } else if (min == 0) { - iMinYear = 1; - } else { - iMinYear = min; - } - } - - public int get(long millis) { - int year = super.get(millis); - if (year <= 0) { - year--; - } - return year; - } - - public long set(long millis, int year) { - FieldUtils.verifyValueBounds(this, year, iMinYear, getMaximumValue()); - return super.set(millis, adjustYearForSet(year)); - } - - public int getMinimumValue() { - return iMinYear; - } - - private Object readResolve() { - return iChronology.year(); - } - } - - static class NoWeekyearZeroField extends NoYearZeroField { - private static final long serialVersionUID = -5013429014495501104L; - - NoWeekyearZeroField(BaseGJChronology chronology, DateTimeField field) { - super(chronology, field); - } - - private Object readResolve() { - return iChronology.weekyear(); - } - } - } Index: 3rdParty_sources/joda-time/org/joda/time/chrono/LenientChronology.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/LenientChronology.java (.../LenientChronology.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/LenientChronology.java (.../LenientChronology.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -148,10 +110,45 @@ fields.halfdayOfDay = convertField(fields.halfdayOfDay); } - private static final DateTimeField convertField(DateTimeField field) { - return LenientDateTimeField.getInstance(field); + private final DateTimeField convertField(DateTimeField field) { + return LenientDateTimeField.getInstance(field, getBase()); } + //----------------------------------------------------------------------- + /** + * A lenient chronology is only equal to a lenient chronology with the + * same base chronology. + * + * @param obj the object to compare to + * @return true if equal + * @since 1.4 + */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LenientChronology == false) { + return false; + } + LenientChronology chrono = (LenientChronology) obj; + return getBase().equals(chrono.getBase()); + } + + /** + * A suitable hashcode for the chronology. + * + * @return the hashcode + * @since 1.4 + */ + public int hashCode() { + return 236548278 + getBase().hashCode() * 7; + } + + /** + * A debugging string for the chronology. + * + * @return the debugging string + */ public String toString() { return "LenientChronology[" + getBase().toString() + ']'; } Index: 3rdParty_sources/joda-time/org/joda/time/chrono/LimitChronology.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/LimitChronology.java (.../LimitChronology.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/LimitChronology.java (.../LimitChronology.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -65,7 +27,8 @@ import org.joda.time.ReadableDateTime; import org.joda.time.field.DecoratedDateTimeField; import org.joda.time.field.DecoratedDurationField; -import org.joda.time.format.DateTimePrinter; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; /** @@ -243,7 +206,7 @@ protected void assemble(Fields fields) { // Keep a local cache of converted fields so as not to create redundant // objects. - HashMap converted = new HashMap(); + HashMap converted = new HashMap(); // Convert duration fields... @@ -289,7 +252,7 @@ fields.halfdayOfDay = convertField(fields.halfdayOfDay, converted); } - private DurationField convertField(DurationField field, HashMap converted) { + private DurationField convertField(DurationField field, HashMap converted) { if (field == null || !field.isSupported()) { return field; } @@ -301,7 +264,7 @@ return limitField; } - private DateTimeField convertField(DateTimeField field, HashMap converted) { + private DateTimeField convertField(DateTimeField field, HashMap converted) { if (field == null || !field.isSupported()) { return field; } @@ -317,10 +280,6 @@ return limitField; } - public String toString() { - return getBase().toString(); - } - void checkLimits(long instant, String desc) { DateTime limit; if ((limit = iLowerLimit) != null && instant < limit.getMillis()) { @@ -331,7 +290,56 @@ } } + //----------------------------------------------------------------------- /** + * A limit chronology is only equal to a limit chronology with the + * same base chronology and limits. + * + * @param obj the object to compare to + * @return true if equal + * @since 1.4 + */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LimitChronology == false) { + return false; + } + LimitChronology chrono = (LimitChronology) obj; + return + getBase().equals(chrono.getBase()) && + FieldUtils.equals(getLowerLimit(), chrono.getLowerLimit()) && + FieldUtils.equals(getUpperLimit(), chrono.getUpperLimit()); + } + + /** + * A suitable hashcode for the chronology. + * + * @return the hashcode + * @since 1.4 + */ + public int hashCode() { + int hash = 317351877; + hash += (getLowerLimit() != null ? getLowerLimit().hashCode() : 0); + hash += (getUpperLimit() != null ? getUpperLimit().hashCode() : 0); + hash += getBase().hashCode() * 7; + return hash; + } + + /** + * A debugging string for the chronology. + * + * @return the debugging string + */ + public String toString() { + return "LimitChronology[" + getBase().toString() + ", " + + (getLowerLimit() == null ? "NoLimit" : getLowerLimit().toString()) + ", " + + (getUpperLimit() == null ? "NoLimit" : getUpperLimit().toString()) + ']'; + } + + //----------------------------------------------------------------------- + /** * Extends IllegalArgumentException such that the exception message is not * generated unless it is actually requested. */ @@ -355,14 +363,14 @@ } buf.append(" instant is "); - DateTimePrinter p = ISODateTimeFormat.getInstance().dateTime(); - + DateTimeFormatter p = ISODateTimeFormat.dateTime(); + p = p.withChronology(getBase()); if (iIsLow) { buf.append("below the supported minimum of "); - p.printTo(buf, getLowerLimit().getMillis(), getBase()); + p.printTo(buf, getLowerLimit().getMillis()); } else { buf.append("above the supported maximum of "); - p.printTo(buf, getUpperLimit().getMillis(), getBase()); + p.printTo(buf, getUpperLimit().getMillis()); } buf.append(" ("); Index: 3rdParty_sources/joda-time/org/joda/time/chrono/StrictChronology.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/StrictChronology.java (.../StrictChronology.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/StrictChronology.java (.../StrictChronology.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -152,6 +114,41 @@ return StrictDateTimeField.getInstance(field); } + //----------------------------------------------------------------------- + /** + * A strict chronology is only equal to a strict chronology with the + * same base chronology. + * + * @param obj the object to compare to + * @return true if equal + * @since 1.4 + */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof StrictChronology == false) { + return false; + } + StrictChronology chrono = (StrictChronology) obj; + return getBase().equals(chrono.getBase()); + } + + /** + * A suitable hashcode for the chronology. + * + * @return the hashcode + * @since 1.4 + */ + public int hashCode() { + return 352831696 + getBase().hashCode() * 7; + } + + /** + * A debugging string for the chronology. + * + * @return the debugging string + */ public String toString() { return "StrictChronology[" + getBase().toString() + ']'; } Index: 3rdParty_sources/joda-time/org/joda/time/chrono/ZonedChronology.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/ZonedChronology.java (.../ZonedChronology.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/ZonedChronology.java (.../ZonedChronology.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.chrono; @@ -61,8 +23,12 @@ import org.joda.time.DateTimeField; import org.joda.time.DateTimeZone; import org.joda.time.DurationField; +import org.joda.time.IllegalFieldValueException; +import org.joda.time.Instant; +import org.joda.time.ReadablePartial; import org.joda.time.field.BaseDateTimeField; import org.joda.time.field.BaseDurationField; +import org.joda.time.format.DateTimeFormat; /** * Wraps another Chronology to add support for time zones. @@ -175,15 +141,16 @@ instant -= offset; if (offset != zone.getOffset(instant)) { throw new IllegalArgumentException - ("Illegal instant due to time zone offset transition"); + ("Illegal instant due to time zone offset transition: " + + DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS").print(new Instant(instant))); } return instant; } protected void assemble(Fields fields) { // Keep a local cache of converted fields so as not to create redundant // objects. - HashMap converted = new HashMap(); + HashMap converted = new HashMap(); // Convert duration fields... @@ -229,7 +196,7 @@ fields.halfdayOfDay = convertField(fields.halfdayOfDay, converted); } - private DurationField convertField(DurationField field, HashMap converted) { + private DurationField convertField(DurationField field, HashMap converted) { if (field == null || !field.isSupported()) { return field; } @@ -241,7 +208,7 @@ return zonedField; } - private DateTimeField convertField(DateTimeField field, HashMap converted) { + private DateTimeField convertField(DateTimeField field, HashMap converted) { if (field == null || !field.isSupported()) { return field; } @@ -257,18 +224,55 @@ return zonedField; } + //----------------------------------------------------------------------- + /** + * A zoned chronology is only equal to a zoned chronology with the + * same base chronology and zone. + * + * @param obj the object to compare to + * @return true if equal + * @since 1.4 + */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ZonedChronology == false) { + return false; + } + ZonedChronology chrono = (ZonedChronology) obj; + return + getBase().equals(chrono.getBase()) && + getZone().equals(chrono.getZone()); + } + + /** + * A suitable hashcode for the chronology. + * + * @return the hashcode + * @since 1.4 + */ + public int hashCode() { + return 326565 + getZone().hashCode() * 11 + getBase().hashCode() * 7; + } + + /** + * A debugging string for the chronology. + * + * @return the debugging string + */ public String toString() { return "ZonedChronology[" + getBase() + ", " + getZone().getID() + ']'; } + //----------------------------------------------------------------------- /* * Because time durations are typically smaller than time zone offsets, the * arithmetic methods subtract the original offset. This produces a more * expected behavior when crossing time zone offset transitions. For dates, * the new offset is subtracted off. This behavior, if applied to time * fields, can nullify or reverse an add when crossing a transition. */ - static class ZonedDurationField extends BaseDurationField { private static final long serialVersionUID = -485345310999208286L; @@ -283,58 +287,82 @@ } iField = field; iTimeField = useTimeArithmetic(field); - this.iZone = zone; + iZone = zone; } public boolean isPrecise() { - return iTimeField ? iField.isPrecise() : iZone.isFixed(); + return iTimeField ? iField.isPrecise() : iField.isPrecise() && this.iZone.isFixed(); } public long getUnitMillis() { return iField.getUnitMillis(); } public int getValue(long duration, long instant) { - return iField.getValue(duration, instant + this.iZone.getOffset(instant)); + return iField.getValue(duration, addOffset(instant)); } public long getValueAsLong(long duration, long instant) { - return iField.getValueAsLong(duration, instant + this.iZone.getOffset(instant)); + return iField.getValueAsLong(duration, addOffset(instant)); } public long getMillis(int value, long instant) { - return iField.getMillis(value, instant + this.iZone.getOffset(instant)); + return iField.getMillis(value, addOffset(instant)); } public long getMillis(long value, long instant) { - return iField.getMillis(value, instant + this.iZone.getOffset(instant)); + return iField.getMillis(value, addOffset(instant)); } public long add(long instant, int value) { - int offset = this.iZone.getOffset(instant); + int offset = getOffsetToAdd(instant); instant = iField.add(instant + offset, value); - return instant - (iTimeField ? offset : this.iZone.getOffsetFromLocal(instant)); + return instant - (iTimeField ? offset : getOffsetFromLocalToSubtract(instant)); } public long add(long instant, long value) { - int offset = this.iZone.getOffset(instant); + int offset = getOffsetToAdd(instant); instant = iField.add(instant + offset, value); - return instant - (iTimeField ? offset : this.iZone.getOffsetFromLocal(instant)); + return instant - (iTimeField ? offset : getOffsetFromLocalToSubtract(instant)); } public int getDifference(long minuendInstant, long subtrahendInstant) { - int offset = this.iZone.getOffset(subtrahendInstant); + int offset = getOffsetToAdd(subtrahendInstant); return iField.getDifference - (minuendInstant + (iTimeField ? offset : this.iZone.getOffset(minuendInstant)), + (minuendInstant + (iTimeField ? offset : getOffsetToAdd(minuendInstant)), subtrahendInstant + offset); } public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) { - int offset = this.iZone.getOffset(subtrahendInstant); + int offset = getOffsetToAdd(subtrahendInstant); return iField.getDifferenceAsLong - (minuendInstant + (iTimeField ? offset : this.iZone.getOffset(minuendInstant)), + (minuendInstant + (iTimeField ? offset : getOffsetToAdd(minuendInstant)), subtrahendInstant + offset); } + + private int getOffsetToAdd(long instant) { + int offset = this.iZone.getOffset(instant); + long sum = instant + offset; + // If there is a sign change, but the two values have the same sign... + if ((instant ^ sum) < 0 && (instant ^ offset) >= 0) { + throw new ArithmeticException("Adding time zone offset caused overflow"); + } + return offset; + } + + private int getOffsetFromLocalToSubtract(long instant) { + int offset = this.iZone.getOffsetFromLocal(instant); + long diff = instant - offset; + // If there is a sign change, but the two values have different signs... + if ((instant ^ diff) < 0 && (instant ^ offset) < 0) { + throw new ArithmeticException("Subtracting time zone offset caused overflow"); + } + return offset; + } + + private long addOffset(long instant) { + return iZone.convertUTCToLocal(instant); + } } /** @@ -363,7 +391,7 @@ throw new IllegalArgumentException(); } iField = field; - this.iZone = zone; + iZone = zone; iDurationField = durationField; iTimeField = useTimeArithmetic(durationField); iRangeDurationField = rangeDurationField; @@ -375,69 +403,95 @@ } public int get(long instant) { - return iField.get(instant + this.iZone.getOffset(instant)); + long localInstant = iZone.convertUTCToLocal(instant); + return iField.get(localInstant); } public String getAsText(long instant, Locale locale) { - return iField.getAsText(instant + this.iZone.getOffset(instant), locale); + long localInstant = iZone.convertUTCToLocal(instant); + return iField.getAsText(localInstant, locale); } public String getAsShortText(long instant, Locale locale) { - return iField.getAsShortText(instant + this.iZone.getOffset(instant), locale); + long localInstant = iZone.convertUTCToLocal(instant); + return iField.getAsShortText(localInstant, locale); } + public String getAsText(int fieldValue, Locale locale) { + return iField.getAsText(fieldValue, locale); + } + + public String getAsShortText(int fieldValue, Locale locale) { + return iField.getAsShortText(fieldValue, locale); + } + public long add(long instant, int value) { - int offset = this.iZone.getOffset(instant); - instant = iField.add(instant + offset, value); - return instant - (iTimeField ? offset : this.iZone.getOffsetFromLocal(instant)); + if (iTimeField) { + int offset = getOffsetToAdd(instant); + long localInstant = iField.add(instant + offset, value); + return localInstant - offset; + } else { + long localInstant = iZone.convertUTCToLocal(instant); + localInstant = iField.add(localInstant, value); + return iZone.convertLocalToUTC(localInstant, false, instant); + } } public long add(long instant, long value) { - int offset = this.iZone.getOffset(instant); - instant = iField.add(instant + offset, value); - return instant - (iTimeField ? offset : this.iZone.getOffsetFromLocal(instant)); + if (iTimeField) { + int offset = getOffsetToAdd(instant); + long localInstant = iField.add(instant + offset, value); + return localInstant - offset; + } else { + long localInstant = iZone.convertUTCToLocal(instant); + localInstant = iField.add(localInstant, value); + return iZone.convertLocalToUTC(localInstant, false, instant); + } } public long addWrapField(long instant, int value) { - int offset = this.iZone.getOffset(instant); - instant = iField.addWrapField(instant + offset, value); - return instant - (iTimeField ? offset : this.iZone.getOffsetFromLocal(instant)); + if (iTimeField) { + int offset = getOffsetToAdd(instant); + long localInstant = iField.addWrapField(instant + offset, value); + return localInstant - offset; + } else { + long localInstant = iZone.convertUTCToLocal(instant); + localInstant = iField.addWrapField(localInstant, value); + return iZone.convertLocalToUTC(localInstant, false, instant); + } } public long set(long instant, int value) { - long offset = this.iZone.getOffset(instant); - - instant = iField.set(instant + offset, value); - long offsetFromLocal = this.iZone.getOffsetFromLocal(instant); - instant -= offsetFromLocal; - - if (offset != offsetFromLocal) { - if (get(instant) != value) { - throw new IllegalArgumentException - ("Illegal value for " + iField.getName() + ": " + value); - } + long localInstant = iZone.convertUTCToLocal(instant); + localInstant = iField.set(localInstant, value); + long result = iZone.convertLocalToUTC(localInstant, false, instant); + if (get(result) != value) { + throw new IllegalFieldValueException(iField.getType(), Integer.valueOf(value), + "Illegal instant due to time zone offset transition: " + + DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS").print(new Instant(localInstant)) + + " (" + iZone.getID() + ")"); } - - return instant; + return result; } public long set(long instant, String text, Locale locale) { - instant = iField.set(instant + this.iZone.getOffset(instant), text, locale); - // Cannot verify that new value stuck because set may be lenient. - return instant - this.iZone.getOffsetFromLocal(instant); + // cannot verify that new value stuck because set may be lenient + long localInstant = iZone.convertUTCToLocal(instant); + localInstant = iField.set(localInstant, text, locale); + return iZone.convertLocalToUTC(localInstant, false, instant); } public int getDifference(long minuendInstant, long subtrahendInstant) { - int offset = this.iZone.getOffset(subtrahendInstant); + int offset = getOffsetToAdd(subtrahendInstant); return iField.getDifference - (minuendInstant + (iTimeField ? offset : this.iZone.getOffset(minuendInstant)), + (minuendInstant + (iTimeField ? offset : getOffsetToAdd(minuendInstant)), subtrahendInstant + offset); } public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) { - int offset = this.iZone.getOffset(subtrahendInstant); + int offset = getOffsetToAdd(subtrahendInstant); return iField.getDifferenceAsLong - (minuendInstant + (iTimeField ? offset : this.iZone.getOffset(minuendInstant)), + (minuendInstant + (iTimeField ? offset : getOffsetToAdd(minuendInstant)), subtrahendInstant + offset); } @@ -450,56 +504,99 @@ } public boolean isLeap(long instant) { - return iField.isLeap(instant + this.iZone.getOffset(instant)); + long localInstant = iZone.convertUTCToLocal(instant); + return iField.isLeap(localInstant); } public int getLeapAmount(long instant) { - return iField.getLeapAmount(instant + this.iZone.getOffset(instant)); + long localInstant = iZone.convertUTCToLocal(instant); + return iField.getLeapAmount(localInstant); } public final DurationField getLeapDurationField() { return iLeapDurationField; } public long roundFloor(long instant) { - int offset = this.iZone.getOffset(instant); - instant = iField.roundFloor(instant + offset); - return instant - (iTimeField ? offset : this.iZone.getOffsetFromLocal(instant)); + if (iTimeField) { + int offset = getOffsetToAdd(instant); + instant = iField.roundFloor(instant + offset); + return instant - offset; + } else { + long localInstant = iZone.convertUTCToLocal(instant); + localInstant = iField.roundFloor(localInstant); + return iZone.convertLocalToUTC(localInstant, false, instant); + } } public long roundCeiling(long instant) { - int offset = this.iZone.getOffset(instant); - instant = iField.roundCeiling(instant + offset); - return instant - (iTimeField ? offset : this.iZone.getOffsetFromLocal(instant)); + if (iTimeField) { + int offset = getOffsetToAdd(instant); + instant = iField.roundCeiling(instant + offset); + return instant - offset; + } else { + long localInstant = iZone.convertUTCToLocal(instant); + localInstant = iField.roundCeiling(localInstant); + return iZone.convertLocalToUTC(localInstant, false, instant); + } } public long remainder(long instant) { - return iField.remainder(instant + this.iZone.getOffset(instant)); + long localInstant = iZone.convertUTCToLocal(instant); + return iField.remainder(localInstant); } public int getMinimumValue() { return iField.getMinimumValue(); } public int getMinimumValue(long instant) { - return iField.getMinimumValue(instant + this.iZone.getOffset(instant)); + long localInstant = iZone.convertUTCToLocal(instant); + return iField.getMinimumValue(localInstant); } + public int getMinimumValue(ReadablePartial instant) { + return iField.getMinimumValue(instant); + } + + public int getMinimumValue(ReadablePartial instant, int[] values) { + return iField.getMinimumValue(instant, values); + } + public int getMaximumValue() { return iField.getMaximumValue(); } public int getMaximumValue(long instant) { - return iField.getMaximumValue(instant + this.iZone.getOffset(instant)); + long localInstant = iZone.convertUTCToLocal(instant); + return iField.getMaximumValue(localInstant); } + public int getMaximumValue(ReadablePartial instant) { + return iField.getMaximumValue(instant); + } + + public int getMaximumValue(ReadablePartial instant, int[] values) { + return iField.getMaximumValue(instant, values); + } + public int getMaximumTextLength(Locale locale) { return iField.getMaximumTextLength(locale); } public int getMaximumShortTextLength(Locale locale) { return iField.getMaximumShortTextLength(locale); } + + private int getOffsetToAdd(long instant) { + int offset = this.iZone.getOffset(instant); + long sum = instant + offset; + // If there is a sign change, but the two values have the same sign... + if ((instant ^ sum) < 0 && (instant ^ offset) >= 0) { + throw new ArithmeticException("Adding time zone offset caused overflow"); + } + return offset; + } } } Index: 3rdParty_sources/joda-time/org/joda/time/chrono/package.html =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/chrono/package.html (.../package.html) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/chrono/package.html (.../package.html) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -4,69 +4,48 @@ org.joda.time.chrono package

                -Implementation package providing the Chronology implementaions. +Package containing the chronology classes which define the calendar systems.

                This package contains all of the chronology implementations within the library. -It also contains all of the specialised field implementations. -Most applications will create chronologies using the static factory methods on -the Chronology class itself in the main package. +A chronology represents all the rules of a calendar system. +Applications will create chronologies using the static factory methods on +each specific Chronology class - getInstance. +The currently provided chronology implementations are: +

                  +
                • ISO
                • +
                • GJ (GregorianJulian)
                • +
                • Gregorian
                • +
                • Julian
                • +
                • Buddhist
                • +
                • Coptic
                • +
                • Ethiopic
                • +
                • Islamic
                • +

                +

                +The package also contains all of the specialised field implementations. +These classes are package scoped, along with various other chronology helper classes. +The package scoped classes (which are not shown in the javadoc) do not form part +of the public API of Joda-Time and may change at any time. +

                Index: 3rdParty_sources/joda-time/org/joda/time/convert/AbstractConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/AbstractConverter.java (.../AbstractConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/AbstractConverter.java (.../AbstractConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2006 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -58,6 +20,8 @@ import org.joda.time.DateTimeZone; import org.joda.time.PeriodType; import org.joda.time.ReadablePartial; +import org.joda.time.chrono.ISOChronology; +import org.joda.time.format.DateTimeFormatter; /** * AbstractConverter simplifies the process of implementing a converter. @@ -100,7 +64,7 @@ * @return the chronology, never null */ public Chronology getChronology(Object object, DateTimeZone zone) { - return Chronology.getISO(zone); + return ISOChronology.getInstance(zone); } /** @@ -123,18 +87,42 @@ * Extracts the values of the partial from an object of this converter's type. * The chrono parameter is a hint to the converter, should it require a * chronology to aid in conversion. + *

                + * This implementation calls {@link #getInstantMillis(Object, Chronology)}. * * @param fieldSource a partial that provides access to the fields. * This partial may be incomplete and only getFieldType(int) should be used * @param object the object to convert * @param chrono the chronology to use, which is the non-null result of getChronology() - * @return the array of field values that match the + * @return the array of field values that match the fieldSource, must be non-null valid + * @throws ClassCastException if the object is invalid */ public int[] getPartialValues(ReadablePartial fieldSource, Object object, Chronology chrono) { long instant = getInstantMillis(object, chrono); return chrono.get(fieldSource, instant); } + /** + * Extracts the values of the partial from an object of this converter's type. + * The chrono parameter is a hint to the converter, should it require a + * chronology to aid in conversion. + *

                + * This implementation calls {@link #getPartialValues(ReadablePartial, Object, Chronology)}. + * + * @param fieldSource a partial that provides access to the fields. + * This partial may be incomplete and only getFieldType(int) should be used + * @param object the object to convert + * @param chrono the chronology to use, which is the non-null result of getChronology() + * @param parser if converting from a String, the given parser is preferred + * @return the array of field values that match the fieldSource, must be non-null valid + * @throws ClassCastException if the object is invalid + * @since 1.3 + */ + public int[] getPartialValues(ReadablePartial fieldSource, + Object object, Chronology chrono, DateTimeFormatter parser) { + return getPartialValues(fieldSource, object, chrono); + } + //----------------------------------------------------------------------- /** * Selects a suitable period type for the given object. Index: 3rdParty_sources/joda-time/org/joda/time/convert/CalendarConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/CalendarConverter.java (.../CalendarConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/CalendarConverter.java (.../CalendarConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -60,6 +22,9 @@ import org.joda.time.DateTimeZone; import org.joda.time.chrono.BuddhistChronology; import org.joda.time.chrono.GJChronology; +import org.joda.time.chrono.GregorianChronology; +import org.joda.time.chrono.ISOChronology; +import org.joda.time.chrono.JulianChronology; /** * CalendarConverter converts a java util Calendar to an instant or partial. @@ -106,7 +71,7 @@ Calendar cal = (Calendar) object; DateTimeZone zone = null; try { - zone = DateTimeZone.getInstance(cal.getTimeZone()); + zone = DateTimeZone.forTimeZone(cal.getTimeZone()); } catch (IllegalArgumentException ex) { zone = DateTimeZone.getDefault(); @@ -132,14 +97,14 @@ GregorianCalendar gc = (GregorianCalendar) object; long cutover = gc.getGregorianChange().getTime(); if (cutover == Long.MIN_VALUE) { - return Chronology.getGregorian(zone); + return GregorianChronology.getInstance(zone); } else if (cutover == Long.MAX_VALUE) { - return Chronology.getJulian(zone); + return JulianChronology.getInstance(zone); } else { return GJChronology.getInstance(zone, cutover, 4); } } else { - return Chronology.getISO(zone); + return ISOChronology.getInstance(zone); } } @@ -153,7 +118,8 @@ * @throws ClassCastException if the object is an invalid type */ public long getInstantMillis(Object object, Chronology chrono) { - return ((Calendar) object).getTime().getTime(); + Calendar calendar = (Calendar) object; + return calendar.getTime().getTime(); } //----------------------------------------------------------------------- @@ -162,7 +128,7 @@ * * @return Calendar.class */ - public Class getSupportedType() { + public Class getSupportedType() { return Calendar.class; } Index: 3rdParty_sources/joda-time/org/joda/time/convert/Converter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/Converter.java (.../Converter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/Converter.java (.../Converter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -60,11 +22,13 @@ * @since 1.0 */ public interface Converter { + /** * Returns the object type that this converter supports, which may * specified by a class, superclass, abstract class, interface, or null. * * @return the object type that this converter supports */ - Class getSupportedType(); + Class getSupportedType(); + } Index: 3rdParty_sources/joda-time/org/joda/time/convert/ConverterManager.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/ConverterManager.java (.../ConverterManager.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/ConverterManager.java (.../ConverterManager.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -72,7 +34,7 @@ *

              • ReadableInstant *
              • String *
              • Calendar - *
              • Date + *
              • Date (includes sql package subclasses) *
              • Long (milliseconds) *
              • null (now) *
              @@ -83,7 +45,7 @@ *
            • ReadableInstant *
            • String *
            • Calendar - *
            • Date + *
            • Date (includes sql package subclasses) *
            • Long (milliseconds) *
            • null (now) *
            Index: 3rdParty_sources/joda-time/org/joda/time/convert/ConverterSet.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/ConverterSet.java (.../ConverterSet.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/ConverterSet.java (.../ConverterSet.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -82,7 +44,7 @@ * @throws IllegalStateException if multiple converters match the type * equally well */ - Converter select(Class type) throws IllegalStateException { + Converter select(Class type) throws IllegalStateException { // Check the hashtable first. Entry[] entries = iSelectEntries; int length = entries.length; @@ -277,14 +239,14 @@ * Returns the closest matching converter for the given type, but not very * efficiently. */ - private static Converter selectSlow(ConverterSet set, Class type) { + private static Converter selectSlow(ConverterSet set, Class type) { Converter[] converters = set.iConverters; int length = converters.length; Converter converter; for (int i=length; --i>=0; ) { converter = converters[i]; - Class supportedType = converter.getSupportedType(); + Class supportedType = converter.getSupportedType(); if (supportedType == type) { // Exact match. @@ -314,7 +276,7 @@ // Eliminate supertypes. for (int i=length; --i>=0; ) { converter = converters[i]; - Class supportedType = converter.getSupportedType(); + Class supportedType = converter.getSupportedType(); for (int j=length; --j>=0; ) { if (j != i && converters[j].getSupportedType().isAssignableFrom(supportedType)) { // Eliminate supertype. @@ -342,7 +304,7 @@ msg.append("\" from remaining set: "); for (int i=0; i supportedType = converter.getSupportedType(); msg.append(converter.getClass().getName()); msg.append('['); @@ -354,10 +316,10 @@ } static class Entry { - final Class iType; + final Class iType; final Converter iConverter; - Entry(Class type, Converter converter) { + Entry(Class type, Converter converter) { iType = type; iConverter = converter; } Index: 3rdParty_sources/joda-time/org/joda/time/convert/DateConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/DateConverter.java (.../DateConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/DateConverter.java (.../DateConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -90,7 +52,8 @@ * @throws ClassCastException if the object is an invalid type */ public long getInstantMillis(Object object, Chronology chrono) { - return ((Date) object).getTime(); + Date date = (Date) object; + return date.getTime(); } //----------------------------------------------------------------------- @@ -99,7 +62,7 @@ * * @return Date.class */ - public Class getSupportedType() { + public Class getSupportedType() { return Date.class; } Index: 3rdParty_sources/joda-time/org/joda/time/convert/DurationConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/DurationConverter.java (.../DurationConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/DurationConverter.java (.../DurationConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; Index: 3rdParty_sources/joda-time/org/joda/time/convert/InstantConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/InstantConverter.java (.../InstantConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/InstantConverter.java (.../InstantConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -103,6 +65,7 @@ * @param chrono the chronology to use, which is the non-null result of getChronology() * @return the millisecond instant * @throws ClassCastException if the object is invalid + * @throws IllegalArgumentException if object conversion fails */ long getInstantMillis(Object object, Chronology chrono); Index: 3rdParty_sources/joda-time/org/joda/time/convert/IntervalConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/IntervalConverter.java (.../IntervalConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/IntervalConverter.java (.../IntervalConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; Index: 3rdParty_sources/joda-time/org/joda/time/convert/LongConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/LongConverter.java (.../LongConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/LongConverter.java (.../LongConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -111,7 +73,7 @@ * * @return Long.class */ - public Class getSupportedType() { + public Class getSupportedType() { return Long.class; } Index: 3rdParty_sources/joda-time/org/joda/time/convert/NullConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/NullConverter.java (.../NullConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/NullConverter.java (.../NullConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -129,7 +91,7 @@ * * @return null */ - public Class getSupportedType() { + public Class getSupportedType() { return null; } Index: 3rdParty_sources/joda-time/org/joda/time/convert/PartialConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/PartialConverter.java (.../PartialConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/PartialConverter.java (.../PartialConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,60 +1,24 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2006 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; import org.joda.time.Chronology; +import org.joda.time.DateTimeZone; import org.joda.time.ReadablePartial; +import org.joda.time.format.DateTimeFormatter; /** * PartialConverter defines how an object is converted to a ReadablePartial. @@ -70,6 +34,18 @@ /** * Extracts the chronology from an object of this converter's type + * where the time zone is specified. + * + * @param object the object to convert + * @param zone the specified zone to use, null means default zone + * @return the chronology, never null + * @throws ClassCastException if the object is invalid + * @since 1.3 + */ + Chronology getChronology(Object object, DateTimeZone zone); + + /** + * Extracts the chronology from an object of this converter's type * where the chronology is specified. * * @param object the object to convert @@ -93,4 +69,21 @@ */ int[] getPartialValues(ReadablePartial fieldSource, Object object, Chronology chrono); + /** + * Extracts the values of the partial from an object of this converter's type. + * The chrono parameter is a hint to the converter, should it require a + * chronology to aid in conversion. + * + * @param fieldSource a partial that provides access to the fields. + * This partial may be incomplete and only getFieldType(int) should be used + * @param object the object to convert + * @param chrono the chronology to use, which is the non-null result of getChronology() + * @param parser if converting from a String, the given parser is preferred + * @return the array of field values that match the fieldSource, must be non-null valid + * @throws ClassCastException if the object is invalid + * @since 1.3 + */ + int[] getPartialValues(ReadablePartial fieldSource, Object object, Chronology chrono, + DateTimeFormatter parser); + } Index: 3rdParty_sources/joda-time/org/joda/time/convert/PeriodConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/PeriodConverter.java (.../PeriodConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/PeriodConverter.java (.../PeriodConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; Index: 3rdParty_sources/joda-time/org/joda/time/convert/ReadableDurationConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/ReadableDurationConverter.java (.../ReadableDurationConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/ReadableDurationConverter.java (.../ReadableDurationConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -122,7 +84,7 @@ * * @return ReadableDuration.class */ - public Class getSupportedType() { + public Class getSupportedType() { return ReadableDuration.class; } Index: 3rdParty_sources/joda-time/org/joda/time/convert/ReadableInstantConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/ReadableInstantConverter.java (.../ReadableInstantConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/ReadableInstantConverter.java (.../ReadableInstantConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -144,7 +106,7 @@ * * @return ReadableInstant.class */ - public Class getSupportedType() { + public Class getSupportedType() { return ReadableInstant.class; } Index: 3rdParty_sources/joda-time/org/joda/time/convert/ReadableIntervalConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/ReadableIntervalConverter.java (.../ReadableIntervalConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/ReadableIntervalConverter.java (.../ReadableIntervalConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -147,7 +109,7 @@ /** * Returns ReadableInterval.class. */ - public Class getSupportedType() { + public Class getSupportedType() { return ReadableInterval.class; } Index: 3rdParty_sources/joda-time/org/joda/time/convert/ReadablePartialConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/ReadablePartialConverter.java (.../ReadablePartialConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/ReadablePartialConverter.java (.../ReadablePartialConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -124,15 +86,9 @@ public int[] getPartialValues(ReadablePartial fieldSource, Object object, Chronology chrono) { ReadablePartial input = (ReadablePartial) object; int size = fieldSource.size(); - if (input.size() != size) { - throw new IllegalArgumentException("Partial field type lists are different"); - } int[] values = new int[size]; for (int i = 0; i < size; i++) { - if (fieldSource.getFieldType(i) != input.getFieldType(i)) { - throw new IllegalArgumentException("Partial field type lists are different"); - } - values[i] = input.getValue(i); + values[i] = input.get(fieldSource.getFieldType(i)); } chrono.validate(fieldSource, values); return values; @@ -144,7 +100,7 @@ * * @return ReadableInstant.class */ - public Class getSupportedType() { + public Class getSupportedType() { return ReadablePartial.class; } Index: 3rdParty_sources/joda-time/org/joda/time/convert/ReadablePeriodConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/ReadablePeriodConverter.java (.../ReadablePeriodConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/ReadablePeriodConverter.java (.../ReadablePeriodConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -115,7 +77,7 @@ * * @return ReadablePeriod.class */ - public Class getSupportedType() { + public Class getSupportedType() { return ReadablePeriod.class; } Index: 3rdParty_sources/joda-time/org/joda/time/convert/StringConverter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/StringConverter.java (.../StringConverter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/StringConverter.java (.../StringConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.convert; @@ -58,12 +20,12 @@ import org.joda.time.Period; import org.joda.time.ReadWritableInterval; import org.joda.time.ReadWritablePeriod; +import org.joda.time.ReadablePartial; import org.joda.time.field.FieldUtils; -import org.joda.time.format.DateTimeParser; +import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; import org.joda.time.format.ISOPeriodFormat; import org.joda.time.format.PeriodFormatter; -import org.joda.time.format.PeriodParser; /** * StringConverter converts from a String to an instant, partial, @@ -99,10 +61,33 @@ */ public long getInstantMillis(Object object, Chronology chrono) { String str = (String) object; - DateTimeParser p = ISODateTimeFormat.getInstance().dateTimeParser(); - return p.parseMillis(str, chrono); + DateTimeFormatter p = ISODateTimeFormat.dateTimeParser(); + return p.withChronology(chrono).parseMillis(str); } + /** + * Extracts the values of the partial from an object of this converter's type. + * This method checks if the parser has a zone, and uses it if present. + * This is most useful for parsing local times with UTC. + * + * @param fieldSource a partial that provides access to the fields. + * This partial may be incomplete and only getFieldType(int) should be used + * @param object the object to convert + * @param chrono the chronology to use, which is the non-null result of getChronology() + * @param parser the parser to use, may be null + * @return the array of field values that match the fieldSource, must be non-null valid + * @throws ClassCastException if the object is invalid + * @throws IllegalArgumentException if the value if invalid + * @since 1.3 + */ + public int[] getPartialValues(ReadablePartial fieldSource, Object object, Chronology chrono, DateTimeFormatter parser) { + if (parser.getZone() != null) { + chrono = chrono.withZone(parser.getZone()); + } + long millis = parser.withChronology(chrono).parseMillis((String) object); + return chrono.get(fieldSource, millis); + } + //----------------------------------------------------------------------- /** * Gets the duration of the string using the standard type. @@ -169,13 +154,13 @@ */ public void setInto(ReadWritablePeriod period, Object object, Chronology chrono) { String str = (String) object; - PeriodParser parser = ISOPeriodFormat.getInstance().standard(); + PeriodFormatter parser = ISOPeriodFormat.standard(); period.clear(); int pos = parser.parseInto(period, str, 0); if (pos < str.length()) { if (pos < 0) { // Parse again to get a better exception thrown. - parser.parseMutablePeriod(period.getPeriodType(), str); + parser.withParseType(period.getPeriodType()).parseMutablePeriod(str); } throw new IllegalArgumentException("Invalid format: \"" + str + '"'); } @@ -206,18 +191,19 @@ throw new IllegalArgumentException("Format invalid: " + str); } - DateTimeParser dateTimeParser = ISODateTimeFormat.getInstance().dateTimeParser(); - PeriodFormatter periodParser = ISOPeriodFormat.getInstance().standard(); + DateTimeFormatter dateTimeParser = ISODateTimeFormat.dateTimeParser(); + dateTimeParser = dateTimeParser.withChronology(chrono); + PeriodFormatter periodParser = ISOPeriodFormat.standard(); long startInstant = 0, endInstant = 0; Period period = null; Chronology parsedChrono = null; // before slash char c = leftStr.charAt(0); if (c == 'P' || c == 'p') { - period = periodParser.parsePeriod(getPeriodType(leftStr), leftStr); + period = periodParser.withParseType(getPeriodType(leftStr)).parsePeriod(leftStr); } else { - DateTime start = dateTimeParser.parseDateTime(leftStr, chrono); + DateTime start = dateTimeParser.parseDateTime(leftStr); startInstant = start.getMillis(); parsedChrono = start.getChronology(); } @@ -228,11 +214,11 @@ if (period != null) { throw new IllegalArgumentException("Interval composed of two durations: " + str); } - period = periodParser.parsePeriod(getPeriodType(rightStr), rightStr); + period = periodParser.withParseType(getPeriodType(rightStr)).parsePeriod(rightStr); chrono = (chrono != null ? chrono : parsedChrono); endInstant = chrono.add(period, startInstant, 1); } else { - DateTime end = dateTimeParser.parseDateTime(rightStr, chrono); + DateTime end = dateTimeParser.parseDateTime(rightStr); endInstant = end.getMillis(); parsedChrono = (parsedChrono != null ? parsedChrono : end.getChronology()); chrono = (chrono != null ? chrono : parsedChrono); @@ -251,7 +237,7 @@ * * @return String.class */ - public Class getSupportedType() { + public Class getSupportedType() { return String.class; } Index: 3rdParty_sources/joda-time/org/joda/time/convert/package.html =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/convert/package.html (.../package.html) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/convert/package.html (.../package.html) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -4,57 +4,19 @@ org.joda.time.convert package Index: 3rdParty_sources/joda-time/org/joda/time/field/AbstractPartialFieldProperty.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/AbstractPartialFieldProperty.java (.../AbstractPartialFieldProperty.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/AbstractPartialFieldProperty.java (.../AbstractPartialFieldProperty.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,64 +1,24 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2006 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; import java.util.Locale; -import org.joda.time.Chronology; import org.joda.time.DateTimeField; import org.joda.time.DateTimeFieldType; -import org.joda.time.DateTimeUtils; import org.joda.time.DurationField; import org.joda.time.ReadableInstant; import org.joda.time.ReadablePartial; @@ -114,29 +74,45 @@ * * @return the partial instant */ - public abstract ReadablePartial getReadablePartial(); + protected abstract ReadablePartial getReadablePartial(); //----------------------------------------------------------------------- /** - * Gets a value from the partial instant. + * Gets the value of this property from the instant. + *

            + * For example, the following two lines of code are equivalent: + *

            +     * partial.getDayOfMonth();
            +     * partial.dayOfMonth().get();
            +     * 
            * * @return the current value */ public abstract int get(); /** - * Gets a text value from the partial instant. + * Gets the value of this property from the instant as a string. + *

            + * This method returns the value converted to a String + * using Integer.toString. This method does NOT return + * textual descriptions such as 'Monday' or 'January'. + * See {@link #getAsText()} and {@link #getAsShortText()} for those. * - * @param locale optional locale to use for selecting a text symbol - * @return the current text value - * @see DateTimeField#getAsText + * @return the current value + * @see DateTimeField#get + * @since 1.1 */ - public String getAsText(Locale locale) { - return getField().getAsText(getReadablePartial(), get(), locale); + public String getAsString() { + return Integer.toString(get()); } /** - * Gets a text value from the partial instant. + * Gets the textual value of this property from the instant as a + * string in the default locale. + *

            + * This method returns the value converted to a String + * returning the appropriate textual description wherever possible. + * Thus, a day of week of 1 would return 'Monday' in English. * * @return the current text value * @see DateTimeField#getAsText @@ -146,18 +122,28 @@ } /** - * Gets a short text value from the partial instant. + * Gets the textual value of this property from the instant as a + * string in the specified locale. + *

            + * This method returns the value converted to a String + * returning the appropriate textual description wherever possible. + * Thus, a day of week of 1 would return 'Monday' in English. * - * @param locale optional locale to use for selecting a text symbol + * @param locale locale to use for selecting a text symbol, null means default * @return the current text value - * @see DateTimeField#getAsShortText + * @see DateTimeField#getAsText */ - public String getAsShortText(Locale locale) { - return getField().getAsShortText(getReadablePartial(), get(), locale); + public String getAsText(Locale locale) { + return getField().getAsText(getReadablePartial(), get(), locale); } /** - * Gets a short text value from the partial instant. + * Gets the short textual value of this property from the instant as a + * string in the default locale. + *

            + * This method returns the value converted to a String + * returning the appropriate textual description wherever possible. + * Thus, a day of week of 1 would return 'Mon' in English. * * @return the current text value * @see DateTimeField#getAsShortText @@ -166,6 +152,22 @@ return getAsShortText(null); } + /** + * Gets the short textual value of this property from the instant as a + * string in the specified locale. + *

            + * This method returns the value converted to a String + * returning the appropriate textual description wherever possible. + * Thus, a day of week of 1 would return 'Mon' in English. + * + * @param locale locale to use for selecting a text symbol, null means default + * @return the current text value + * @see DateTimeField#getAsShortText + */ + public String getAsShortText(Locale locale) { + return getField().getAsShortText(getReadablePartial(), get(), locale); + } + //----------------------------------------------------------------------- /** * Returns the duration per unit value of this field. For example, if this @@ -270,8 +272,7 @@ throw new IllegalArgumentException("The instant must not be null"); } int thisValue = get(); - Chronology chrono = DateTimeUtils.getChronology(instant.getChronology()); - int otherValue = getFieldType().getField(chrono).get(instant.getMillis()); + int otherValue = instant.get(getFieldType()); if (thisValue < otherValue) { return -1; } else if (thisValue > otherValue) { @@ -321,19 +322,33 @@ if (this == object) { return true; } - if (object instanceof AbstractPartialFieldProperty) { - AbstractPartialFieldProperty other = (AbstractPartialFieldProperty) object; - if (get() == other.get() && - getFieldType() == other.getFieldType() && - getReadablePartial().getChronology() == other.getReadablePartial().getChronology()) { - return true; - } + if (object instanceof AbstractPartialFieldProperty == false) { + return false; } - return false; + AbstractPartialFieldProperty other = (AbstractPartialFieldProperty) object; + return + get() == other.get() && + getFieldType() == other.getFieldType() && + FieldUtils.equals(getReadablePartial().getChronology(), other.getReadablePartial().getChronology()); } //----------------------------------------------------------------------- /** + * Gets a suitable hashcode for the object. + * + * @return the hashcode + * @since 1.3 + */ + public int hashCode() { + int hash = 19; + hash = 13 * hash + get(); + hash = 13 * hash + getFieldType().hashCode(); + hash = 13 * hash + getReadablePartial().getChronology().hashCode(); + return hash; + } + + //----------------------------------------------------------------------- + /** * Output a debugging string. * * @return debugging string Index: 3rdParty_sources/joda-time/org/joda/time/field/AbstractReadableInstantFieldProperty.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/AbstractReadableInstantFieldProperty.java (.../AbstractReadableInstantFieldProperty.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/AbstractReadableInstantFieldProperty.java (.../AbstractReadableInstantFieldProperty.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; @@ -61,6 +23,7 @@ import org.joda.time.DateTimeFieldType; import org.joda.time.DateTimeUtils; import org.joda.time.DurationField; +import org.joda.time.Interval; import org.joda.time.ReadableInstant; import org.joda.time.ReadablePartial; @@ -77,10 +40,11 @@ * * @author Stephen Colebourne * @author Brian S O'Neill + * @author Mike Schrag * @since 1.0 */ public abstract class AbstractReadableInstantFieldProperty implements Serializable { - + /** Serialization version. */ private static final long serialVersionUID = 1971226328211649661L; @@ -118,63 +82,120 @@ } /** - * Gets the instant being used. + * Gets the milliseconds of the datetime that this property is linked to. * - * @return the instant + * @return the milliseconds */ - public abstract ReadableInstant getReadableInstant(); + protected abstract long getMillis(); + /** + * Gets the chronology of the datetime that this property is linked to. + *

            + * This implementation throws UnsupportedOperationException, and must be + * implemented by subclasses to enable the equals() and hashCode() methods. + * + * @return the chronology + * @since 1.4 + */ + protected Chronology getChronology() { + throw new UnsupportedOperationException( + "The method getChronology() was added in v1.4 and needs " + + "to be implemented by subclasses of AbstractReadableInstantFieldProperty"); + } + //----------------------------------------------------------------------- /** - * Gets a value from the instant. + * Gets the value of this property from the instant. + *

            + * For example, the following two lines of code are equivalent: + *

            +     * datetime.getDayOfMonth();
            +     * datetime.dayOfMonth().get();
            +     * 
            * * @return the current value * @see DateTimeField#get */ public int get() { - return getField().get(getReadableInstant().getMillis()); + return getField().get(getMillis()); } /** - * Gets a text value from the instant. + * Gets the value of this property from the instant as a string. + *

            + * This method returns the value converted to a String + * using Integer.toString. This method does NOT return + * textual descriptions such as 'Monday' or 'January'. + * See {@link #getAsText()} and {@link #getAsShortText()} for those. * - * @param locale optional locale to use for selecting a text symbol + * @return the current value + * @see DateTimeField#get + * @since 1.1 + */ + public String getAsString() { + return Integer.toString(get()); + } + + /** + * Gets the textual value of this property from the instant as a + * string in the default locale. + *

            + * This method returns the value converted to a String + * returning the appropriate textual description wherever possible. + * Thus, a day of week of 1 would return 'Monday' in English. + * * @return the current text value * @see DateTimeField#getAsText */ - public String getAsText(Locale locale) { - return getField().getAsText(getReadableInstant().getMillis(), locale); + public String getAsText() { + return getAsText(null); } /** - * Gets a text value from the instant. + * Gets the textual value of this property from the instant as a + * string in the specified locale. + *

            + * This method returns the value converted to a String + * returning the appropriate textual description wherever possible. + * Thus, a day of week of 1 would return 'Monday' in English. * + * @param locale locale to use for selecting a text symbol, null means default * @return the current text value * @see DateTimeField#getAsText */ - public final String getAsText() { - return getAsText(null); + public String getAsText(Locale locale) { + return getField().getAsText(getMillis(), locale); } /** - * Gets a short text value from the instant. + * Gets the short textual value of this property from the instant as a + * string in the default locale. + *

            + * This method returns the value converted to a String + * returning the appropriate textual description wherever possible. + * Thus, a day of week of 1 would return 'Mon' in English. * - * @param locale optional locale to use for selecting a text symbol * @return the current text value * @see DateTimeField#getAsShortText */ - public String getAsShortText(Locale locale) { - return getField().getAsShortText(getReadableInstant().getMillis(), locale); + public String getAsShortText() { + return getAsShortText(null); } /** - * Gets a short text value from the instant. + * Gets the short textual value of this property from the instant as a + * string in the specified locale. + *

            + * This method returns the value converted to a String + * returning the appropriate textual description wherever possible. + * Thus, a day of week of 1 would return 'Mon' in English. * + * @param locale locale to use for selecting a text symbol, null means default * @return the current text value * @see DateTimeField#getAsShortText */ - public final String getAsShortText() { - return getAsShortText(null); + public String getAsShortText(Locale locale) { + return getField().getAsShortText(getMillis(), locale); } //----------------------------------------------------------------------- @@ -190,9 +211,9 @@ */ public int getDifference(ReadableInstant instant) { if (instant == null) { - return getField().getDifference(getReadableInstant().getMillis(), DateTimeUtils.currentTimeMillis()); + return getField().getDifference(getMillis(), DateTimeUtils.currentTimeMillis()); } - return getField().getDifference(getReadableInstant().getMillis(), instant.getMillis()); + return getField().getDifference(getMillis(), instant.getMillis()); } /** @@ -207,9 +228,9 @@ */ public long getDifferenceAsLong(ReadableInstant instant) { if (instant == null) { - return getField().getDifferenceAsLong(getReadableInstant().getMillis(), DateTimeUtils.currentTimeMillis()); + return getField().getDifferenceAsLong(getMillis(), DateTimeUtils.currentTimeMillis()); } - return getField().getDifferenceAsLong(getReadableInstant().getMillis(), instant.getMillis()); + return getField().getDifferenceAsLong(getMillis(), instant.getMillis()); } //----------------------------------------------------------------------- @@ -240,7 +261,7 @@ * @see DateTimeField#isLeap */ public boolean isLeap() { - return getField().isLeap(getReadableInstant().getMillis()); + return getField().isLeap(getMillis()); } /** @@ -250,7 +271,7 @@ * @see DateTimeField#getLeapAmount */ public int getLeapAmount() { - return getField().getLeapAmount(getReadableInstant().getMillis()); + return getField().getLeapAmount(getMillis()); } /** @@ -279,7 +300,7 @@ * @see DateTimeField#getMinimumValue */ public int getMinimumValue() { - return getField().getMinimumValue(getReadableInstant().getMillis()); + return getField().getMinimumValue(getMillis()); } /** @@ -299,7 +320,7 @@ * @see DateTimeField#getMaximumValue */ public int getMaximumValue() { - return getField().getMaximumValue(getReadableInstant().getMillis()); + return getField().getMaximumValue(getMillis()); } /** @@ -332,9 +353,27 @@ * @return remainder duration, in milliseconds */ public long remainder() { - return getField().remainder(getReadableInstant().getMillis()); + return getField().remainder(getMillis()); } + /** + * Returns the interval that represents the range of the minimum + * and maximum values of this field. + *

            + * For example, datetime.monthOfYear().toInterval() + * will return an interval over the whole month. + * + * @return the interval of this field + * @since 1.2 + */ + public Interval toInterval() { + DateTimeField field = getField(); + long start = field.roundFloor(getMillis()); + long end = field.add(start, 1); + Interval interval = new Interval(start, end); + return interval; + } + //----------------------------------------------------------------------- /** * Compare this field to the same field on another instant. @@ -353,8 +392,7 @@ throw new IllegalArgumentException("The instant must not be null"); } int thisValue = get(); - Chronology chrono = DateTimeUtils.getChronology(instant.getChronology()); - int otherValue = getFieldType().getField(chrono).get(instant.getMillis()); + int otherValue = instant.get(getFieldType()); if (thisValue < otherValue) { return -1; } else if (thisValue > otherValue) { @@ -364,6 +402,7 @@ } } + //----------------------------------------------------------------------- /** * Compare this field to the same field on another partial instant. *

            @@ -374,13 +413,12 @@ * * @param partial the partial to compare to * @return negative value if this is less, 0 if equal, or positive value if greater - * @throws IllegalArgumentException if the instant is null - * @throws IllegalArgumentException if the field of this property cannot be queried - * on the specified instant + * @throws IllegalArgumentException if the partial is null + * @throws IllegalArgumentException if the partial doesn't support this field */ public int compareTo(ReadablePartial partial) { if (partial == null) { - throw new IllegalArgumentException("The instant must not be null"); + throw new IllegalArgumentException("The partial must not be null"); } int thisValue = get(); int otherValue = partial.get(getFieldType()); @@ -404,17 +442,25 @@ if (this == object) { return true; } - if (object instanceof AbstractReadableInstantFieldProperty) { - AbstractReadableInstantFieldProperty other = (AbstractReadableInstantFieldProperty) object; - if (get() == other.get() && - getFieldType() == other.getFieldType() && - getReadableInstant().getChronology() == other.getReadableInstant().getChronology()) { - return true; - } + if (object instanceof AbstractReadableInstantFieldProperty == false) { + return false; } - return false; + AbstractReadableInstantFieldProperty other = (AbstractReadableInstantFieldProperty) object; + return + get() == other.get() && + getFieldType().equals(other.getFieldType()) && + FieldUtils.equals(getChronology(), other.getChronology()); } + /** + * Returns a hashcode compatible with the equals method. + * + * @return the hashcode + */ + public int hashCode() { + return get() * 17 + getFieldType().hashCode() + getChronology().hashCode(); + } + //----------------------------------------------------------------------- /** * Output a debugging string. Index: 3rdParty_sources/joda-time/org/joda/time/field/BaseDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/BaseDateTimeField.java (.../BaseDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/BaseDateTimeField.java (.../BaseDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; @@ -58,6 +20,7 @@ import org.joda.time.DateTimeField; import org.joda.time.DateTimeFieldType; import org.joda.time.DurationField; +import org.joda.time.IllegalFieldValueException; import org.joda.time.ReadablePartial; /** @@ -186,7 +149,7 @@ * @param locale the locale to use for selecting a text symbol, null for default * @return the text value of the field */ - protected String getAsText(int fieldValue, Locale locale) { + public String getAsText(int fieldValue, Locale locale) { return Integer.toString(fieldValue); } @@ -260,7 +223,7 @@ * @param locale the locale to use for selecting a text symbol, null for default * @return the text value of the field */ - protected String getAsShortText(int fieldValue, Locale locale) { + public String getAsShortText(int fieldValue, Locale locale) { return getAsText(fieldValue, locale); } @@ -325,7 +288,7 @@ * 2001-01-31 add two months is 2001-03-31
            * * @param instant the partial instant - * @param fieldIndex the index of this field in the instant + * @param fieldIndex the index of this field in the partial * @param values the values of the partial instant which should be updated * @param valueToAdd the value to add, in the units of the field * @return the passed in values @@ -353,13 +316,13 @@ } nextField = instant.getField(fieldIndex - 1); // test only works if this field is UTC (ie. local) - if (getRangeDurationField() != nextField.getDurationField()) { + if (getRangeDurationField().getType() != nextField.getDurationField().getType()) { throw new IllegalArgumentException("Fields invalid for add"); } } - valueToAdd -= (max + 1) - values[fieldIndex]; - values = nextField.add(instant, fieldIndex - 1, values, 1); - values[fieldIndex] = getMinimumValue(instant, values); + valueToAdd -= (max + 1) - values[fieldIndex]; // reduce the amount to add + values = nextField.add(instant, fieldIndex - 1, values, 1); // add 1 to next bigger field + values[fieldIndex] = getMinimumValue(instant, values); // reset this field to zero } while (valueToAdd < 0) { int min = getMinimumValue(instant, values); @@ -373,19 +336,104 @@ throw new IllegalArgumentException("Maximum value exceeded for add"); } nextField = instant.getField(fieldIndex - 1); - if (getRangeDurationField() != nextField.getDurationField()) { + if (getRangeDurationField().getType() != nextField.getDurationField().getType()) { throw new IllegalArgumentException("Fields invalid for add"); } } - valueToAdd -= (min - 1) - values[fieldIndex]; - values = nextField.add(instant, fieldIndex - 1, values, -1); - values[fieldIndex] = getMaximumValue(instant, values); + valueToAdd -= (min - 1) - values[fieldIndex]; // reduce the amount to add + values = nextField.add(instant, fieldIndex - 1, values, -1); // subtract 1 from next bigger field + values[fieldIndex] = getMaximumValue(instant, values); // reset this field to max value } return set(instant, fieldIndex, values, values[fieldIndex]); // adjusts smaller fields } /** + * Adds a value (which may be negative) to the partial instant, + * wrapping the whole partial if the maximum size of the partial is reached. + *

            + * The value will be added to this field, overflowing into larger fields + * if necessary. Smaller fields should be unaffected, except where the + * result would be an invalid value for a smaller field. In this case the + * smaller field is adjusted to be in range. + *

            + * Partial instants only contain some fields. This may result in a maximum + * possible value, such as TimeOfDay normally being limited to 23:59:59:999. + * If ths limit is reached by the addition, this method will wrap back to + * 00:00:00.000. In fact, you would generally only use this method for + * classes that have a limitation such as this. + *

            + * For example, in the ISO chronology:
            + * 10:20:30 add 20 minutes is 10:40:30
            + * 10:20:30 add 45 minutes is 11:05:30
            + * 10:20:30 add 16 hours is 02:20:30
            + * + * @param instant the partial instant + * @param fieldIndex the index of this field in the partial + * @param values the values of the partial instant which should be updated + * @param valueToAdd the value to add, in the units of the field + * @return the passed in values + * @throws IllegalArgumentException if the value is invalid or the maximum instant is reached + */ + public int[] addWrapPartial(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd) { + if (valueToAdd == 0) { + return values; + } + // there are more efficient algorithms than this (especially for time only fields) + // trouble is when dealing with days and months, so we use this technique of + // adding/removing one from the larger field at a time + DateTimeField nextField = null; + + while (valueToAdd > 0) { + int max = getMaximumValue(instant, values); + long proposed = values[fieldIndex] + valueToAdd; + if (proposed <= max) { + values[fieldIndex] = (int) proposed; + break; + } + if (nextField == null) { + if (fieldIndex == 0) { + valueToAdd -= (max + 1) - values[fieldIndex]; + values[fieldIndex] = getMinimumValue(instant, values); + continue; + } + nextField = instant.getField(fieldIndex - 1); + // test only works if this field is UTC (ie. local) + if (getRangeDurationField().getType() != nextField.getDurationField().getType()) { + throw new IllegalArgumentException("Fields invalid for add"); + } + } + valueToAdd -= (max + 1) - values[fieldIndex]; // reduce the amount to add + values = nextField.addWrapPartial(instant, fieldIndex - 1, values, 1); // add 1 to next bigger field + values[fieldIndex] = getMinimumValue(instant, values); // reset this field to zero + } + while (valueToAdd < 0) { + int min = getMinimumValue(instant, values); + long proposed = values[fieldIndex] + valueToAdd; + if (proposed >= min) { + values[fieldIndex] = (int) proposed; + break; + } + if (nextField == null) { + if (fieldIndex == 0) { + valueToAdd -= (min - 1) - values[fieldIndex]; + values[fieldIndex] = getMaximumValue(instant, values); + continue; + } + nextField = instant.getField(fieldIndex - 1); + if (getRangeDurationField().getType() != nextField.getDurationField().getType()) { + throw new IllegalArgumentException("Fields invalid for add"); + } + } + valueToAdd -= (min - 1) - values[fieldIndex]; // reduce the amount to add + values = nextField.addWrapPartial(instant, fieldIndex - 1, values, -1); // subtract 1 from next bigger field + values[fieldIndex] = getMaximumValue(instant, values); // reset this field to max value + } + + return set(instant, fieldIndex, values, values[fieldIndex]); // adjusts smaller fields + } + + /** * Adds a value (which may be negative) to the instant value, * wrapping within this field. *

            @@ -554,7 +602,7 @@ * Sets a value in the milliseconds supplied from a human-readable, text value. * If the specified locale is null, the default locale is used. *

            - * This implementation uses {@link #convertText(String, Locale)} and + * This implementation uses convertText(String, Locale) and * {@link #set(long, int)}. *

            * Note: subclasses that override this method should also override @@ -591,7 +639,7 @@ * Sets a value in the milliseconds supplied from a human-readable, text value. * If the specified locale is null, the default locale is used. *

            - * This implementation uses {@link #convertText(String, Locale)} and + * This implementation uses convertText(String, Locale) and * {@link #set(ReadablePartial, int, int[], int)}. * * @param instant the partial instant @@ -619,7 +667,7 @@ try { return Integer.parseInt(text); } catch (NumberFormatException ex) { - throw new IllegalArgumentException("Invalid " + getName() + " text: " + text); + throw new IllegalFieldValueException(getType(), text); } } Index: 3rdParty_sources/joda-time/org/joda/time/field/BaseDurationField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/BaseDurationField.java (.../BaseDurationField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/BaseDurationField.java (.../BaseDurationField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,59 +1,22 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; import java.io.Serializable; + import org.joda.time.DurationField; import org.joda.time.DurationFieldType; @@ -70,6 +33,7 @@ * * @author Brian S O'Neill * @see DecoratedDurationField + * @since 1.0 */ public abstract class BaseDurationField extends DurationField implements Serializable { @@ -178,8 +142,7 @@ } //------------------------------------------------------------------------ - public int compareTo(Object durationField) { - DurationField otherField = (DurationField) durationField; + public int compareTo(DurationField otherField) { long otherMillis = otherField.getUnitMillis(); long thisMillis = getUnitMillis(); // cannot do (thisMillis - otherMillis) as can overflow Index: 3rdParty_sources/joda-time/org/joda/time/field/DecoratedDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/DecoratedDateTimeField.java (.../DecoratedDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/DecoratedDateTimeField.java (.../DecoratedDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; Index: 3rdParty_sources/joda-time/org/joda/time/field/DecoratedDurationField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/DecoratedDurationField.java (.../DecoratedDurationField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/DecoratedDurationField.java (.../DecoratedDurationField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; @@ -71,6 +33,7 @@ * * @author Brian S O'Neill * @see DelegatedDurationField + * @since 1.0 */ public class DecoratedDurationField extends BaseDurationField { Index: 3rdParty_sources/joda-time/org/joda/time/field/DelegatedDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/DelegatedDateTimeField.java (.../DelegatedDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/DelegatedDateTimeField.java (.../DelegatedDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; @@ -86,7 +48,7 @@ * * @param field the field being decorated */ - protected DelegatedDateTimeField(DateTimeField field) { + public DelegatedDateTimeField(DateTimeField field) { this(field, null); } @@ -96,7 +58,7 @@ * @param field the field being decorated * @param type the field type override */ - protected DelegatedDateTimeField(DateTimeField field, DateTimeFieldType type) { + public DelegatedDateTimeField(DateTimeField field, DateTimeFieldType type) { super(); if (field == null) { throw new IllegalArgumentException("The field must not be null"); @@ -150,6 +112,10 @@ return iField.getAsText(partial, locale); } + public String getAsText(int fieldValue, Locale locale) { + return iField.getAsText(fieldValue, locale); + } + public String getAsShortText(long instant, Locale locale) { return iField.getAsShortText(instant, locale); } @@ -166,6 +132,10 @@ return iField.getAsShortText(partial, locale); } + public String getAsShortText(int fieldValue, Locale locale) { + return iField.getAsShortText(fieldValue, locale); + } + public long add(long instant, int value) { return iField.add(instant, value); } @@ -178,6 +148,10 @@ return iField.add(instant, fieldIndex, values, valueToAdd); } + public int[] addWrapPartial(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd) { + return iField.addWrapPartial(instant, fieldIndex, values, valueToAdd); + } + public long addWrapField(long instant, int value) { return iField.addWrapField(instant, value); } Index: 3rdParty_sources/joda-time/org/joda/time/field/DelegatedDurationField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/DelegatedDurationField.java (.../DelegatedDurationField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/DelegatedDurationField.java (.../DelegatedDurationField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,59 +1,22 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; import java.io.Serializable; + import org.joda.time.DurationField; import org.joda.time.DurationFieldType; @@ -66,6 +29,7 @@ * * @author Brian S O'Neill * @see DecoratedDurationField + * @since 1.0 */ public class DelegatedDurationField extends DurationField implements Serializable { @@ -182,10 +146,21 @@ return iField.getUnitMillis(); } - public int compareTo(Object durationField) { + public int compareTo(DurationField durationField) { return iField.compareTo(durationField); } + public boolean equals(Object obj) { + if (obj instanceof DelegatedDurationField) { + return iField.equals(((DelegatedDurationField) obj).iField); + } + return false; + } + + public int hashCode() { + return iField.hashCode() ^ iType.hashCode(); + } + public String toString() { return (iType == null) ? iField.toString() : ("DurationField[" + iType + ']'); Index: 3rdParty_sources/joda-time/org/joda/time/field/DividedDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/DividedDateTimeField.java (.../DividedDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/DividedDateTimeField.java (.../DividedDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; Index: 3rdParty_sources/joda-time/org/joda/time/field/FieldUtils.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/FieldUtils.java (.../FieldUtils.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/FieldUtils.java (.../FieldUtils.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,59 +1,23 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; import org.joda.time.DateTimeField; +import org.joda.time.DateTimeFieldType; +import org.joda.time.IllegalFieldValueException; /** * General utilities that don't fit elsewhere. @@ -74,18 +38,36 @@ //------------------------------------------------------------------------ /** + * Negates the input throwing an exception if it can't negate it. + * + * @param value the value to negate + * @return the negated value + * @throws ArithmeticException if the value is Integer.MIN_VALUE + * @since 1.1 + */ + public static int safeNegate(int value) { + if (value == Integer.MIN_VALUE) { + throw new ArithmeticException("Integer.MIN_VALUE cannot be negated"); + } + return -value; + } + + /** * Add two values throwing an exception if overflow occurs. * * @param val1 the first value * @param val2 the second value * @return the new total + * @throws ArithmeticException if the value is too big or too small */ public static int safeAdd(int val1, int val2) { - long total = ((long) val1) + ((long) val2); - if (total < Integer.MIN_VALUE || total > Integer.MAX_VALUE) { - throw new ArithmeticException("The calculation caused an overflow: " + val1 +" + " + val2); + int sum = val1 + val2; + // If there is a sign change, but the two values have the same sign... + if ((val1 ^ sum) < 0 && (val1 ^ val2) >= 0) { + throw new ArithmeticException + ("The calculation caused an overflow: " + val1 + " + " + val2); } - return (int) total; + return sum; } /** @@ -94,16 +76,16 @@ * @param val1 the first value * @param val2 the second value * @return the new total + * @throws ArithmeticException if the value is too big or too small */ public static long safeAdd(long val1, long val2) { - long total = val1 + val2; - if (val1 > 0 && val2 > 0 && total < 0) { - throw new ArithmeticException("The calculation caused an overflow: " + val1 +" + " + val2); + long sum = val1 + val2; + // If there is a sign change, but the two values have the same sign... + if ((val1 ^ sum) < 0 && (val1 ^ val2) >= 0) { + throw new ArithmeticException + ("The calculation caused an overflow: " + val1 + " + " + val2); } - if (val1 < 0 && val2 < 0 && total > 0) { - throw new ArithmeticException("The calculation caused an overflow: " + val1 +" + " + val2); - } - return total; + return sum; } /** @@ -112,15 +94,16 @@ * @param val1 the first value, to be taken away from * @param val2 the second value, the amount to take away * @return the new total + * @throws ArithmeticException if the value is too big or too small */ public static long safeSubtract(long val1, long val2) { - if (val2 == Long.MIN_VALUE) { - if (val1 <= 0L) { - return (val1 - val2); - } - throw new ArithmeticException("The calculation caused an overflow: " + val1 +" - " + val2); + long diff = val1 - val2; + // If there is a sign change, but the two values have different signs... + if ((val1 ^ diff) < 0 && (val1 ^ val2) < 0) { + throw new ArithmeticException + ("The calculation caused an overflow: " + val1 + " - " + val2); } - return safeAdd(val1, -val2); + return diff; } /** @@ -129,14 +112,65 @@ * @param val1 the first value * @param val2 the second value * @return the new total + * @throws ArithmeticException if the value is too big or too small + * @since 1.2 */ - public static long safeMultiply(long val1, long val2) { - if (val1 == 0 || val2 == 0) { + public static int safeMultiply(int val1, int val2) { + long total = (long) val1 * (long) val2; + if (total < Integer.MIN_VALUE || total > Integer.MAX_VALUE) { + throw new ArithmeticException + ("The calculation caused an overflow: " + val1 + " * " + val2); + } + return (int) total; + } + + /** + * Multiply two values throwing an exception if overflow occurs. + * + * @param val1 the first value + * @param scalar the second value + * @return the new total + * @throws ArithmeticException if the value is too big or too small + * @since 1.2 + */ + public static long safeMultiply(long val1, int scalar) { + switch (scalar) { + case -1: + return -val1; + case 0: return 0L; + case 1: + return val1; } + long total = val1 * scalar; + if (total / scalar != val1) { + throw new ArithmeticException + ("The calculation caused an overflow: " + val1 + " * " + scalar); + } + return total; + } + + /** + * Multiply two values throwing an exception if overflow occurs. + * + * @param val1 the first value + * @param val2 the second value + * @return the new total + * @throws ArithmeticException if the value is too big or too small + */ + public static long safeMultiply(long val1, long val2) { + if (val2 == 1) { + return val1; + } + if (val1 == 1) { + return val2; + } + if (val1 == 0 || val2 == 0) { + return 0; + } long total = val1 * val2; - if (total / val2 != val1) { - throw new ArithmeticException("The calculation caused an overflow: " + val1 +" * " + val2); + if (total / val2 != val1 || val1 == Long.MIN_VALUE && val2 == -1 || val2 == Long.MIN_VALUE && val1 == -1) { + throw new ArithmeticException("Multiplication overflows a long: " + val1 + " * " + val2); } return total; } @@ -146,6 +180,7 @@ * * @param value the value * @return the value as an int + * @throws ArithmeticException if the value is too big or too small */ public static int safeToInt(long value) { if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) { @@ -160,33 +195,28 @@ * @param val1 the first value * @param val2 the second value * @return the new total + * @throws ArithmeticException if the value is too big or too small */ public static int safeMultiplyToInt(long val1, long val2) { long val = FieldUtils.safeMultiply(val1, val2); return FieldUtils.safeToInt(val); } - + + //----------------------------------------------------------------------- /** * Verify that input values are within specified bounds. * * @param value the value to check * @param lowerBound the lower bound allowed for value * @param upperBound the upper bound allowed for value - * @throws IllegalArgumentException if value is not in the specified bounds + * @throws IllegalFieldValueException if value is not in the specified bounds */ public static void verifyValueBounds(DateTimeField field, int value, int lowerBound, int upperBound) { if ((value < lowerBound) || (value > upperBound)) { - throw new IllegalArgumentException( - "Value " - + value - + " for " - + field.getName() - + " must be in the range [" - + lowerBound - + ',' - + upperBound - + ']'); + throw new IllegalFieldValueException + (field.getType(), Integer.valueOf(value), + Integer.valueOf(lowerBound), Integer.valueOf(upperBound)); } } @@ -196,21 +226,32 @@ * @param value the value to check * @param lowerBound the lower bound allowed for value * @param upperBound the upper bound allowed for value - * @throws IllegalArgumentException if value is not in the specified bounds + * @throws IllegalFieldValueException if value is not in the specified bounds + * @since 1.1 */ + public static void verifyValueBounds(DateTimeFieldType fieldType, + int value, int lowerBound, int upperBound) { + if ((value < lowerBound) || (value > upperBound)) { + throw new IllegalFieldValueException + (fieldType, Integer.valueOf(value), + Integer.valueOf(lowerBound), Integer.valueOf(upperBound)); + } + } + + /** + * Verify that input values are within specified bounds. + * + * @param value the value to check + * @param lowerBound the lower bound allowed for value + * @param upperBound the upper bound allowed for value + * @throws IllegalFieldValueException if value is not in the specified bounds + */ public static void verifyValueBounds(String fieldName, int value, int lowerBound, int upperBound) { if ((value < lowerBound) || (value > upperBound)) { - throw new IllegalArgumentException( - "Value " - + value - + " for " - + fieldName - + " must be in the range [" - + lowerBound - + ',' - + upperBound - + ']'); + throw new IllegalFieldValueException + (fieldName, Integer.valueOf(value), + Integer.valueOf(lowerBound), Integer.valueOf(upperBound)); } } @@ -266,4 +307,23 @@ return (wrapRange - remByRange) + minValue; } + //----------------------------------------------------------------------- + /** + * Compares two objects as equals handling null. + * + * @param object1 the first object + * @param object2 the second object + * @return true if equal + * @since 1.4 + */ + public static boolean equals(Object object1, Object object2) { + if (object1 == object2) { + return true; + } + if (object1 == null || object2 == null) { + return false; + } + return object1.equals(object2); + } + } Index: 3rdParty_sources/joda-time/org/joda/time/field/ImpreciseDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/ImpreciseDateTimeField.java (.../ImpreciseDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/ImpreciseDateTimeField.java (.../ImpreciseDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; @@ -74,6 +36,7 @@ * * @author Brian S O'Neill * @see PreciseDateTimeField + * @since 1.0 */ public abstract class ImpreciseDateTimeField extends BaseDateTimeField { Index: 3rdParty_sources/joda-time/org/joda/time/field/LenientDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/LenientDateTimeField.java (.../LenientDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/LenientDateTimeField.java (.../LenientDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,58 +1,21 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2007 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; +import org.joda.time.Chronology; import org.joda.time.DateTimeField; /** @@ -64,17 +27,20 @@ * @author Brian S O'Neill * @see org.joda.time.chrono.LenientChronology * @see StrictDateTimeField + * @since 1.0 */ public class LenientDateTimeField extends DelegatedDateTimeField { private static final long serialVersionUID = 8714085824173290599L; + private final Chronology iBase; + /** * Returns a lenient version of the given field. If it is already lenient, * then it is returned as-is. Otherwise, a new LenientDateTimeField is * returned. */ - public static DateTimeField getInstance(DateTimeField field) { + public static DateTimeField getInstance(DateTimeField field, Chronology base) { if (field == null) { return null; } @@ -84,27 +50,28 @@ if (field.isLenient()) { return field; } - return new LenientDateTimeField(field); + return new LenientDateTimeField(field, base); } - protected LenientDateTimeField(DateTimeField field) { + protected LenientDateTimeField(DateTimeField field, Chronology base) { super(field); + iBase = base; } public final boolean isLenient() { return true; } /** - * Set values which may be out of bounds. If the value is out of bounds, - * the instant is first set to the minimum allowed value, and then the - * difference is added. + * Set values which may be out of bounds by adding the difference between + * the new value and the current value. */ public long set(long instant, int value) { - int min = getMinimumValue(instant); - if (value >= min && value < getMaximumValue(instant)) { - return super.set(instant, value); - } - return add(super.set(instant, min), value - min); + // lenient needs to handle time zone chronologies + // so we do the calculation using local milliseconds + long localInstant = iBase.getZone().convertUTCToLocal(instant); + long difference = FieldUtils.safeSubtract(value, get(instant)); + localInstant = getType().getField(iBase.withUTC()).add(localInstant, difference); + return iBase.getZone().convertLocalToUTC(localInstant, false, instant); } } Index: 3rdParty_sources/joda-time/org/joda/time/field/MillisDurationField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/MillisDurationField.java (.../MillisDurationField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/MillisDurationField.java (.../MillisDurationField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; @@ -65,6 +27,7 @@ * MillisDurationField is thread-safe and immutable. * * @author Brian S O'Neill + * @since 1.0 */ public final class MillisDurationField extends DurationField implements Serializable { @@ -167,8 +130,7 @@ } //------------------------------------------------------------------------ - public int compareTo(Object durationField) { - DurationField otherField = (DurationField) durationField; + public int compareTo(DurationField otherField) { long otherMillis = otherField.getUnitMillis(); long thisMillis = getUnitMillis(); // cannot do (thisMillis - otherMillis) as can overflow @@ -182,6 +144,17 @@ } } + public boolean equals(Object obj) { + if (obj instanceof MillisDurationField) { + return getUnitMillis() == ((MillisDurationField) obj).getUnitMillis(); + } + return false; + } + + public int hashCode() { + return (int) getUnitMillis(); + } + /** * Get a suitable debug string. * Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/field/NonZeroDateTimeField.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/joda-time/org/joda/time/field/OffsetDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/OffsetDateTimeField.java (.../OffsetDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/OffsetDateTimeField.java (.../OffsetDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; Index: 3rdParty_sources/joda-time/org/joda/time/field/PreciseDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/PreciseDateTimeField.java (.../PreciseDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/PreciseDateTimeField.java (.../PreciseDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; Index: 3rdParty_sources/joda-time/org/joda/time/field/PreciseDurationDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/PreciseDurationDateTimeField.java (.../PreciseDurationDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/PreciseDurationDateTimeField.java (.../PreciseDurationDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; @@ -63,6 +25,7 @@ * subclasses must be as well. * * @author Brian S O'Neill + * @since 1.0 */ public abstract class PreciseDurationDateTimeField extends BaseDateTimeField { Index: 3rdParty_sources/joda-time/org/joda/time/field/PreciseDurationField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/PreciseDurationField.java (.../PreciseDurationField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/PreciseDurationField.java (.../PreciseDurationField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; Index: 3rdParty_sources/joda-time/org/joda/time/field/RemainderDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/RemainderDateTimeField.java (.../RemainderDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/RemainderDateTimeField.java (.../RemainderDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; Index: 3rdParty_sources/joda-time/org/joda/time/field/ScaledDurationField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/ScaledDurationField.java (.../ScaledDurationField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/ScaledDurationField.java (.../ScaledDurationField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; @@ -65,6 +27,7 @@ * @see PreciseDurationField * * @author Brian S O'Neill + * @since 1.0 */ public class ScaledDurationField extends DecoratedDurationField { Index: 3rdParty_sources/joda-time/org/joda/time/field/SkipDateTimeField.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/field/SkipDateTimeField.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/field/SkipDateTimeField.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,107 @@ +/* + * Copyright 2001-2005 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.field; + +import org.joda.time.Chronology; +import org.joda.time.DateTimeField; +import org.joda.time.DateTimeFieldType; +import org.joda.time.IllegalFieldValueException; + +/** + * Wraps another field such that a certain value is skipped. + *

            + * This is most useful for years where you want to skip zero, so the + * sequence runs ...,2,1,-1,-2,... + *

            + * SkipDateTimeField is thread-safe and immutable. + * + * @author Brian S O'Neill + * @author Stephen Colebourne + * @since 1.0 + */ +public final class SkipDateTimeField extends DelegatedDateTimeField { + + /** Serialization version. */ + private static final long serialVersionUID = -8869148464118507846L; + + /** The chronology to wrap. */ + private final Chronology iChronology; + /** The value to skip. */ + private final int iSkip; + /** The calculated minimum value. */ + private transient int iMinValue; + + /** + * Constructor that skips zero. + * + * @param chronology the chronoogy to use + * @param field the field to skip zero on + */ + public SkipDateTimeField(Chronology chronology, DateTimeField field) { + this(chronology, field, 0); + } + + /** + * Constructor. + * + * @param chronology the chronoogy to use + * @param field the field to skip zero on + * @param skip the value to skip + */ + public SkipDateTimeField(Chronology chronology, DateTimeField field, int skip) { + super(field); + iChronology = chronology; + int min = super.getMinimumValue(); + if (min < skip) { + iMinValue = min - 1; + } else if (min == skip) { + iMinValue = skip + 1; + } else { + iMinValue = min; + } + iSkip = skip; + } + + //----------------------------------------------------------------------- + public int get(long millis) { + int value = super.get(millis); + if (value <= iSkip) { + value--; + } + return value; + } + + public long set(long millis, int value) { + FieldUtils.verifyValueBounds(this, value, iMinValue, getMaximumValue()); + if (value <= iSkip) { + if (value == iSkip) { + throw new IllegalFieldValueException + (DateTimeFieldType.year(), Integer.valueOf(value), null, null); + } + value++; + } + return super.set(millis, value); + } + + public int getMinimumValue() { + return iMinValue; + } + + private Object readResolve() { + return getType().getField(iChronology); + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/field/SkipUndoDateTimeField.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/field/SkipUndoDateTimeField.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/field/SkipUndoDateTimeField.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,102 @@ +/* + * Copyright 2001-2005 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.field; + +import org.joda.time.Chronology; +import org.joda.time.DateTimeField; + +/** + * Wraps another field such that a certain value is added back into + * the sequence of numbers. + *

            + * This reverses the effect of SkipDateTimeField. This isn't very + * elegant. + *

            + * SkipUndoDateTimeField is thread-safe and immutable. + * + * @author Brian S O'Neill + * @author Stephen Colebourne + * @since 1.0 + */ +public final class SkipUndoDateTimeField extends DelegatedDateTimeField { + + /** Serialization version. */ + private static final long serialVersionUID = -5875876968979L; + + /** The chronology to wrap. */ + private final Chronology iChronology; + /** The value to skip. */ + private final int iSkip; + /** The calculated minimum value. */ + private transient int iMinValue; + + /** + * Constructor that reinserts zero. + * + * @param chronology the chronoogy to use + * @param field the field to skip zero on + */ + public SkipUndoDateTimeField(Chronology chronology, DateTimeField field) { + this(chronology, field, 0); + } + + /** + * Constructor. + * + * @param chronology the chronoogy to use + * @param field the field to skip zero on + * @param skip the value to skip + */ + public SkipUndoDateTimeField(Chronology chronology, DateTimeField field, int skip) { + super(field); + iChronology = chronology; + int min = super.getMinimumValue(); + if (min < skip) { + iMinValue = min + 1; + } else if (min == skip + 1) { + iMinValue = skip; + } else { + iMinValue = min; + } + iSkip = skip; + } + + //----------------------------------------------------------------------- + public int get(long millis) { + int value = super.get(millis); + if (value < iSkip) { + value++; + } + return value; + } + + public long set(long millis, int value) { + FieldUtils.verifyValueBounds(this, value, iMinValue, getMaximumValue()); + if (value <= iSkip) { + value--; + } + return super.set(millis, value); + } + + public int getMinimumValue() { + return iMinValue; + } + + private Object readResolve() { + return getType().getField(iChronology); + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/field/StrictDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/StrictDateTimeField.java (.../StrictDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/StrictDateTimeField.java (.../StrictDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; @@ -64,6 +26,7 @@ * @author Brian S O'Neill * @see org.joda.time.chrono.StrictChronology * @see LenientDateTimeField + * @since 1.0 */ public class StrictDateTimeField extends DelegatedDateTimeField { Index: 3rdParty_sources/joda-time/org/joda/time/field/UnsupportedDateTimeField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/UnsupportedDateTimeField.java (.../UnsupportedDateTimeField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/UnsupportedDateTimeField.java (.../UnsupportedDateTimeField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; @@ -67,14 +29,15 @@ * UnsupportedDateTimeField is thread-safe and immutable. * * @author Brian S O'Neill + * @since 1.0 */ public final class UnsupportedDateTimeField extends DateTimeField implements Serializable { /** Serialilzation version */ private static final long serialVersionUID = -1934618396111902255L; /** The cache of unsupported datetime field instances */ - private static HashMap cCache; + private static HashMap cCache; /** * Gets an instance of UnsupportedDateTimeField for a specific named field. @@ -90,10 +53,10 @@ UnsupportedDateTimeField field; if (cCache == null) { - cCache = new HashMap(7); + cCache = new HashMap(7); field = null; } else { - field = (UnsupportedDateTimeField)cCache.get(type); + field = cCache.get(type); if (field != null && field.getDurationField() != durationField) { field = null; } @@ -204,6 +167,15 @@ * * @throws UnsupportedOperationException */ + public String getAsText(int fieldValue, Locale locale) { + throw unsupported(); + } + + /** + * Always throws UnsupportedOperationException + * + * @throws UnsupportedOperationException + */ public String getAsShortText(long instant, Locale locale) { throw unsupported(); } @@ -236,6 +208,15 @@ } /** + * Always throws UnsupportedOperationException + * + * @throws UnsupportedOperationException + */ + public String getAsShortText(int fieldValue, Locale locale) { + throw unsupported(); + } + + /** * Delegates to the duration field. * * @throws UnsupportedOperationException if the duration is unsupported @@ -267,6 +248,15 @@ * * @throws UnsupportedOperationException */ + public int[] addWrapPartial(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd) { + throw unsupported(); + } + + /** + * Always throws UnsupportedOperationException + * + * @throws UnsupportedOperationException + */ public long addWrapField(long instant, int value) { throw unsupported(); } Index: 3rdParty_sources/joda-time/org/joda/time/field/UnsupportedDurationField.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/UnsupportedDurationField.java (.../UnsupportedDurationField.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/UnsupportedDurationField.java (.../UnsupportedDurationField.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,60 +1,23 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.field; import java.io.Serializable; import java.util.HashMap; + import org.joda.time.DurationField; import org.joda.time.DurationFieldType; @@ -64,18 +27,18 @@ * UnsupportedDurationField is thread-safe and immutable. * * @author Brian S O'Neill + * @since 1.0 */ public final class UnsupportedDurationField extends DurationField implements Serializable { /** Serialization lock. */ private static final long serialVersionUID = -6390301302770925357L; /** The cache of unsupported duration field instances */ - private static HashMap cCache; + private static HashMap cCache; /** * Gets an instance of UnsupportedDurationField for a specific named field. - * Names should be plural, such as 'years' or 'hours'. * The returned instance is cached. * * @param type the type to obtain @@ -84,10 +47,10 @@ public static synchronized UnsupportedDurationField getInstance(DurationFieldType type) { UnsupportedDurationField field; if (cCache == null) { - cCache = new HashMap(7); + cCache = new HashMap(7); field = null; } else { - field = (UnsupportedDurationField) cCache.get(type); + field = cCache.get(type); } if (field == null) { field = new UnsupportedDurationField(type); @@ -260,7 +223,7 @@ * * @return zero always */ - public int compareTo(Object durationField) { + public int compareTo(DurationField durationField) { return 0; } Index: 3rdParty_sources/joda-time/org/joda/time/field/ZeroIsMaxDateTimeField.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/field/ZeroIsMaxDateTimeField.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/field/ZeroIsMaxDateTimeField.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,204 @@ +/* + * Copyright 2001-2005 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.field; + +import org.joda.time.DateTimeField; +import org.joda.time.DateTimeFieldType; +import org.joda.time.DurationField; +import org.joda.time.ReadablePartial; + +/** + * Wraps another field such that zero values are replaced with one more than + * it's maximum. This is particularly useful for implementing an clockhourOfDay + * field, where the midnight value of 0 is replaced with 24. + *

            + * ZeroIsMaxDateTimeField is thread-safe and immutable. + * + * @author Brian S O'Neill + * @since 1.0 + */ +public final class ZeroIsMaxDateTimeField extends DecoratedDateTimeField { + + private static final long serialVersionUID = 961749798233026866L; + + /** + * Constructor. + * + * @param field the base field + * @param type the field type this field will actually use + * @throws IllegalArgumentException if wrapped field's minimum value is not zero + */ + public ZeroIsMaxDateTimeField(DateTimeField field, DateTimeFieldType type) { + super(field, type); + if (field.getMinimumValue() != 0) { + throw new IllegalArgumentException("Wrapped field's minumum value must be zero"); + } + } + + public int get(long instant) { + int value = getWrappedField().get(instant); + if (value == 0) { + value = getMaximumValue(); + } + return value; + } + + public long add(long instant, int value) { + return getWrappedField().add(instant, value); + } + + public long add(long instant, long value) { + return getWrappedField().add(instant, value); + } + + public long addWrapField(long instant, int value) { + return getWrappedField().addWrapField(instant, value); + } + + public int[] addWrapField(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd) { + return getWrappedField().addWrapField(instant, fieldIndex, values, valueToAdd); + } + + public int getDifference(long minuendInstant, long subtrahendInstant) { + return getWrappedField().getDifference(minuendInstant, subtrahendInstant); + } + + public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) { + return getWrappedField().getDifferenceAsLong(minuendInstant, subtrahendInstant); + } + + public long set(long instant, int value) { + int max = getMaximumValue(); + FieldUtils.verifyValueBounds(this, value, 1, max); + if (value == max) { + value = 0; + } + return getWrappedField().set(instant, value); + } + + public boolean isLeap(long instant) { + return getWrappedField().isLeap(instant); + } + + public int getLeapAmount(long instant) { + return getWrappedField().getLeapAmount(instant); + } + + public DurationField getLeapDurationField() { + return getWrappedField().getLeapDurationField(); + } + + /** + * Always returns 1. + * + * @return the minimum value of 1 + */ + public int getMinimumValue() { + return 1; + } + + /** + * Always returns 1. + * + * @return the minimum value of 1 + */ + public int getMinimumValue(long instant) { + return 1; + } + + /** + * Always returns 1. + * + * @return the minimum value of 1 + */ + public int getMinimumValue(ReadablePartial instant) { + return 1; + } + + /** + * Always returns 1. + * + * @return the minimum value of 1 + */ + public int getMinimumValue(ReadablePartial instant, int[] values) { + return 1; + } + + /** + * Get the maximum value for the field, which is one more than the wrapped + * field's maximum value. + * + * @return the maximum value + */ + public int getMaximumValue() { + return getWrappedField().getMaximumValue() + 1; + } + + /** + * Get the maximum value for the field, which is one more than the wrapped + * field's maximum value. + * + * @return the maximum value + */ + public int getMaximumValue(long instant) { + return getWrappedField().getMaximumValue(instant) + 1; + } + + /** + * Get the maximum value for the field, which is one more than the wrapped + * field's maximum value. + * + * @return the maximum value + */ + public int getMaximumValue(ReadablePartial instant) { + return getWrappedField().getMaximumValue(instant) + 1; + } + + /** + * Get the maximum value for the field, which is one more than the wrapped + * field's maximum value. + * + * @return the maximum value + */ + public int getMaximumValue(ReadablePartial instant, int[] values) { + return getWrappedField().getMaximumValue(instant, values) + 1; + } + + public long roundFloor(long instant) { + return getWrappedField().roundFloor(instant); + } + + public long roundCeiling(long instant) { + return getWrappedField().roundCeiling(instant); + } + + public long roundHalfFloor(long instant) { + return getWrappedField().roundHalfFloor(instant); + } + + public long roundHalfCeiling(long instant) { + return getWrappedField().roundHalfCeiling(instant); + } + + public long roundHalfEven(long instant) { + return getWrappedField().roundHalfEven(instant); + } + + public long remainder(long instant) { + return getWrappedField().remainder(instant); + } + +} Index: 3rdParty_sources/joda-time/org/joda/time/field/package.html =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/field/package.html (.../package.html) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/field/package.html (.../package.html) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -4,57 +4,19 @@ org.joda.time.field package Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/format/BaseDateTimeFormatter.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/format/BasePeriodFormatter.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/joda-time/org/joda/time/format/DateTimeFormat.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/format/DateTimeFormat.java (.../DateTimeFormat.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/format/DateTimeFormat.java (.../DateTimeFormat.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.format; @@ -63,38 +25,34 @@ import org.joda.time.Chronology; import org.joda.time.DateTime; -import org.joda.time.DateTimeField; -import org.joda.time.DateTimeFieldType; import org.joda.time.DateTimeZone; -import org.joda.time.DurationFieldType; -import org.joda.time.MutableDateTime; -import org.joda.time.ReadWritableInstant; -import org.joda.time.ReadableInstant; import org.joda.time.ReadablePartial; -import org.joda.time.field.RemainderDateTimeField; /** - * DateTimeFormat provides localized printing and parsing capabilities for all - * dates and times. + * Factory that creates instances of DateTimeFormatter from patterns and styles. *

            - * This class provides access to the actual DateTimeFormatter instances in two ways: + * Datetime formatting is performed by the {@link DateTimeFormatter} class. + * Three classes provide factory methods to create formatters, and this is one. + * The others are {@link ISODateTimeFormat} and {@link DateTimeFormatterBuilder}. + *

            + * This class provides two types of factory: *

              *
            • {@link #forPattern(String) Pattern} provides a DateTimeFormatter based on - * a pattern string that is compatible with the JDK date patterns. + * a pattern string that is mostly compatible with the JDK date patterns. *
            • {@link #forStyle(String) Style} provides a DateTimeFormatter based on a * two character style, representing short, medium, long and full. *
            *

            * For example, to use a patterm: *

              * DateTime dt = new DateTime();
            - * DateTimeFormatter fmt = DateTimeFormat.getInstance().forPattern("MMMM, yyyy");
            + * DateTimeFormatter fmt = DateTimeFormat.forPattern("MMMM, yyyy");
              * String str = fmt.print(dt);
              * 
            * - * The pattern syntax is compatible with java.text.SimpleDateFormat, but a few - * more symbols are also supported. All ASCII letters are reserved as pattern - * letters, which are defined as the following: + * The pattern syntax is mostly compatible with java.text.SimpleDateFormat - + * time zone names cannot be parsed and a few more symbols are supported. + * All ASCII letters are reserved as pattern letters, which are defined as follows: *
            *
              * Symbol  Meaning                      Presentation  Examples
            @@ -124,7 +82,7 @@
              * S       fraction of second           number        978
              *
              * z       time zone                    text          Pacific Standard Time; PST
            - * Z       time zone offset             text          -08:00; -0800
            + * Z       time zone offset/id          zone          -0800; -08:00; America/Los_Angeles
              *
              * '       escape for text              delimiter
              * ''      single quote                 literal       '
            @@ -146,65 +104,299 @@
              * 

            * Month: 3 or over, use text, otherwise use number. *

            + * Zone: 'Z' outputs offset without a colon, 'ZZ' outputs + * the offset with a colon, 'ZZZ' or more outputs the zone id. + *

            + * Zone names: Time zone names ('z') cannot be parsed. + *

            * Any characters in the pattern that are not in the ranges of ['a'..'z'] * and ['A'..'Z'] will be treated as quoted text. For instance, characters - * like ':', '.', ' ', '#' and '@' will appear in the resulting time text + * like ':', '.', ' ', '#' and '?' will appear in the resulting time text * even they are not embraced within single quotes. *

            * DateTimeFormat is thread-safe and immutable, and the formatters it returns * are as well. * * @author Brian S O'Neill + * @author Maxim Zhao * @since 1.0 * @see ISODateTimeFormat * @see DateTimeFormatterBuilder */ public class DateTimeFormat { + /** Style constant for FULL. */ + static final int FULL = 0; // DateFormat.FULL + /** Style constant for LONG. */ + static final int LONG = 1; // DateFormat.LONG + /** Style constant for MEDIUM. */ + static final int MEDIUM = 2; // DateFormat.MEDIUM + /** Style constant for SHORT. */ + static final int SHORT = 3; // DateFormat.SHORT + /** Style constant for NONE. */ + static final int NONE = 4; + + /** Type constant for DATE only. */ + static final int DATE = 0; + /** Type constant for TIME only. */ + static final int TIME = 1; + /** Type constant for DATETIME. */ + static final int DATETIME = 2; + + /** Maps patterns to formatters, patterns don't vary by locale. */ + private static final Map cPatternedCache = new HashMap(7); + /** Maps patterns to formatters, patterns don't vary by locale. */ + private static final DateTimeFormatter[] cStyleCache = new DateTimeFormatter[25]; + + //----------------------------------------------------------------------- /** - * Cache that maps Chronology instances to maps that map - * Locales to DateTimeFormat instances. + * Factory to create a formatter from a pattern string. + * The pattern string is described above in the class level javadoc. + * It is very similar to SimpleDateFormat patterns. + *

            + * The format may contain locale specific output, and this will change as + * you change the locale of the formatter. + * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale. + * For example: + *

            +     * DateTimeFormat.forPattern(pattern).withLocale(Locale.FRANCE).print(dt);
            +     * 
            + * + * @param pattern pattern specification + * @return the formatter + * @throws IllegalArgumentException if the pattern is invalid */ - private static Map cInstanceCache = new HashMap(7); + public static DateTimeFormatter forPattern(String pattern) { + return createFormatterForPattern(pattern); + } - //----------------------------------------------------------------------- /** - * Gets an instance of the formatter provider that works with the default locale. - * - * @return a format provider + * Factory to create a format from a two character style pattern. + *

            + * The first character is the date style, and the second character is the + * time style. Specify a character of 'S' for short style, 'M' for medium, + * 'L' for long, and 'F' for full. + * A date or time may be ommitted by specifying a style character '-'. + *

            + * The returned formatter will dynamically adjust to the locale that + * the print/parse takes place in. Thus you just call + * {@link DateTimeFormatter#withLocale(Locale)} and the Short/Medium/Long/Full + * style for that locale will be output. For example: + *

            +     * DateTimeFormat.forStyle(style).withLocale(Locale.FRANCE).print(dt);
            +     * 
            + * + * @param style two characters from the set {"S", "M", "L", "F", "-"} + * @return the formatter + * @throws IllegalArgumentException if the style is invalid */ - public static DateTimeFormat getInstance() { - return getInstance(Locale.getDefault()); + public static DateTimeFormatter forStyle(String style) { + return createFormatterForStyle(style); } /** - * Gets an instance of the formatter provider that works with the given locale. - * - * @param locale the Locale to use, null for default locale - * @return a format provider + * Returns the pattern used by a particular style and locale. + *

            + * The first character is the date style, and the second character is the + * time style. Specify a character of 'S' for short style, 'M' for medium, + * 'L' for long, and 'F' for full. + * A date or time may be ommitted by specifying a style character '-'. + * + * @param style two characters from the set {"S", "M", "L", "F", "-"} + * @param locale locale to use, null means default + * @return the formatter + * @throws IllegalArgumentException if the style is invalid + * @since 1.3 */ - public synchronized static DateTimeFormat getInstance(Locale locale) { + public static String patternForStyle(String style, Locale locale) { + DateTimeFormatter formatter = createFormatterForStyle(style); if (locale == null) { locale = Locale.getDefault(); } - DateTimeFormat dtf = (DateTimeFormat) cInstanceCache.get(locale); - if (dtf == null) { - dtf = new DateTimeFormat(locale); - cInstanceCache.put(locale, dtf); - } - return dtf; + // Not pretty, but it works. + return ((StyleFormatter) formatter.getPrinter()).getPattern(locale); } //----------------------------------------------------------------------- /** + * Creates a format that outputs a short date format. + *

            + * The format will change as you change the locale of the formatter. + * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale. + * + * @return the formatter + */ + public static DateTimeFormatter shortDate() { + return createFormatterForStyleIndex(SHORT, NONE); + } + + /** + * Creates a format that outputs a short time format. + *

            + * The format will change as you change the locale of the formatter. + * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale. + * + * @return the formatter + */ + public static DateTimeFormatter shortTime() { + return createFormatterForStyleIndex(NONE, SHORT); + } + + /** + * Creates a format that outputs a short datetime format. + *

            + * The format will change as you change the locale of the formatter. + * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale. + * + * @return the formatter + */ + public static DateTimeFormatter shortDateTime() { + return createFormatterForStyleIndex(SHORT, SHORT); + } + + //----------------------------------------------------------------------- + /** + * Creates a format that outputs a medium date format. + *

            + * The format will change as you change the locale of the formatter. + * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale. + * + * @return the formatter + */ + public static DateTimeFormatter mediumDate() { + return createFormatterForStyleIndex(MEDIUM, NONE); + } + + /** + * Creates a format that outputs a medium time format. + *

            + * The format will change as you change the locale of the formatter. + * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale. + * + * @return the formatter + */ + public static DateTimeFormatter mediumTime() { + return createFormatterForStyleIndex(NONE, MEDIUM); + } + + /** + * Creates a format that outputs a medium datetime format. + *

            + * The format will change as you change the locale of the formatter. + * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale. + * + * @return the formatter + */ + public static DateTimeFormatter mediumDateTime() { + return createFormatterForStyleIndex(MEDIUM, MEDIUM); + } + + //----------------------------------------------------------------------- + /** + * Creates a format that outputs a long date format. + *

            + * The format will change as you change the locale of the formatter. + * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale. + * + * @return the formatter + */ + public static DateTimeFormatter longDate() { + return createFormatterForStyleIndex(LONG, NONE); + } + + /** + * Creates a format that outputs a long time format. + *

            + * The format will change as you change the locale of the formatter. + * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale. + * + * @return the formatter + */ + public static DateTimeFormatter longTime() { + return createFormatterForStyleIndex(NONE, LONG); + } + + /** + * Creates a format that outputs a long datetime format. + *

            + * The format will change as you change the locale of the formatter. + * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale. + * + * @return the formatter + */ + public static DateTimeFormatter longDateTime() { + return createFormatterForStyleIndex(LONG, LONG); + } + + //----------------------------------------------------------------------- + /** + * Creates a format that outputs a full date format. + *

            + * The format will change as you change the locale of the formatter. + * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale. + * + * @return the formatter + */ + public static DateTimeFormatter fullDate() { + return createFormatterForStyleIndex(FULL, NONE); + } + + /** + * Creates a format that outputs a full time format. + *

            + * The format will change as you change the locale of the formatter. + * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale. + * + * @return the formatter + */ + public static DateTimeFormatter fullTime() { + return createFormatterForStyleIndex(NONE, FULL); + } + + /** + * Creates a format that outputs a full datetime format. + *

            + * The format will change as you change the locale of the formatter. + * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale. + * + * @return the formatter + */ + public static DateTimeFormatter fullDateTime() { + return createFormatterForStyleIndex(FULL, FULL); + } + + //----------------------------------------------------------------------- + /** * Parses the given pattern and appends the rules to the given * DateTimeFormatterBuilder. * * @param pattern pattern specification * @throws IllegalArgumentException if the pattern is invalid + */ + static void appendPatternTo(DateTimeFormatterBuilder builder, String pattern) { + parsePatternTo(builder, pattern); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @since 1.1 (previously private) + */ + protected DateTimeFormat() { + super(); + } + + //----------------------------------------------------------------------- + /** + * Parses the given pattern and appends the rules to the given + * DateTimeFormatterBuilder. + * + * @param pattern pattern specification + * @throws IllegalArgumentException if the pattern is invalid * @see #forPattern */ - public static void appendPatternTo(DateTimeFormatterBuilder builder, String pattern) { + private static void parsePatternTo(DateTimeFormatterBuilder builder, String pattern) { int length = pattern.length(); int[] indexRef = new int[1]; @@ -230,24 +422,32 @@ case 'y': // year (number) case 'Y': // year of era (number) if (tokenLen == 2) { - // Use a new remainder type to ensure that the year of - // century is zero-based. - DateTimeFieldType type; + boolean lenientParse = true; + + // Peek ahead to next token. + if (i + 1 < length) { + indexRef[0]++; + if (isNumericToken(parseToken(pattern, indexRef))) { + // If next token is a number, cannot support + // lenient parse, because it will consume digits + // that it should not. + lenientParse = false; + } + indexRef[0]--; + } + + // Use pivots which are compatible with SimpleDateFormat. switch (c) { case 'x': - type = new RemainderType(DateTimeFieldType.weekyear(), - DateTimeFieldType.weekyearOfCentury(), 100); + builder.appendTwoDigitWeekyear + (new DateTime().getWeekyear() - 30, lenientParse); break; - case 'y': default: - type = new RemainderType(DateTimeFieldType.year(), - DateTimeFieldType.yearOfCentury(), 100); - break; + case 'y': case 'Y': - type = new RemainderType(DateTimeFieldType.yearOfEra(), - DateTimeFieldType.yearOfCentury(), 100); + default: + builder.appendTwoDigitYear(new DateTime().getYear() - 30, lenientParse); break; } - builder.appendDecimal(type, 2, 2); } else { // Try to support long year values. int maxDigits = 9; @@ -289,12 +489,21 @@ case 'd': // day of month (number) builder.appendDayOfMonth(tokenLen); break; - case 'h': // hour of day (number, 1..12) + case 'a': // am/pm marker (text) + builder.appendHalfdayOfDayText(); + break; + case 'h': // clockhour of halfday (number, 1..12) builder.appendClockhourOfHalfday(tokenLen); break; case 'H': // hour of day (number, 0..23) builder.appendHourOfDay(tokenLen); break; + case 'k': // clockhour of day (1..24) + builder.appendClockhourOfDay(tokenLen); + break; + case 'K': // hour of halfday (0..11) + builder.appendHourOfHalfday(tokenLen); + break; case 'm': // minute of hour (number) builder.appendMinuteOfHour(tokenLen); break; @@ -320,15 +529,6 @@ case 'w': // week of weekyear (number) builder.appendWeekOfWeekyear(tokenLen); break; - case 'a': // am/pm marker (text) - builder.appendHalfdayOfDayText(); - break; - case 'k': // hour of day (1..24) - builder.appendClockhourOfDay(tokenLen); - break; - case 'K': // hour of day (0..11) - builder.appendClockhourOfHalfday(tokenLen); - break; case 'z': // time zone (text) if (tokenLen >= 4) { builder.appendTimeZoneName(); @@ -337,10 +537,12 @@ } break; case 'Z': // time zone offset - if (tokenLen >= 4) { - builder.appendTimeZoneOffset(null, true, 2, 2); + if (tokenLen == 1) { + builder.appendTimeZoneOffset(null, "Z", false, 2, 2); + } else if (tokenLen == 2) { + builder.appendTimeZoneOffset(null, "Z", true, 2, 2); } else { - builder.appendTimeZoneOffset(null, false, 2, 2); + builder.appendTimeZoneId(); } break; case '\'': // literal text @@ -360,7 +562,15 @@ } } - private static String parseToken(final String pattern, final int[] indexRef) { + /** + * Parses an individual token. + * + * @param pattern the pattern string + * @param indexRef a single element array, where the input is the start + * location and the output is the location after parsing the token + * @return the parsed token + */ + private static String parseToken(String pattern, int[] indexRef) { StringBuffer buf = new StringBuffer(); int i = indexRef[0]; @@ -412,8 +622,13 @@ return buf.toString(); } - // Returns true if token should be parsed as a numeric field. - private static boolean isNumericToken(final String token) { + /** + * Returns true if token should be parsed as a numeric field. + * + * @param token the token to parse + * @return true if numeric field + */ + private static boolean isNumericToken(String token) { int tokenLen = token.length(); if (tokenLen > 0) { char c = token.charAt(0); @@ -448,58 +663,28 @@ } //----------------------------------------------------------------------- - /** The locale to use */ - private final Locale iLocale; - - /** Maps patterns to formatters */ - private transient Map iPatternedCache = new HashMap(7); - - /** Maps styles to formatters */ - private transient Map iStyledCache = new HashMap(7); - /** - * Constructor. - * - * @param locale the locale to use, must not be null - */ - private DateTimeFormat(final Locale locale) { - super(); - iLocale = locale; - } - - //----------------------------------------------------------------------- - /** * Select a format from a custom pattern. * * @param pattern pattern specification * @throws IllegalArgumentException if the pattern is invalid * @see #appendPatternTo */ - public synchronized DateTimeFormatter forPattern(final String pattern) { - DateTimeFormatter formatter = (DateTimeFormatter) iPatternedCache.get(pattern); - if (formatter != null) { - return formatter; - } - - if (pattern == null) { + private static DateTimeFormatter createFormatterForPattern(String pattern) { + if (pattern == null || pattern.length() == 0) { throw new IllegalArgumentException("Invalid pattern specification"); } + DateTimeFormatter formatter = null; + synchronized (cPatternedCache) { + formatter = cPatternedCache.get(pattern); + if (formatter == null) { + DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder(); + parsePatternTo(builder, pattern); + formatter = builder.toFormatter(); - DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder(iLocale); - appendPatternTo(builder, pattern); - - if (builder.canBuildFormatter()) { - formatter = builder.toFormatter(); - } else if (builder.canBuildPrinter()) { - formatter = new FPrinter(builder.toPrinter()); - } else if (builder.canBuildParser()) { - // I don't expect this case to ever occur. - formatter = new FParser(builder.toParser()); - } else { - throw new UnsupportedOperationException("Pattern unsupported: " + pattern); + cPatternedCache.put(pattern, formatter); + } } - - iPatternedCache.put(pattern, formatter); return formatter; } @@ -512,368 +697,156 @@ * @param style two characters from the set {"S", "M", "L", "F", "-"} * @throws IllegalArgumentException if the style is invalid */ - public synchronized DateTimeFormatter forStyle(final String style) { - DateTimeFormatter formatter = (DateTimeFormatter)iStyledCache.get(style); - if (formatter == null) { - formatter = forPattern(getPatternForStyle(style)); - iStyledCache.put(style, formatter); - } - return formatter; - } - - /** - * Returns a pattern specification from a two character style. The first - * character is the date style, and the second character is the time - * style. Specify a character of 'S' for short style, 'M' for medium, 'L' - * for long, and 'F' for full. A date or time may be ommitted by specifying - * a style character '-'. - * - * @param style two characters from the set {"S", "M", "L", "F", "-"} - * @throws IllegalArgumentException if the style is invalid - */ - public String getPatternForStyle(final String style) { + private static DateTimeFormatter createFormatterForStyle(String style) { if (style == null || style.length() != 2) { throw new IllegalArgumentException("Invalid style specification: " + style); } - - if (style.charAt(1) == '-') { - // date only - return getDatePattern(style.charAt(0)); - } else if (style.charAt(0) == '-') { - // time only - return getTimePattern(style.charAt(1)); - } else { - // datetime - return getDateTimePattern(style.charAt(0), style.charAt(1)); + int dateStyle = selectStyle(style.charAt(0)); + int timeStyle = selectStyle(style.charAt(1)); + if (dateStyle == NONE && timeStyle == NONE) { + throw new IllegalArgumentException("Style '--' is invalid"); } + return createFormatterForStyleIndex(dateStyle, timeStyle); } - private String getDatePattern(final char style) { - int istyle = selectStyle(style); - try { - return ((SimpleDateFormat)DateFormat.getDateInstance(istyle, iLocale)).toPattern(); - } catch (ClassCastException e) { - throw new IllegalArgumentException("No date pattern for locale: " + iLocale); + /** + * Gets the formatter for the specified style. + * + * @param dateStyle the date style + * @param timeStyle the time style + * @return the formatter + */ + private static DateTimeFormatter createFormatterForStyleIndex(int dateStyle, int timeStyle) { + int index = ((dateStyle << 2) + dateStyle) + timeStyle; + DateTimeFormatter f = null; + synchronized (cStyleCache) { + f = cStyleCache[index]; + if (f == null) { + int type = DATETIME; + if (dateStyle == NONE) { + type = TIME; + } else if (timeStyle == NONE) { + type = DATE; + } + StyleFormatter llf = new StyleFormatter( + dateStyle, timeStyle, type); + f = new DateTimeFormatter(llf, llf); + cStyleCache[index] = f; + } } + return f; } - private String getTimePattern(final char style) { - int istyle = selectStyle(style); - try { - return ((SimpleDateFormat)DateFormat.getTimeInstance(istyle, iLocale)).toPattern(); - } catch (ClassCastException e) { - throw new IllegalArgumentException("No time pattern for locale: " + iLocale); - } - } - - private String getDateTimePattern(final char dateStyle, final char timeStyle) { - int idateStyle = selectStyle(dateStyle); - int itimeStyle = selectStyle(dateStyle); - try { - return ((SimpleDateFormat)DateFormat.getDateTimeInstance - (idateStyle, itimeStyle, iLocale)).toPattern(); - } catch (ClassCastException e) { - throw new IllegalArgumentException("No datetime pattern for locale: " + iLocale); - } - } - - private int selectStyle(final char c) { - switch (c) { + /** + * Gets the JDK style code from the Joda code. + * + * @param ch the Joda style code + * @return the JDK style code + */ + private static int selectStyle(char ch) { + switch (ch) { case 'S': - return DateFormat.SHORT; + return SHORT; case 'M': - return DateFormat.MEDIUM; + return MEDIUM; case 'L': - return DateFormat.LONG; + return LONG; case 'F': - return DateFormat.FULL; + return FULL; + case '-': + return NONE; default: - throw new IllegalArgumentException("Invalid style character: " + c); + throw new IllegalArgumentException("Invalid style character: " + ch); } } //----------------------------------------------------------------------- - /** - * Special field type which derives a new field as a remainder. - */ - static class RemainderType extends DateTimeFieldType { - private final DateTimeFieldType iWrappedType; - private final DateTimeFieldType iType; - private final int iDivisor; + static class StyleFormatter + implements DateTimePrinter, DateTimeParser { - private transient RemainderDateTimeField iRecent; + private static final Map cCache = new HashMap(); // manual sync + + private final int iDateStyle; + private final int iTimeStyle; + private final int iType; - RemainderType(DateTimeFieldType wrappedType, DateTimeFieldType type, int divisor) { - super(type.getName()); - iWrappedType = wrappedType; + StyleFormatter(int dateStyle, int timeStyle, int type) { + super(); + iDateStyle = dateStyle; + iTimeStyle = timeStyle; iType = type; - iDivisor = divisor; } - public DurationFieldType getDurationType() { - return iType.getDurationType(); + public int estimatePrintedLength() { + return 40; // guess } - public DurationFieldType getRangeDurationType() { - return iType.getRangeDurationType(); + public void printTo( + StringBuffer buf, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) { + DateTimePrinter p = getFormatter(locale).getPrinter(); + p.printTo(buf, instant, chrono, displayOffset, displayZone, locale); } - public DateTimeField getField(Chronology chrono) { - DateTimeField wrappedField = iWrappedType.getField(chrono); - RemainderDateTimeField field = iRecent; - if (field.getWrappedField() == wrappedField) { - return field; - } - field = new RemainderDateTimeField(wrappedField, iType, iDivisor); - iRecent = field; - return field; + public void printTo( + Writer out, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) throws IOException { + DateTimePrinter p = getFormatter(locale).getPrinter(); + p.printTo(out, instant, chrono, displayOffset, displayZone, locale); } - } - /** - * A fake formatter that can only print. - */ - static class FPrinter implements DateTimeFormatter { - private final DateTimePrinter mPrinter; - - FPrinter(DateTimePrinter printer) { - super(); - mPrinter = printer; + public void printTo(StringBuffer buf, ReadablePartial partial, Locale locale) { + DateTimePrinter p = getFormatter(locale).getPrinter(); + p.printTo(buf, partial, locale); } - public void printTo(StringBuffer buf, ReadableInstant instant) { - mPrinter.printTo(buf, instant); + public void printTo(Writer out, ReadablePartial partial, Locale locale) throws IOException { + DateTimePrinter p = getFormatter(locale).getPrinter(); + p.printTo(out, partial, locale); } - public void printTo(Writer out, ReadableInstant instant) throws IOException { - mPrinter.printTo(out, instant); - } - - public void printTo(StringBuffer buf, long instant) { - mPrinter.printTo(buf, instant); - } - - public void printTo(Writer out, long instant) throws IOException { - mPrinter.printTo(out, instant); - } - - public void printTo(StringBuffer buf, long instant, DateTimeZone zone) { - mPrinter.printTo(buf, instant, zone); - } - - public void printTo(Writer out, long instant, DateTimeZone zone) - throws IOException { - mPrinter.printTo(out, instant, zone); - } - - public void printTo(StringBuffer buf, long instant, Chronology chrono) { - mPrinter.printTo(buf, instant, chrono); - } - - public void printTo(Writer out, long instant, Chronology chrono) throws IOException { - mPrinter.printTo(out, instant, chrono); - } - - public void printTo(StringBuffer buf, ReadablePartial instant) { - mPrinter.printTo(buf, instant); - } - - public void printTo(Writer out, ReadablePartial instant) throws IOException { - mPrinter.printTo(out, instant); - } - - public String print(ReadableInstant instant) { - return mPrinter.print(instant); - } - - public String print(long instant) { - return mPrinter.print(instant); - } - - public String print(long instant, DateTimeZone zone) { - return mPrinter.print(instant, zone); - } - - public String print(long instant, Chronology chrono) { - return mPrinter.print(instant, chrono); - } - - public String print(ReadablePartial partial) { - return mPrinter.print(partial); - } - public int estimateParsedLength() { - return 0; + return 40; // guess } - public int parseInto(ReadWritableInstant instant, String text, int position) { - throw unsupported(); + public int parseInto(DateTimeParserBucket bucket, String text, int position) { + DateTimeParser p = getFormatter(bucket.getLocale()).getParser(); + return p.parseInto(bucket, text, position); } - public long parseMillis(String text) { - throw unsupported(); + private DateTimeFormatter getFormatter(Locale locale) { + locale = (locale == null ? Locale.getDefault() : locale); + String key = Integer.toString(iType + (iDateStyle << 4) + (iTimeStyle << 8)) + locale.toString(); + DateTimeFormatter f = null; + synchronized (cCache) { + f = cCache.get(key); + if (f == null) { + String pattern = getPattern(locale); + f = DateTimeFormat.forPattern(pattern); + cCache.put(key, f); + } + } + return f; } - public long parseMillis(String text, Chronology chrono) { - throw unsupported(); + String getPattern(Locale locale) { + DateFormat f = null; + switch (iType) { + case DATE: + f = DateFormat.getDateInstance(iDateStyle, locale); + break; + case TIME: + f = DateFormat.getTimeInstance(iTimeStyle, locale); + break; + case DATETIME: + f = DateFormat.getDateTimeInstance(iDateStyle, iTimeStyle, locale); + break; + } + if (f instanceof SimpleDateFormat == false) { + throw new IllegalArgumentException("No datetime pattern for locale: " + locale); + } + return ((SimpleDateFormat) f).toPattern(); } - - public long parseMillis(String text, long instantLocal) { - throw unsupported(); - } - - public long parseMillis(String text, long instant, Chronology chrono) { - throw unsupported(); - } - - public DateTime parseDateTime(String text) { - throw unsupported(); - } - - public DateTime parseDateTime(String text, Chronology chrono) { - throw unsupported(); - } - - public DateTime parseDateTime(String text, ReadableInstant instant) { - throw unsupported(); - } - - public MutableDateTime parseMutableDateTime(String text) { - throw unsupported(); - } - - public MutableDateTime parseMutableDateTime(String text, Chronology chrono) { - throw unsupported(); - } - - public MutableDateTime parseMutableDateTime(String text, - ReadableInstant instant) { - throw unsupported(); - } - - private UnsupportedOperationException unsupported() { - return new UnsupportedOperationException("Parsing not supported"); - } } - //----------------------------------------------------------------------- - /** - * A fake formatter that can only parse. - */ - static class FParser implements DateTimeFormatter { - private final DateTimeParser mParser; - - FParser(DateTimeParser parser) { - super(); - mParser = parser; - } - - public void printTo(StringBuffer buf, ReadableInstant instant) { - throw unsupported(); - } - - public void printTo(Writer out, ReadableInstant instant) throws IOException { - throw unsupported(); - } - - public void printTo(StringBuffer buf, long instant) { - throw unsupported(); - } - - public void printTo(Writer out, long instant) throws IOException { - throw unsupported(); - } - - public void printTo(StringBuffer buf, long instant, DateTimeZone zone) { - throw unsupported(); - } - - public void printTo(Writer out, long instant, DateTimeZone zone) { - throw unsupported(); - } - - public void printTo(StringBuffer buf, long instant, Chronology chrono) { - throw unsupported(); - } - - public void printTo(Writer out, long instant, Chronology chrono) throws IOException { - throw unsupported(); - } - - public void printTo(StringBuffer buf, ReadablePartial instant) { - throw unsupported(); - } - - public void printTo(Writer out, ReadablePartial instant) throws IOException { - throw unsupported(); - } - - public String print(ReadableInstant instant) { - throw unsupported(); - } - - public String print(long instant) { - throw unsupported(); - } - - public String print(long instant, DateTimeZone zone) { - throw unsupported(); - } - - public String print(long instant, Chronology chrono) { - throw unsupported(); - } - - public String print(ReadablePartial partial) { - throw unsupported(); - } - - public int parseInto(ReadWritableInstant instant, String text, int position) { - return mParser.parseInto(instant, text, position); - } - - public long parseMillis(String text) { - return mParser.parseMillis(text); - } - - public long parseMillis(String text, Chronology chrono) { - return mParser.parseMillis(text, chrono); - } - - public long parseMillis(String text, long instant) { - return mParser.parseMillis(text, instant); - } - - public long parseMillis(String text, long instant, Chronology chrono) { - return mParser.parseMillis(text, instant, chrono); - } - - public DateTime parseDateTime(String text) { - return mParser.parseDateTime(text); - } - - public DateTime parseDateTime(String text, Chronology chrono) { - return mParser.parseDateTime(text, chrono); - } - - public DateTime parseDateTime(String text, ReadableInstant instant) { - return mParser.parseDateTime(text, instant); - } - - public MutableDateTime parseMutableDateTime(String text) { - return mParser.parseMutableDateTime(text); - } - - public MutableDateTime parseMutableDateTime(String text, Chronology chrono) { - return mParser.parseMutableDateTime(text, chrono); - } - - public MutableDateTime parseMutableDateTime(String text, ReadableInstant instant) { - return mParser.parseMutableDateTime(text, instant); - } - - private UnsupportedOperationException unsupported() { - return new UnsupportedOperationException("Printing not supported"); - } - } } Index: 3rdParty_sources/joda-time/org/joda/time/format/DateTimeFormatter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/format/DateTimeFormatter.java (.../DateTimeFormatter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/format/DateTimeFormatter.java (.../DateTimeFormatter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,70 +1,945 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.format; +import java.io.IOException; +import java.io.Writer; +import java.util.Locale; + +import org.joda.time.Chronology; +import org.joda.time.DateTime; +import org.joda.time.DateTimeUtils; +import org.joda.time.DateTimeZone; +import org.joda.time.LocalDate; +import org.joda.time.LocalDateTime; +import org.joda.time.LocalTime; +import org.joda.time.MutableDateTime; +import org.joda.time.ReadWritableInstant; +import org.joda.time.ReadableInstant; +import org.joda.time.ReadablePartial; + /** - * Combined interface for printing and parsing. + * Controls the printing and parsing of a datetime to and from a string. *

            - * See each extended interface for details of the methods. + * This class is the main API for printing and parsing used by most applications. + * Instances of this class are created via one of three factory classes: + *

              + *
            • {@link DateTimeFormat} - formats by pattern and style
            • + *
            • {@link ISODateTimeFormat} - ISO8601 formats
            • + *
            • {@link DateTimeFormatterBuilder} - complex formats created via method calls
            • + *
            *

            - * Note: This interface represents a view onto {@link BaseDateTimeFormatter}. - * All implementations must extend BaseDateTimeFormatter. - * + * An instance of this class holds a reference internally to one printer and + * one parser. It is possible that one of these may be null, in which case the + * formatter cannot print/parse. This can be checked via the {@link #isPrinter()} + * and {@link #isParser()} methods. + *

            + * The underlying printer/parser can be altered to behave exactly as required + * by using one of the decorator modifiers: + *

              + *
            • {@link #withLocale(Locale)} - returns a new formatter that uses the specified locale
            • + *
            • {@link #withZone(DateTimeZone)} - returns a new formatter that uses the specified time zone
            • + *
            • {@link #withChronology(Chronology)} - returns a new formatter that uses the specified chronology
            • + *
            • {@link #withOffsetParsed()} - returns a new formatter that returns the parsed time zone offset
            • + *
            + * Each of these returns a new formatter (instances of this class are immutable). + *

            + * The main methods of the class are the printXxx and + * parseXxx methods. These are used as follows: + *

            + * // print using the defaults (default locale, chronology/zone of the datetime)
            + * String dateStr = formatter.print(dt);
            + * // print using the French locale
            + * String dateStr = formatter.withLocale(Locale.FRENCH).print(dt);
            + * // print using the UTC zone
            + * String dateStr = formatter.withZone(DateTimeZone.UTC).print(dt);
            + * 
            + * // parse using the Paris zone
            + * DateTime date = formatter.withZone(DateTimeZone.forID("Europe/Paris")).parseDateTime(str);
            + * 
            + * * @author Brian S O'Neill + * @author Stephen Colebourne + * @author Fredrik Borgh * @since 1.0 */ -public interface DateTimeFormatter extends DateTimePrinter, DateTimeParser { - - // Methods inherited +public class DateTimeFormatter { + + /** The internal printer used to output the datetime. */ + private final DateTimePrinter iPrinter; + /** The internal parser used to output the datetime. */ + private final DateTimeParser iParser; + /** The locale to use for printing and parsing. */ + private final Locale iLocale; + /** Whether the offset is parsed. */ + private final boolean iOffsetParsed; + /** The chronology to use as an override. */ + private final Chronology iChrono; + /** The zone to use as an override. */ + private final DateTimeZone iZone; + /** The pivot year to use for two-digit year parsing. */ + private final Integer iPivotYear; + /** The default year for parsing month/day without year. */ + private final int iDefaultYear; + + /** + * Creates a new formatter, however you will normally use the factory + * or the builder. + * + * @param printer the internal printer, null if cannot print + * @param parser the internal parser, null if cannot parse + */ + public DateTimeFormatter( + DateTimePrinter printer, DateTimeParser parser) { + super(); + iPrinter = printer; + iParser = parser; + iLocale = null; + iOffsetParsed = false; + iChrono = null; + iZone = null; + iPivotYear = null; + iDefaultYear = 2000; + } + + /** + * Constructor. + */ + private DateTimeFormatter( + DateTimePrinter printer, DateTimeParser parser, + Locale locale, boolean offsetParsed, + Chronology chrono, DateTimeZone zone, + Integer pivotYear, int defaultYear) { + super(); + iPrinter = printer; + iParser = parser; + iLocale = locale; + iOffsetParsed = offsetParsed; + iChrono = chrono; + iZone = zone; + iPivotYear = pivotYear; + iDefaultYear = defaultYear; + } + + //----------------------------------------------------------------------- + /** + * Is this formatter capable of printing. + * + * @return true if this is a printer + */ + public boolean isPrinter() { + return (iPrinter != null); + } + + /** + * Gets the internal printer object that performs the real printing work. + * + * @return the internal printer; is null if printing not supported + */ + public DateTimePrinter getPrinter() { + return iPrinter; + } + + /** + * Is this formatter capable of parsing. + * + * @return true if this is a parser + */ + public boolean isParser() { + return (iParser != null); + } + + /** + * Gets the internal parser object that performs the real parsing work. + * + * @return the internal parser; is null if parsing not supported + */ + public DateTimeParser getParser() { + return iParser; + } + + //----------------------------------------------------------------------- + /** + * Returns a new formatter with a different locale that will be used + * for printing and parsing. + *

            + * A DateTimeFormatter is immutable, so a new instance is returned, + * and the original is unaltered and still usable. + * + * @param locale the locale to use; if null, formatter uses default locale + * at invocation time + * @return the new formatter + */ + public DateTimeFormatter withLocale(Locale locale) { + if (locale == getLocale() || (locale != null && locale.equals(getLocale()))) { + return this; + } + return new DateTimeFormatter(iPrinter, iParser, locale, + iOffsetParsed, iChrono, iZone, iPivotYear, iDefaultYear); + } + + /** + * Gets the locale that will be used for printing and parsing. + * + * @return the locale to use; if null, formatter uses default locale at + * invocation time + */ + public Locale getLocale() { + return iLocale; + } + + //----------------------------------------------------------------------- + /** + * Returns a new formatter that will create a datetime with a time zone + * equal to that of the offset of the parsed string. + *

            + * After calling this method, a string '2004-06-09T10:20:30-08:00' will + * create a datetime with a zone of -08:00 (a fixed zone, with no daylight + * savings rules). If the parsed string represents a local time (no zone + * offset) the parsed datetime will be in the default zone. + *

            + * Calling this method sets the override zone to null. + * Calling the override zone method sets this flag off. + * + * @return the new formatter + */ + public DateTimeFormatter withOffsetParsed() { + if (iOffsetParsed == true) { + return this; + } + return new DateTimeFormatter(iPrinter, iParser, iLocale, + true, iChrono, null, iPivotYear, iDefaultYear); + } + + /** + * Checks whether the offset from the string is used as the zone of + * the parsed datetime. + * + * @return true if the offset from the string is used as the zone + */ + public boolean isOffsetParsed() { + return iOffsetParsed; + } + + //----------------------------------------------------------------------- + /** + * Returns a new formatter that will use the specified chronology in + * preference to that of the printed object, or ISO on a parse. + *

            + * When printing, this chronolgy will be used in preference to the chronology + * from the datetime that would otherwise be used. + *

            + * When parsing, this chronology will be set on the parsed datetime. + *

            + * A null chronology means no-override. + * If both an override chronology and an override zone are set, the + * override zone will take precedence over the zone in the chronology. + * + * @param chrono the chronology to use as an override + * @return the new formatter + */ + public DateTimeFormatter withChronology(Chronology chrono) { + if (iChrono == chrono) { + return this; + } + return new DateTimeFormatter(iPrinter, iParser, iLocale, + iOffsetParsed, chrono, iZone, iPivotYear, iDefaultYear); + } + + /** + * Gets the chronology to use as an override. + * + * @return the chronology to use as an override + */ + public Chronology getChronology() { + return iChrono; + } + + /** + * Gets the chronology to use as an override. + * + * @return the chronology to use as an override + * @deprecated Use the method with the correct spelling + */ + @Deprecated + public Chronology getChronolgy() { + return iChrono; + } + + //----------------------------------------------------------------------- + /** + * Returns a new formatter that will use the UTC zone in preference + * to the zone of the printed object, or default zone on a parse. + *

            + * When printing, UTC will be used in preference to the zone + * from the datetime that would otherwise be used. + *

            + * When parsing, UTC will be set on the parsed datetime. + *

            + * If both an override chronology and an override zone are set, the + * override zone will take precedence over the zone in the chronology. + * + * @return the new formatter, never null + * @since 2.0 + */ + public DateTimeFormatter withZoneUTC() { + return withZone(DateTimeZone.UTC); + } + + /** + * Returns a new formatter that will use the specified zone in preference + * to the zone of the printed object, or default zone on a parse. + *

            + * When printing, this zone will be used in preference to the zone + * from the datetime that would otherwise be used. + *

            + * When parsing, this zone will be set on the parsed datetime. + *

            + * A null zone means of no-override. + * If both an override chronology and an override zone are set, the + * override zone will take precedence over the zone in the chronology. + * + * @param zone the zone to use as an override + * @return the new formatter + */ + public DateTimeFormatter withZone(DateTimeZone zone) { + if (iZone == zone) { + return this; + } + return new DateTimeFormatter(iPrinter, iParser, iLocale, + false, iChrono, zone, iPivotYear, iDefaultYear); + } + + /** + * Gets the zone to use as an override. + * + * @return the zone to use as an override + */ + public DateTimeZone getZone() { + return iZone; + } + + //----------------------------------------------------------------------- + /** + * Returns a new formatter that will use the specified pivot year for two + * digit year parsing in preference to that stored in the parser. + *

            + * This setting is useful for changing the pivot year of formats built + * using a pattern - {@link DateTimeFormat#forPattern(String)}. + *

            + * When parsing, this pivot year is used. Null means no-override. + * There is no effect when printing. + *

            + * The pivot year enables a two digit year to be converted to a four + * digit year. The pivot represents the year in the middle of the + * supported range of years. Thus the full range of years that will + * be built is (pivot - 50) .. (pivot + 49). + * + *

            +     * pivot   supported range   00 is   20 is   40 is   60 is   80 is
            +     * ---------------------------------------------------------------
            +     * 1950      1900..1999      1900    1920    1940    1960    1980
            +     * 1975      1925..2024      2000    2020    1940    1960    1980
            +     * 2000      1950..2049      2000    2020    2040    1960    1980
            +     * 2025      1975..2074      2000    2020    2040    2060    1980
            +     * 2050      2000..2099      2000    2020    2040    2060    2080
            +     * 
            + * + * @param pivotYear the pivot year to use as an override when parsing + * @return the new formatter + * @since 1.1 + */ + public DateTimeFormatter withPivotYear(Integer pivotYear) { + if (iPivotYear == pivotYear || (iPivotYear != null && iPivotYear.equals(pivotYear))) { + return this; + } + return new DateTimeFormatter(iPrinter, iParser, iLocale, + iOffsetParsed, iChrono, iZone, pivotYear, iDefaultYear); + } + + /** + * Returns a new formatter that will use the specified pivot year for two + * digit year parsing in preference to that stored in the parser. + *

            + * This setting is useful for changing the pivot year of formats built + * using a pattern - {@link DateTimeFormat#forPattern(String)}. + *

            + * When parsing, this pivot year is used. + * There is no effect when printing. + *

            + * The pivot year enables a two digit year to be converted to a four + * digit year. The pivot represents the year in the middle of the + * supported range of years. Thus the full range of years that will + * be built is (pivot - 50) .. (pivot + 49). + * + *

            +     * pivot   supported range   00 is   20 is   40 is   60 is   80 is
            +     * ---------------------------------------------------------------
            +     * 1950      1900..1999      1900    1920    1940    1960    1980
            +     * 1975      1925..2024      2000    2020    1940    1960    1980
            +     * 2000      1950..2049      2000    2020    2040    1960    1980
            +     * 2025      1975..2074      2000    2020    2040    2060    1980
            +     * 2050      2000..2099      2000    2020    2040    2060    2080
            +     * 
            + * + * @param pivotYear the pivot year to use as an override when parsing + * @return the new formatter + * @since 1.1 + */ + public DateTimeFormatter withPivotYear(int pivotYear) { + return withPivotYear(Integer.valueOf(pivotYear)); + } + + /** + * Gets the pivot year to use as an override. + * + * @return the pivot year to use as an override + * @since 1.1 + */ + public Integer getPivotYear() { + return iPivotYear; + } + + //----------------------------------------------------------------------- + /** + * Returns a new formatter that will use the specified default year. + *

            + * The default year is used when parsing in the case where there is a + * month or a day but not a year. Specifically, it is used if there is + * a field parsed with a duration between the length of a month and the + * length of a day inclusive. + *

            + * This value is typically used to move the year from 1970 to a leap year + * to enable February 29th to be parsed. + * Unless customised, the year 2000 is used. + *

            + * This setting has no effect when printing. + * + * @param defaultYear the default year to use + * @return the new formatter, not null + * @since 2.0 + */ + public DateTimeFormatter withDefaultYear(int defaultYear) { + return new DateTimeFormatter(iPrinter, iParser, iLocale, + iOffsetParsed, iChrono, iZone, iPivotYear, defaultYear); + } + + /** + * Gets the default year for parsing months and days. + * + * @return the default year for parsing months and days + * @since 2.0 + */ + public int getDefaultYear() { + return iDefaultYear; + } + + //----------------------------------------------------------------------- + /** + * Prints a ReadableInstant, using the chronology supplied by the instant. + * + * @param buf the destination to format to, not null + * @param instant instant to format, null means now + */ + public void printTo(StringBuffer buf, ReadableInstant instant) { + long millis = DateTimeUtils.getInstantMillis(instant); + Chronology chrono = DateTimeUtils.getInstantChronology(instant); + printTo(buf, millis, chrono); + } + + /** + * Prints a ReadableInstant, using the chronology supplied by the instant. + * + * @param out the destination to format to, not null + * @param instant instant to format, null means now + */ + public void printTo(Writer out, ReadableInstant instant) throws IOException { + long millis = DateTimeUtils.getInstantMillis(instant); + Chronology chrono = DateTimeUtils.getInstantChronology(instant); + printTo(out, millis, chrono); + } + + /** + * Prints a ReadableInstant, using the chronology supplied by the instant. + * + * @param appendable the destination to format to, not null + * @param instant instant to format, null means now + * @since 2.0 + */ + public void printTo(Appendable appendable, ReadableInstant instant) throws IOException { + appendable.append(print(instant)); + } + + //----------------------------------------------------------------------- + /** + * Prints an instant from milliseconds since 1970-01-01T00:00:00Z, + * using ISO chronology in the default DateTimeZone. + * + * @param buf the destination to format to, not null + * @param instant millis since 1970-01-01T00:00:00Z + */ + public void printTo(StringBuffer buf, long instant) { + printTo(buf, instant, null); + } + + /** + * Prints an instant from milliseconds since 1970-01-01T00:00:00Z, + * using ISO chronology in the default DateTimeZone. + * + * @param out the destination to format to, not null + * @param instant millis since 1970-01-01T00:00:00Z + */ + public void printTo(Writer out, long instant) throws IOException { + printTo(out, instant, null); + } + + /** + * Prints an instant from milliseconds since 1970-01-01T00:00:00Z, + * using ISO chronology in the default DateTimeZone. + * + * @param appendable the destination to format to, not null + * @param instant millis since 1970-01-01T00:00:00Z + * @since 2.0 + */ + public void printTo(Appendable appendable, long instant) throws IOException { + appendable.append(print(instant)); + } + + //----------------------------------------------------------------------- + /** + * Prints a ReadablePartial. + *

            + * Neither the override chronology nor the override zone are used + * by this method. + * + * @param buf the destination to format to, not null + * @param partial partial to format + */ + public void printTo(StringBuffer buf, ReadablePartial partial) { + DateTimePrinter printer = requirePrinter(); + if (partial == null) { + throw new IllegalArgumentException("The partial must not be null"); + } + printer.printTo(buf, partial, iLocale); + } + + /** + * Prints a ReadablePartial. + *

            + * Neither the override chronology nor the override zone are used + * by this method. + * + * @param out the destination to format to, not null + * @param partial partial to format + */ + public void printTo(Writer out, ReadablePartial partial) throws IOException { + DateTimePrinter printer = requirePrinter(); + if (partial == null) { + throw new IllegalArgumentException("The partial must not be null"); + } + printer.printTo(out, partial, iLocale); + } + + /** + * Prints a ReadablePartial. + *

            + * Neither the override chronology nor the override zone are used + * by this method. + * + * @param appendable the destination to format to, not null + * @param partial partial to format + * @since 2.0 + */ + public void printTo(Appendable appendable, ReadablePartial partial) throws IOException { + appendable.append(print(partial)); + } + + //----------------------------------------------------------------------- + /** + * Prints a ReadableInstant to a String. + *

            + * This method will use the override zone and the override chronololgy if + * they are set. Otherwise it will use the chronology and zone of the instant. + * + * @param instant instant to format, null means now + * @return the printed result + */ + public String print(ReadableInstant instant) { + StringBuffer buf = new StringBuffer(requirePrinter().estimatePrintedLength()); + printTo(buf, instant); + return buf.toString(); + } + + /** + * Prints a millisecond instant to a String. + *

            + * This method will use the override zone and the override chronololgy if + * they are set. Otherwise it will use the ISO chronology and default zone. + * + * @param instant millis since 1970-01-01T00:00:00Z + * @return the printed result + */ + public String print(long instant) { + StringBuffer buf = new StringBuffer(requirePrinter().estimatePrintedLength()); + printTo(buf, instant); + return buf.toString(); + } + + /** + * Prints a ReadablePartial to a new String. + *

            + * Neither the override chronology nor the override zone are used + * by this method. + * + * @param partial partial to format + * @return the printed result + */ + public String print(ReadablePartial partial) { + StringBuffer buf = new StringBuffer(requirePrinter().estimatePrintedLength()); + printTo(buf, partial); + return buf.toString(); + } + + private void printTo(StringBuffer buf, long instant, Chronology chrono) { + DateTimePrinter printer = requirePrinter(); + chrono = selectChronology(chrono); + // Shift instant into local time (UTC) to avoid excessive offset + // calculations when printing multiple fields in a composite printer. + DateTimeZone zone = chrono.getZone(); + int offset = zone.getOffset(instant); + long adjustedInstant = instant + offset; + if ((instant ^ adjustedInstant) < 0 && (instant ^ offset) >= 0) { + // Time zone offset overflow, so revert to UTC. + zone = DateTimeZone.UTC; + offset = 0; + adjustedInstant = instant; + } + printer.printTo(buf, adjustedInstant, chrono.withUTC(), offset, zone, iLocale); + } + + private void printTo(Writer buf, long instant, Chronology chrono) throws IOException { + DateTimePrinter printer = requirePrinter(); + chrono = selectChronology(chrono); + // Shift instant into local time (UTC) to avoid excessive offset + // calculations when printing multiple fields in a composite printer. + DateTimeZone zone = chrono.getZone(); + int offset = zone.getOffset(instant); + long adjustedInstant = instant + offset; + if ((instant ^ adjustedInstant) < 0 && (instant ^ offset) >= 0) { + // Time zone offset overflow, so revert to UTC. + zone = DateTimeZone.UTC; + offset = 0; + adjustedInstant = instant; + } + printer.printTo(buf, adjustedInstant, chrono.withUTC(), offset, zone, iLocale); + } + + /** + * Checks whether printing is supported. + * + * @throws UnsupportedOperationException if printing is not supported + */ + private DateTimePrinter requirePrinter() { + DateTimePrinter printer = iPrinter; + if (printer == null) { + throw new UnsupportedOperationException("Printing not supported"); + } + return printer; + } + + //----------------------------------------------------------------------- + /** + * Parses a datetime from the given text, at the given position, saving the + * result into the fields of the given ReadWritableInstant. If the parse + * succeeds, the return value is the new text position. Note that the parse + * may succeed without fully reading the text and in this case those fields + * that were read will be set. + *

            + * Only those fields present in the string will be changed in the specified + * instant. All other fields will remain unaltered. Thus if the string only + * contains a year and a month, then the day and time will be retained from + * the input instant. If this is not the behaviour you want, then reset the + * fields before calling this method, or use {@link #parseDateTime(String)} + * or {@link #parseMutableDateTime(String)}. + *

            + * If it fails, the return value is negative, but the instant may still be + * modified. To determine the position where the parse failed, apply the + * one's complement operator (~) on the return value. + *

            + * The parse will use the chronology of the instant. + * + * @param instant an instant that will be modified, not null + * @param text the text to parse + * @param position position to start parsing from + * @return new position, negative value means parse failed - + * apply complement operator (~) to get position of failure + * @throws UnsupportedOperationException if parsing is not supported + * @throws IllegalArgumentException if the instant is null + * @throws IllegalArgumentException if any field is out of range + */ + public int parseInto(ReadWritableInstant instant, String text, int position) { + DateTimeParser parser = requireParser(); + if (instant == null) { + throw new IllegalArgumentException("Instant must not be null"); + } + + long instantMillis = instant.getMillis(); + Chronology chrono = instant.getChronology(); + long instantLocal = instantMillis + chrono.getZone().getOffset(instantMillis); + chrono = selectChronology(chrono); + + DateTimeParserBucket bucket = new DateTimeParserBucket( + instantLocal, chrono, iLocale, iPivotYear, iDefaultYear); + int newPos = parser.parseInto(bucket, text, position); + instant.setMillis(bucket.computeMillis(false, text)); + if (iOffsetParsed && bucket.getOffsetInteger() != null) { + int parsedOffset = bucket.getOffsetInteger(); + DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset); + chrono = chrono.withZone(parsedZone); + } else if (bucket.getZone() != null) { + chrono = chrono.withZone(bucket.getZone()); + } + instant.setChronology(chrono); + if (iZone != null) { + instant.setZone(iZone); + } + return newPos; + } + + /** + * Parses a datetime from the given text, returning the number of + * milliseconds since the epoch, 1970-01-01T00:00:00Z. + *

            + * The parse will use the ISO chronology, and the default time zone. + * If the text contains a time zone string then that will be taken into account. + * + * @param text text to parse + * @return parsed value expressed in milliseconds since the epoch + * @throws UnsupportedOperationException if parsing is not supported + * @throws IllegalArgumentException if the text to parse is invalid + */ + public long parseMillis(String text) { + DateTimeParser parser = requireParser(); + + Chronology chrono = selectChronology(iChrono); + DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear, iDefaultYear); + int newPos = parser.parseInto(bucket, text, 0); + if (newPos >= 0) { + if (newPos >= text.length()) { + return bucket.computeMillis(true, text); + } + } else { + newPos = ~newPos; + } + throw new IllegalArgumentException(FormatUtils.createErrorMessage(text, newPos)); + } + + /** + * Parses only the local date from the given text, returning a new LocalDate. + *

            + * This will parse the text fully according to the formatter, using the UTC zone. + * Once parsed, only the local date will be used. + * This means that any parsed time, time-zone or offset field is completely ignored. + * It also means that the zone and offset-parsed settings are ignored. + * + * @param text the text to parse, not null + * @return the parsed date, never null + * @throws UnsupportedOperationException if parsing is not supported + * @throws IllegalArgumentException if the text to parse is invalid + * @since 2.0 + */ + public LocalDate parseLocalDate(String text) { + return parseLocalDateTime(text).toLocalDate(); + } + + /** + * Parses only the local time from the given text, returning a new LocalDate. + *

            + * This will parse the text fully according to the formatter, using the UTC zone. + * Once parsed, only the local time will be used. + * This means that any parsed date, time-zone or offset field is completely ignored. + * It also means that the zone and offset-parsed settings are ignored. + * + * @param text the text to parse, not null + * @return the parsed time, never null + * @throws UnsupportedOperationException if parsing is not supported + * @throws IllegalArgumentException if the text to parse is invalid + * @since 2.0 + */ + public LocalTime parseLocalTime(String text) { + return parseLocalDateTime(text).toLocalTime(); + } + + /** + * Parses only the local date-time from the given text, returning a new LocalDate. + *

            + * This will parse the text fully according to the formatter, using the UTC zone. + * Once parsed, only the local date-time will be used. + * This means that any parsed time-zone or offset field is completely ignored. + * It also means that the zone and offset-parsed settings are ignored. + * + * @param text the text to parse, not null + * @return the parsed date-time, never null + * @throws UnsupportedOperationException if parsing is not supported + * @throws IllegalArgumentException if the text to parse is invalid + * @since 2.0 + */ + public LocalDateTime parseLocalDateTime(String text) { + DateTimeParser parser = requireParser(); + + Chronology chrono = selectChronology(null).withUTC(); // always use UTC, avoiding DST gaps + DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear, iDefaultYear); + int newPos = parser.parseInto(bucket, text, 0); + if (newPos >= 0) { + if (newPos >= text.length()) { + long millis = bucket.computeMillis(true, text); + if (bucket.getOffsetInteger() != null) { // treat withOffsetParsed() as being true + int parsedOffset = bucket.getOffsetInteger(); + DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset); + chrono = chrono.withZone(parsedZone); + } else if (bucket.getZone() != null) { + chrono = chrono.withZone(bucket.getZone()); + } + return new LocalDateTime(millis, chrono); + } + } else { + newPos = ~newPos; + } + throw new IllegalArgumentException(FormatUtils.createErrorMessage(text, newPos)); + } + + /** + * Parses a date-time from the given text, returning a new DateTime. + *

            + * The parse will use the zone and chronology specified on this formatter. + *

            + * If the text contains a time zone string then that will be taken into + * account in adjusting the time of day as follows. + * If the {@link #withOffsetParsed()} has been called, then the resulting + * DateTime will have a fixed offset based on the parsed time zone. + * Otherwise the resulting DateTime will have the zone of this formatter, + * but the parsed zone may have caused the time to be adjusted. + * + * @param text the text to parse, not null + * @return the parsed date-time, never null + * @throws UnsupportedOperationException if parsing is not supported + * @throws IllegalArgumentException if the text to parse is invalid + */ + public DateTime parseDateTime(String text) { + DateTimeParser parser = requireParser(); + + Chronology chrono = selectChronology(null); + DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear, iDefaultYear); + int newPos = parser.parseInto(bucket, text, 0); + if (newPos >= 0) { + if (newPos >= text.length()) { + long millis = bucket.computeMillis(true, text); + if (iOffsetParsed && bucket.getOffsetInteger() != null) { + int parsedOffset = bucket.getOffsetInteger(); + DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset); + chrono = chrono.withZone(parsedZone); + } else if (bucket.getZone() != null) { + chrono = chrono.withZone(bucket.getZone()); + } + DateTime dt = new DateTime(millis, chrono); + if (iZone != null) { + dt = dt.withZone(iZone); + } + return dt; + } + } else { + newPos = ~newPos; + } + throw new IllegalArgumentException(FormatUtils.createErrorMessage(text, newPos)); + } + + /** + * Parses a date-time from the given text, returning a new MutableDateTime. + *

            + * The parse will use the zone and chronology specified on this formatter. + *

            + * If the text contains a time zone string then that will be taken into + * account in adjusting the time of day as follows. + * If the {@link #withOffsetParsed()} has been called, then the resulting + * DateTime will have a fixed offset based on the parsed time zone. + * Otherwise the resulting DateTime will have the zone of this formatter, + * but the parsed zone may have caused the time to be adjusted. + * + * @param text the text to parse, not null + * @return the parsed date-time, never null + * @throws UnsupportedOperationException if parsing is not supported + * @throws IllegalArgumentException if the text to parse is invalid + */ + public MutableDateTime parseMutableDateTime(String text) { + DateTimeParser parser = requireParser(); + + Chronology chrono = selectChronology(null); + DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear, iDefaultYear); + int newPos = parser.parseInto(bucket, text, 0); + if (newPos >= 0) { + if (newPos >= text.length()) { + long millis = bucket.computeMillis(true, text); + if (iOffsetParsed && bucket.getOffsetInteger() != null) { + int parsedOffset = bucket.getOffsetInteger(); + DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset); + chrono = chrono.withZone(parsedZone); + } else if (bucket.getZone() != null) { + chrono = chrono.withZone(bucket.getZone()); + } + MutableDateTime dt = new MutableDateTime(millis, chrono); + if (iZone != null) { + dt.setZone(iZone); + } + return dt; + } + } else { + newPos = ~newPos; + } + throw new IllegalArgumentException(FormatUtils.createErrorMessage(text, newPos)); + } + + /** + * Checks whether parsing is supported. + * + * @throws UnsupportedOperationException if parsing is not supported + */ + private DateTimeParser requireParser() { + DateTimeParser parser = iParser; + if (parser == null) { + throw new UnsupportedOperationException("Parsing not supported"); + } + return parser; + } + + //----------------------------------------------------------------------- + /** + * Determines the correct chronology to use. + * + * @param chrono the proposed chronology + * @return the actual chronology + */ + private Chronology selectChronology(Chronology chrono) { + chrono = DateTimeUtils.getChronology(chrono); + if (iChrono != null) { + chrono = iChrono; + } + if (iZone != null) { + chrono = chrono.withZone(iZone); + } + return chrono; + } + } Index: 3rdParty_sources/joda-time/org/joda/time/format/DateTimeFormatterBuilder.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/format/DateTimeFormatterBuilder.java (.../DateTimeFormatterBuilder.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/format/DateTimeFormatterBuilder.java (.../DateTimeFormatterBuilder.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,79 +1,52 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.format; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.Set; import org.joda.time.Chronology; import org.joda.time.DateTimeConstants; import org.joda.time.DateTimeField; import org.joda.time.DateTimeFieldType; import org.joda.time.DateTimeZone; +import org.joda.time.MutableDateTime; import org.joda.time.ReadablePartial; +import org.joda.time.MutableDateTime.Property; import org.joda.time.field.MillisDurationField; import org.joda.time.field.PreciseDateTimeField; /** - * DateTimeFormatterBuilder is used for constructing {@link DateTimeFormatter}s. - * DateTimeFormatters can be built by appending specific fields or other - * formatters. All formatters must extend {@link BaseDateTimeFormatter}. - * + * Factory that creates complex instances of DateTimeFormatter via method calls. *

            + * Datetime formatting is performed by the {@link DateTimeFormatter} class. + * Three classes provide factory methods to create formatters, and this is one. + * The others are {@link DateTimeFormat} and {@link ISODateTimeFormat}. + *

            + * DateTimeFormatterBuilder is used for constructing formatters which are then + * used to print or parse. The formatters are built by appending specific fields + * or other formatters to an instance of this builder. + *

            * For example, a formatter that prints month and year, like "January 1970", * can be constructed as follows: *

            @@ -90,101 +63,115 @@ * * @author Brian S O'Neill * @author Stephen Colebourne + * @author Fredrik Borgh * @since 1.0 * @see DateTimeFormat * @see ISODateTimeFormat */ public class DateTimeFormatterBuilder { - /** The locale the builder uses. */ - private final Locale iLocale; - - // Array contents alternate between printers and parsers. - private ArrayList iElementPairs; + /** Array of printers and parsers (alternating). */ + private ArrayList iElementPairs; + /** Cache of the last returned formatter. */ private Object iFormatter; //----------------------------------------------------------------------- /** - * Creates a DateTimeFormatterBuilder for the default locale. + * Creates a DateTimeFormatterBuilder. */ public DateTimeFormatterBuilder() { - this(Locale.getDefault()); + super(); + iElementPairs = new ArrayList(); } + //----------------------------------------------------------------------- /** - * Creates a DateTimeFormatterBuilder for the specified locale. - * - * @param locale Locale to use, or null for default + * Constructs a DateTimeFormatter using all the appended elements. + *

            + * This is the main method used by applications at the end of the build + * process to create a usable formatter. + *

            + * Subsequent changes to this builder do not affect the returned formatter. + *

            + * The returned formatter may not support both printing and parsing. + * The methods {@link DateTimeFormatter#isPrinter()} and + * {@link DateTimeFormatter#isParser()} will help you determine the state + * of the formatter. + * + * @throws UnsupportedOperationException if neither printing nor parsing is supported */ - public DateTimeFormatterBuilder(Locale locale) { - if (locale == null) { - locale = Locale.getDefault(); + public DateTimeFormatter toFormatter() { + Object f = getFormatter(); + DateTimePrinter printer = null; + if (isPrinter(f)) { + printer = (DateTimePrinter) f; } - iLocale = locale; - iElementPairs = new ArrayList(); + DateTimeParser parser = null; + if (isParser(f)) { + parser = (DateTimeParser) f; + } + if (printer != null || parser != null) { + return new DateTimeFormatter(printer, parser); + } + throw new UnsupportedOperationException("Both printing and parsing not supported"); } - //----------------------------------------------------------------------- /** - * Returns the locale being used by the formatter builder, never null. - */ - public Locale getLocale() { - return iLocale; - } - - //----------------------------------------------------------------------- - /** - * Converts to a DateTimePrinter that prints using all the appended - * elements. Subsequent changes to this builder do not affect the returned - * printer. + * Internal method to create a DateTimePrinter instance using all the + * appended elements. + *

            + * Most applications will not use this method. + * If you want a printer in an application, call {@link #toFormatter()} + * and just use the printing API. + *

            + * Subsequent changes to this builder do not affect the returned printer. * - * @throws UnsupportedOperationException if any formatter element doesn't support - * printing + * @throws UnsupportedOperationException if printing is not supported */ - public DateTimePrinter toPrinter() throws UnsupportedOperationException { + public DateTimePrinter toPrinter() { Object f = getFormatter(); if (isPrinter(f)) { - return (DateTimePrinter)f; + return (DateTimePrinter) f; } - throw new UnsupportedOperationException("Printing not supported"); + throw new UnsupportedOperationException("Printing is not supported"); } /** - * Converts to a DateTimeParser that parses using all the appended - * elements. Subsequent changes to this builder do not affect the returned - * parser. + * Internal method to create a DateTimeParser instance using all the + * appended elements. + *

            + * Most applications will not use this method. + * If you want a parser in an application, call {@link #toFormatter()} + * and just use the parsing API. + *

            + * Subsequent changes to this builder do not affect the returned parser. * - * @throws UnsupportedOperationException if any formatter element doesn't support - * parsing + * @throws UnsupportedOperationException if parsing is not supported */ - public DateTimeParser toParser() throws UnsupportedOperationException { + public DateTimeParser toParser() { Object f = getFormatter(); if (isParser(f)) { - return (DateTimeParser)f; + return (DateTimeParser) f; } - throw new UnsupportedOperationException("Parsing not supported"); + throw new UnsupportedOperationException("Parsing is not supported"); } + //----------------------------------------------------------------------- /** - * Converts to a DateTimeFormatter that prints and parses using all the - * appended elements. Subsequent changes to this builder do not affect the - * returned formatter. - * - * @throws UnsupportedOperationException if any formatter element doesn't support - * both printing and parsing + * Returns true if toFormatter can be called without throwing an + * UnsupportedOperationException. + * + * @return true if a formatter can be built */ - public DateTimeFormatter toFormatter() throws UnsupportedOperationException { - Object f = getFormatter(); - if (isFormatter(f)) { - return (DateTimeFormatter)f; - } - throw new UnsupportedOperationException("Both printing and parsing not supported"); + public boolean canBuildFormatter() { + return isFormatter(getFormatter()); } - //----------------------------------------------------------------------- /** * Returns true if toPrinter can be called without throwing an * UnsupportedOperationException. + * + * @return true if a printer can be built */ public boolean canBuildPrinter() { return isPrinter(getFormatter()); @@ -193,19 +180,13 @@ /** * Returns true if toParser can be called without throwing an * UnsupportedOperationException. + * + * @return true if a parser can be built */ public boolean canBuildParser() { return isParser(getFormatter()); } - /** - * Returns true if toFormatter can be called without throwing an - * UnsupportedOperationException. - */ - public boolean canBuildFormatter() { - return isFormatter(getFormatter()); - } - //----------------------------------------------------------------------- /** * Clears out all the appended elements, allowing this builder to be @@ -219,33 +200,24 @@ //----------------------------------------------------------------------- /** * Appends another formatter. - *

            - * The formatter must extend DateTimeFormatterProvider. - * This is an internal class, which all supplied format classes extend. * * @param formatter the formatter to add - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining * @throws IllegalArgumentException if formatter is null or of an invalid type */ public DateTimeFormatterBuilder append(DateTimeFormatter formatter) { if (formatter == null) { throw new IllegalArgumentException("No formatter supplied"); } - if (formatter instanceof BaseDateTimeFormatter == false) { - throw new IllegalArgumentException("Formatter must extend BaseDateTimeFormatter"); - } - return append0(formatter); + return append0(formatter.getPrinter(), formatter.getParser()); } /** * Appends just a printer. With no matching parser, a parser cannot be * built from this DateTimeFormatterBuilder. - *

            - * The printer added must extend BaseDateTimeFormatter. - * This is an internal class, which all supplied format classes extend. * * @param printer the printer to add - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining * @throws IllegalArgumentException if printer is null or of an invalid type */ public DateTimeFormatterBuilder append(DateTimePrinter printer) { @@ -256,12 +228,9 @@ /** * Appends just a parser. With no matching printer, a printer cannot be * built from this builder. - *

            - * The parser added must extend BaseDateTimeFormatter. - * This is an internal class, which all supplied format classes extend. * * @param parser the parser to add - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining * @throws IllegalArgumentException if parser is null or of an invalid type */ public DateTimeFormatterBuilder append(DateTimeParser parser) { @@ -271,13 +240,10 @@ /** * Appends a printer/parser pair. - *

            - * The printer and parser must extend BaseDateTimeFormatter. - * This is an internal class, which all supplied format classes extend. * * @param printer the printer to add * @param parser the parser to add - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining * @throws IllegalArgumentException if printer or parser is null or of an invalid type */ public DateTimeFormatterBuilder append(DateTimePrinter printer, DateTimeParser parser) { @@ -292,17 +258,14 @@ * chosen, and so on. If none of these parsers succeeds, then the failed * position of the parser that made the greatest progress is returned. *

            - * Only the printer is optional. In addtion, it is illegal for any but the + * Only the printer is optional. In addition, it is illegal for any but the * last of the parser array elements to be null. If the last element is * null, this represents the empty parser. The presence of an empty parser * indicates that the entire array of parse formats is optional. - *

            - * The printer and parsers must extend BaseDateTimeFormatter. - * This is an internal class, which all supplied format classes extend. * * @param printer the printer to add * @param parsers the parsers to add - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining * @throws IllegalArgumentException if any printer or parser is of an invalid type * @throws IllegalArgumentException if any parser element but the last is null */ @@ -314,38 +277,35 @@ throw new IllegalArgumentException("No parsers supplied"); } int length = parsers.length; - BaseDateTimeFormatter[] copyOfParsers = new BaseDateTimeFormatter[length]; - for (int i = 0; i < length; i++) { - DateTimeParser parser = parsers[i]; - if (i == length - 1 && parser == null) { - // ok - } else { - if (parser == null) { - throw new IllegalArgumentException("Incomplete parser array"); - } else if (parser instanceof BaseDateTimeFormatter == false) { - throw new IllegalArgumentException("Parser must extend BaseDateTimeFormatter"); - } - copyOfParsers[i] = (BaseDateTimeFormatter) parser; + if (length == 1) { + if (parsers[0] == null) { + throw new IllegalArgumentException("No parser supplied"); } + return append0(printer, parsers[0]); } - + + DateTimeParser[] copyOfParsers = new DateTimeParser[length]; + int i; + for (i = 0; i < length - 1; i++) { + if ((copyOfParsers[i] = parsers[i]) == null) { + throw new IllegalArgumentException("Incomplete parser array"); + } + } + copyOfParsers[i] = parsers[i]; + return append0(printer, new MatchingParser(copyOfParsers)); } /** * Appends just a parser element which is optional. With no matching * printer, a printer cannot be built from this DateTimeFormatterBuilder. - *

            - * The parser must implement BaseDateTimeFormatter. - * This is an internal interface, which all supplied format classes implement. * - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining * @throws IllegalArgumentException if parser is null or of an invalid type */ public DateTimeFormatterBuilder appendOptional(DateTimeParser parser) { checkParser(parser); - BaseDateTimeFormatter[] parsers = new BaseDateTimeFormatter[] { - (BaseDateTimeFormatter) parser, null}; + DateTimeParser[] parsers = new DateTimeParser[] {parser, null}; return append0(null, new MatchingParser(parsers)); } @@ -359,9 +319,6 @@ if (parser == null) { throw new IllegalArgumentException("No parser supplied"); } - if (parser instanceof BaseDateTimeFormatter == false) { - throw new IllegalArgumentException("Parser must extend BaseDateTimeFormatter"); - } } /** @@ -373,9 +330,6 @@ if (printer == null) { throw new IllegalArgumentException("No printer supplied"); } - if (printer instanceof BaseDateTimeFormatter == false) { - throw new IllegalArgumentException("Printer must extend BaseDateTimeFormatter"); - } } private DateTimeFormatterBuilder append0(Object element) { @@ -399,7 +353,7 @@ * Instructs the printer to emit a specific character, and the parser to * expect it. The parser is case-insensitive. * - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendLiteral(char c) { return append0(new CharacterLiteral(c)); @@ -409,7 +363,7 @@ * Instructs the printer to emit specific text, and the parser to expect * it. The parser is case-insensitive. * - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining * @throws IllegalArgumentException if text is null */ public DateTimeFormatterBuilder appendLiteral(String text) { @@ -430,11 +384,11 @@ * Instructs the printer to emit a field value as a decimal number, and the * parser to expect an unsigned decimal number. * - * @param fieldType type of field to append - * @param minDigits minumum number of digits to print - * @param maxDigits maximum number of digits to parse, or the estimated + * @param fieldType type of field to append + * @param minDigits minimum number of digits to print + * @param maxDigits maximum number of digits to parse, or the estimated * maximum number of digits to print - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining * @throws IllegalArgumentException if field type is null */ public DateTimeFormatterBuilder appendDecimal( @@ -456,14 +410,37 @@ } /** + * Instructs the printer to emit a field value as a fixed-width decimal + * number (smaller numbers will be left-padded with zeros), and the parser + * to expect an unsigned decimal number with the same fixed width. + * + * @param fieldType type of field to append + * @param numDigits the exact number of digits to parse or print, except if + * printed value requires more digits + * @return this DateTimeFormatterBuilder, for chaining + * @throws IllegalArgumentException if field type is null or if numDigits <= 0 + * @since 1.5 + */ + public DateTimeFormatterBuilder appendFixedDecimal( + DateTimeFieldType fieldType, int numDigits) { + if (fieldType == null) { + throw new IllegalArgumentException("Field type must not be null"); + } + if (numDigits <= 0) { + throw new IllegalArgumentException("Illegal number of digits: " + numDigits); + } + return append0(new FixedNumber(fieldType, numDigits, false)); + } + + /** * Instructs the printer to emit a field value as a decimal number, and the * parser to expect a signed decimal number. * - * @param fieldType type of field to append - * @param minDigits minumum number of digits to print - * @param maxDigits maximum number of digits to parse, or the estimated + * @param fieldType type of field to append + * @param minDigits minimum number of digits to print + * @param maxDigits maximum number of digits to parse, or the estimated * maximum number of digits to print - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining * @throws IllegalArgumentException if field type is null */ public DateTimeFormatterBuilder appendSignedDecimal( @@ -485,46 +462,69 @@ } /** + * Instructs the printer to emit a field value as a fixed-width decimal + * number (smaller numbers will be left-padded with zeros), and the parser + * to expect an signed decimal number with the same fixed width. + * + * @param fieldType type of field to append + * @param numDigits the exact number of digits to parse or print, except if + * printed value requires more digits + * @return this DateTimeFormatterBuilder, for chaining + * @throws IllegalArgumentException if field type is null or if numDigits <= 0 + * @since 1.5 + */ + public DateTimeFormatterBuilder appendFixedSignedDecimal( + DateTimeFieldType fieldType, int numDigits) { + if (fieldType == null) { + throw new IllegalArgumentException("Field type must not be null"); + } + if (numDigits <= 0) { + throw new IllegalArgumentException("Illegal number of digits: " + numDigits); + } + return append0(new FixedNumber(fieldType, numDigits, true)); + } + + /** * Instructs the printer to emit a field value as text, and the * parser to expect text. * - * @param fieldType type of field to append - * @return this DateTimeFormatterBuilder + * @param fieldType type of field to append + * @return this DateTimeFormatterBuilder, for chaining * @throws IllegalArgumentException if field type is null */ public DateTimeFormatterBuilder appendText(DateTimeFieldType fieldType) { if (fieldType == null) { throw new IllegalArgumentException("Field type must not be null"); } - return append0(new TextField(fieldType, iLocale, false)); + return append0(new TextField(fieldType, false)); } /** * Instructs the printer to emit a field value as short text, and the * parser to expect text. * - * @param fieldType type of field to append - * @return this DateTimeFormatterBuilder + * @param fieldType type of field to append + * @return this DateTimeFormatterBuilder, for chaining * @throws IllegalArgumentException if field type is null */ public DateTimeFormatterBuilder appendShortText(DateTimeFieldType fieldType) { if (fieldType == null) { throw new IllegalArgumentException("Field type must not be null"); } - return append0(new TextField(fieldType, iLocale, true)); + return append0(new TextField(fieldType, true)); } /** * Instructs the printer to emit a remainder of time as a decimal fraction, - * sans decimal point. For example, if the field is specified as + * without decimal point. For example, if the field is specified as * minuteOfHour and the time is 12:30:45, the value printed is 75. A * decimal point is implied, so the fraction is 0.75, or three-quarters of * a minute. * - * @param fieldType type of field to append - * @param minDigits minumum number of digits to print. - * @param maxDigits maximum number of digits to print or parse. - * @return this DateTimeFormatterBuilder + * @param fieldType type of field to append + * @param minDigits minimum number of digits to print. + * @param maxDigits maximum number of digits to print or parse. + * @return this DateTimeFormatterBuilder, for chaining * @throws IllegalArgumentException if field type is null */ public DateTimeFormatterBuilder appendFraction( @@ -542,46 +542,86 @@ } /** - * @param minDigits minumum number of digits to print - * @param maxDigits maximum number of digits to print or parse - * @return this DateTimeFormatterBuilder + * Appends the print/parse of a fractional second. + *

            + * This reliably handles the case where fractional digits are being handled + * beyond a visible decimal point. The digits parsed will always be treated + * as the most significant (numerically largest) digits. + * Thus '23' will be parsed as 230 milliseconds. + * Contrast this behaviour to {@link #appendMillisOfSecond}. + * This method does not print or parse the decimal point itself. + * + * @param minDigits minimum number of digits to print + * @param maxDigits maximum number of digits to print or parse + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendFractionOfSecond(int minDigits, int maxDigits) { return appendFraction(DateTimeFieldType.secondOfDay(), minDigits, maxDigits); } /** - * @param minDigits minumum number of digits to print - * @param maxDigits maximum number of digits to print or parse - * @return this DateTimeFormatterBuilder + * Appends the print/parse of a fractional minute. + *

            + * This reliably handles the case where fractional digits are being handled + * beyond a visible decimal point. The digits parsed will always be treated + * as the most significant (numerically largest) digits. + * Thus '23' will be parsed as 0.23 minutes (converted to milliseconds). + * This method does not print or parse the decimal point itself. + * + * @param minDigits minimum number of digits to print + * @param maxDigits maximum number of digits to print or parse + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendFractionOfMinute(int minDigits, int maxDigits) { return appendFraction(DateTimeFieldType.minuteOfDay(), minDigits, maxDigits); } /** - * @param minDigits minumum number of digits to print - * @param maxDigits maximum number of digits to print or parse - * @return this DateTimeFormatterBuilder + * Appends the print/parse of a fractional hour. + *

            + * This reliably handles the case where fractional digits are being handled + * beyond a visible decimal point. The digits parsed will always be treated + * as the most significant (numerically largest) digits. + * Thus '23' will be parsed as 0.23 hours (converted to milliseconds). + * This method does not print or parse the decimal point itself. + * + * @param minDigits minimum number of digits to print + * @param maxDigits maximum number of digits to print or parse + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendFractionOfHour(int minDigits, int maxDigits) { return appendFraction(DateTimeFieldType.hourOfDay(), minDigits, maxDigits); } /** - * @param minDigits minumum number of digits to print - * @param maxDigits maximum number of digits to print or parse - * @return this DateTimeFormatterBuilder + * Appends the print/parse of a fractional day. + *

            + * This reliably handles the case where fractional digits are being handled + * beyond a visible decimal point. The digits parsed will always be treated + * as the most significant (numerically largest) digits. + * Thus '23' will be parsed as 0.23 days (converted to milliseconds). + * This method does not print or parse the decimal point itself. + * + * @param minDigits minimum number of digits to print + * @param maxDigits maximum number of digits to print or parse + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendFractionOfDay(int minDigits, int maxDigits) { return appendFraction(DateTimeFieldType.dayOfYear(), minDigits, maxDigits); } /** * Instructs the printer to emit a numeric millisOfSecond field. + *

            + * This method will append a field that prints a three digit value. + * During parsing the value that is parsed is assumed to be three digits. + * If less than three digits are present then they will be counted as the + * smallest parts of the millisecond. This is probably not what you want + * if you are using the field as a fraction. Instead, a fractional + * millisecond should be produced using {@link #appendFractionOfSecond}. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendMillisOfSecond(int minDigits) { return appendDecimal(DateTimeFieldType.millisOfSecond(), minDigits, 3); @@ -590,8 +630,8 @@ /** * Instructs the printer to emit a numeric millisOfDay field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendMillisOfDay(int minDigits) { return appendDecimal(DateTimeFieldType.millisOfDay(), minDigits, 8); @@ -600,8 +640,8 @@ /** * Instructs the printer to emit a numeric secondOfMinute field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendSecondOfMinute(int minDigits) { return appendDecimal(DateTimeFieldType.secondOfMinute(), minDigits, 2); @@ -610,8 +650,8 @@ /** * Instructs the printer to emit a numeric secondOfDay field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendSecondOfDay(int minDigits) { return appendDecimal(DateTimeFieldType.secondOfDay(), minDigits, 5); @@ -620,8 +660,8 @@ /** * Instructs the printer to emit a numeric minuteOfHour field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendMinuteOfHour(int minDigits) { return appendDecimal(DateTimeFieldType.minuteOfHour(), minDigits, 2); @@ -630,8 +670,8 @@ /** * Instructs the printer to emit a numeric minuteOfDay field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendMinuteOfDay(int minDigits) { return appendDecimal(DateTimeFieldType.minuteOfDay(), minDigits, 4); @@ -640,8 +680,8 @@ /** * Instructs the printer to emit a numeric hourOfDay field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendHourOfDay(int minDigits) { return appendDecimal(DateTimeFieldType.hourOfDay(), minDigits, 2); @@ -650,8 +690,8 @@ /** * Instructs the printer to emit a numeric clockhourOfDay field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendClockhourOfDay(int minDigits) { return appendDecimal(DateTimeFieldType.clockhourOfDay(), minDigits, 2); @@ -660,8 +700,8 @@ /** * Instructs the printer to emit a numeric hourOfHalfday field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendHourOfHalfday(int minDigits) { return appendDecimal(DateTimeFieldType.hourOfHalfday(), minDigits, 2); @@ -670,8 +710,8 @@ /** * Instructs the printer to emit a numeric clockhourOfHalfday field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendClockhourOfHalfday(int minDigits) { return appendDecimal(DateTimeFieldType.clockhourOfHalfday(), minDigits, 2); @@ -680,8 +720,8 @@ /** * Instructs the printer to emit a numeric dayOfWeek field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendDayOfWeek(int minDigits) { return appendDecimal(DateTimeFieldType.dayOfWeek(), minDigits, 1); @@ -690,8 +730,8 @@ /** * Instructs the printer to emit a numeric dayOfMonth field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendDayOfMonth(int minDigits) { return appendDecimal(DateTimeFieldType.dayOfMonth(), minDigits, 2); @@ -700,8 +740,8 @@ /** * Instructs the printer to emit a numeric dayOfYear field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendDayOfYear(int minDigits) { return appendDecimal(DateTimeFieldType.dayOfYear(), minDigits, 3); @@ -710,8 +750,8 @@ /** * Instructs the printer to emit a numeric weekOfWeekyear field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendWeekOfWeekyear(int minDigits) { return appendDecimal(DateTimeFieldType.weekOfWeekyear(), minDigits, 2); @@ -720,10 +760,10 @@ /** * Instructs the printer to emit a numeric weekyear field. * - * @param minDigits minumum number of digits to print - * @param maxDigits maximum number of digits to parse, or the estimated + * @param minDigits minimum number of digits to print + * @param maxDigits maximum number of digits to parse, or the estimated * maximum number of digits to print - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendWeekyear(int minDigits, int maxDigits) { return appendSignedDecimal(DateTimeFieldType.weekyear(), minDigits, maxDigits); @@ -732,8 +772,8 @@ /** * Instructs the printer to emit a numeric monthOfYear field. * - * @param minDigits minumum number of digits to print - * @return this DateTimeFormatterBuilder + * @param minDigits minimum number of digits to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendMonthOfYear(int minDigits) { return appendDecimal(DateTimeFieldType.monthOfYear(), minDigits, 2); @@ -742,10 +782,10 @@ /** * Instructs the printer to emit a numeric year field. * - * @param minDigits minumum number of digits to print - * @param maxDigits maximum number of digits to parse, or the estimated + * @param minDigits minimum number of digits to print + * @param maxDigits maximum number of digits to parse, or the estimated * maximum number of digits to print - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendYear(int minDigits, int maxDigits) { return appendSignedDecimal(DateTimeFieldType.year(), minDigits, maxDigits); @@ -766,20 +806,78 @@ * 2050 2000..2099 2000 2020 2040 2060 2080 * * - * @param pivot pivot year to use when parsing - * @return this DateTimeFormatterBuilder + * @param pivot pivot year to use when parsing + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendTwoDigitYear(int pivot) { - return append0(new TwoDigitYear(pivot)); + return appendTwoDigitYear(pivot, false); } /** + * Instructs the printer to emit a numeric year field which always prints + * two digits. A pivot year is used during parsing to determine the range + * of supported years as (pivot - 50) .. (pivot + 49). If + * parse is instructed to be lenient and the digit count is not two, it is + * treated as an absolute year. With lenient parsing, specifying a positive + * or negative sign before the year also makes it absolute. + * + * @param pivot pivot year to use when parsing + * @param lenientParse when true, if digit count is not two, it is treated + * as an absolute year + * @return this DateTimeFormatterBuilder, for chaining + * @since 1.1 + */ + public DateTimeFormatterBuilder appendTwoDigitYear(int pivot, boolean lenientParse) { + return append0(new TwoDigitYear(DateTimeFieldType.year(), pivot, lenientParse)); + } + + /** + * Instructs the printer to emit a numeric weekyear field which always prints + * and parses two digits. A pivot year is used during parsing to determine + * the range of supported years as (pivot - 50) .. (pivot + 49). + * + *

            +     * pivot   supported range   00 is   20 is   40 is   60 is   80 is
            +     * ---------------------------------------------------------------
            +     * 1950      1900..1999      1900    1920    1940    1960    1980
            +     * 1975      1925..2024      2000    2020    1940    1960    1980
            +     * 2000      1950..2049      2000    2020    2040    1960    1980
            +     * 2025      1975..2074      2000    2020    2040    2060    1980
            +     * 2050      2000..2099      2000    2020    2040    2060    2080
            +     * 
            + * + * @param pivot pivot weekyear to use when parsing + * @return this DateTimeFormatterBuilder, for chaining + */ + public DateTimeFormatterBuilder appendTwoDigitWeekyear(int pivot) { + return appendTwoDigitWeekyear(pivot, false); + } + + /** + * Instructs the printer to emit a numeric weekyear field which always prints + * two digits. A pivot year is used during parsing to determine the range + * of supported years as (pivot - 50) .. (pivot + 49). If + * parse is instructed to be lenient and the digit count is not two, it is + * treated as an absolute weekyear. With lenient parsing, specifying a positive + * or negative sign before the weekyear also makes it absolute. + * + * @param pivot pivot weekyear to use when parsing + * @param lenientParse when true, if digit count is not two, it is treated + * as an absolute weekyear + * @return this DateTimeFormatterBuilder, for chaining + * @since 1.1 + */ + public DateTimeFormatterBuilder appendTwoDigitWeekyear(int pivot, boolean lenientParse) { + return append0(new TwoDigitYear(DateTimeFieldType.weekyear(), pivot, lenientParse)); + } + + /** * Instructs the printer to emit a numeric yearOfEra field. * - * @param minDigits minumum number of digits to print - * @param maxDigits maximum number of digits to parse, or the estimated + * @param minDigits minimum number of digits to print + * @param maxDigits maximum number of digits to parse, or the estimated * maximum number of digits to print - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendYearOfEra(int minDigits, int maxDigits) { return appendDecimal(DateTimeFieldType.yearOfEra(), minDigits, maxDigits); @@ -788,10 +886,10 @@ /** * Instructs the printer to emit a numeric year of century field. * - * @param minDigits minumum number of digits to print - * @param maxDigits maximum number of digits to parse, or the estimated + * @param minDigits minimum number of digits to print + * @param maxDigits maximum number of digits to parse, or the estimated * maximum number of digits to print - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendYearOfCentury(int minDigits, int maxDigits) { return appendDecimal(DateTimeFieldType.yearOfCentury(), minDigits, maxDigits); @@ -800,10 +898,10 @@ /** * Instructs the printer to emit a numeric century of era field. * - * @param minDigits minumum number of digits to print - * @param maxDigits maximum number of digits to parse, or the estimated + * @param minDigits minimum number of digits to print + * @param maxDigits maximum number of digits to parse, or the estimated * maximum number of digits to print - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendCenturyOfEra(int minDigits, int maxDigits) { return appendSignedDecimal(DateTimeFieldType.centuryOfEra(), minDigits, maxDigits); @@ -813,7 +911,7 @@ * Instructs the printer to emit a locale-specific AM/PM text, and the * parser to expect it. The parser is case-insensitive. * - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendHalfdayOfDayText() { return appendText(DateTimeFieldType.halfdayOfDay()); @@ -823,7 +921,7 @@ * Instructs the printer to emit a locale-specific dayOfWeek text. The * parser will accept a long or short dayOfWeek text, case-insensitive. * - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendDayOfWeekText() { return appendText(DateTimeFieldType.dayOfWeek()); @@ -834,7 +932,7 @@ * text. The parser will accept a long or short dayOfWeek text, * case-insensitive. * - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendDayOfWeekShortText() { return appendShortText(DateTimeFieldType.dayOfWeek()); @@ -845,7 +943,7 @@ * text. The parser will accept a long or short monthOfYear text, * case-insensitive. * - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendMonthOfYearText() { return appendText(DateTimeFieldType.monthOfYear()); @@ -855,7 +953,7 @@ * Instructs the printer to emit a locale-specific monthOfYear text. The * parser will accept a long or short monthOfYear text, case-insensitive. * - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendMonthOfYearShortText() { return appendShortText(DateTimeFieldType.monthOfYear()); @@ -865,68 +963,139 @@ * Instructs the printer to emit a locale-specific era text (BC/AD), and * the parser to expect it. The parser is case-insensitive. * - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendEraText() { return appendText(DateTimeFieldType.era()); } /** - * Instructs the printer to emit a locale-specific time zone name. A - * parser cannot be created from this builder if a time zone name is - * appended. + * Instructs the printer to emit a locale-specific time zone name. + * Using this method prevents parsing, because time zone names are not unique. + * See {@link #appendTimeZoneName(Map)}. * - * @return this DateTimeFormatterBuilder + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendTimeZoneName() { - return append0(new TimeZonePrinter( iLocale, false), null); + return append0(new TimeZoneName(TimeZoneName.LONG_NAME, null), null); } /** - * Instructs the printer to emit a short locale-specific time zone - * name. A parser cannot be created from this builder if time zone - * name is appended. + * Instructs the printer to emit a locale-specific time zone name, providing a lookup for parsing. + * Time zone names are not unique, thus the API forces you to supply the lookup. + * The names are searched in the order of the map, thus it is strongly recommended + * to use a {@code LinkedHashMap} or similar. * - * @return this DateTimeFormatterBuilder + * @param parseLookup the table of names, not null + * @return this DateTimeFormatterBuilder, for chaining */ + public DateTimeFormatterBuilder appendTimeZoneName(Map parseLookup) { + TimeZoneName pp = new TimeZoneName(TimeZoneName.LONG_NAME, parseLookup); + return append0(pp, pp); + } + + /** + * Instructs the printer to emit a short locale-specific time zone name. + * Using this method prevents parsing, because time zone names are not unique. + * See {@link #appendTimeZoneShortName(Map)}. + * + * @return this DateTimeFormatterBuilder, for chaining + */ public DateTimeFormatterBuilder appendTimeZoneShortName() { - return append0(new TimeZonePrinter( iLocale, true), null); + return append0(new TimeZoneName(TimeZoneName.SHORT_NAME, null), null); } /** + * Instructs the printer to emit a short locale-specific time zone + * name, providing a lookup for parsing. + * Time zone names are not unique, thus the API forces you to supply the lookup. + * The names are searched in the order of the map, thus it is strongly recommended + * to use a {@code LinkedHashMap} or similar. + * + * @param parseLookup the table of names, not null + * @return this DateTimeFormatterBuilder, for chaining + */ + public DateTimeFormatterBuilder appendTimeZoneShortName(Map parseLookup) { + TimeZoneName pp = new TimeZoneName(TimeZoneName.SHORT_NAME, parseLookup); + return append0(pp, pp); + } + + /** + * Instructs the printer to emit the identifier of the time zone. + * From version 2.0, this field can be parsed. + * + * @return this DateTimeFormatterBuilder, for chaining + */ + public DateTimeFormatterBuilder appendTimeZoneId() { + return append0(TimeZoneId.INSTANCE, TimeZoneId.INSTANCE); + } + + /** * Instructs the printer to emit text and numbers to display time zone * offset from UTC. A parser will use the parsed time zone offset to adjust * the datetime. + *

            + * If zero offset text is supplied, then it will be printed when the zone is zero. + * During parsing, either the zero offset text, or the offset will be parsed. * - * @param zeroOffsetText Text to use if time zone offset is zero. If + * @param zeroOffsetText the text to use if time zone offset is zero. If * null, offset is always shown. - * @param showSeparators If true, prints ':' separator before minute and + * @param showSeparators if true, prints ':' separator before minute and * second field and prints '.' separator before fraction field. - * @param minFields minimum number of fields to print, stopping when no + * @param minFields minimum number of fields to print, stopping when no * more precision is required. 1=hours, 2=minutes, 3=seconds, 4=fraction - * @param maxFields maximum number of fields to print - * @return this DateTimeFormatterBuilder + * @param maxFields maximum number of fields to print + * @return this DateTimeFormatterBuilder, for chaining */ public DateTimeFormatterBuilder appendTimeZoneOffset( String zeroOffsetText, boolean showSeparators, int minFields, int maxFields) { - return append0(new TimeZoneOffsetFormatter - (zeroOffsetText, showSeparators, minFields, maxFields)); + return append0(new TimeZoneOffset + (zeroOffsetText, zeroOffsetText, showSeparators, minFields, maxFields)); } /** + * Instructs the printer to emit text and numbers to display time zone + * offset from UTC. A parser will use the parsed time zone offset to adjust + * the datetime. + *

            + * If zero offset print text is supplied, then it will be printed when the zone is zero. + * If zero offset parse text is supplied, then either it or the offset will be parsed. + * + * @param zeroOffsetPrintText the text to print if time zone offset is zero. If + * null, offset is always shown. + * @param zeroOffsetParseText the text to optionally parse to indicate that the time + * zone offset is zero. If null, then always use the offset. + * @param showSeparators if true, prints ':' separator before minute and + * second field and prints '.' separator before fraction field. + * @param minFields minimum number of fields to print, stopping when no + * more precision is required. 1=hours, 2=minutes, 3=seconds, 4=fraction + * @param maxFields maximum number of fields to print + * @return this DateTimeFormatterBuilder, for chaining + * @since 2.0 + */ + public DateTimeFormatterBuilder appendTimeZoneOffset( + String zeroOffsetPrintText, String zeroOffsetParseText, boolean showSeparators, + int minFields, int maxFields) { + return append0(new TimeZoneOffset + (zeroOffsetPrintText, zeroOffsetParseText, showSeparators, minFields, maxFields)); + } + + //----------------------------------------------------------------------- + /** * Calls upon {@link DateTimeFormat} to parse the pattern and append the * results into this builder. * * @param pattern pattern specification * @throws IllegalArgumentException if the pattern is invalid - * @see DateTimeFormat#appendPatternTo(DateTimeFormatterBuilder,String) + * @see DateTimeFormat */ public DateTimeFormatterBuilder appendPattern(String pattern) { DateTimeFormat.appendPatternTo(this, pattern); return this; } + //----------------------------------------------------------------------- private Object getFormatter() { Object f = iFormatter; @@ -975,14 +1144,7 @@ } private boolean isFormatter(Object f) { - if (f instanceof DateTimeFormatter) { - if (f instanceof Composite) { - return ((Composite)f).isPrinter() - && ((Composite)f).isParser(); - } - return true; - } - return false; + return (isPrinter(f) || isParser(f)); } static void appendUnknownString(StringBuffer buf, int len) { @@ -999,8 +1161,7 @@ //----------------------------------------------------------------------- static class CharacterLiteral - extends BaseDateTimeFormatter - implements DateTimeFormatter { + implements DateTimePrinter, DateTimeParser { private final char iValue; @@ -1013,40 +1174,31 @@ return 1; } - protected void printTo(StringBuffer buf, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) { + public void printTo( + StringBuffer buf, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) { buf.append(iValue); } - protected void printTo(Writer out, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) throws IOException { + public void printTo( + Writer out, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) throws IOException { out.write(iValue); } - public void printTo(StringBuffer buf, ReadablePartial partial) { + public void printTo(StringBuffer buf, ReadablePartial partial, Locale locale) { buf.append(iValue); } - public void printTo(Writer out, ReadablePartial partial) throws IOException { + public void printTo(Writer out, ReadablePartial partial, Locale locale) throws IOException { out.write(iValue); } - protected String print(long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) { - return String.valueOf(iValue); - } - - public String print(ReadablePartial partial) { - return String.valueOf(iValue); - } - - protected int estimateParsedLength() { + public int estimateParsedLength() { return 1; } - protected int parseInto(ParseBucket bucket, String text, int position) { + public int parseInto(DateTimeParserBucket bucket, String text, int position) { if (position >= text.length()) { return ~position; } @@ -1072,8 +1224,7 @@ //----------------------------------------------------------------------- static class StringLiteral - extends BaseDateTimeFormatter - implements DateTimeFormatter { + implements DateTimePrinter, DateTimeParser { private final String iValue; @@ -1086,40 +1237,31 @@ return iValue.length(); } - protected void printTo(StringBuffer buf, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) { + public void printTo( + StringBuffer buf, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) { buf.append(iValue); } - protected void printTo(Writer out, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) throws IOException { + public void printTo( + Writer out, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) throws IOException { out.write(iValue); } - public void printTo(StringBuffer buf, ReadablePartial partial) { + public void printTo(StringBuffer buf, ReadablePartial partial, Locale locale) { buf.append(iValue); } - public void printTo(Writer out, ReadablePartial partial) throws IOException { + public void printTo(Writer out, ReadablePartial partial, Locale locale) throws IOException { out.write(iValue); } - protected String print(long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) { - return iValue; - } - - public String print(ReadablePartial partial) { - return iValue; - } - public int estimateParsedLength() { return iValue.length(); } - public int parseInto(ParseBucket bucket, String text, int position) { + public int parseInto(DateTimeParserBucket bucket, String text, int position) { if (text.regionMatches(true, position, iValue, 0, iValue.length())) { return position + iValue.length(); } @@ -1129,8 +1271,7 @@ //----------------------------------------------------------------------- static abstract class NumberFormatter - extends BaseDateTimeFormatter - implements DateTimeFormatter { + implements DateTimePrinter, DateTimeParser { protected final DateTimeFieldType iFieldType; protected final int iMaxParsedDigits; protected final boolean iSigned; @@ -1143,11 +1284,11 @@ iSigned = signed; } - protected int estimateParsedLength() { + public int estimateParsedLength() { return iMaxParsedDigits; } - protected int parseInto(ParseBucket bucket, String text, int position) { + public int parseInto(DateTimeParserBucket bucket, String text, int position) { int limit = Math.min(iMaxParsedDigits, text.length() - position); boolean negative = false; @@ -1156,6 +1297,14 @@ char c = text.charAt(position + length); if (length == 0 && (c == '-' || c == '+') && iSigned) { negative = c == '-'; + + // Next character must be a digit. + if (length + 1 >= limit || + (c = text.charAt(position + length + 1)) < '0' || c > '9') + { + break; + } + if (negative) { length++; } else { @@ -1180,14 +1329,17 @@ if (length >= 9) { // Since value may exceed integer limits, use stock parser // which checks for this. - value = Integer.parseInt - (text.substring(position, position += length)); + value = Integer.parseInt(text.substring(position, position += length)); } else { int i = position; if (negative) { i++; } - value = text.charAt(i++) - '0'; + try { + value = text.charAt(i++) - '0'; + } catch (StringIndexOutOfBoundsException e) { + return ~position; + } position += length; while (i < position) { value = ((value << 3) + (value << 1)) + text.charAt(i++) - '0'; @@ -1211,33 +1363,33 @@ super(fieldType, maxParsedDigits, signed); } - protected int estimatePrintedLength() { + public int estimatePrintedLength() { return iMaxParsedDigits; } - protected void printTo(StringBuffer buf, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) { + public void printTo( + StringBuffer buf, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) { try { - DateTimeField field = iFieldType.getField(chronoLocal); - FormatUtils.appendUnpaddedInteger(buf, field.get(instantLocal)); + DateTimeField field = iFieldType.getField(chrono); + FormatUtils.appendUnpaddedInteger(buf, field.get(instant)); } catch (RuntimeException e) { buf.append('\ufffd'); } } - protected void printTo(Writer out, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) throws IOException { + public void printTo( + Writer out, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) throws IOException { try { - DateTimeField field = iFieldType.getField(chronoLocal); - FormatUtils.writeUnpaddedInteger(out, field.get(instantLocal)); + DateTimeField field = iFieldType.getField(chrono); + FormatUtils.writeUnpaddedInteger(out, field.get(instant)); } catch (RuntimeException e) { out.write('\ufffd'); } } - public void printTo(StringBuffer buf, ReadablePartial partial) { + public void printTo(StringBuffer buf, ReadablePartial partial, Locale locale) { if (partial.isSupported(iFieldType)) { try { FormatUtils.appendUnpaddedInteger(buf, partial.get(iFieldType)); @@ -1249,7 +1401,7 @@ } } - public void printTo(Writer out, ReadablePartial partial) throws IOException { + public void printTo(Writer out, ReadablePartial partial, Locale locale) throws IOException { if (partial.isSupported(iFieldType)) { try { FormatUtils.writeUnpaddedInteger(out, partial.get(iFieldType)); @@ -1274,33 +1426,33 @@ iMinPrintedDigits = minPrintedDigits; } - protected int estimatePrintedLength() { + public int estimatePrintedLength() { return iMaxParsedDigits; } - protected void printTo(StringBuffer buf, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) { + public void printTo( + StringBuffer buf, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) { try { - DateTimeField field = iFieldType.getField(chronoLocal); - FormatUtils.appendPaddedInteger(buf, field.get(instantLocal), iMinPrintedDigits); + DateTimeField field = iFieldType.getField(chrono); + FormatUtils.appendPaddedInteger(buf, field.get(instant), iMinPrintedDigits); } catch (RuntimeException e) { appendUnknownString(buf, iMinPrintedDigits); } } - protected void printTo(Writer out, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) throws IOException { + public void printTo( + Writer out, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) throws IOException { try { - DateTimeField field = iFieldType.getField(chronoLocal); - FormatUtils.writePaddedInteger(out, field.get(instantLocal), iMinPrintedDigits); + DateTimeField field = iFieldType.getField(chrono); + FormatUtils.writePaddedInteger(out, field.get(instant), iMinPrintedDigits); } catch (RuntimeException e) { printUnknownString(out, iMinPrintedDigits); } } - public void printTo(StringBuffer buf, ReadablePartial partial) { + public void printTo(StringBuffer buf, ReadablePartial partial, Locale locale) { if (partial.isSupported(iFieldType)) { try { FormatUtils.appendPaddedInteger(buf, partial.get(iFieldType), iMinPrintedDigits); @@ -1312,7 +1464,7 @@ } } - public void printTo(Writer out, ReadablePartial partial) throws IOException { + public void printTo(Writer out, ReadablePartial partial, Locale locale) throws IOException { if (partial.isSupported(iFieldType)) { try { FormatUtils.writePaddedInteger(out, partial.get(iFieldType), iMinPrintedDigits); @@ -1326,25 +1478,122 @@ } //----------------------------------------------------------------------- + static class FixedNumber extends PaddedNumber { + + protected FixedNumber(DateTimeFieldType fieldType, int numDigits, boolean signed) { + super(fieldType, numDigits, signed, numDigits); + } + + public int parseInto(DateTimeParserBucket bucket, String text, int position) { + int newPos = super.parseInto(bucket, text, position); + if (newPos < 0) { + return newPos; + } + int expectedPos = position + iMaxParsedDigits; + if (newPos != expectedPos) { + if (iSigned) { + char c = text.charAt(position); + if (c == '-' || c == '+') { + expectedPos++; + } + } + if (newPos > expectedPos) { + // The failure is at the position of the first extra digit. + return ~(expectedPos + 1); + } else if (newPos < expectedPos) { + // The failure is at the position where the next digit should be. + return ~newPos; + } + } + return newPos; + } + } + + //----------------------------------------------------------------------- static class TwoDigitYear - extends BaseDateTimeFormatter - implements DateTimeFormatter { + implements DateTimePrinter, DateTimeParser { + /** The field to print/parse. */ + private final DateTimeFieldType iType; + /** The pivot year. */ private final int iPivot; + private final boolean iLenientParse; - TwoDigitYear(int pivot) { + TwoDigitYear(DateTimeFieldType type, int pivot, boolean lenientParse) { super(); + iType = type; iPivot = pivot; + iLenientParse = lenientParse; } - protected int estimateParsedLength() { - return 2; + public int estimateParsedLength() { + return iLenientParse ? 4 : 2; } - protected int parseInto(ParseBucket bucket, String text, int position) { - int limit = Math.min(2, text.length() - position); - if (limit < 2) { - return ~position; + public int parseInto(DateTimeParserBucket bucket, String text, int position) { + int limit = text.length() - position; + + if (!iLenientParse) { + limit = Math.min(2, limit); + if (limit < 2) { + return ~position; + } + } else { + boolean hasSignChar = false; + boolean negative = false; + int length = 0; + while (length < limit) { + char c = text.charAt(position + length); + if (length == 0 && (c == '-' || c == '+')) { + hasSignChar = true; + negative = c == '-'; + if (negative) { + length++; + } else { + // Skip the '+' for parseInt to succeed. + position++; + limit--; + } + continue; + } + if (c < '0' || c > '9') { + break; + } + length++; + } + + if (length == 0) { + return ~position; + } + + if (hasSignChar || length != 2) { + int value; + if (length >= 9) { + // Since value may exceed integer limits, use stock + // parser which checks for this. + value = Integer.parseInt(text.substring(position, position += length)); + } else { + int i = position; + if (negative) { + i++; + } + try { + value = text.charAt(i++) - '0'; + } catch (StringIndexOutOfBoundsException e) { + return ~position; + } + position += length; + while (i < position) { + value = ((value << 3) + (value << 1)) + text.charAt(i++) - '0'; + } + if (negative) { + value = -value; + } + } + + bucket.saveField(iType, value); + return position; + } } int year; @@ -1359,8 +1608,14 @@ } year = ((year << 3) + (year << 1)) + c - '0'; - int low = iPivot - 50; + int pivot = iPivot; + // If the bucket pivot year is non-null, use that when parsing + if (bucket.getPivotYear() != null) { + pivot = bucket.getPivotYear().intValue(); + } + int low = pivot - 50; + int t; if (low >= 0) { t = low % 100; @@ -1370,18 +1625,18 @@ year += low + ((year < t) ? 100 : 0) - t; - bucket.saveField(DateTimeFieldType.year(), year); + bucket.saveField(iType, year); return position + 2; } - protected int estimatePrintedLength() { + public int estimatePrintedLength() { return 2; } - protected void printTo(StringBuffer buf, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) { - int year = getTwoDigitYear(instantLocal, chronoLocal); + public void printTo( + StringBuffer buf, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) { + int year = getTwoDigitYear(instant, chrono); if (year < 0) { buf.append('\ufffd'); buf.append('\ufffd'); @@ -1390,10 +1645,10 @@ } } - protected void printTo(Writer out, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) throws IOException { - int year = getTwoDigitYear(instantLocal, chronoLocal); + public void printTo( + Writer out, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) throws IOException { + int year = getTwoDigitYear(instant, chrono); if (year < 0) { out.write('\ufffd'); out.write('\ufffd'); @@ -1402,9 +1657,9 @@ } } - private int getTwoDigitYear(long instantLocal, Chronology chronoLocal) { + private int getTwoDigitYear(long instant, Chronology chrono) { try { - int year = chronoLocal.year().get(instantLocal); + int year = iType.getField(chrono).get(instant); if (year < 0) { year = -year; } @@ -1414,7 +1669,7 @@ } } - public void printTo(StringBuffer buf, ReadablePartial partial) { + public void printTo(StringBuffer buf, ReadablePartial partial, Locale locale) { int year = getTwoDigitYear(partial); if (year < 0) { buf.append('\ufffd'); @@ -1424,7 +1679,7 @@ } } - public void printTo(Writer out, ReadablePartial partial) throws IOException { + public void printTo(Writer out, ReadablePartial partial, Locale locale) throws IOException { int year = getTwoDigitYear(partial); if (year < 0) { out.write('\ufffd'); @@ -1435,9 +1690,9 @@ } private int getTwoDigitYear(ReadablePartial partial) { - if (partial.isSupported(DateTimeFieldType.year())) { + if (partial.isSupported(iType)) { try { - int year = partial.get(DateTimeFieldType.year()); + int year = partial.get(iType); if (year < 0) { year = -year; } @@ -1450,115 +1705,149 @@ //----------------------------------------------------------------------- static class TextField - extends BaseDateTimeFormatter - implements DateTimeFormatter { + implements DateTimePrinter, DateTimeParser { + private static Map> cParseCache = + new HashMap>(); private final DateTimeFieldType iFieldType; - private final Locale iLocale; private final boolean iShort; - TextField(DateTimeFieldType fieldType, Locale locale, boolean isShort) { + TextField(DateTimeFieldType fieldType, boolean isShort) { super(); iFieldType = fieldType; - iLocale = locale; iShort = isShort; } - protected int estimatePrintedLength() { + public int estimatePrintedLength() { return iShort ? 6 : 20; } - protected void printTo(StringBuffer buf, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) { + public void printTo( + StringBuffer buf, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) { try { - buf.append(print(instantLocal, chronoLocal, instant, chrono)); + buf.append(print(instant, chrono, locale)); } catch (RuntimeException e) { buf.append('\ufffd'); } } - protected void printTo(Writer out, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) throws IOException { + public void printTo( + Writer out, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) throws IOException { try { - out.write(print(instantLocal, chronoLocal, instant, chrono)); + out.write(print(instant, chrono, locale)); } catch (RuntimeException e) { out.write('\ufffd'); } } - public void printTo(StringBuffer buf, ReadablePartial partial) { + public void printTo(StringBuffer buf, ReadablePartial partial, Locale locale) { try { - buf.append(print(partial)); + buf.append(print(partial, locale)); } catch (RuntimeException e) { buf.append('\ufffd'); } } - public void printTo(Writer out, ReadablePartial partial) throws IOException { + public void printTo(Writer out, ReadablePartial partial, Locale locale) throws IOException { try { - out.write(print(partial)); + out.write(print(partial, locale)); } catch (RuntimeException e) { out.write('\ufffd'); } } - protected String print(long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) { + private String print(long instant, Chronology chrono, Locale locale) { DateTimeField field = iFieldType.getField(chrono); if (iShort) { - return field.getAsShortText(instantLocal, iLocale); + return field.getAsShortText(instant, locale); } else { - return field.getAsText(instantLocal, iLocale); + return field.getAsText(instant, locale); } } - public String print(ReadablePartial partial) { + private String print(ReadablePartial partial, Locale locale) { if (partial.isSupported(iFieldType)) { DateTimeField field = iFieldType.getField(partial.getChronology()); if (iShort) { - return field.getAsShortText(partial, iLocale); + return field.getAsShortText(partial, locale); } else { - return field.getAsText(partial, iLocale); + return field.getAsText(partial, locale); } } else { return "\ufffd"; } } - protected int estimateParsedLength() { + public int estimateParsedLength() { return estimatePrintedLength(); } - protected int parseInto(ParseBucket bucket, String text, int position) { - int limit = text.length(); - int i = position; - for (; i validValues = null; + int maxLength = 0; + synchronized (cParseCache) { + Map innerMap = cParseCache.get(locale); + if (innerMap == null) { + innerMap = new HashMap(); + cParseCache.put(locale, innerMap); } - if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || Character.isLetter(c)) { - continue; + Object[] array = innerMap.get(iFieldType); + if (array == null) { + validValues = new HashSet(32); + MutableDateTime dt = new MutableDateTime(0L, DateTimeZone.UTC); + Property property = dt.property(iFieldType); + int min = property.getMinimumValueOverall(); + int max = property.getMaximumValueOverall(); + if (max - min > 32) { // protect against invalid fields + return ~position; + } + maxLength = property.getMaximumTextLength(locale); + for (int i = min; i <= max; i++) { + property.set(i); + validValues.add(property.getAsShortText(locale)); + validValues.add(property.getAsShortText(locale).toLowerCase(locale)); + validValues.add(property.getAsShortText(locale).toUpperCase(locale)); + validValues.add(property.getAsText(locale)); + validValues.add(property.getAsText(locale).toLowerCase(locale)); + validValues.add(property.getAsText(locale).toUpperCase(locale)); + } + if ("en".equals(locale.getLanguage()) && iFieldType == DateTimeFieldType.era()) { + // hack to support for parsing "BCE" and "CE" if the language is English + validValues.add("BCE"); + validValues.add("bce"); + validValues.add("CE"); + validValues.add("ce"); + maxLength = 3; + } + array = new Object[] {validValues, Integer.valueOf(maxLength)}; + innerMap.put(iFieldType, array); + } else { + validValues = (Set) array[0]; + maxLength = ((Integer) array[1]).intValue(); } - break; } - - if (i == position) { - return ~position; + // match the longest string first using our knowledge of the max length + int limit = Math.min(text.length(), position + maxLength); + for (int i = limit; i > position; i--) { + String match = text.substring(position, i); + if (validValues.contains(match)) { + bucket.saveField(iFieldType, match, locale); + return i; + } } - - bucket.saveField(iFieldType, text.substring(position, i), iLocale); - - return i; + return ~position; } } //----------------------------------------------------------------------- static class Fraction - extends BaseDateTimeFormatter - implements DateTimeFormatter { + implements DateTimePrinter, DateTimeParser { private final DateTimeFieldType iFieldType; protected int iMinDigits; @@ -1575,57 +1864,53 @@ iMaxDigits = maxDigits; } - protected int estimatePrintedLength() { + public int estimatePrintedLength() { return iMaxDigits; } - protected void printTo(StringBuffer buf, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) { + public void printTo( + StringBuffer buf, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) { try { - printTo(buf, null, instantLocal, chronoLocal); + printTo(buf, null, instant, chrono); } catch (IOException e) { // Not gonna happen. } } - protected void printTo(Writer out, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) throws IOException { - printTo(null, out, instantLocal, chronoLocal); + public void printTo( + Writer out, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) throws IOException { + printTo(null, out, instant, chrono); } - public void printTo(StringBuffer buf, ReadablePartial partial) { - if (partial.isSupported(iFieldType)) { - long millis = partial.getChronology().set(partial, 0L); - try { - printTo(buf, null, millis, partial.getChronology()); - } catch (IOException e) { - // Not gonna happen. - } - } else { - buf.append('\ufffd'); + public void printTo(StringBuffer buf, ReadablePartial partial, Locale locale) { + // removed check whether field is supported, as input field is typically + // secondOfDay which is unsupported by TimeOfDay + long millis = partial.getChronology().set(partial, 0L); + try { + printTo(buf, null, millis, partial.getChronology()); + } catch (IOException e) { + // Not gonna happen. } } - public void printTo(Writer out, ReadablePartial partial) throws IOException { - if (partial.isSupported(iFieldType)) { - long millis = partial.getChronology().set(partial, 0L); - printTo(null, out, millis, partial.getChronology()); - } else { - out.write('\ufffd'); - } + public void printTo(Writer out, ReadablePartial partial, Locale locale) throws IOException { + // removed check whether field is supported, as input field is typically + // secondOfDay which is unsupported by TimeOfDay + long millis = partial.getChronology().set(partial, 0L); + printTo(null, out, millis, partial.getChronology()); } - protected void printTo(StringBuffer buf, Writer out, long instantLocal, Chronology chronoLocal) + protected void printTo(StringBuffer buf, Writer out, long instant, Chronology chrono) throws IOException { - DateTimeField field = iFieldType.getField(chronoLocal); + DateTimeField field = iFieldType.getField(chrono); int minDigits = iMinDigits; long fraction; try { - fraction = field.remainder(instantLocal); + fraction = field.remainder(instant); } catch (RuntimeException e) { if (buf != null) { appendUnknownString(buf, minDigits); @@ -1737,11 +2022,11 @@ return new long[] {fraction * scalar / rangeMillis, maxDigits}; } - protected int estimateParsedLength() { + public int estimateParsedLength() { return iMaxDigits; } - protected int parseInto(ParseBucket bucket, String text, int position) { + public int parseInto(DateTimeParserBucket bucket, String text, int position) { DateTimeField field = iFieldType.getField(bucket.getChronology()); int limit = Math.min(iMaxDigits, text.length() - position); @@ -1782,21 +2067,22 @@ } //----------------------------------------------------------------------- - static class TimeZoneOffsetFormatter - extends BaseDateTimeFormatter - implements DateTimeFormatter { + static class TimeZoneOffset + implements DateTimePrinter, DateTimeParser { - private final String iZeroOffsetText; + private final String iZeroOffsetPrintText; + private final String iZeroOffsetParseText; private final boolean iShowSeparators; private final int iMinFields; private final int iMaxFields; - TimeZoneOffsetFormatter(String zeroOffsetText, + TimeZoneOffset(String zeroOffsetPrintText, String zeroOffsetParseText, boolean showSeparators, int minFields, int maxFields) { super(); - iZeroOffsetText = zeroOffsetText; + iZeroOffsetPrintText = zeroOffsetPrintText; + iZeroOffsetParseText = zeroOffsetParseText; iShowSeparators = showSeparators; if (minFields <= 0 || maxFields < minFields) { throw new IllegalArgumentException(); @@ -1809,165 +2095,166 @@ iMaxFields = maxFields; } - protected int estimatePrintedLength() { + public int estimatePrintedLength() { int est = 1 + iMinFields << 1; if (iShowSeparators) { est += iMinFields - 1; } - if (iZeroOffsetText != null && iZeroOffsetText.length() > est) { - est = iZeroOffsetText.length(); + if (iZeroOffsetPrintText != null && iZeroOffsetPrintText.length() > est) { + est = iZeroOffsetPrintText.length(); } return est; } - protected void printTo(StringBuffer buf, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) { - int offset = (int)(instantLocal - instant); - - if (offset == 0 && iZeroOffsetText != null) { - buf.append(iZeroOffsetText); + public void printTo( + StringBuffer buf, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) { + if (displayZone == null) { + return; // no zone + } + if (displayOffset == 0 && iZeroOffsetPrintText != null) { + buf.append(iZeroOffsetPrintText); return; } - if (offset >= 0) { + if (displayOffset >= 0) { buf.append('+'); } else { buf.append('-'); - offset = -offset; + displayOffset = -displayOffset; } - int hours = offset / DateTimeConstants.MILLIS_PER_HOUR; + int hours = displayOffset / DateTimeConstants.MILLIS_PER_HOUR; FormatUtils.appendPaddedInteger(buf, hours, 2); if (iMaxFields == 1) { return; } - offset -= hours * (int)DateTimeConstants.MILLIS_PER_HOUR; - if (offset == 0 && iMinFields <= 1) { + displayOffset -= hours * (int)DateTimeConstants.MILLIS_PER_HOUR; + if (displayOffset == 0 && iMinFields <= 1) { return; } - int minutes = offset / DateTimeConstants.MILLIS_PER_MINUTE; + int minutes = displayOffset / DateTimeConstants.MILLIS_PER_MINUTE; if (iShowSeparators) { buf.append(':'); } FormatUtils.appendPaddedInteger(buf, minutes, 2); if (iMaxFields == 2) { return; } - offset -= minutes * DateTimeConstants.MILLIS_PER_MINUTE; - if (offset == 0 && iMinFields <= 2) { + displayOffset -= minutes * DateTimeConstants.MILLIS_PER_MINUTE; + if (displayOffset == 0 && iMinFields <= 2) { return; } - int seconds = offset / DateTimeConstants.MILLIS_PER_SECOND; + int seconds = displayOffset / DateTimeConstants.MILLIS_PER_SECOND; if (iShowSeparators) { buf.append(':'); } FormatUtils.appendPaddedInteger(buf, seconds, 2); if (iMaxFields == 3) { return; } - offset -= seconds * DateTimeConstants.MILLIS_PER_SECOND; - if (offset == 0 && iMinFields <= 3) { + displayOffset -= seconds * DateTimeConstants.MILLIS_PER_SECOND; + if (displayOffset == 0 && iMinFields <= 3) { return; } if (iShowSeparators) { buf.append('.'); } - FormatUtils.appendPaddedInteger(buf, offset, 3); + FormatUtils.appendPaddedInteger(buf, displayOffset, 3); } - protected void printTo(Writer out, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) throws IOException { - int offset = (int)(instantLocal - instant); - - if (offset == 0 && iZeroOffsetText != null) { - out.write(iZeroOffsetText); + public void printTo( + Writer out, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) throws IOException { + if (displayZone == null) { + return; // no zone + } + if (displayOffset == 0 && iZeroOffsetPrintText != null) { + out.write(iZeroOffsetPrintText); return; } - if (offset >= 0) { + if (displayOffset >= 0) { out.write('+'); } else { out.write('-'); - offset = -offset; + displayOffset = -displayOffset; } - int hours = offset / DateTimeConstants.MILLIS_PER_HOUR; + int hours = displayOffset / DateTimeConstants.MILLIS_PER_HOUR; FormatUtils.writePaddedInteger(out, hours, 2); if (iMaxFields == 1) { return; } - offset -= hours * (int)DateTimeConstants.MILLIS_PER_HOUR; - if (offset == 0 && iMinFields == 1) { + displayOffset -= hours * (int)DateTimeConstants.MILLIS_PER_HOUR; + if (displayOffset == 0 && iMinFields == 1) { return; } - int minutes = offset / DateTimeConstants.MILLIS_PER_MINUTE; + int minutes = displayOffset / DateTimeConstants.MILLIS_PER_MINUTE; if (iShowSeparators) { out.write(':'); } FormatUtils.writePaddedInteger(out, minutes, 2); if (iMaxFields == 2) { return; } - offset -= minutes * DateTimeConstants.MILLIS_PER_MINUTE; - if (offset == 0 && iMinFields == 2) { + displayOffset -= minutes * DateTimeConstants.MILLIS_PER_MINUTE; + if (displayOffset == 0 && iMinFields == 2) { return; } - int seconds = offset / DateTimeConstants.MILLIS_PER_SECOND; + int seconds = displayOffset / DateTimeConstants.MILLIS_PER_SECOND; if (iShowSeparators) { out.write(':'); } FormatUtils.writePaddedInteger(out, seconds, 2); if (iMaxFields == 3) { return; } - offset -= seconds * DateTimeConstants.MILLIS_PER_SECOND; - if (offset == 0 && iMinFields == 3) { + displayOffset -= seconds * DateTimeConstants.MILLIS_PER_SECOND; + if (displayOffset == 0 && iMinFields == 3) { return; } if (iShowSeparators) { out.write('.'); } - FormatUtils.writePaddedInteger(out, offset, 3); + FormatUtils.writePaddedInteger(out, displayOffset, 3); } - public void printTo(StringBuffer buf, ReadablePartial partial) { + public void printTo(StringBuffer buf, ReadablePartial partial, Locale locale) { // no zone info } - public void printTo(Writer out, ReadablePartial partial) throws IOException { + public void printTo(Writer out, ReadablePartial partial, Locale locale) throws IOException { // no zone info } - protected int estimateParsedLength() { + public int estimateParsedLength() { return estimatePrintedLength(); } - protected int parseInto(ParseBucket bucket, String text, int position) { + public int parseInto(DateTimeParserBucket bucket, String text, int position) { int limit = text.length() - position; zeroOffset: - if (iZeroOffsetText != null) { - if (iZeroOffsetText.length() == 0) { + if (iZeroOffsetParseText != null) { + if (iZeroOffsetParseText.length() == 0) { // Peek ahead, looking for sign character. if (limit > 0) { char c = text.charAt(position); if (c == '-' || c == '+') { break zeroOffset; } } - bucket.setOffset(0); + bucket.setOffset(Integer.valueOf(0)); return position; } - if (text.regionMatches(true, position, iZeroOffsetText, 0, - iZeroOffsetText.length())) { - bucket.setOffset(0); - return position + iZeroOffsetText.length(); + if (text.regionMatches(true, position, iZeroOffsetParseText, 0, iZeroOffsetParseText.length())) { + bucket.setOffset(Integer.valueOf(0)); + return position + iZeroOffsetParseText.length(); } } @@ -2116,7 +2403,7 @@ } } - bucket.setOffset(negative ? -offset : offset); + bucket.setOffset(Integer.valueOf(negative ? -offset : offset)); return position; } @@ -2139,70 +2426,150 @@ } //----------------------------------------------------------------------- - static class TimeZonePrinter - extends BaseDateTimeFormatter - implements DateTimePrinter { + static class TimeZoneName + implements DateTimePrinter, DateTimeParser { - private final Locale iLocale; - private final boolean iShortFormat; + static final int LONG_NAME = 0; + static final int SHORT_NAME = 1; - TimeZonePrinter(Locale locale, boolean shortFormat) { + private final Map iParseLookup; + private final int iType; + + TimeZoneName(int type, Map parseLookup) { super(); - iLocale = locale; - iShortFormat = shortFormat; + iType = type; + iParseLookup = parseLookup; } - protected int estimatePrintedLength() { - return iShortFormat ? 4 : 20; + public int estimatePrintedLength() { + return (iType == SHORT_NAME ? 4 : 20); } - protected void printTo(StringBuffer buf, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) { - buf.append(print(instantLocal, chronoLocal, instant, chrono)); + public void printTo( + StringBuffer buf, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) { + buf.append(print(instant - displayOffset, displayZone, locale)); } - protected void printTo(Writer out, - long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) throws IOException { - out.write(print(instantLocal, chronoLocal, instant, chrono)); + public void printTo( + Writer out, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) throws IOException { + out.write(print(instant - displayOffset, displayZone, locale)); } - protected String print(long instantLocal, Chronology chronoLocal, - long instant, Chronology chrono) { - DateTimeZone zone = chrono.getZone(); - if (iShortFormat) { - return zone.getShortName(instant, this.iLocale); - } else { - return zone.getName(instant, this.iLocale); + private String print(long instant, DateTimeZone displayZone, Locale locale) { + if (displayZone == null) { + return ""; // no zone } + switch (iType) { + case LONG_NAME: + return displayZone.getName(instant, locale); + case SHORT_NAME: + return displayZone.getShortName(instant, locale); + } + return ""; } - public void printTo(StringBuffer buf, ReadablePartial partial) { + public void printTo(StringBuffer buf, ReadablePartial partial, Locale locale) { // no zone info } - public void printTo(Writer out, ReadablePartial partial) throws IOException { + public void printTo(Writer out, ReadablePartial partial, Locale locale) throws IOException { // no zone info } + + public int estimateParsedLength() { + return (iType == SHORT_NAME ? 4 : 20); + } + + public int parseInto(DateTimeParserBucket bucket, String text, int position) { + String str = text.substring(position); + for (String name : iParseLookup.keySet()) { + if (str.startsWith(name)) { + bucket.setZone(iParseLookup.get(name)); + return position + name.length(); + } + } + return ~position; + } } //----------------------------------------------------------------------- + static enum TimeZoneId + implements DateTimePrinter, DateTimeParser { + + INSTANCE; + static final Set ALL_IDS = DateTimeZone.getAvailableIDs(); + static final int MAX_LENGTH; + static { + int max = 0; + for (String id : ALL_IDS) { + max = Math.max(max, id.length()); + } + MAX_LENGTH = max; + } + + public int estimatePrintedLength() { + return MAX_LENGTH; + } + + public void printTo( + StringBuffer buf, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) { + buf.append(displayZone != null ? displayZone.getID() : ""); + } + + public void printTo( + Writer out, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) throws IOException { + out.write(displayZone != null ? displayZone.getID() : ""); + } + + public void printTo(StringBuffer buf, ReadablePartial partial, Locale locale) { + // no zone info + } + + public void printTo(Writer out, ReadablePartial partial, Locale locale) throws IOException { + // no zone info + } + + public int estimateParsedLength() { + return MAX_LENGTH; + } + + public int parseInto(DateTimeParserBucket bucket, String text, int position) { + String str = text.substring(position); + String best = null; + for (String id : ALL_IDS) { + if (str.startsWith(id)) { + if (best == null || id.length() > best.length()) { + best = id; + } + } + } + if (best != null) { + bucket.setZone(DateTimeZone.forID(best)); + return position + best.length(); + } + return ~position; + } + } + + //----------------------------------------------------------------------- static class Composite - extends BaseDateTimeFormatter - implements DateTimeFormatter { + implements DateTimePrinter, DateTimeParser { - private final BaseDateTimeFormatter[] iPrinters; - private final BaseDateTimeFormatter[] iParsers; + private final DateTimePrinter[] iPrinters; + private final DateTimeParser[] iParsers; private final int iPrintedLengthEstimate; private final int iParsedLengthEstimate; - Composite(List elementPairs) { + Composite(List elementPairs) { super(); - List printerList = new ArrayList(); - List parserList = new ArrayList(); + List printerList = new ArrayList(); + List parserList = new ArrayList(); decompose(elementPairs, printerList, parserList); @@ -2211,10 +2578,10 @@ iPrintedLengthEstimate = 0; } else { int size = printerList.size(); - iPrinters = new BaseDateTimeFormatter[size]; + iPrinters = new DateTimePrinter[size]; int printEst = 0; for (int i=0; i elementPairs, List printerList, List parserList) { int size = elementPairs.size(); for (int i=0; i list, Object[] array) { if (array != null) { for (int i=0; i=0 ;) { - BaseDateTimeFormatter parser = parsers[i]; + DateTimeParser parser = parsers[i]; if (parser != null) { int len = parser.estimateParsedLength(); if (len > est) { - len = est; + est = len; } } } iParsedLengthEstimate = est; } - protected int estimateParsedLength() { + public int estimateParsedLength() { return iParsedLengthEstimate; } - protected int parseInto(ParseBucket bucket, String text, int position) { - BaseDateTimeFormatter[] parsers = iParsers; + public int parseInto(DateTimeParserBucket bucket, String text, int position) { + DateTimeParser[] parsers = iParsers; int length = parsers.length; final Object originalState = bucket.saveState(); @@ -2402,7 +2781,7 @@ int bestInvalidPos = position; for (int i=0; i. For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.format; -import org.joda.time.Chronology; -import org.joda.time.DateTime; -import org.joda.time.MutableDateTime; -import org.joda.time.ReadWritableInstant; -import org.joda.time.ReadableInstant; - /** - * Defines an interface for parsing textual representations of datetimes. + * Internal interface for parsing textual representations of datetimes. *

            - * Note: This interface represents a view onto {@link BaseDateTimeFormatter}. - * All implementations must extend BaseDateTimeFormatter. + * Application users will rarely use this class directly. Instead, you + * will use one of the factory classes to create a {@link DateTimeFormatter}. + *

            + * The factory classes are:
            + * - {@link DateTimeFormatterBuilder}
            + * - {@link DateTimeFormat}
            + * - {@link ISODateTimeFormat}
            * * @author Brian S O'Neill * @see DateTimeFormatter @@ -74,167 +35,30 @@ public interface DateTimeParser { /** - * Parses a datetime from the given text, at the given position, saving the - * result into the fields of the given ReadWritableInstant. If the parse - * succeeds, the return value is the new text position. Note that the parse - * may succeed without fully reading the text. + * Returns the expected maximum number of characters consumed. + * The actual amount should rarely exceed this estimate. + * + * @return the estimated length + */ + int estimateParsedLength(); + + /** + * Parse an element from the given text, saving any fields into the given + * DateTimeParserBucket. If the parse succeeds, the return value is the new + * text position. Note that the parse may succeed without fully reading the + * text. *

            - * If it fails, the return value is negative, but the instant may still be - * modified. To determine the position where the parse failed, apply the - * one's complement operator (~) on the return value. - *

            - * The parse will use the chronology of the instant. + * If it fails, the return value is negative. To determine the position + * where the parse failed, apply the one's complement operator (~) on the + * return value. * - * @param instant an instant that will be modified - * @param text the text to parse + * @param bucket field are saved into this, not null + * @param text the text to parse, not null * @param position position to start parsing from * @return new position, negative value means parse failed - * apply complement operator (~) to get position of failure - * @throws IllegalArgumentException if the instant is null * @throws IllegalArgumentException if any field is out of range */ - int parseInto(ReadWritableInstant instant, String text, int position); + int parseInto(DateTimeParserBucket bucket, String text, int position); - //----------------------------------------------------------------------- - /** - * Parses a datetime from the given text, returning the number of - * milliseconds since the epoch, 1970-01-01T00:00:00Z. - *

            - * The parse will use the ISO chronology, and the default time zone. - * If the text contains a time zone string then that will be taken into account. - * - * @param text text to parse - * @return parsed value expressed in milliseconds since the epoch - * @throws IllegalArgumentException if the text to parse is invalid - */ - long parseMillis(String text); - - /** - * Parses a datetime from the given text, returning the number of - * milliseconds since the epoch, 1970-01-01T00:00:00Z. - *

            - * The parse will use the given chronology and time zone. - * If the text contains a time zone string then that will be taken into account. - * - * @param text the text to parse - * @param chrono the chronology to use, null means ISO default - * @return parsed value expressed in milliseconds since the epoch - * @throws IllegalArgumentException if the text to parse is invalid - */ - long parseMillis(String text, Chronology chrono); - - //----------------------------------------------------------------------- - /** - * Parses a datetime from the given text, at the given position, returning - * the number of milliseconds since the epoch, 1970-01-01T00:00:00Z. - * An initial millisecond value is passed in, which is relative to the epoch, - * local time, and which can default field values. - *

            - * The parse will use the ISO chronology and default time zone. - * If the text contains a time zone string then that will be taken into account. - * - * @param text the text to parse - * @param instant initial value of instant, relative to the epoch, local time - * @return parsed value expressed in milliseconds since the epoch, UTC - * @throws IllegalArgumentException if the text to parse is invalid - */ - long parseMillis(String text, long instant); - - /** - * Parses a datetime from the given text, at the given position, returning - * the number of milliseconds since the epoch, 1970-01-01T00:00:00Z. - * An initial millisecond value is passed in, which is relative to the epoch, - * which can default field values. - *

            - * The parse will use the given chronology and time zone. - * If the text contains a time zone string then that will be taken into account. - * - * @param text the text to parse - * @param instant initial value of instant, relative to the epoch - * @param chrono the chronology to use, null means ISO default - * @return parsed value expressed in milliseconds since the epoch, UTC - * @throws IllegalArgumentException if the text to parse is invalid - */ - long parseMillis(String text, long instant, Chronology chrono); - - //----------------------------------------------------------------------- - /** - * Parses a datetime from the given text, returning a new DateTime. - *

            - * The parse will use the ISO chronology and default time zone. - * If the text contains a time zone string then that will be taken into account. - * - * @param text the text to parse - * @return parsed value in a DateTime object - * @throws IllegalArgumentException if the text to parse is invalid - */ - DateTime parseDateTime(String text); - - /** - * Parses a datetime from the given text, returning a new DateTime. - *

            - * The parse will use the given chronology and time zone. - * If the text contains a time zone string then that will be taken into account. - * - * @param text the text to parse - * @param chrono the chronology to use, null means ISO default - * @return parsed value in a DateTime object - * @throws IllegalArgumentException if the text to parse is invalid - */ - DateTime parseDateTime(String text, Chronology chrono); - - /** - * Parses a datetime from the given text, returning a new DateTime, using - * the given instant to supply field values that were not parsed. - *

            - * The parse will use the instant's chronology and time zone. - * If the text contains a time zone string then that will be taken into account. - * - * @param text the text to parse - * @param instant initial value of DateTime - * @return parsed value in a DateTime object - * @throws IllegalArgumentException if the text to parse is invalid - */ - DateTime parseDateTime(String text, ReadableInstant instant); - - //----------------------------------------------------------------------- - /** - * Parses a datetime from the given text, returning a new MutableDateTime. - *

            - * The parse will use the ISO chronology and default time zone. - * If the text contains a time zone string then that will be taken into account. - * - * @param text the text to parse - * @return parsed value in a MutableDateTime object - * @throws IllegalArgumentException if the text to parse is invalid - */ - MutableDateTime parseMutableDateTime(String text); - - /** - * Parses a datetime from the given text, returning a new MutableDateTime. - *

            - * The parse will use the given chronology and time zone. - * If the text contains a time zone string then that will be taken into account. - * - * @param text the text to parse - * @param chrono the chronology to use, null means ISO default - * @return parsed value in a MutableDateTime object - * @throws IllegalArgumentException if the text to parse is invalid - */ - MutableDateTime parseMutableDateTime(String text, Chronology chrono); - - /** - * Parses a datetime from the given text, returning a new MutableDateTime, - * using the given instant to supply field values that were not parsed. - *

            - * The parse will use the instant's chronology and time zone. - * If the text contains a time zone string then that will be taken into account. - * - * @param text the text to parse - * @param instant initial value of DateTime - * @return parsed value in a MutableDateTime object - * @throws IllegalArgumentException if the text to parse is invalid - */ - MutableDateTime parseMutableDateTime(String text, ReadableInstant instant); - } Index: 3rdParty_sources/joda-time/org/joda/time/format/DateTimeParserBucket.java =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/format/DateTimeParserBucket.java (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/format/DateTimeParserBucket.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,522 @@ +/* + * Copyright 2001-2011 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time.format; + +import java.util.Arrays; +import java.util.Locale; + +import org.joda.time.Chronology; +import org.joda.time.DateTimeField; +import org.joda.time.DateTimeFieldType; +import org.joda.time.DateTimeUtils; +import org.joda.time.DateTimeZone; +import org.joda.time.DurationField; +import org.joda.time.DurationFieldType; +import org.joda.time.IllegalFieldValueException; + +/** + * DateTimeParserBucket is an advanced class, intended mainly for parser + * implementations. It can also be used during normal parsing operations to + * capture more information about the parse. + *

            + * This class allows fields to be saved in any order, but be physically set in + * a consistent order. This is useful for parsing against formats that allow + * field values to contradict each other. + *

            + * Field values are applied in an order where the "larger" fields are set + * first, making their value less likely to stick. A field is larger than + * another when it's range duration is longer. If both ranges are the same, + * then the larger field has the longer duration. If it cannot be determined + * which field is larger, then the fields are set in the order they were saved. + *

            + * For example, these fields were saved in this order: dayOfWeek, monthOfYear, + * dayOfMonth, dayOfYear. When computeMillis is called, the fields are set in + * this order: monthOfYear, dayOfYear, dayOfMonth, dayOfWeek. + *

            + * DateTimeParserBucket is mutable and not thread-safe. + * + * @author Brian S O'Neill + * @author Fredrik Borgh + * @since 1.0 + */ +public class DateTimeParserBucket { + + /** The chronology to use for parsing. */ + private final Chronology iChrono; + private final long iMillis; + + /** The parsed zone, initialised to formatter zone. */ + private DateTimeZone iZone; + /** The parsed offset. */ + private Integer iOffset; + /** The locale to use for parsing. */ + private Locale iLocale; + /** Used for parsing two-digit years. */ + private Integer iPivotYear; + /** Used for parsing month/day without year. */ + private int iDefaultYear; + + private SavedField[] iSavedFields = new SavedField[8]; + private int iSavedFieldsCount; + private boolean iSavedFieldsShared; + + private Object iSavedState; + + /** + * Constructs a bucket. + * + * @param instantLocal the initial millis from 1970-01-01T00:00:00, local time + * @param chrono the chronology to use + * @param locale the locale to use + * @deprecated Use longer constructor + */ + @Deprecated + public DateTimeParserBucket(long instantLocal, Chronology chrono, Locale locale) { + this(instantLocal, chrono, locale, null, 2000); + } + + /** + * Constructs a bucket, with the option of specifying the pivot year for + * two-digit year parsing. + * + * @param instantLocal the initial millis from 1970-01-01T00:00:00, local time + * @param chrono the chronology to use + * @param locale the locale to use + * @param pivotYear the pivot year to use when parsing two-digit years + * @since 1.1 + * @deprecated Use longer constructor + */ + @Deprecated + public DateTimeParserBucket(long instantLocal, Chronology chrono, Locale locale, Integer pivotYear) { + this(instantLocal, chrono, locale, pivotYear, 2000); + } + + /** + * Constructs a bucket, with the option of specifying the pivot year for + * two-digit year parsing. + * + * @param instantLocal the initial millis from 1970-01-01T00:00:00, local time + * @param chrono the chronology to use + * @param locale the locale to use + * @param pivotYear the pivot year to use when parsing two-digit years + * @since 2.0 + */ + public DateTimeParserBucket(long instantLocal, Chronology chrono, + Locale locale, Integer pivotYear, int defaultYear) { + super(); + chrono = DateTimeUtils.getChronology(chrono); + iMillis = instantLocal; + iZone = chrono.getZone(); + iChrono = chrono.withUTC(); + iLocale = (locale == null ? Locale.getDefault() : locale); + iPivotYear = pivotYear; + iDefaultYear = defaultYear; + } + + //----------------------------------------------------------------------- + /** + * Gets the chronology of the bucket, which will be a local (UTC) chronology. + */ + public Chronology getChronology() { + return iChrono; + } + + //----------------------------------------------------------------------- + /** + * Returns the locale to be used during parsing. + * + * @return the locale to use + */ + public Locale getLocale() { + return iLocale; + } + + //----------------------------------------------------------------------- + /** + * Returns the time zone used by computeMillis. + */ + public DateTimeZone getZone() { + return iZone; + } + + /** + * Set a time zone to be used when computeMillis is called. + */ + public void setZone(DateTimeZone zone) { + iSavedState = null; + iZone = zone; + } + + //----------------------------------------------------------------------- + /** + * Returns the time zone offset in milliseconds used by computeMillis. + * @deprecated use Integer version + */ + @Deprecated + public int getOffset() { + return (iOffset != null ? iOffset : 0); + } + + /** + * Returns the time zone offset in milliseconds used by computeMillis. + */ + public Integer getOffsetInteger() { + return iOffset; + } + + /** + * Set a time zone offset to be used when computeMillis is called. + * @deprecated use Integer version + */ + @Deprecated + public void setOffset(int offset) { + iSavedState = null; + iOffset = offset; + } + + /** + * Set a time zone offset to be used when computeMillis is called. + */ + public void setOffset(Integer offset) { + iSavedState = null; + iOffset = offset; + } + + //----------------------------------------------------------------------- + /** + * Returns the default year used when information is incomplete. + *

            + * This is used for two-digit years and when the largest parsed field is + * months or days. + *

            + * A null value for two-digit years means to use the value from DateTimeFormatterBuilder. + * A null value for month/day only parsing will cause the default of 2000 to be used. + * + * @return Integer value of the pivot year, null if not set + * @since 1.1 + */ + public Integer getPivotYear() { + return iPivotYear; + } + + /** + * Sets the pivot year to use when parsing two digit years. + *

            + * If the value is set to null, this will indicate that default + * behaviour should be used. + * + * @param pivotYear the pivot year to use + * @since 1.1 + */ + public void setPivotYear(Integer pivotYear) { + iPivotYear = pivotYear; + } + + //----------------------------------------------------------------------- + /** + * Saves a datetime field value. + * + * @param field the field, whose chronology must match that of this bucket + * @param value the value + */ + public void saveField(DateTimeField field, int value) { + saveField(new SavedField(field, value)); + } + + /** + * Saves a datetime field value. + * + * @param fieldType the field type + * @param value the value + */ + public void saveField(DateTimeFieldType fieldType, int value) { + saveField(new SavedField(fieldType.getField(iChrono), value)); + } + + /** + * Saves a datetime field text value. + * + * @param fieldType the field type + * @param text the text value + * @param locale the locale to use + */ + public void saveField(DateTimeFieldType fieldType, String text, Locale locale) { + saveField(new SavedField(fieldType.getField(iChrono), text, locale)); + } + + private void saveField(SavedField field) { + SavedField[] savedFields = iSavedFields; + int savedFieldsCount = iSavedFieldsCount; + + if (savedFieldsCount == savedFields.length || iSavedFieldsShared) { + // Expand capacity or merely copy if saved fields are shared. + SavedField[] newArray = new SavedField + [savedFieldsCount == savedFields.length ? savedFieldsCount * 2 : savedFields.length]; + System.arraycopy(savedFields, 0, newArray, 0, savedFieldsCount); + iSavedFields = savedFields = newArray; + iSavedFieldsShared = false; + } + + iSavedState = null; + savedFields[savedFieldsCount] = field; + iSavedFieldsCount = savedFieldsCount + 1; + } + + /** + * Saves the state of this bucket, returning it in an opaque object. Call + * restoreState to undo any changes that were made since the state was + * saved. Calls to saveState may be nested. + * + * @return opaque saved state, which may be passed to restoreState + */ + public Object saveState() { + if (iSavedState == null) { + iSavedState = new SavedState(); + } + return iSavedState; + } + + /** + * Restores the state of this bucket from a previously saved state. The + * state object passed into this method is not consumed, and it can be used + * later to restore to that state again. + * + * @param savedState opaque saved state, returned from saveState + * @return true state object is valid and state restored + */ + public boolean restoreState(Object savedState) { + if (savedState instanceof SavedState) { + if (((SavedState) savedState).restoreState(this)) { + iSavedState = savedState; + return true; + } + } + return false; + } + + /** + * Computes the parsed datetime by setting the saved fields. + * This method is idempotent, but it is not thread-safe. + * + * @return milliseconds since 1970-01-01T00:00:00Z + * @throws IllegalArgumentException if any field is out of range + */ + public long computeMillis() { + return computeMillis(false, null); + } + + /** + * Computes the parsed datetime by setting the saved fields. + * This method is idempotent, but it is not thread-safe. + * + * @param resetFields false by default, but when true, unsaved field values are cleared + * @return milliseconds since 1970-01-01T00:00:00Z + * @throws IllegalArgumentException if any field is out of range + */ + public long computeMillis(boolean resetFields) { + return computeMillis(resetFields, null); + } + + /** + * Computes the parsed datetime by setting the saved fields. + * This method is idempotent, but it is not thread-safe. + * + * @param resetFields false by default, but when true, unsaved field values are cleared + * @param text optional text being parsed, to be included in any error message + * @return milliseconds since 1970-01-01T00:00:00Z + * @throws IllegalArgumentException if any field is out of range + * @since 1.3 + */ + public long computeMillis(boolean resetFields, String text) { + SavedField[] savedFields = iSavedFields; + int count = iSavedFieldsCount; + if (iSavedFieldsShared) { + iSavedFields = savedFields = (SavedField[])iSavedFields.clone(); + iSavedFieldsShared = false; + } + sort(savedFields, count); + if (count > 0) { + // alter base year for parsing if first field is month or day + DurationField months = DurationFieldType.months().getField(iChrono); + DurationField days = DurationFieldType.days().getField(iChrono); + DurationField first = savedFields[0].iField.getDurationField(); + if (compareReverse(first, months) >= 0 && compareReverse(first, days) <= 0) { + saveField(DateTimeFieldType.year(), iDefaultYear); + return computeMillis(resetFields, text); + } + } + + long millis = iMillis; + try { + for (int i = 0; i < count; i++) { + millis = savedFields[i].set(millis, resetFields); + } + if (resetFields) { + for (int i = 0; i < count; i++) { + millis = savedFields[i].set(millis, i == (count - 1)); + } + } + } catch (IllegalFieldValueException e) { + if (text != null) { + e.prependMessage("Cannot parse \"" + text + '"'); + } + throw e; + } + + if (iOffset != null) { + millis -= iOffset; + } else if (iZone != null) { + int offset = iZone.getOffsetFromLocal(millis); + millis -= offset; + if (offset != iZone.getOffset(millis)) { + String message = + "Illegal instant due to time zone offset transition (" + iZone + ')'; + if (text != null) { + message = "Cannot parse \"" + text + "\": " + message; + } + throw new IllegalArgumentException(message); + } + } + + return millis; + } + + /** + * Sorts elements [0,high). Calling java.util.Arrays isn't always the right + * choice since it always creates an internal copy of the array, even if it + * doesn't need to. If the array slice is small enough, an insertion sort + * is chosen instead, but it doesn't need a copy! + *

            + * This method has a modified version of that insertion sort, except it + * doesn't create an unnecessary array copy. If high is over 10, then + * java.util.Arrays is called, which will perform a merge sort, which is + * faster than insertion sort on large lists. + *

            + * The end result is much greater performance when computeMillis is called. + * Since the amount of saved fields is small, the insertion sort is a + * better choice. Additional performance is gained since there is no extra + * array allocation and copying. Also, the insertion sort here does not + * perform any casting operations. The version in java.util.Arrays performs + * casts within the insertion sort loop. + */ + private static void sort(SavedField[] array, int high) { + if (high > 10) { + Arrays.sort(array, 0, high); + } else { + for (int i=0; i0 && (array[j-1]).compareTo(array[j])>0; j--) { + SavedField t = array[j]; + array[j] = array[j-1]; + array[j-1] = t; + } + } + } + } + + class SavedState { + final DateTimeZone iZone; + final Integer iOffset; + final SavedField[] iSavedFields; + final int iSavedFieldsCount; + + SavedState() { + this.iZone = DateTimeParserBucket.this.iZone; + this.iOffset = DateTimeParserBucket.this.iOffset; + this.iSavedFields = DateTimeParserBucket.this.iSavedFields; + this.iSavedFieldsCount = DateTimeParserBucket.this.iSavedFieldsCount; + } + + boolean restoreState(DateTimeParserBucket enclosing) { + if (enclosing != DateTimeParserBucket.this) { + return false; + } + enclosing.iZone = this.iZone; + enclosing.iOffset = this.iOffset; + enclosing.iSavedFields = this.iSavedFields; + if (this.iSavedFieldsCount < enclosing.iSavedFieldsCount) { + // Since count is being restored to a lower count, the + // potential exists for new saved fields to destroy data being + // shared by another state. Set this flag such that the array + // of saved fields is cloned prior to modification. + enclosing.iSavedFieldsShared = true; + } + enclosing.iSavedFieldsCount = this.iSavedFieldsCount; + return true; + } + } + + static class SavedField implements Comparable { + final DateTimeField iField; + final int iValue; + final String iText; + final Locale iLocale; + + SavedField(DateTimeField field, int value) { + iField = field; + iValue = value; + iText = null; + iLocale = null; + } + + SavedField(DateTimeField field, String text, Locale locale) { + iField = field; + iValue = 0; + iText = text; + iLocale = locale; + } + + long set(long millis, boolean reset) { + if (iText == null) { + millis = iField.set(millis, iValue); + } else { + millis = iField.set(millis, iText, iLocale); + } + if (reset) { + millis = iField.roundFloor(millis); + } + return millis; + } + + /** + * The field with the longer range duration is ordered first, where + * null is considered infinite. If the ranges match, then the field + * with the longer duration is ordered first. + */ + public int compareTo(SavedField obj) { + DateTimeField other = obj.iField; + int result = compareReverse + (iField.getRangeDurationField(), other.getRangeDurationField()); + if (result != 0) { + return result; + } + return compareReverse + (iField.getDurationField(), other.getDurationField()); + } + } + + static int compareReverse(DurationField a, DurationField b) { + if (a == null || !a.isSupported()) { + if (b == null || !b.isSupported()) { + return 0; + } + return -1; + } + if (b == null || !b.isSupported()) { + return 1; + } + return -a.compareTo(b); + } +} Index: 3rdParty_sources/joda-time/org/joda/time/format/DateTimePrinter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/format/DateTimePrinter.java (.../DateTimePrinter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/format/DateTimePrinter.java (.../DateTimePrinter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,73 +1,38 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.format; import java.io.IOException; import java.io.Writer; +import java.util.Locale; import org.joda.time.Chronology; import org.joda.time.DateTimeZone; -import org.joda.time.ReadableInstant; import org.joda.time.ReadablePartial; /** - * Defines an interface for creating textual representations of datetimes. + * Internal interface for creating textual representations of datetimes. *

            - * Instances of this interface are provided by the various builder classes. + * Application users will rarely use this class directly. Instead, you + * will use one of the factory classes to create a {@link DateTimeFormatter}. *

            - * Note: This interface represents a view onto {@link BaseDateTimeFormatter}. - * All implementations must extend BaseDateTimeFormatter. + * The factory classes are:
            + * - {@link DateTimeFormatterBuilder}
            + * - {@link DateTimeFormat}
            + * - {@link ISODateTimeFormat}
            * * @author Brian S O'Neill * @author Stephen Colebourne @@ -79,143 +44,61 @@ public interface DateTimePrinter { /** - * Prints a ReadableInstant, using the chronology supplied by the instant. - * - * @param buf formatted instant is appended to this buffer - * @param instant instant to format, null means now + * Returns the expected maximum number of characters produced. + * The actual amount should rarely exceed this estimate. + * + * @return the estimated length */ - void printTo(StringBuffer buf, ReadableInstant instant); + int estimatePrintedLength(); - /** - * Prints a ReadableInstant, using the chronology supplied by the instant. - * - * @param out formatted instant is written out - * @param instant instant to format, null means now - */ - void printTo(Writer out, ReadableInstant instant) throws IOException; - //----------------------------------------------------------------------- /** * Prints an instant from milliseconds since 1970-01-01T00:00:00Z, - * using ISO chronology in the default DateTimeZone. - * - * @param buf formatted instant is appended to this buffer - * @param instant millis since 1970-01-01T00:00:00Z - */ - void printTo(StringBuffer buf, long instant); - - /** - * Prints an instant from milliseconds since 1970-01-01T00:00:00Z, - * using ISO chronology in the default DateTimeZone. - * - * @param out formatted instant is written out - * @param instant millis since 1970-01-01T00:00:00Z - */ - void printTo(Writer out, long instant) throws IOException; - - //----------------------------------------------------------------------- - /** - * Prints an instant from milliseconds since 1970-01-01T00:00:00Z, - * using ISO chronology in the given DateTimeZone. - * - * @param buf formatted instant is appended to this buffer - * @param instant millis since 1970-01-01T00:00:00Z - * @param zone the zone to use, null means default - */ - void printTo(StringBuffer buf, long instant, DateTimeZone zone); - - /** - * Prints an instant from milliseconds since 1970-01-01T00:00:00Z, - * using ISO chronology in the given DateTimeZone. - * - * @param out formatted instant is written out - * @param instant millis since 1970-01-01T00:00:00Z - * @param zone the zone to use, null means default - */ - void printTo(Writer out, long instant, DateTimeZone zone) throws IOException; - - //----------------------------------------------------------------------- - /** - * Prints an instant from milliseconds since 1970-01-01T00:00:00Z, * using the given Chronology. * - * @param buf formatted instant is appended to this buffer + * @param buf formatted instant is appended to this buffer, not null * @param instant millis since 1970-01-01T00:00:00Z - * @param chrono the chronology to use, null means ISO default + * @param chrono the chronology to use, not null + * @param displayOffset if a time zone offset is printed, force it to use + * this millisecond value + * @param displayZone the time zone to use, null means local time + * @param locale the locale to use, null means default locale */ - void printTo(StringBuffer buf, long instant, Chronology chrono); + void printTo(StringBuffer buf, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale); /** * Prints an instant from milliseconds since 1970-01-01T00:00:00Z, * using the given Chronology. * * @param out formatted instant is written out * @param instant millis since 1970-01-01T00:00:00Z - * @param chrono the chronology to use, null means ISO default + * @param chrono the chronology to use, not null + * @param displayOffset if a time zone offset is printed, force it to use + * this millisecond value + * @param displayZone the time zone to use, null means local time + * @param locale the locale to use, null means default locale */ - void printTo(Writer out, long instant, Chronology chrono) throws IOException; + void printTo(Writer out, long instant, Chronology chrono, + int displayOffset, DateTimeZone displayZone, Locale locale) throws IOException; //----------------------------------------------------------------------- /** * Prints a ReadablePartial. * - * @param buf formatted partial is appended to this buffer - * @param partial partial to format + * @param buf formatted partial is appended to this buffer, not null + * @param partial partial to format, not null + * @param locale the locale to use, null means default locale */ - void printTo(StringBuffer buf, ReadablePartial partial); + void printTo(StringBuffer buf, ReadablePartial partial, Locale locale); /** * Prints a ReadablePartial. * - * @param out formatted partial is written out - * @param partial partial to format + * @param out formatted partial is written out, not null + * @param partial partial to format, not null + * @param locale the locale to use, null means default locale */ - void printTo(Writer out, ReadablePartial partial) throws IOException; + void printTo(Writer out, ReadablePartial partial, Locale locale) throws IOException; - //----------------------------------------------------------------------- - /** - * Prints a ReadableInstant to a new String, using the chronology of the instant. - * - * @param instant instant to format, null means now - * @return the printed result - */ - String print(ReadableInstant instant); - - /** - * Prints an instant from milliseconds since 1970-01-01T00:00:00Z, - * using ISO chronology in the default zone. - * - * @param instant millis since 1970-01-01T00:00:00Z - * @return the printed result - */ - String print(long instant); - - /** - * Prints an instant from milliseconds since 1970-01-01T00:00:00Z, - * using ISO chronology in the given zone. - * - * @param instant millis since 1970-01-01T00:00:00Z - * @param zone the zone to use, null means default - * @return the printed result - */ - String print(long instant, DateTimeZone zone); - - /** - * Prints an instant from milliseconds since 1970-01-01T00:00:00Z, - * using the given chronology. - * - * @param instant millis since 1970-01-01T00:00:00Z - * @param chrono the chronoogy to use - * @return the printed result - */ - String print(long instant, Chronology chrono); - - /** - * Prints a ReadablePartial to a new String. - * - * @param partial partial to format - * @return the printed result - */ - String print(ReadablePartial partial); - } Index: 3rdParty_sources/joda-time/org/joda/time/format/FormatUtils.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/format/FormatUtils.java (.../FormatUtils.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/format/FormatUtils.java (.../FormatUtils.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.format; @@ -106,8 +68,13 @@ for (; size > 2; size--) { buf.append('0'); } - buf.append((char)(value / 10 + '0')); - buf.append((char)(value % 10 + '0')); + // Calculate value div/mod by 10 without using two expensive + // division operations. (2 ^ 27) / 10 = 13421772. Add one to + // value to correct rounding error. + int d = ((value + 1) * 13421772) >> 27; + buf.append((char) (d + '0')); + // Append remainder by calculating (value - d * 10). + buf.append((char) (value - (d << 3) - (d << 1) + '0')); } else { int digits; if (value < 1000) { @@ -195,8 +162,13 @@ for (; size > 2; size--) { out.write('0'); } - out.write(value / 10 + '0'); - out.write(value % 10 + '0'); + // Calculate value div/mod by 10 without using two expensive + // division operations. (2 ^ 27) / 10 = 13421772. Add one to + // value to correct rounding error. + int d = ((value + 1) * 13421772) >> 27; + out.write(d + '0'); + // Append remainder by calculating (value - d * 10). + out.write(value - (d << 3) - (d << 1) + '0'); } else { int digits; if (value < 1000) { @@ -273,8 +245,13 @@ if (value < 10) { buf.append((char)(value + '0')); } else if (value < 100) { - buf.append((char)(value / 10 + '0')); - buf.append((char)(value % 10 + '0')); + // Calculate value div/mod by 10 without using two expensive + // division operations. (2 ^ 27) / 10 = 13421772. Add one to + // value to correct rounding error. + int d = ((value + 1) * 13421772) >> 27; + buf.append((char) (d + '0')); + // Append remainder by calculating (value - d * 10). + buf.append((char) (value - (d << 3) - (d << 1) + '0')); } else { buf.append(Integer.toString(value)); } @@ -320,8 +297,13 @@ if (value < 10) { out.write(value + '0'); } else if (value < 100) { - out.write(value / 10 + '0'); - out.write(value % 10 + '0'); + // Calculate value div/mod by 10 without using two expensive + // division operations. (2 ^ 27) / 10 = 13421772. Add one to + // value to correct rounding error. + int d = ((value + 1) * 13421772) >> 27; + out.write(d + '0'); + // Append remainder by calculating (value - d * 10). + out.write(value - (d << 3) - (d << 1) + '0'); } else { out.write(Integer.toString(value)); } @@ -372,7 +354,7 @@ } static String createErrorMessage(final String text, final int errorPos) { - int sampleLen = errorPos + 20; + int sampleLen = errorPos + 32; String sampleText; if (text.length() <= sampleLen + 3) { sampleText = text; Index: 3rdParty_sources/joda-time/org/joda/time/format/ISODateTimeFormat.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/format/ISODateTimeFormat.java (.../ISODateTimeFormat.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/format/ISODateTimeFormat.java (.../ISODateTimeFormat.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,62 +1,33 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.format; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import org.joda.time.DateTimeFieldType; + /** - * ISODateTimeFormat provides factory methods for the ISO8601 standard. + * Factory that creates instances of DateTimeFormatter for the ISO8601 standard. *

            + * Datetime formatting is performed by the {@link DateTimeFormatter} class. + * Three classes provide factory methods to create formatters, and this is one. + * The others are {@link DateTimeFormat} and {@link DateTimeFormatterBuilder}. + *

            * ISO8601 is the international standard for data interchange. It defines a * framework, rather than an absolute standard. As a result this provider has a * number of methods that represent common uses of the framework. The most common @@ -65,10 +36,18 @@ * For example, to format a date time in ISO format: *

              * DateTime dt = new DateTime();
            - * DateTimeFormatter fmt = DateTimeFormat.getInstance().dateTime();
            + * DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
              * String str = fmt.print(dt);
              * 
            *

            + * It is important to understand that these formatters are not linked to + * the ISOChronology. These formatters may be used with any + * chronology, however there may be certain side effects with more unusual + * chronologies. For example, the ISO formatters rely on dayOfWeek being + * single digit, dayOfMonth being two digit and dayOfYear being three digit. + * A chronology with a ten day week would thus cause issues. However, in + * general, it is safe to use these formatters with other chronologies. + *

            * ISODateTimeFormat is thread-safe and immutable, and the formatters it * returns are as well. * @@ -79,20 +58,8 @@ */ public class ISODateTimeFormat { - /** The singleton instance. */ - private static final ISODateTimeFormat INSTANCE = new ISODateTimeFormat(); - - /** - * Gets an instance of a the format provider. - * - * @return a format provider - */ - public static ISODateTimeFormat getInstance() { - return INSTANCE; - } - //----------------------------------------------------------------------- - private transient DateTimeFormatter + private static DateTimeFormatter ye, // year element (yyyy) mye, // monthOfYear element (-MM) dme, // dayOfMonth element (-dd) @@ -103,7 +70,6 @@ hde, // hourOfDay element (HH) mhe, // minuteOfHour element (:mm) sme, // secondOfMinute element (:ss) - lse, // millisOfSecond element (.SSS) fse, // fractionOfSecond element (.SSSSSSSSS) ze, // zone offset element lte, // literal 'T' element @@ -140,6 +106,10 @@ wdt, // week date time wdtx, // week date time no millis + od, // ordinal date (same as yd) + odt, // ordinal date time + odtx, // ordinal date time no millis + bd, // basic date bt, // basic time btx, // basic time no millis @@ -148,29 +118,444 @@ bdt, // basic date time bdtx, // basic date time no millis + bod, // basic ordinal date + bodt, // basic ordinal date time + bodtx, // basic ordinal date time no millis + bwd, // basic week date bwdt, // basic week date time - bwdtx; // basic week date time no millis + bwdtx, // basic week date time no millis - private transient DateTimeParser dpe, // date parser element tpe, // time parser element dp, // date parser + ldp, // local date parser tp, // time parser - dtp; // date time parser + ltp, // local time parser + dtp, // date time parser + dotp, // date optional time parser + ldotp; // local date optional time parser /** - * Restricted constructor. + * Constructor. + * + * @since 1.1 (previously private) + */ + protected ISODateTimeFormat() { + super(); + } + + //----------------------------------------------------------------------- + /** + * Returns a formatter that outputs only those fields specified. + *

            + * This method examines the fields provided and returns an ISO-style + * formatter that best fits. This can be useful for outputting + * less-common ISO styles, such as YearMonth (YYYY-MM) or MonthDay (--MM-DD). + *

            + * The list provided may have overlapping fields, such as dayOfWeek and + * dayOfMonth. In this case, the style is chosen based on the following + * list, thus in the example, the calendar style is chosen as dayOfMonth + * is higher in priority than dayOfWeek: + *

              + *
            • monthOfYear - calendar date style + *
            • dayOfYear - ordinal date style + *
            • weekOfWeekYear - week date style + *
            • dayOfMonth - calendar date style + *
            • dayOfWeek - week date style + *
            • year + *
            • weekyear + *
            + * The supported formats are: + *
            +     * Extended      Basic       Fields
            +     * 2005-03-25    20050325    year/monthOfYear/dayOfMonth
            +     * 2005-03       2005-03     year/monthOfYear
            +     * 2005--25      2005--25    year/dayOfMonth *
            +     * 2005          2005        year
            +     * --03-25       --0325      monthOfYear/dayOfMonth
            +     * --03          --03        monthOfYear
            +     * ---03         ---03       dayOfMonth
            +     * 2005-084      2005084     year/dayOfYear
            +     * -084          -084        dayOfYear
            +     * 2005-W12-5    2005W125    weekyear/weekOfWeekyear/dayOfWeek
            +     * 2005-W-5      2005W-5     weekyear/dayOfWeek *
            +     * 2005-W12      2005W12     weekyear/weekOfWeekyear
            +     * -W12-5        -W125       weekOfWeekyear/dayOfWeek
            +     * -W12          -W12        weekOfWeekyear
            +     * -W-5          -W-5        dayOfWeek
            +     * 10:20:30.040  102030.040  hour/minute/second/milli
            +     * 10:20:30      102030      hour/minute/second
            +     * 10:20         1020        hour/minute
            +     * 10            10          hour
            +     * -20:30.040    -2030.040   minute/second/milli
            +     * -20:30        -2030       minute/second
            +     * -20           -20         minute
            +     * --30.040      --30.040    second/milli
            +     * --30          --30        second
            +     * ---.040       ---.040     milli *
            +     * 10-30.040     10-30.040   hour/second/milli *
            +     * 10:20-.040    1020-.040   hour/minute/milli *
            +     * 10-30         10-30       hour/second *
            +     * 10--.040      10--.040    hour/milli *
            +     * -20-.040      -20-.040    minute/milli *
            +     *   plus datetime formats like {date}T{time}
            +     * 
            + * * indiates that this is not an official ISO format and can be excluded + * by passing in strictISO as true. + *

            + * This method can side effect the input collection of fields. + * If the input collection is modifiable, then each field that was added to + * the formatter will be removed from the collection, including any duplicates. + * If the input collection is unmodifiable then no side effect occurs. + *

            + * This side effect processing is useful if you need to know whether all + * the fields were converted into the formatter or not. To achieve this, + * pass in a modifiable list, and check that it is empty on exit. + * + * @param fields the fields to get a formatter for, not null, + * updated by the method call unless unmodifiable, + * removing those fields built in the formatter + * @param extended true to use the extended format (with separators) + * @param strictISO true to stick exactly to ISO8601, false to include additional formats + * @return a suitable formatter + * @throws IllegalArgumentException if there is no format for the fields + * @since 1.1 + */ + public static DateTimeFormatter forFields( + Collection fields, + boolean extended, + boolean strictISO) { + + if (fields == null || fields.size() == 0) { + throw new IllegalArgumentException("The fields must not be null or empty"); + } + Set workingFields = new HashSet(fields); + int inputSize = workingFields.size(); + boolean reducedPrec = false; + DateTimeFormatterBuilder bld = new DateTimeFormatterBuilder(); + // date + if (workingFields.contains(DateTimeFieldType.monthOfYear())) { + reducedPrec = dateByMonth(bld, workingFields, extended, strictISO); + } else if (workingFields.contains(DateTimeFieldType.dayOfYear())) { + reducedPrec = dateByOrdinal(bld, workingFields, extended, strictISO); + } else if (workingFields.contains(DateTimeFieldType.weekOfWeekyear())) { + reducedPrec = dateByWeek(bld, workingFields, extended, strictISO); + } else if (workingFields.contains(DateTimeFieldType.dayOfMonth())) { + reducedPrec = dateByMonth(bld, workingFields, extended, strictISO); + } else if (workingFields.contains(DateTimeFieldType.dayOfWeek())) { + reducedPrec = dateByWeek(bld, workingFields, extended, strictISO); + } else if (workingFields.remove(DateTimeFieldType.year())) { + bld.append(yearElement()); + reducedPrec = true; + } else if (workingFields.remove(DateTimeFieldType.weekyear())) { + bld.append(weekyearElement()); + reducedPrec = true; + } + boolean datePresent = (workingFields.size() < inputSize); + + // time + time(bld, workingFields, extended, strictISO, reducedPrec, datePresent); + + // result + if (bld.canBuildFormatter() == false) { + throw new IllegalArgumentException("No valid format for fields: " + fields); + } + + // side effect the input collection to indicate the processed fields + // handling unmodifiable collections with no side effect + try { + fields.retainAll(workingFields); + } catch (UnsupportedOperationException ex) { + // ignore, so we can handle unmodifiable collections + } + return bld.toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Creates a date using the calendar date format. + * Specification reference: 5.2.1. + * + * @param bld the builder + * @param fields the fields + * @param extended true to use extended format + * @param strictISO true to only allow ISO formats + * @return true if reduced precision + * @since 1.1 + */ + private static boolean dateByMonth( + DateTimeFormatterBuilder bld, + Collection fields, + boolean extended, + boolean strictISO) { + + boolean reducedPrec = false; + if (fields.remove(DateTimeFieldType.year())) { + bld.append(yearElement()); + if (fields.remove(DateTimeFieldType.monthOfYear())) { + if (fields.remove(DateTimeFieldType.dayOfMonth())) { + // YYYY-MM-DD/YYYYMMDD + appendSeparator(bld, extended); + bld.appendMonthOfYear(2); + appendSeparator(bld, extended); + bld.appendDayOfMonth(2); + } else { + // YYYY-MM/YYYY-MM + bld.appendLiteral('-'); + bld.appendMonthOfYear(2); + reducedPrec = true; + } + } else { + if (fields.remove(DateTimeFieldType.dayOfMonth())) { + // YYYY--DD/YYYY--DD (non-iso) + checkNotStrictISO(fields, strictISO); + bld.appendLiteral('-'); + bld.appendLiteral('-'); + bld.appendDayOfMonth(2); + } else { + // YYYY/YYYY + reducedPrec = true; + } + } + + } else if (fields.remove(DateTimeFieldType.monthOfYear())) { + bld.appendLiteral('-'); + bld.appendLiteral('-'); + bld.appendMonthOfYear(2); + if (fields.remove(DateTimeFieldType.dayOfMonth())) { + // --MM-DD/--MMDD + appendSeparator(bld, extended); + bld.appendDayOfMonth(2); + } else { + // --MM/--MM + reducedPrec = true; + } + } else if (fields.remove(DateTimeFieldType.dayOfMonth())) { + // ---DD/---DD + bld.appendLiteral('-'); + bld.appendLiteral('-'); + bld.appendLiteral('-'); + bld.appendDayOfMonth(2); + } + return reducedPrec; + } + + //----------------------------------------------------------------------- + /** + * Creates a date using the ordinal date format. + * Specification reference: 5.2.2. + * + * @param bld the builder + * @param fields the fields + * @param extended true to use extended format + * @param strictISO true to only allow ISO formats + * @since 1.1 + */ + private static boolean dateByOrdinal( + DateTimeFormatterBuilder bld, + Collection fields, + boolean extended, + boolean strictISO) { + + boolean reducedPrec = false; + if (fields.remove(DateTimeFieldType.year())) { + bld.append(yearElement()); + if (fields.remove(DateTimeFieldType.dayOfYear())) { + // YYYY-DDD/YYYYDDD + appendSeparator(bld, extended); + bld.appendDayOfYear(3); + } else { + // YYYY/YYYY + reducedPrec = true; + } + + } else if (fields.remove(DateTimeFieldType.dayOfYear())) { + // -DDD/-DDD + bld.appendLiteral('-'); + bld.appendDayOfYear(3); + } + return reducedPrec; + } + + //----------------------------------------------------------------------- + /** + * Creates a date using the calendar date format. + * Specification reference: 5.2.3. + * + * @param bld the builder + * @param fields the fields + * @param extended true to use extended format + * @param strictISO true to only allow ISO formats + * @since 1.1 + */ + private static boolean dateByWeek( + DateTimeFormatterBuilder bld, + Collection fields, + boolean extended, + boolean strictISO) { + + boolean reducedPrec = false; + if (fields.remove(DateTimeFieldType.weekyear())) { + bld.append(weekyearElement()); + if (fields.remove(DateTimeFieldType.weekOfWeekyear())) { + appendSeparator(bld, extended); + bld.appendLiteral('W'); + bld.appendWeekOfWeekyear(2); + if (fields.remove(DateTimeFieldType.dayOfWeek())) { + // YYYY-WWW-D/YYYYWWWD + appendSeparator(bld, extended); + bld.appendDayOfWeek(1); + } else { + // YYYY-WWW/YYYY-WWW + reducedPrec = true; + } + } else { + if (fields.remove(DateTimeFieldType.dayOfWeek())) { + // YYYY-W-D/YYYYW-D (non-iso) + checkNotStrictISO(fields, strictISO); + appendSeparator(bld, extended); + bld.appendLiteral('W'); + bld.appendLiteral('-'); + bld.appendDayOfWeek(1); + } else { + // YYYY/YYYY + reducedPrec = true; + } + } + + } else if (fields.remove(DateTimeFieldType.weekOfWeekyear())) { + bld.appendLiteral('-'); + bld.appendLiteral('W'); + bld.appendWeekOfWeekyear(2); + if (fields.remove(DateTimeFieldType.dayOfWeek())) { + // -WWW-D/-WWWD + appendSeparator(bld, extended); + bld.appendDayOfWeek(1); + } else { + // -WWW/-WWW + reducedPrec = true; + } + } else if (fields.remove(DateTimeFieldType.dayOfWeek())) { + // -W-D/-W-D + bld.appendLiteral('-'); + bld.appendLiteral('W'); + bld.appendLiteral('-'); + bld.appendDayOfWeek(1); + } + return reducedPrec; + } + + //----------------------------------------------------------------------- + /** + * Adds the time fields to the builder. + * Specification reference: 5.3.1. * - * @param chrono the chronology to use, must not be null + * @param bld the builder + * @param fields the fields + * @param extended whether to use the extended format + * @param strictISO whether to be strict + * @param reducedPrec whether the date was reduced precision + * @param datePresent whether there was a date + * @since 1.1 */ - private ISODateTimeFormat() { + private static void time( + DateTimeFormatterBuilder bld, + Collection fields, + boolean extended, + boolean strictISO, + boolean reducedPrec, + boolean datePresent) { + + boolean hour = fields.remove(DateTimeFieldType.hourOfDay()); + boolean minute = fields.remove(DateTimeFieldType.minuteOfHour()); + boolean second = fields.remove(DateTimeFieldType.secondOfMinute()); + boolean milli = fields.remove(DateTimeFieldType.millisOfSecond()); + if (!hour && !minute && !second && !milli) { + return; + } + if (hour || minute || second || milli) { + if (strictISO && reducedPrec) { + throw new IllegalArgumentException("No valid ISO8601 format for fields because Date was reduced precision: " + fields); + } + if (datePresent) { + bld.appendLiteral('T'); + } + } + if (hour && minute && second || (hour && !second && !milli)) { + // OK - HMSm/HMS/HM/H - valid in combination with date + } else { + if (strictISO && datePresent) { + throw new IllegalArgumentException("No valid ISO8601 format for fields because Time was truncated: " + fields); + } + if (!hour && (minute && second || (minute && !milli) || second)) { + // OK - MSm/MS/M/Sm/S - valid ISO formats + } else { + if (strictISO) { + throw new IllegalArgumentException("No valid ISO8601 format for fields: " + fields); + } + } + } + if (hour) { + bld.appendHourOfDay(2); + } else if (minute || second || milli) { + bld.appendLiteral('-'); + } + if (extended && hour && minute) { + bld.appendLiteral(':'); + } + if (minute) { + bld.appendMinuteOfHour(2); + } else if (second || milli) { + bld.appendLiteral('-'); + } + if (extended && minute && second) { + bld.appendLiteral(':'); + } + if (second) { + bld.appendSecondOfMinute(2); + } else if (milli) { + bld.appendLiteral('-'); + } + if (milli) { + bld.appendLiteral('.'); + bld.appendMillisOfSecond(3); + } } //----------------------------------------------------------------------- /** - * Returns a generic ISO date parser. It accepts formats described by - * the following syntax: + * Checks that the iso only flag is not set, throwing an exception if it is. + * + * @param fields the fields + * @param strictISO true if only ISO formats allowed + * @since 1.1 + */ + private static void checkNotStrictISO(Collection fields, boolean strictISO) { + if (strictISO) { + throw new IllegalArgumentException("No valid ISO8601 format for fields: " + fields); + } + } + + /** + * Appends the separator if necessary. + * + * @param bld the builder + * @param extended whether to append the separator + * @param sep the separator + * @since 1.1 + */ + private static void appendSeparator(DateTimeFormatterBuilder bld, boolean extended) { + if (extended) { + bld.appendLiteral('-'); + } + } + + //----------------------------------------------------------------------- + /** + * Returns a generic ISO date parser for parsing dates with a possible zone. + *

            + * It accepts formats described by the following syntax: *

                  * date              = date-element ['T' offset]
                  * date-element      = std-date-element | ord-date-element | week-date-element
            @@ -180,31 +565,51 @@
                  * offset            = 'Z' | (('+' | '-') HH [':' mm [':' ss [('.' | ',') SSS]]])
                  * 
            */ - public DateTimeParser dateParser() { + public static DateTimeFormatter dateParser() { if (dp == null) { + DateTimeParser tOffset = new DateTimeFormatterBuilder() + .appendLiteral('T') + .append(offsetElement()).toParser(); dp = new DateTimeFormatterBuilder() .append(dateElementParser()) - .appendOptional - (new DateTimeFormatterBuilder() - .appendLiteral('T') - .append(offsetElement()) - .toParser()) - .toParser(); + .appendOptional(tOffset) + .toFormatter(); } return dp; } /** - * Returns a generic ISO date parser. It accepts formats described by - * the following syntax: + * Returns a generic ISO date parser for parsing local dates. + * This parser is initialised with the local (UTC) time zone. + *

            + * It accepts formats described by the following syntax: *

                  * date-element      = std-date-element | ord-date-element | week-date-element
                  * std-date-element  = yyyy ['-' MM ['-' dd]]
                  * ord-date-element  = yyyy ['-' DDD]
                  * week-date-element = xxxx '-W' ww ['-' e]
                  * 
            + * @since 1.3 */ - public DateTimeParser dateElementParser() { + public static DateTimeFormatter localDateParser() { + if (ldp == null) { + ldp = dateElementParser().withZoneUTC(); + } + return ldp; + } + + /** + * Returns a generic ISO date parser for parsing dates. + *

            + * It accepts formats described by the following syntax: + *

            +     * date-element      = std-date-element | ord-date-element | week-date-element
            +     * std-date-element  = yyyy ['-' MM ['-' dd]]
            +     * ord-date-element  = yyyy ['-' DDD]
            +     * week-date-element = xxxx '-W' ww ['-' e]
            +     * 
            + */ + public static DateTimeFormatter dateElementParser() { if (dpe == null) { dpe = new DateTimeFormatterBuilder() .append(null, new DateTimeParser[] { @@ -213,27 +618,29 @@ .appendOptional (new DateTimeFormatterBuilder() .append(monthElement()) - .appendOptional(dayOfMonthElement()) + .appendOptional(dayOfMonthElement().getParser()) .toParser()) .toParser(), new DateTimeFormatterBuilder() .append(weekyearElement()) .append(weekElement()) - .appendOptional(dayOfWeekElement()) + .appendOptional(dayOfWeekElement().getParser()) .toParser(), new DateTimeFormatterBuilder() .append(yearElement()) .append(dayOfYearElement()) .toParser() }) - .toParser(); + .toFormatter(); } return dpe; } /** - * Returns a generic ISO time parser. It accepts formats described by - * the following syntax: + * Returns a generic ISO time parser for parsing times with a possible zone. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. + *

            + * It accepts formats described by the following syntax: *

                  * time           = ['T'] time-element [offset]
                  * time-element   = HH [minute-element] | [fraction]
            @@ -243,31 +650,55 @@
                  * offset         = 'Z' | (('+' | '-') HH [':' mm [':' ss [('.' | ',') SSS]]])
                  * 
            */ - public DateTimeParser timeParser() { + public static DateTimeFormatter timeParser() { if (tp == null) { tp = new DateTimeFormatterBuilder() - .appendOptional - (new DateTimeFormatterBuilder() - .appendLiteral('T') - .toParser()) + .appendOptional(literalTElement().getParser()) .append(timeElementParser()) - .appendOptional(offsetElement()) - .toParser(); + .appendOptional(offsetElement().getParser()) + .toFormatter(); } return tp; } /** - * Returns a generic ISO time parser. It accepts formats described by - * the following syntax: + * Returns a generic ISO time parser for parsing local times. + * This parser is initialised with the local (UTC) time zone. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. + *

            + * It accepts formats described by the following syntax: *

            +     * time           = ['T'] time-element
                  * time-element   = HH [minute-element] | [fraction]
                  * minute-element = ':' mm [second-element] | [fraction]
                  * second-element = ':' ss [fraction]
                  * fraction       = ('.' | ',') digit+
                  * 
            + * @since 1.3 */ - public DateTimeParser timeElementParser() { + public static DateTimeFormatter localTimeParser() { + if (ltp == null) { + ltp = new DateTimeFormatterBuilder() + .appendOptional(literalTElement().getParser()) + .append(timeElementParser()) + .toFormatter().withZoneUTC(); + } + return ltp; + } + + /** + * Returns a generic ISO time parser. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. + *

            + * It accepts formats described by the following syntax: + *

            +     * time-element   = HH [minute-element] | [fraction]
            +     * minute-element = ':' mm [second-element] | [fraction]
            +     * second-element = ':' ss [fraction]
            +     * fraction       = ('.' | ',') digit+
            +     * 
            + */ + public static DateTimeFormatter timeElementParser() { if (tpe == null) { // Decimal point can be either '.' or ',' DateTimeParser decimalPoint = new DateTimeFormatterBuilder() @@ -315,17 +746,20 @@ .toParser(), null }) - .toParser(); + .toFormatter(); } return tpe; } /** - * Returns a generic ISO datetime parser. It accepts formats described by - * the following syntax: + * Returns a generic ISO datetime parser which parses either a date or + * a time or both. The parser is strict by default, thus time string {@code 24:00} cannot be parsed. + *

            + * It accepts formats described by the following syntax: *

            -     * datetime          = time | (date-element [time | ('T' offset)])
            +     * datetime          = time | date-opt-time
                  * time              = 'T' time-element [offset]
            +     * date-opt-time     = date-element ['T' [time-element] [offset]]
                  * date-element      = std-date-element | ord-date-element | week-date-element
                  * std-date-element  = yyyy ['-' MM ['-' dd]]
                  * ord-date-element  = yyyy ['-' DDD]
            @@ -337,59 +771,114 @@
                  * offset            = 'Z' | (('+' | '-') HH [':' mm [':' ss [('.' | ',') SSS]]])
                  * 
            */ - public DateTimeParser dateTimeParser() { + public static DateTimeFormatter dateTimeParser() { if (dtp == null) { // This is different from the general time parser in that the 'T' // is required. DateTimeParser time = new DateTimeFormatterBuilder() .appendLiteral('T') .append(timeElementParser()) - .appendOptional(offsetElement()) + .appendOptional(offsetElement().getParser()) .toParser(); - dtp = new DateTimeFormatterBuilder() - .append(null, new DateTimeParser[] { - time, - new DateTimeFormatterBuilder() - .append(dateElementParser()) - .append(null, new DateTimeParser[] { - time, - new DateTimeFormatterBuilder() - .appendLiteral('T') - .append(offsetElement()) - .toParser(), - null - }) - .toParser() - }) - .toParser(); + .append(null, new DateTimeParser[] {time, dateOptionalTimeParser().getParser()}) + .toFormatter(); } return dtp; } + /** + * Returns a generic ISO datetime parser where the date is mandatory and + * the time is optional. This parser can parse zoned datetimes. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. + *

            + * It accepts formats described by the following syntax: + *

            +     * date-opt-time     = date-element ['T' [time-element] [offset]]
            +     * date-element      = std-date-element | ord-date-element | week-date-element
            +     * std-date-element  = yyyy ['-' MM ['-' dd]]
            +     * ord-date-element  = yyyy ['-' DDD]
            +     * week-date-element = xxxx '-W' ww ['-' e]
            +     * time-element      = HH [minute-element] | [fraction]
            +     * minute-element    = ':' mm [second-element] | [fraction]
            +     * second-element    = ':' ss [fraction]
            +     * fraction          = ('.' | ',') digit+
            +     * 
            + * @since 1.3 + */ + public static DateTimeFormatter dateOptionalTimeParser() { + if (dotp == null) { + DateTimeParser timeOrOffset = new DateTimeFormatterBuilder() + .appendLiteral('T') + .appendOptional(timeElementParser().getParser()) + .appendOptional(offsetElement().getParser()) + .toParser(); + dotp = new DateTimeFormatterBuilder() + .append(dateElementParser()) + .appendOptional(timeOrOffset) + .toFormatter(); + } + return dotp; + } + + /** + * Returns a generic ISO datetime parser where the date is mandatory and + * the time is optional. This parser only parses local datetimes. + * This parser is initialised with the local (UTC) time zone. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. + *

            + * It accepts formats described by the following syntax: + *

            +     * datetime          = date-element ['T' time-element]
            +     * date-element      = std-date-element | ord-date-element | week-date-element
            +     * std-date-element  = yyyy ['-' MM ['-' dd]]
            +     * ord-date-element  = yyyy ['-' DDD]
            +     * week-date-element = xxxx '-W' ww ['-' e]
            +     * time-element      = HH [minute-element] | [fraction]
            +     * minute-element    = ':' mm [second-element] | [fraction]
            +     * second-element    = ':' ss [fraction]
            +     * fraction          = ('.' | ',') digit+
            +     * 
            + * @since 1.3 + */ + public static DateTimeFormatter localDateOptionalTimeParser() { + if (ldotp == null) { + DateTimeParser time = new DateTimeFormatterBuilder() + .appendLiteral('T') + .append(timeElementParser()) + .toParser(); + ldotp = new DateTimeFormatterBuilder() + .append(dateElementParser()) + .appendOptional(time) + .toFormatter().withZoneUTC(); + } + return ldotp; + } + //----------------------------------------------------------------------- /** * Returns a formatter for a full date as four digit year, two digit month * of year, and two digit day of month (yyyy-MM-dd). * * @return a formatter for yyyy-MM-dd */ - public DateTimeFormatter date() { + public static DateTimeFormatter date() { return yearMonthDay(); } /** * Returns a formatter for a two digit hour of day, two digit minute of * hour, two digit second of minute, three digit fraction of second, and - * time zone offset (HH:mm:ss.SSSZ). + * time zone offset (HH:mm:ss.SSSZZ). * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * - * @return a formatter for HH:mm:ss.SSSZ + * @return a formatter for HH:mm:ss.SSSZZ */ - public DateTimeFormatter time() { + public static DateTimeFormatter time() { if (t == null) { t = new DateTimeFormatterBuilder() - .append(hourMinuteSecondMillis()) + .append(hourMinuteSecondFraction()) .append(offsetElement()) .toFormatter(); } @@ -398,12 +887,13 @@ /** * Returns a formatter for a two digit hour of day, two digit minute of - * hour, two digit second of minute, and time zone offset (HH:mm:ssZ). + * hour, two digit second of minute, and time zone offset (HH:mm:ssZZ). * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * - * @return a formatter for HH:mm:ssZ + * @return a formatter for HH:mm:ssZZ */ - public DateTimeFormatter timeNoMillis() { + public static DateTimeFormatter timeNoMillis() { if (tx == null) { tx = new DateTimeFormatterBuilder() .append(hourMinuteSecond()) @@ -416,12 +906,13 @@ /** * Returns a formatter for a two digit hour of day, two digit minute of * hour, two digit second of minute, three digit fraction of second, and - * time zone offset prefixed by 'T' ('T'HH:mm:ss.SSSZ). + * time zone offset prefixed by 'T' ('T'HH:mm:ss.SSSZZ). * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * - * @return a formatter for 'T'HH:mm:ss.SSSZ + * @return a formatter for 'T'HH:mm:ss.SSSZZ */ - public DateTimeFormatter tTime() { + public static DateTimeFormatter tTime() { if (tt == null) { tt = new DateTimeFormatterBuilder() .append(literalTElement()) @@ -434,12 +925,13 @@ /** * Returns a formatter for a two digit hour of day, two digit minute of * hour, two digit second of minute, and time zone offset prefixed - * by 'T' ('T'HH:mm:ssZ). + * by 'T' ('T'HH:mm:ssZZ). * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * - * @return a formatter for 'T'HH:mm:ssZ + * @return a formatter for 'T'HH:mm:ssZZ */ - public DateTimeFormatter tTimeNoMillis() { + public static DateTimeFormatter tTimeNoMillis() { if (ttx == null) { ttx = new DateTimeFormatterBuilder() .append(literalTElement()) @@ -451,12 +943,13 @@ /** * Returns a formatter that combines a full date and time, separated by a 'T' - * (yyyy-MM-dd'T'HH:mm:ss.SSSZ). + * (yyyy-MM-dd'T'HH:mm:ss.SSSZZ). * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * - * @return a formatter for yyyy-MM-dd'T'HH:mm:ss.SSSZ + * @return a formatter for yyyy-MM-dd'T'HH:mm:ss.SSSZZ */ - public DateTimeFormatter dateTime() { + public static DateTimeFormatter dateTime() { if (dt == null) { dt = new DateTimeFormatterBuilder() .append(date()) @@ -468,12 +961,13 @@ /** * Returns a formatter that combines a full date and time without millis, - * separated by a 'T' (yyyy-MM-dd'T'HH:mm:ssZ). + * separated by a 'T' (yyyy-MM-dd'T'HH:mm:ssZZ). * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * - * @return a formatter for yyyy-MM-dd'T'HH:mm:ssZ + * @return a formatter for yyyy-MM-dd'T'HH:mm:ssZZ */ - public DateTimeFormatter dateTimeNoMillis() { + public static DateTimeFormatter dateTimeNoMillis() { if (dtx == null) { dtx = new DateTimeFormatterBuilder() .append(date()) @@ -484,23 +978,79 @@ } /** + * Returns a formatter for a full ordinal date, using a four + * digit year and three digit dayOfYear (yyyy-DDD). + * + * @return a formatter for yyyy-DDD + * @since 1.1 + */ + public static DateTimeFormatter ordinalDate() { + if (od == null) { + od = new DateTimeFormatterBuilder() + .append(yearElement()) + .append(dayOfYearElement()) + .toFormatter(); + } + return od; + } + + /** + * Returns a formatter for a full ordinal date and time, using a four + * digit year and three digit dayOfYear (yyyy-DDD'T'HH:mm:ss.SSSZZ). + * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. + * + * @return a formatter for yyyy-DDD'T'HH:mm:ss.SSSZZ + * @since 1.1 + */ + public static DateTimeFormatter ordinalDateTime() { + if (odt == null) { + odt = new DateTimeFormatterBuilder() + .append(ordinalDate()) + .append(tTime()) + .toFormatter(); + } + return odt; + } + + /** + * Returns a formatter for a full ordinal date and time without millis, + * using a four digit year and three digit dayOfYear (yyyy-DDD'T'HH:mm:ssZZ). + * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. + * + * @return a formatter for yyyy-DDD'T'HH:mm:ssZZ + * @since 1.1 + */ + public static DateTimeFormatter ordinalDateTimeNoMillis() { + if (odtx == null) { + odtx = new DateTimeFormatterBuilder() + .append(ordinalDate()) + .append(tTimeNoMillis()) + .toFormatter(); + } + return odtx; + } + + /** * Returns a formatter for a full date as four digit weekyear, two digit * week of weekyear, and one digit day of week (xxxx-'W'ww-e). * * @return a formatter for xxxx-'W'ww-e */ - public DateTimeFormatter weekDate() { + public static DateTimeFormatter weekDate() { return weekyearWeekDay(); } /** * Returns a formatter that combines a full weekyear date and time, - * separated by a 'T' (xxxx-'W'ww-e'T'HH:mm:ss.SSSZ). + * separated by a 'T' (xxxx-'W'ww-e'T'HH:mm:ss.SSSZZ). * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * - * @return a formatter for xxxx-'W'ww-e'T'HH:mm:ss.SSSZ + * @return a formatter for xxxx-'W'ww-e'T'HH:mm:ss.SSSZZ */ - public DateTimeFormatter weekDateTime() { + public static DateTimeFormatter weekDateTime() { if (wdt == null) { wdt = new DateTimeFormatterBuilder() .append(weekDate()) @@ -512,12 +1062,13 @@ /** * Returns a formatter that combines a full weekyear date and time without millis, - * separated by a 'T' (xxxx-'W'ww-e'T'HH:mm:ssZ). + * separated by a 'T' (xxxx-'W'ww-e'T'HH:mm:ssZZ). * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * - * @return a formatter for xxxx-'W'ww-e'T'HH:mm:ssZ + * @return a formatter for xxxx-'W'ww-e'T'HH:mm:ssZZ */ - public DateTimeFormatter weekDateTimeNoMillis() { + public static DateTimeFormatter weekDateTimeNoMillis() { if (wdtx == null) { wdtx = new DateTimeFormatterBuilder() .append(weekDate()) @@ -534,12 +1085,12 @@ * * @return a formatter for yyyyMMdd */ - public DateTimeFormatter basicDate() { + public static DateTimeFormatter basicDate() { if (bd == null) { bd = new DateTimeFormatterBuilder() .appendYear(4, 4) - .appendMonthOfYear(2) - .appendDayOfMonth(2) + .appendFixedDecimal(DateTimeFieldType.monthOfYear(), 2) + .appendFixedDecimal(DateTimeFieldType.dayOfMonth(), 2) .toFormatter(); } return bd; @@ -549,18 +1100,19 @@ * Returns a basic formatter for a two digit hour of day, two digit minute * of hour, two digit second of minute, three digit millis, and time zone * offset (HHmmss.SSSZ). - * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * * @return a formatter for HHmmss.SSSZ */ - public DateTimeFormatter basicTime() { + public static DateTimeFormatter basicTime() { if (bt == null) { bt = new DateTimeFormatterBuilder() - .appendHourOfDay(2) - .appendMinuteOfHour(2) - .appendSecondOfMinute(2) + .appendFixedDecimal(DateTimeFieldType.hourOfDay(), 2) + .appendFixedDecimal(DateTimeFieldType.minuteOfHour(), 2) + .appendFixedDecimal(DateTimeFieldType.secondOfMinute(), 2) .appendLiteral('.') - .appendMillisOfSecond(3) + .appendFractionOfSecond(3, 9) .appendTimeZoneOffset("Z", false, 2, 2) .toFormatter(); } @@ -570,16 +1122,17 @@ /** * Returns a basic formatter for a two digit hour of day, two digit minute * of hour, two digit second of minute, and time zone offset (HHmmssZ). - * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * * @return a formatter for HHmmssZ */ - public DateTimeFormatter basicTimeNoMillis() { + public static DateTimeFormatter basicTimeNoMillis() { if (btx == null) { btx = new DateTimeFormatterBuilder() - .appendHourOfDay(2) - .appendMinuteOfHour(2) - .appendSecondOfMinute(2) + .appendFixedDecimal(DateTimeFieldType.hourOfDay(), 2) + .appendFixedDecimal(DateTimeFieldType.minuteOfHour(), 2) + .appendFixedDecimal(DateTimeFieldType.secondOfMinute(), 2) .appendTimeZoneOffset("Z", false, 2, 2) .toFormatter(); } @@ -590,11 +1143,12 @@ * Returns a basic formatter for a two digit hour of day, two digit minute * of hour, two digit second of minute, three digit millis, and time zone * offset prefixed by 'T' ('T'HHmmss.SSSZ). - * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * * @return a formatter for 'T'HHmmss.SSSZ */ - public DateTimeFormatter basicTTime() { + public static DateTimeFormatter basicTTime() { if (btt == null) { btt = new DateTimeFormatterBuilder() .append(literalTElement()) @@ -608,11 +1162,12 @@ * Returns a basic formatter for a two digit hour of day, two digit minute * of hour, two digit second of minute, and time zone offset prefixed by 'T' * ('T'HHmmssZ). - * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * * @return a formatter for 'T'HHmmssZ */ - public DateTimeFormatter basicTTimeNoMillis() { + public static DateTimeFormatter basicTTimeNoMillis() { if (bttx == null) { bttx = new DateTimeFormatterBuilder() .append(literalTElement()) @@ -625,11 +1180,12 @@ /** * Returns a basic formatter that combines a basic date and time, separated * by a 'T' (yyyyMMdd'T'HHmmss.SSSZ). - * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * * @return a formatter for yyyyMMdd'T'HHmmss.SSSZ */ - public DateTimeFormatter basicDateTime() { + public static DateTimeFormatter basicDateTime() { if (bdt == null) { bdt = new DateTimeFormatterBuilder() .append(basicDate()) @@ -642,11 +1198,12 @@ /** * Returns a basic formatter that combines a basic date and time without millis, * separated by a 'T' (yyyyMMdd'T'HHmmssZ). - * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * * @return a formatter for yyyyMMdd'T'HHmmssZ */ - public DateTimeFormatter basicDateTimeNoMillis() { + public static DateTimeFormatter basicDateTimeNoMillis() { if (bdtx == null) { bdtx = new DateTimeFormatterBuilder() .append(basicDate()) @@ -657,18 +1214,73 @@ } /** + * Returns a formatter for a full ordinal date, using a four + * digit year and three digit dayOfYear (yyyyDDD). + * + * @return a formatter for yyyyDDD + * @since 1.1 + */ + public static DateTimeFormatter basicOrdinalDate() { + if (bod == null) { + bod = new DateTimeFormatterBuilder() + .appendYear(4, 4) + .appendFixedDecimal(DateTimeFieldType.dayOfYear(), 3) + .toFormatter(); + } + return bod; + } + + /** + * Returns a formatter for a full ordinal date and time, using a four + * digit year and three digit dayOfYear (yyyyDDD'T'HHmmss.SSSZ). + * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. + * + * @return a formatter for yyyyDDD'T'HHmmss.SSSZ + * @since 1.1 + */ + public static DateTimeFormatter basicOrdinalDateTime() { + if (bodt == null) { + bodt = new DateTimeFormatterBuilder() + .append(basicOrdinalDate()) + .append(basicTTime()) + .toFormatter(); + } + return bodt; + } + + /** + * Returns a formatter for a full ordinal date and time without millis, + * using a four digit year and three digit dayOfYear (yyyyDDD'T'HHmmssZ). + * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. + * + * @return a formatter for yyyyDDD'T'HHmmssZ + * @since 1.1 + */ + public static DateTimeFormatter basicOrdinalDateTimeNoMillis() { + if (bodtx == null) { + bodtx = new DateTimeFormatterBuilder() + .append(basicOrdinalDate()) + .append(basicTTimeNoMillis()) + .toFormatter(); + } + return bodtx; + } + + /** * Returns a basic formatter for a full date as four digit weekyear, two * digit week of weekyear, and one digit day of week (xxxx'W'wwe). * * @return a formatter for xxxx'W'wwe */ - public DateTimeFormatter basicWeekDate() { + public static DateTimeFormatter basicWeekDate() { if (bwd == null) { bwd = new DateTimeFormatterBuilder() .appendWeekyear(4, 4) .appendLiteral('W') - .appendWeekOfWeekyear(2) - .appendDayOfWeek(1) + .appendFixedDecimal(DateTimeFieldType.weekOfWeekyear(), 2) + .appendFixedDecimal(DateTimeFieldType.dayOfWeek(), 1) .toFormatter(); } return bwd; @@ -677,11 +1289,12 @@ /** * Returns a basic formatter that combines a basic weekyear date and time, * separated by a 'T' (xxxx'W'wwe'T'HHmmss.SSSZ). - * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * * @return a formatter for xxxx'W'wwe'T'HHmmss.SSSZ */ - public DateTimeFormatter basicWeekDateTime() { + public static DateTimeFormatter basicWeekDateTime() { if (bwdt == null) { bwdt = new DateTimeFormatterBuilder() .append(basicWeekDate()) @@ -694,11 +1307,12 @@ /** * Returns a basic formatter that combines a basic weekyear date and time * without millis, separated by a 'T' (xxxx'W'wwe'T'HHmmssZ). - * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero. + * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero. + * The parser is strict by default, thus time string {@code 24:00} cannot be parsed. * * @return a formatter for xxxx'W'wwe'T'HHmmssZ */ - public DateTimeFormatter basicWeekDateTimeNoMillis() { + public static DateTimeFormatter basicWeekDateTimeNoMillis() { if (bwdtx == null) { bwdtx = new DateTimeFormatterBuilder() .append(basicWeekDate()) @@ -714,7 +1328,7 @@ * * @return a formatter for yyyy */ - public DateTimeFormatter year() { + public static DateTimeFormatter year() { return yearElement(); } @@ -724,7 +1338,7 @@ * * @return a formatter for yyyy-MM */ - public DateTimeFormatter yearMonth() { + public static DateTimeFormatter yearMonth() { if (ym == null) { ym = new DateTimeFormatterBuilder() .append(yearElement()) @@ -740,7 +1354,7 @@ * * @return a formatter for yyyy-MM-dd */ - public DateTimeFormatter yearMonthDay() { + public static DateTimeFormatter yearMonthDay() { if (ymd == null) { ymd = new DateTimeFormatterBuilder() .append(yearElement()) @@ -756,7 +1370,7 @@ * * @return a formatter for xxxx */ - public DateTimeFormatter weekyear() { + public static DateTimeFormatter weekyear() { return weekyearElement(); } @@ -766,7 +1380,7 @@ * * @return a formatter for xxxx-'W'ww */ - public DateTimeFormatter weekyearWeek() { + public static DateTimeFormatter weekyearWeek() { if (ww == null) { ww = new DateTimeFormatterBuilder() .append(weekyearElement()) @@ -782,7 +1396,7 @@ * * @return a formatter for xxxx-'W'ww-e */ - public DateTimeFormatter weekyearWeekDay() { + public static DateTimeFormatter weekyearWeekDay() { if (wwd == null) { wwd = new DateTimeFormatterBuilder() .append(weekyearElement()) @@ -798,7 +1412,7 @@ * * @return a formatter for HH */ - public DateTimeFormatter hour() { + public static DateTimeFormatter hour() { return hourElement(); } @@ -808,7 +1422,7 @@ * * @return a formatter for HH:mm */ - public DateTimeFormatter hourMinute() { + public static DateTimeFormatter hourMinute() { if (hm == null) { hm = new DateTimeFormatterBuilder() .append(hourElement()) @@ -824,7 +1438,7 @@ * * @return a formatter for HH:mm:ss */ - public DateTimeFormatter hourMinuteSecond() { + public static DateTimeFormatter hourMinuteSecond() { if (hms == null) { hms = new DateTimeFormatterBuilder() .append(hourElement()) @@ -838,17 +1452,19 @@ /** * Returns a formatter for a two digit hour of day, two digit minute of * hour, two digit second of minute, and three digit fraction of - * second. (HH:mm:ss.SSS) + * second (HH:mm:ss.SSS). Parsing will parse up to 3 fractional second + * digits. * * @return a formatter for HH:mm:ss.SSS */ - public DateTimeFormatter hourMinuteSecondMillis() { + public static DateTimeFormatter hourMinuteSecondMillis() { if (hmsl == null) { hmsl = new DateTimeFormatterBuilder() .append(hourElement()) .append(minuteElement()) .append(secondElement()) - .append(millisElement()) + .appendLiteral('.') + .appendFractionOfSecond(3, 3) .toFormatter(); } return hmsl; @@ -857,11 +1473,12 @@ /** * Returns a formatter for a two digit hour of day, two digit minute of * hour, two digit second of minute, and three digit fraction of - * second. (HH:mm:ss.SSS) + * second (HH:mm:ss.SSS). Parsing will parse up to 9 fractional second + * digits, throwing away all except the first three. * * @return a formatter for HH:mm:ss.SSS */ - public DateTimeFormatter hourMinuteSecondFraction() { + public static DateTimeFormatter hourMinuteSecondFraction() { if (hmsf == null) { hmsf = new DateTimeFormatterBuilder() .append(hourElement()) @@ -879,7 +1496,7 @@ * * @return a formatter for yyyy-MM-dd'T'HH */ - public DateTimeFormatter dateHour() { + public static DateTimeFormatter dateHour() { if (dh == null) { dh = new DateTimeFormatterBuilder() .append(date()) @@ -896,7 +1513,7 @@ * * @return a formatter for yyyy-MM-dd'T'HH:mm */ - public DateTimeFormatter dateHourMinute() { + public static DateTimeFormatter dateHourMinute() { if (dhm == null) { dhm = new DateTimeFormatterBuilder() .append(date()) @@ -914,7 +1531,7 @@ * * @return a formatter for yyyy-MM-dd'T'HH:mm:ss */ - public DateTimeFormatter dateHourMinuteSecond() { + public static DateTimeFormatter dateHourMinuteSecond() { if (dhms == null) { dhms = new DateTimeFormatterBuilder() .append(date()) @@ -928,11 +1545,12 @@ /** * Returns a formatter that combines a full date, two digit hour of day, * two digit minute of hour, two digit second of minute, and three digit - * fraction of second. (yyyy-MM-dd'T'HH:mm:ss.SSS) + * fraction of second (yyyy-MM-dd'T'HH:mm:ss.SSS). Parsing will parse up + * to 3 fractional second digits. * * @return a formatter for yyyy-MM-dd'T'HH:mm:ss.SSS */ - public DateTimeFormatter dateHourMinuteSecondMillis() { + public static DateTimeFormatter dateHourMinuteSecondMillis() { if (dhmsl == null) { dhmsl = new DateTimeFormatterBuilder() .append(date()) @@ -946,11 +1564,12 @@ /** * Returns a formatter that combines a full date, two digit hour of day, * two digit minute of hour, two digit second of minute, and three digit - * fraction of second. (yyyy-MM-dd'T'HH:mm:ss.SSS) + * fraction of second (yyyy-MM-dd'T'HH:mm:ss.SSS). Parsing will parse up + * to 9 fractional second digits, throwing away all except the first three. * * @return a formatter for yyyy-MM-dd'T'HH:mm:ss.SSS */ - public DateTimeFormatter dateHourMinuteSecondFraction() { + public static DateTimeFormatter dateHourMinuteSecondFraction() { if (dhmsf == null) { dhmsf = new DateTimeFormatterBuilder() .append(date()) @@ -962,7 +1581,7 @@ } //----------------------------------------------------------------------- - private DateTimeFormatter yearElement() { + private static DateTimeFormatter yearElement() { if (ye == null) { ye = new DateTimeFormatterBuilder() .appendYear(4, 9) @@ -971,7 +1590,7 @@ return ye; } - private DateTimeFormatter monthElement() { + private static DateTimeFormatter monthElement() { if (mye == null) { mye = new DateTimeFormatterBuilder() .appendLiteral('-') @@ -981,7 +1600,7 @@ return mye; } - private DateTimeFormatter dayOfMonthElement() { + private static DateTimeFormatter dayOfMonthElement() { if (dme == null) { dme = new DateTimeFormatterBuilder() .appendLiteral('-') @@ -991,7 +1610,7 @@ return dme; } - private DateTimeFormatter weekyearElement() { + private static DateTimeFormatter weekyearElement() { if (we == null) { we = new DateTimeFormatterBuilder() .appendWeekyear(4, 9) @@ -1000,7 +1619,7 @@ return we; } - private DateTimeFormatter weekElement() { + private static DateTimeFormatter weekElement() { if (wwe == null) { wwe = new DateTimeFormatterBuilder() .appendLiteral("-W") @@ -1010,7 +1629,7 @@ return wwe; } - private DateTimeFormatter dayOfWeekElement() { + private static DateTimeFormatter dayOfWeekElement() { if (dwe == null) { dwe = new DateTimeFormatterBuilder() .appendLiteral('-') @@ -1020,7 +1639,7 @@ return dwe; } - private DateTimeFormatter dayOfYearElement() { + private static DateTimeFormatter dayOfYearElement() { if (dye == null) { dye = new DateTimeFormatterBuilder() .appendLiteral('-') @@ -1030,7 +1649,7 @@ return dye; } - private DateTimeFormatter literalTElement() { + private static DateTimeFormatter literalTElement() { if (lte == null) { lte = new DateTimeFormatterBuilder() .appendLiteral('T') @@ -1039,7 +1658,7 @@ return lte; } - private DateTimeFormatter hourElement() { + private static DateTimeFormatter hourElement() { if (hde == null) { hde = new DateTimeFormatterBuilder() .appendHourOfDay(2) @@ -1048,7 +1667,7 @@ return hde; } - private DateTimeFormatter minuteElement() { + private static DateTimeFormatter minuteElement() { if (mhe == null) { mhe = new DateTimeFormatterBuilder() .appendLiteral(':') @@ -1058,7 +1677,7 @@ return mhe; } - private DateTimeFormatter secondElement() { + private static DateTimeFormatter secondElement() { if (sme == null) { sme = new DateTimeFormatterBuilder() .appendLiteral(':') @@ -1068,17 +1687,7 @@ return sme; } - private DateTimeFormatter millisElement() { - if (lse == null) { - lse = new DateTimeFormatterBuilder() - .appendLiteral('.') - .appendMillisOfSecond(3) - .toFormatter(); - } - return lse; - } - - private DateTimeFormatter fractionElement() { + private static DateTimeFormatter fractionElement() { if (fse == null) { fse = new DateTimeFormatterBuilder() .appendLiteral('.') @@ -1090,13 +1699,13 @@ return fse; } - private DateTimeFormatter offsetElement() { + private static DateTimeFormatter offsetElement() { if (ze == null) { ze = new DateTimeFormatterBuilder() .appendTimeZoneOffset("Z", true, 2, 4) .toFormatter(); } return ze; } - + } Index: 3rdParty_sources/joda-time/org/joda/time/format/ISOPeriodFormat.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/format/ISOPeriodFormat.java (.../ISOPeriodFormat.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/format/ISOPeriodFormat.java (.../ISOPeriodFormat.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,61 +1,27 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.format; /** - * ISOPeriodFormat provides factory methods for the ISO8601 standard. + * Factory that creates instances of PeriodFormatter for the ISO8601 standard. *

            + * Period formatting is performed by the {@link PeriodFormatter} class. + * Three classes provide factory methods to create formatters, and this is one. + * The others are {@link PeriodFormat} and {@link PeriodFormatterBuilder}. + *

            * ISOPeriodFormat is thread-safe and immutable, and the formatters it * returns are as well. * @@ -66,25 +32,27 @@ */ public class ISOPeriodFormat { - private static final ISOPeriodFormat INSTANCE = new ISOPeriodFormat(); + /** Cache of standard format. */ + private static PeriodFormatter cStandard; + /** Cache of alternate months format. */ + private static PeriodFormatter cAlternate; + /** Cache of alternate extended months format. */ + private static PeriodFormatter cAlternateExtended; + /** Cache of alternate weeks format. */ + private static PeriodFormatter cAlternateWithWeeks; + /** Cache of alternate extended weeks format. */ + private static PeriodFormatter cAlternateExtendedWihWeeks; /** - * Returns a singleton instance of ISOPeriodFormat. + * Constructor. + * + * @since 1.1 (previously private) */ - public static ISOPeriodFormat getInstance() { - return INSTANCE; + protected ISOPeriodFormat() { + super(); } - private transient PeriodFormatter - iStandard, - iAlternate, - iAlternateExtended, - iAlternateWithWeeks, - iAlternateExtendedWihWeeks; - - private ISOPeriodFormat() { - } - + //----------------------------------------------------------------------- /** * The standard ISO format - PyYmMwWdDThHmMsS. * Milliseconds are not output. @@ -93,9 +61,9 @@ * * @return the formatter */ - public PeriodFormatter standard() { - if (iStandard == null) { - iStandard = new PeriodFormatterBuilder() + public static PeriodFormatter standard() { + if (cStandard == null) { + cStandard = new PeriodFormatterBuilder() .appendLiteral("P") .appendYears() .appendSuffix("Y") @@ -114,7 +82,7 @@ .appendSuffix("S") .toFormatter(); } - return iStandard; + return cStandard; } /** @@ -125,9 +93,9 @@ * * @return the formatter */ - public PeriodFormatter alternate() { - if (iAlternate == null) { - iAlternate = new PeriodFormatterBuilder() + public static PeriodFormatter alternate() { + if (cAlternate == null) { + cAlternate = new PeriodFormatterBuilder() .appendLiteral("P") .printZeroAlways() .minimumPrintedDigits(4) @@ -141,7 +109,7 @@ .appendSecondsWithOptionalMillis() .toFormatter(); } - return iAlternate; + return cAlternate; } /** @@ -152,9 +120,9 @@ * * @return the formatter */ - public PeriodFormatter alternateExtended() { - if (iAlternateExtended == null) { - iAlternateExtended = new PeriodFormatterBuilder() + public static PeriodFormatter alternateExtended() { + if (cAlternateExtended == null) { + cAlternateExtended = new PeriodFormatterBuilder() .appendLiteral("P") .printZeroAlways() .minimumPrintedDigits(4) @@ -172,7 +140,7 @@ .appendSecondsWithOptionalMillis() .toFormatter(); } - return iAlternateExtended; + return cAlternateExtended; } /** @@ -183,9 +151,9 @@ * * @return the formatter */ - public PeriodFormatter alternateWithWeeks() { - if (iAlternateWithWeeks == null) { - iAlternateWithWeeks = new PeriodFormatterBuilder() + public static PeriodFormatter alternateWithWeeks() { + if (cAlternateWithWeeks == null) { + cAlternateWithWeeks = new PeriodFormatterBuilder() .appendLiteral("P") .printZeroAlways() .minimumPrintedDigits(4) @@ -200,7 +168,7 @@ .appendSecondsWithOptionalMillis() .toFormatter(); } - return iAlternateWithWeeks; + return cAlternateWithWeeks; } /** @@ -211,9 +179,9 @@ * * @return the formatter */ - public PeriodFormatter alternateExtendedWithWeeks() { - if (iAlternateExtendedWihWeeks == null) { - iAlternateExtendedWihWeeks = new PeriodFormatterBuilder() + public static PeriodFormatter alternateExtendedWithWeeks() { + if (cAlternateExtendedWihWeeks == null) { + cAlternateExtendedWihWeeks = new PeriodFormatterBuilder() .appendLiteral("P") .printZeroAlways() .minimumPrintedDigits(4) @@ -232,7 +200,7 @@ .appendSecondsWithOptionalMillis() .toFormatter(); } - return iAlternateExtendedWihWeeks; + return cAlternateExtendedWihWeeks; } } Index: 3rdParty_sources/joda-time/org/joda/time/format/PeriodFormat.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/format/PeriodFormat.java (.../PeriodFormat.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/format/PeriodFormat.java (.../PeriodFormat.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,64 +1,32 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.format; import java.util.Locale; +import java.util.ResourceBundle; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; /** - * PeriodFormat provides basic printing and parsing capabilities for - * periods. Eventually, this class will also support localization. + * Factory that creates instances of PeriodFormatter. *

            + * Period formatting is performed by the {@link PeriodFormatter} class. + * Three classes provide factory methods to create formatters, and this is one. + * The others are {@link ISOPeriodFormat} and {@link PeriodFormatterBuilder}. + *

            * PeriodFormat is thread-safe and immutable, and the formatters it returns * are as well. * @@ -69,61 +37,95 @@ */ public class PeriodFormat { - private static final PeriodFormat INSTANCE = new PeriodFormat(); + /** + * The resource bundle name. + */ + private static final String BUNDLE_NAME = "org.joda.time.format.messages"; + /** + * The created formatters. + */ + private static final ConcurrentMap FORMATTERS = new ConcurrentHashMap(); /** - * Gets a formatter provider that works using the default locale. - * - * @return a format provider + * Constructor. + * + * @since 1.1 (previously private) */ - public static PeriodFormat getInstance() { - return INSTANCE; + protected PeriodFormat() { + super(); } + //----------------------------------------------------------------------- /** - * Gets a formatter provider that works using the given locale. + * Gets the default formatter that outputs words in English. + *

            + * This calls {@link #wordBased(Locale)} using a locale of {@code ENGLISH}. * - * @param locale the Locale to use, null for default locale - * @return a format provider + * @return the formatter, not null */ - public static PeriodFormat getInstance(Locale locale) { - return INSTANCE; + public static PeriodFormatter getDefault() { + return wordBased(Locale.ENGLISH); } - private final PeriodFormatter iDefault; - - private PeriodFormat() { - iDefault = new PeriodFormatterBuilder() - .appendYears() - .appendSuffix(" year", " years") - .appendSeparator(", ", " and ") - .appendMonths() - .appendSuffix(" month", " months") - .appendSeparator(", ", " and ") - .appendWeeks() - .appendSuffix(" week", " weeks") - .appendSeparator(", ", " and ") - .appendDays() - .appendSuffix(" day", " days") - .appendSeparator(", ", " and ") - .appendHours() - .appendSuffix(" hour", " hours") - .appendSeparator(", ", " and ") - .appendMinutes() - .appendSuffix(" minute", " minutes") - .appendSeparator(", ", " and ") - .appendSeconds() - .appendSuffix(" second", " seconds") - .appendSeparator(", ", " and ") - .appendMillis() - .appendSuffix(" millisecond", " milliseconds") - .toFormatter(); + /** + * Returns a word based formatter for the JDK default locale. + *

            + * This calls {@link #wordBased(Locale)} using the {@link Locale#getDefault() default locale}. + * + * @return the formatter, not null + * @since 2.0 + */ + public static PeriodFormatter wordBased() { + return wordBased(Locale.getDefault()); } /** - * Returns the default PeriodFormatter. + * Returns a word based formatter for the specified locale. + *

            + * The words are configured in a resource bundle text file - + * {@code org.joda.time.format.messages}. + * This can be added to via the normal classpath resource bundle mechanisms. + *

            + * Available languages are English, German, Dutch, French, Spanish and Portuguese. + * + * @return the formatter, not null + * @since 2.0 */ - public PeriodFormatter getDefault() { - return iDefault; + public static PeriodFormatter wordBased(Locale locale) { + PeriodFormatter pf = FORMATTERS.get(locale); + if (pf == null) { + ResourceBundle b = ResourceBundle.getBundle(BUNDLE_NAME, locale); + String[] variants = { + b.getString("PeriodFormat.space"), b.getString("PeriodFormat.comma"), + b.getString("PeriodFormat.commandand"), b.getString("PeriodFormat.commaspaceand")}; + pf = new PeriodFormatterBuilder() + .appendYears() + .appendSuffix(b.getString("PeriodFormat.year"), b.getString("PeriodFormat.years")) + .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) + .appendMonths() + .appendSuffix(b.getString("PeriodFormat.month"), b.getString("PeriodFormat.months")) + .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) + .appendWeeks() + .appendSuffix(b.getString("PeriodFormat.week"), b.getString("PeriodFormat.weeks")) + .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) + .appendDays() + .appendSuffix(b.getString("PeriodFormat.day"), b.getString("PeriodFormat.days")) + .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) + .appendHours() + .appendSuffix(b.getString("PeriodFormat.hour"), b.getString("PeriodFormat.hours")) + .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) + .appendMinutes() + .appendSuffix(b.getString("PeriodFormat.minute"), b.getString("PeriodFormat.minutes")) + .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) + .appendSeconds() + .appendSuffix(b.getString("PeriodFormat.second"), b.getString("PeriodFormat.seconds")) + .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) + .appendMillis() + .appendSuffix(b.getString("PeriodFormat.millisecond"), b.getString("PeriodFormat.milliseconds")) + .toFormatter(); + FORMATTERS.putIfAbsent(locale, pf); + } + return pf; } + } Index: 3rdParty_sources/joda-time/org/joda/time/format/PeriodFormatter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/format/PeriodFormatter.java (.../PeriodFormatter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/format/PeriodFormatter.java (.../PeriodFormatter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,71 +1,340 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.format; +import java.io.IOException; +import java.io.Writer; +import java.util.Locale; + +import org.joda.time.MutablePeriod; +import org.joda.time.Period; +import org.joda.time.PeriodType; +import org.joda.time.ReadWritablePeriod; +import org.joda.time.ReadablePeriod; + /** - * Combined interface for printing and parsing. + * Controls the printing and parsing of a time period to and from a string. *

            - * See each extended interface for details of the methods. + * This class is the main API for printing and parsing used by most applications. + * Instances of this class are created via one of three factory classes: + *

              + *
            • {@link PeriodFormat} - formats by pattern and style
            • + *
            • {@link ISOPeriodFormat} - ISO8601 formats
            • + *
            • {@link PeriodFormatterBuilder} - complex formats created via method calls
            • + *
            *

            - * Note: This interface represents a view onto {@link BasePeriodFormatter}. - * All implementations must extend BasePeriodFormatter. + * An instance of this class holds a reference internally to one printer and + * one parser. It is possible that one of these may be null, in which case the + * formatter cannot print/parse. This can be checked via the {@link #isPrinter()} + * and {@link #isParser()} methods. + *

            + * The underlying printer/parser can be altered to behave exactly as required + * by using a decorator modifier: + *

              + *
            • {@link #withLocale(Locale)} - returns a new formatter that uses the specified locale
            • + *
            + * This returns a new formatter (instances of this class are immutable). + *

            + * The main methods of the class are the printXxx and + * parseXxx methods. These are used as follows: + *

            + * // print using the default locale
            + * String periodStr = formatter.print(period);
            + * // print using the French locale
            + * String periodStr = formatter.withLocale(Locale.FRENCH).print(period);
            + * 
            + * // parse using the French locale
            + * Period date = formatter.withLocale(Locale.FRENCH).parsePeriod(str);
            + * 
            * * @author Brian S O'Neill * @author Stephen Colebourne * @since 1.0 */ -public interface PeriodFormatter extends PeriodPrinter, PeriodParser { +public class PeriodFormatter { - // Methods inherited + /** The internal printer used to output the datetime. */ + private final PeriodPrinter iPrinter; + /** The internal parser used to output the datetime. */ + private final PeriodParser iParser; + /** The locale to use for printing and parsing. */ + private final Locale iLocale; + /** The period type used in parsing. */ + private final PeriodType iParseType; + + /** + * Creates a new formatter, however you will normally use the factory + * or the builder. + * + * @param printer the internal printer, null if cannot print + * @param parser the internal parser, null if cannot parse + */ + public PeriodFormatter( + PeriodPrinter printer, PeriodParser parser) { + super(); + iPrinter = printer; + iParser = parser; + iLocale = null; + iParseType = null; + } + + /** + * Constructor. + * + * @param printer the internal printer, null if cannot print + * @param parser the internal parser, null if cannot parse + * @param locale the locale to use + * @param type the parse period type + */ + private PeriodFormatter( + PeriodPrinter printer, PeriodParser parser, + Locale locale, PeriodType type) { + super(); + iPrinter = printer; + iParser = parser; + iLocale = locale; + iParseType = type; + } + + //----------------------------------------------------------------------- + /** + * Is this formatter capable of printing. + * + * @return true if this is a printer + */ + public boolean isPrinter() { + return (iPrinter != null); + } + + /** + * Gets the internal printer object that performs the real printing work. + * + * @return the internal printer + */ + public PeriodPrinter getPrinter() { + return iPrinter; + } + + /** + * Is this formatter capable of parsing. + * + * @return true if this is a parser + */ + public boolean isParser() { + return (iParser != null); + } + + /** + * Gets the internal parser object that performs the real parsing work. + * + * @return the internal parser + */ + public PeriodParser getParser() { + return iParser; + } + + //----------------------------------------------------------------------- + /** + * Returns a new formatter with a different locale that will be used + * for printing and parsing. + *

            + * A PeriodFormatter is immutable, so a new instance is returned, + * and the original is unaltered and still usable. + * + * @param locale the locale to use + * @return the new formatter + */ + public PeriodFormatter withLocale(Locale locale) { + if (locale == getLocale() || (locale != null && locale.equals(getLocale()))) { + return this; + } + return new PeriodFormatter(iPrinter, iParser, locale, iParseType); + } + + /** + * Gets the locale that will be used for printing and parsing. + * + * @return the locale to use + */ + public Locale getLocale() { + return iLocale; + } + + //----------------------------------------------------------------------- + /** + * Returns a new formatter with a different PeriodType for parsing. + *

            + * A PeriodFormatter is immutable, so a new instance is returned, + * and the original is unaltered and still usable. + * + * @param type the type to use in parsing + * @return the new formatter + */ + public PeriodFormatter withParseType(PeriodType type) { + if (type == iParseType) { + return this; + } + return new PeriodFormatter(iPrinter, iParser, iLocale, type); + } + + /** + * Gets the PeriodType that will be used for parsing. + * + * @return the parse type to use + */ + public PeriodType getParseType() { + return iParseType; + } + + //----------------------------------------------------------------------- + /** + * Prints a ReadablePeriod to a StringBuffer. + * + * @param buf the formatted period is appended to this buffer + * @param period the period to format, not null + */ + public void printTo(StringBuffer buf, ReadablePeriod period) { + checkPrinter(); + checkPeriod(period); + + getPrinter().printTo(buf, period, iLocale); + } + + /** + * Prints a ReadablePeriod to a Writer. + * + * @param out the formatted period is written out + * @param period the period to format, not null + */ + public void printTo(Writer out, ReadablePeriod period) throws IOException { + checkPrinter(); + checkPeriod(period); + + getPrinter().printTo(out, period, iLocale); + } + + /** + * Prints a ReadablePeriod to a new String. + * + * @param period the period to format, not null + * @return the printed result + */ + public String print(ReadablePeriod period) { + checkPrinter(); + checkPeriod(period); + + PeriodPrinter printer = getPrinter(); + StringBuffer buf = new StringBuffer(printer.calculatePrintedLength(period, iLocale)); + printer.printTo(buf, period, iLocale); + return buf.toString(); + } + + /** + * Checks whether printing is supported. + * + * @throws UnsupportedOperationException if printing is not supported + */ + private void checkPrinter() { + if (iPrinter == null) { + throw new UnsupportedOperationException("Printing not supported"); + } + } + + /** + * Checks whether the period is non-null. + * + * @throws IllegalArgumentException if the period is null + */ + private void checkPeriod(ReadablePeriod period) { + if (period == null) { + throw new IllegalArgumentException("Period must not be null"); + } + } + + //----------------------------------------------------------------------- + /** + * Parses a period from the given text, at the given position, saving the + * result into the fields of the given ReadWritablePeriod. If the parse + * succeeds, the return value is the new text position. Note that the parse + * may succeed without fully reading the text. + *

            + * The parse type of the formatter is not used by this method. + *

            + * If it fails, the return value is negative, but the period may still be + * modified. To determine the position where the parse failed, apply the + * one's complement operator (~) on the return value. + * + * @param period a period that will be modified + * @param text text to parse + * @param position position to start parsing from + * @return new position, if negative, parse failed. Apply complement + * operator (~) to get position of failure + * @throws IllegalArgumentException if any field is out of range + */ + public int parseInto(ReadWritablePeriod period, String text, int position) { + checkParser(); + checkPeriod(period); + + return getParser().parseInto(period, text, position, iLocale); + } + + /** + * Parses a period from the given text, returning a new Period. + * + * @param text text to parse + * @return parsed value in a Period object + * @throws IllegalArgumentException if any field is out of range + */ + public Period parsePeriod(String text) { + checkParser(); + + return parseMutablePeriod(text).toPeriod(); + } + + /** + * Parses a period from the given text, returning a new MutablePeriod. + * + * @param text text to parse + * @return parsed value in a MutablePeriod object + * @throws IllegalArgumentException if any field is out of range + */ + public MutablePeriod parseMutablePeriod(String text) { + checkParser(); + + MutablePeriod period = new MutablePeriod(0, iParseType); + int newPos = getParser().parseInto(period, text, 0, iLocale); + if (newPos >= 0) { + if (newPos >= text.length()) { + return period; + } + } else { + newPos = ~newPos; + } + throw new IllegalArgumentException(FormatUtils.createErrorMessage(text, newPos)); + } + + /** + * Checks whether parsing is supported. + * + * @throws UnsupportedOperationException if parsing is not supported + */ + private void checkParser() { + if (iParser == null) { + throw new UnsupportedOperationException("Parsing not supported"); + } + } + } Index: 3rdParty_sources/joda-time/org/joda/time/format/PeriodFormatterBuilder.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/format/PeriodFormatterBuilder.java (.../PeriodFormatterBuilder.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/format/PeriodFormatterBuilder.java (.../PeriodFormatterBuilder.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,62 +1,27 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.format; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Locale; +import java.util.TreeSet; import org.joda.time.DateTimeConstants; import org.joda.time.DurationFieldType; @@ -65,10 +30,16 @@ import org.joda.time.ReadablePeriod; /** - * PeriodFormatterBuilder is used for constructing {@link PeriodFormatter}s. - * PeriodFormatters are built by appending specific fields and separators. - * + * Factory that creates complex instances of PeriodFormatter via method calls. *

            + * Period formatting is performed by the {@link PeriodFormatter} class. + * Three classes provide factory methods to create formatters, and this is one. + * The others are {@link PeriodFormat} and {@link ISOPeriodFormat}. + *

            + * PeriodFormatterBuilder is used for constructing formatters which are then + * used to print or parse. The formatters are built by appending specific fields + * or other formatters to an instance of this builder. + *

            * For example, a formatter that prints years and months, like "15 years and 8 months", * can be constructed as follows: *

            @@ -78,7 +49,7 @@ * .appendYears() * .appendSuffix(" year", " years") * .appendSeparator(" and ") - * .printZeroRarely() + * .printZeroRarelyLast() * .appendMonths() * .appendSuffix(" month", " months") * .toFormatter(); @@ -108,6 +79,7 @@ private static final int MILLIS = 7; private static final int SECONDS_MILLIS = 8; private static final int SECONDS_OPTIONAL_MILLIS = 9; + private static final int MAX_FIELD = SECONDS_OPTIONAL_MILLIS; private int iMinPrintedDigits; private int iPrintZeroSetting; @@ -116,8 +88,12 @@ private PeriodFieldAffix iPrefix; - // List of PeriodFormatters used to build a final formatter. - private List iFormatters; + // List of Printers and Parsers used to build a final formatter. + private List iElementPairs; + /** Set to true if the formatter is not a printer. */ + private boolean iNotPrinter; + /** Set to true if the formatter is not a parser. */ + private boolean iNotParser; // Last PeriodFormatter appended of each field type. private FieldFormatter[] iFieldFormatters; @@ -126,47 +102,68 @@ clear(); } + //----------------------------------------------------------------------- /** - * Converts to a PeriodPrinter that prints using all the appended elements. - * Subsequent changes to this builder do not affect the returned printer. + * Constructs a PeriodFormatter using all the appended elements. + *

            + * This is the main method used by applications at the end of the build + * process to create a usable formatter. + *

            + * Subsequent changes to this builder do not affect the returned formatter. + *

            + * The returned formatter may not support both printing and parsing. + * The methods {@link PeriodFormatter#isPrinter()} and + * {@link PeriodFormatter#isParser()} will help you determine the state + * of the formatter. * - * @return the newly created printer + * @return the newly created formatter + * @throws IllegalStateException if the builder can produce neither a printer nor a parser */ - public PeriodPrinter toPrinter() { - return toFormatter(); + public PeriodFormatter toFormatter() { + PeriodFormatter formatter = toFormatter(iElementPairs, iNotPrinter, iNotParser); + iFieldFormatters = (FieldFormatter[]) iFieldFormatters.clone(); + return formatter; } /** - * Converts to a PeriodParser that parses using all the appended elements. - * Subsequent changes to this builder do not affect the returned parser. + * Internal method to create a PeriodPrinter instance using all the + * appended elements. + *

            + * Most applications will not use this method. + * If you want a printer in an application, call {@link #toFormatter()} + * and just use the printing API. + *

            + * Subsequent changes to this builder do not affect the returned printer. * - * @return the newly created parser + * @return the newly created printer, null if builder cannot create a printer */ - public PeriodParser toParser() { - return toFormatter(); + public PeriodPrinter toPrinter() { + if (iNotPrinter) { + return null; + } + return toFormatter().getPrinter(); } /** - * Converts to a PeriodFormatter that formats using all the appended elements. - * Subsequent changes to this builder do not affect the returned formatter. + * Internal method to create a PeriodParser instance using all the + * appended elements. + *

            + * Most applications will not use this method. + * If you want a printer in an application, call {@link #toFormatter()} + * and just use the printing API. + *

            + * Subsequent changes to this builder do not affect the returned parser. * - * @return the newly created formatter + * @return the newly created parser, null if builder cannot create a parser */ - public PeriodFormatter toFormatter() { - PeriodFormatter formatter = toFormatter(iFormatters); - iFieldFormatters = (FieldFormatter[]) iFieldFormatters.clone(); - return formatter; - } - - private static PeriodFormatter toFormatter(List formatters) { - int size = formatters.size(); - if (size >= 1 && formatters.get(0) instanceof Separator) { - Separator sep = (Separator) formatters.get(0); - return sep.finish((BasePeriodFormatter) toFormatter(formatters.subList(1, size))); + public PeriodParser toParser() { + if (iNotParser) { + return null; } - return (PeriodFormatter) createComposite(formatters); + return toFormatter().getParser(); } + //----------------------------------------------------------------------- /** * Clears out all the appended elements, allowing this builder to be reused. */ @@ -176,11 +173,13 @@ iMaxParsedDigits = 10; iRejectSignedValues = false; iPrefix = null; - if (iFormatters == null) { - iFormatters = new ArrayList(); + if (iElementPairs == null) { + iElementPairs = new ArrayList(); } else { - iFormatters.clear(); + iElementPairs.clear(); } + iNotPrinter = false; + iNotParser = false; iFieldFormatters = new FieldFormatter[10]; } @@ -193,11 +192,28 @@ if (formatter == null) { throw new IllegalArgumentException("No formatter supplied"); } - if (formatter instanceof BasePeriodFormatter == false) { - throw new IllegalArgumentException("Formatter must extend BasePeriodFormatter"); + clearPrefix(); + append0(formatter.getPrinter(), formatter.getParser()); + return this; + } + + /** + * Appends a printer parser pair. + *

            + * Either the printer or the parser may be null, in which case the builder will + * be unable to produce a parser or printer repectively. + * + * @param printer appends a printer to the builder, null if printing is not supported + * @param parser appends a parser to the builder, null if parsing is not supported + * @return this PeriodFormatterBuilder + * @throws IllegalArgumentException if both the printer and parser are null + */ + public PeriodFormatterBuilder append(PeriodPrinter printer, PeriodParser parser) { + if (printer == null && parser == null) { + throw new IllegalArgumentException("No printer or parser supplied"); } clearPrefix(); - iFormatters.add(formatter); + append0(printer, parser); return this; } @@ -214,7 +230,7 @@ } clearPrefix(); Literal literal = new Literal(text); - iFormatters.add(literal); + append0(literal, literal); return this; } @@ -314,6 +330,7 @@ return this; } + //----------------------------------------------------------------------- /** * Append a field prefix which applies only to the next appended field. If * the field is not printed, neither is the prefix. @@ -368,8 +385,12 @@ return this; } + //----------------------------------------------------------------------- /** * Instruct the printer to emit an integer years field, if supported. + *

            + * The number of printed and parsed digits can be controlled using + * {@link #minimumPrintedDigits(int)} and {@link #maximumParsedDigits(int)}. * * @return this PeriodFormatterBuilder */ @@ -379,7 +400,10 @@ } /** - * Instruct the printer to emit an integer years field, if supported. + * Instruct the printer to emit an integer months field, if supported. + *

            + * The number of printed and parsed digits can be controlled using + * {@link #minimumPrintedDigits(int)} and {@link #maximumParsedDigits(int)}. * * @return this PeriodFormatterBuilder */ @@ -390,6 +414,9 @@ /** * Instruct the printer to emit an integer weeks field, if supported. + *

            + * The number of printed and parsed digits can be controlled using + * {@link #minimumPrintedDigits(int)} and {@link #maximumParsedDigits(int)}. * * @return this PeriodFormatterBuilder */ @@ -400,6 +427,9 @@ /** * Instruct the printer to emit an integer days field, if supported. + *

            + * The number of printed and parsed digits can be controlled using + * {@link #minimumPrintedDigits(int)} and {@link #maximumParsedDigits(int)}. * * @return this PeriodFormatterBuilder */ @@ -410,6 +440,9 @@ /** * Instruct the printer to emit an integer hours field, if supported. + *

            + * The number of printed and parsed digits can be controlled using + * {@link #minimumPrintedDigits(int)} and {@link #maximumParsedDigits(int)}. * * @return this PeriodFormatterBuilder */ @@ -420,6 +453,9 @@ /** * Instruct the printer to emit an integer minutes field, if supported. + *

            + * The number of printed and parsed digits can be controlled using + * {@link #minimumPrintedDigits(int)} and {@link #maximumParsedDigits(int)}. * * @return this PeriodFormatterBuilder */ @@ -430,6 +466,9 @@ /** * Instruct the printer to emit an integer seconds field, if supported. + *

            + * The number of printed and parsed digits can be controlled using + * {@link #minimumPrintedDigits(int)} and {@link #maximumParsedDigits(int)}. * * @return this PeriodFormatterBuilder */ @@ -464,6 +503,9 @@ /** * Instruct the printer to emit an integer millis field, if supported. + *

            + * The number of printed and parsed digits can be controlled using + * {@link #minimumPrintedDigits(int)} and {@link #maximumParsedDigits(int)}. * * @return this PeriodFormatterBuilder */ @@ -474,6 +516,8 @@ /** * Instruct the printer to emit an integer millis field, if supported. + *

            + * The number of arsed digits can be controlled using {@link #maximumParsedDigits(int)}. * * @return this PeriodFormatterBuilder */ @@ -489,11 +533,12 @@ private void appendField(int type, int minPrinted) { FieldFormatter field = new FieldFormatter(minPrinted, iPrintZeroSetting, iMaxParsedDigits, iRejectSignedValues, type, iFieldFormatters, iPrefix, null); - iFormatters.add(field); + append0(field, field); iFieldFormatters[type] = field; iPrefix = null; } + //----------------------------------------------------------------------- /** * Append a field suffix which applies only to the last appended field. If * the field is not printed, neither is the suffix. @@ -524,7 +569,7 @@ * @see #appendPrefix */ public PeriodFormatterBuilder appendSuffix(String singularText, - String pluralText) { + String pluralText) { if (singularText == null || pluralText == null) { throw new IllegalArgumentException(); } @@ -541,25 +586,32 @@ * @see #appendPrefix */ private PeriodFormatterBuilder appendSuffix(PeriodFieldAffix suffix) { - final Object originalField; - if (iFormatters.size() > 0) { - originalField = iFormatters.get(iFormatters.size() - 1); + final Object originalPrinter; + final Object originalParser; + if (iElementPairs.size() > 0) { + originalPrinter = iElementPairs.get(iElementPairs.size() - 2); + originalParser = iElementPairs.get(iElementPairs.size() - 1); } else { - originalField = null; + originalPrinter = null; + originalParser = null; } - if (originalField == null || !(originalField instanceof FieldFormatter)) { + if (originalPrinter == null || originalParser == null || + originalPrinter != originalParser || + !(originalPrinter instanceof FieldFormatter)) { throw new IllegalStateException("No field to apply suffix to"); } clearPrefix(); - FieldFormatter newField = new FieldFormatter((FieldFormatter) originalField, suffix); - iFormatters.set(iFormatters.size() - 1, newField); + FieldFormatter newField = new FieldFormatter((FieldFormatter) originalPrinter, suffix); + iElementPairs.set(iElementPairs.size() - 2, newField); + iElementPairs.set(iElementPairs.size() - 1, newField); iFieldFormatters[newField.getFieldType()] = newField; return this; } + //----------------------------------------------------------------------- /** * Append a separator, which is output if fields are printed both before * and after the separator. @@ -577,13 +629,14 @@ * @throws IllegalStateException if this separator follows a previous one */ public PeriodFormatterBuilder appendSeparator(String text) { - return appendSeparator(text, text, true, true); + return appendSeparator(text, text, null, true, true); } /** * Append a separator, which is output only if fields are printed after the separator. *

            - * For example, builder.appendDays().appendSeparator(",").appendHours() + * For example, + * builder.appendDays().appendSeparatorIfFieldsAfter(",").appendHours() * will only output the comma if the hours fields is output. *

            * The text will be parsed case-insensitively. @@ -596,13 +649,14 @@ * @throws IllegalStateException if this separator follows a previous one */ public PeriodFormatterBuilder appendSeparatorIfFieldsAfter(String text) { - return appendSeparator(text, text, false, true); + return appendSeparator(text, text, null, false, true); } /** - * Append a separator, which is output only if fields are printed after the separator. + * Append a separator, which is output only if fields are printed before the separator. *

            - * For example, builder.appendDays().appendSeparator(",").appendHours() + * For example, + * builder.appendDays().appendSeparatorIfFieldsBefore(",").appendHours() * will only output the comma if the days fields is output. *

            * The text will be parsed case-insensitively. @@ -615,7 +669,7 @@ * @throws IllegalStateException if this separator follows a previous one */ public PeriodFormatterBuilder appendSeparatorIfFieldsBefore(String text) { - return appendSeparator(text, text, true, false); + return appendSeparator(text, text, null, true, false); } /** @@ -640,63 +694,135 @@ * @throws IllegalStateException if this separator follows a previous one */ public PeriodFormatterBuilder appendSeparator(String text, String finalText) { - return appendSeparator(text, finalText, true, true); + return appendSeparator(text, finalText, null, true, true); } - private PeriodFormatterBuilder appendSeparator(String text, String finalText, boolean useBefore, boolean useAfter) { + /** + * Append a separator, which is output if fields are printed both before + * and after the separator. + *

            + * This method changes the separator depending on whether it is the last separator + * to be output. + *

            + * For example, builder.appendDays().appendSeparator(",", "&").appendHours().appendSeparator(",", "&").appendMinutes() + * will output '1,2&3' if all three fields are output, '1&2' if two fields are output + * and '1' if just one field is output. + *

            + * The text will be parsed case-insensitively. + *

            + * Note: appending a separator discontinues any further work on the latest + * appended field. + * + * @param text the text to use as a separator + * @param finalText the text used used if this is the final separator to be printed + * @param variants set of text values which are also acceptable when parsed + * @return this PeriodFormatterBuilder + * @throws IllegalStateException if this separator follows a previous one + */ + public PeriodFormatterBuilder appendSeparator(String text, String finalText, + String[] variants) { + return appendSeparator(text, finalText, variants, true, true); + } + + private PeriodFormatterBuilder appendSeparator(String text, String finalText, + String[] variants, + boolean useBefore, boolean useAfter) { if (text == null || finalText == null) { throw new IllegalArgumentException(); } clearPrefix(); // optimise zero formatter case - List formatters = iFormatters; - if (formatters.size() == 0) { + List pairs = iElementPairs; + if (pairs.size() == 0) { if (useAfter && useBefore == false) { - formatters.add(new Separator(text, finalText, Literal.EMPTY, useBefore, useAfter)); + Separator separator = new Separator( + text, finalText, variants, + Literal.EMPTY, Literal.EMPTY, useBefore, useAfter); + append0(separator, separator); } return this; } // find the last separator added int i; Separator lastSeparator = null; - for (i=formatters.size(); --i>=0; ) { - if (formatters.get(i) instanceof Separator) { - lastSeparator = (Separator) formatters.get(i); - formatters = formatters.subList(i + 1, formatters.size()); + for (i=pairs.size(); --i>=0; ) { + if (pairs.get(i) instanceof Separator) { + lastSeparator = (Separator) pairs.get(i); + pairs = pairs.subList(i + 1, pairs.size()); break; } + i--; // element pairs } // merge formatters - if (lastSeparator != null && formatters.size() == 0) { + if (lastSeparator != null && pairs.size() == 0) { throw new IllegalStateException("Cannot have two adjacent separators"); } else { - BasePeriodFormatter composite = createComposite(formatters); - formatters.clear(); - formatters.add(new Separator(text, finalText, composite, useBefore, useAfter)); + Object[] comp = createComposite(pairs); + pairs.clear(); + Separator separator = new Separator( + text, finalText, variants, + (PeriodPrinter) comp[0], (PeriodParser) comp[1], + useBefore, useAfter); + pairs.add(separator); + pairs.add(separator); } return this; } + //----------------------------------------------------------------------- private void clearPrefix() throws IllegalStateException { if (iPrefix != null) { throw new IllegalStateException("Prefix not followed by field"); } iPrefix = null; } - private static BasePeriodFormatter createComposite(List formatters) { - switch (formatters.size()) { + private PeriodFormatterBuilder append0(PeriodPrinter printer, PeriodParser parser) { + iElementPairs.add(printer); + iElementPairs.add(parser); + iNotPrinter |= (printer == null); + iNotParser |= (parser == null); + return this; + } + + //----------------------------------------------------------------------- + private static PeriodFormatter toFormatter(List elementPairs, boolean notPrinter, boolean notParser) { + if (notPrinter && notParser) { + throw new IllegalStateException("Builder has created neither a printer nor a parser"); + } + int size = elementPairs.size(); + if (size >= 2 && elementPairs.get(0) instanceof Separator) { + Separator sep = (Separator) elementPairs.get(0); + if (sep.iAfterParser == null && sep.iAfterPrinter == null) { + PeriodFormatter f = toFormatter(elementPairs.subList(2, size), notPrinter, notParser); + sep = sep.finish(f.getPrinter(), f.getParser()); + return new PeriodFormatter(sep, sep); + } + } + Object[] comp = createComposite(elementPairs); + if (notPrinter) { + return new PeriodFormatter(null, (PeriodParser) comp[1]); + } else if (notParser) { + return new PeriodFormatter((PeriodPrinter) comp[0], null); + } else { + return new PeriodFormatter((PeriodPrinter) comp[0], (PeriodParser) comp[1]); + } + } + + private static Object[] createComposite(List elementPairs) { + switch (elementPairs.size()) { case 0: - return Literal.EMPTY; + return new Object[] {Literal.EMPTY, Literal.EMPTY}; case 1: - return (BasePeriodFormatter) formatters.get(0); + return new Object[] {elementPairs.get(0), elementPairs.get(1)}; default: - return new Composite(formatters); + Composite comp = new Composite(elementPairs); + return new Object[] {comp, comp}; } } @@ -759,10 +885,20 @@ String text = iText; int textLength = text.length(); int sourceLength = periodStr.length(); + search: for (int pos = position; pos < sourceLength; pos++) { if (periodStr.regionMatches(true, pos, text, 0, textLength)) { return pos; } + // Only allow number characters to be skipped in search of suffix. + switch (periodStr.charAt(pos)) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '.': case ',': case '+': case '-': + break; + default: + break search; + } } return ~position; } @@ -894,8 +1030,7 @@ * Formats the numeric value of a field, potentially with prefix/suffix. */ static class FieldFormatter - extends BasePeriodFormatter - implements PeriodFormatter { + implements PeriodPrinter, PeriodParser { private final int iMinPrintedDigits; private final int iPrintZeroSetting; private final int iMaxParsedDigits; @@ -911,7 +1046,6 @@ private final PeriodFieldAffix iPrefix; private final PeriodFieldAffix iSuffix; - FieldFormatter(int minPrintedDigits, int printZeroSetting, int maxParsedDigits, boolean rejectSignedValues, @@ -941,30 +1075,34 @@ iSuffix = suffix; } - public int countFieldsToPrint(ReadablePeriod period) { + public int countFieldsToPrint(ReadablePeriod period, int stopAt, Locale locale) { + if (stopAt <= 0) { + return 0; + } if (iPrintZeroSetting == PRINT_ZERO_ALWAYS || getFieldValue(period) != Long.MAX_VALUE) { return 1; } return 0; } - public int countFieldsToPrint(ReadablePeriod period, int stopAt) { - return stopAt <= 0 ? 0 : countFieldsToPrint(period); - } - - public int calculatePrintedLength(ReadablePeriod period) { + public int calculatePrintedLength(ReadablePeriod period, Locale locale) { long valueLong = getFieldValue(period); if (valueLong == Long.MAX_VALUE) { return 0; } int sum = Math.max(FormatUtils.calculateDigitCount(valueLong), iMinPrintedDigits); - if (iFieldType >= 8) { - sum++; // decimal point + if (iFieldType >= SECONDS_MILLIS) { + // valueLong contains the seconds and millis fields + // the minimum output is 0.000, which is 4 digits + sum = Math.max(sum, 4); + // plus one for the decimal point + sum++; if (iFieldType == SECONDS_OPTIONAL_MILLIS && - (Math.abs(valueLong) % DateTimeConstants.MILLIS_PER_SECOND) == 0) { + (Math.abs(valueLong) % DateTimeConstants.MILLIS_PER_SECOND) == 0) { sum -= 4; // remove three digits and decimal point } + // reset valueLong to refer to the seconds part for the prefic/suffix calculation valueLong = valueLong / DateTimeConstants.MILLIS_PER_SECOND; } int value = (int) valueLong; @@ -979,13 +1117,13 @@ return sum; } - public void printTo(StringBuffer buf, ReadablePeriod period) { + public void printTo(StringBuffer buf, ReadablePeriod period, Locale locale) { long valueLong = getFieldValue(period); if (valueLong == Long.MAX_VALUE) { return; } int value = (int) valueLong; - if (iFieldType >= 8) { + if (iFieldType >= SECONDS_MILLIS) { value = (int) (valueLong / DateTimeConstants.MILLIS_PER_SECOND); } @@ -998,7 +1136,7 @@ } else { FormatUtils.appendPaddedInteger(buf, value, minDigits); } - if (iFieldType >= 8) { + if (iFieldType >= SECONDS_MILLIS) { int dp = (int) (Math.abs(valueLong) % DateTimeConstants.MILLIS_PER_SECOND); if (iFieldType == SECONDS_MILLIS || dp > 0) { buf.append('.'); @@ -1010,13 +1148,13 @@ } } - public void printTo(Writer out, ReadablePeriod period) throws IOException { + public void printTo(Writer out, ReadablePeriod period, Locale locale) throws IOException { long valueLong = getFieldValue(period); if (valueLong == Long.MAX_VALUE) { return; } int value = (int) valueLong; - if (iFieldType >= 8) { + if (iFieldType >= SECONDS_MILLIS) { value = (int) (valueLong / DateTimeConstants.MILLIS_PER_SECOND); } @@ -1029,7 +1167,7 @@ } else { FormatUtils.writePaddedInteger(out, value, minDigits); } - if (iFieldType >= 8) { + if (iFieldType >= SECONDS_MILLIS) { int dp = (int) (Math.abs(valueLong) % DateTimeConstants.MILLIS_PER_SECOND); if (iFieldType == SECONDS_MILLIS || dp > 0) { out.write('.'); @@ -1041,8 +1179,9 @@ } } - public int parseInto(ReadWritablePeriod period, - String text, int position) { + public int parseInto( + ReadWritablePeriod period, String text, + int position, Locale locale) { boolean mustParse = (iPrintZeroSetting == PRINT_ZERO_ALWAYS); @@ -1100,16 +1239,24 @@ } else { limit = Math.min(iMaxParsedDigits, text.length() - position); } - + // validate input number - boolean negative = false; int length = 0; - int dp = -1; + int fractPos = -1; + boolean hasDigits = false; while (length < limit) { char c = text.charAt(position + length); // leading sign if (length == 0 && (c == '-' || c == '+') && !iRejectSignedValues) { - negative = (c == '-'); + boolean negative = c == '-'; + + // Next character must be a digit. + if (length + 1 >= limit || + (c = text.charAt(position + length + 1)) < '0' || c > '9') + { + break; + } + if (negative) { length++; } else { @@ -1121,90 +1268,110 @@ continue; } // main number - if (c < '0' || c > '9') { - if (c == '.' && (iFieldType == SECONDS_MILLIS || iFieldType == SECONDS_OPTIONAL_MILLIS)) { - if (dp >= 0) { + if (c >= '0' && c <= '9') { + hasDigits = true; + } else { + if ((c == '.' || c == ',') + && (iFieldType == SECONDS_MILLIS || iFieldType == SECONDS_OPTIONAL_MILLIS)) { + if (fractPos >= 0) { // can't have two decimals - return position + length; + break; } - dp = length; + fractPos = position + length + 1; + // Expand the limit to disregard the decimal point. + limit = Math.min(limit + 1, text.length() - position); } else { break; } } length++; } - if (length == 0 || (length == 1 && dp == 0) || (dp == -1 && iFieldType == SECONDS_MILLIS)) { + + if (!hasDigits) { return ~position; } - if (position + length != suffixPos) { + if (suffixPos >= 0 && position + length != suffixPos) { // If there are additional non-digit characters before the // suffix is reached, then assume that the suffix found belongs // to a field not yet reached. Return original position so that // another parser can continue on. return position; } - - if (iFieldType == SECONDS_MILLIS || iFieldType == SECONDS_OPTIONAL_MILLIS) { - if (dp == -1) { - position = parseField(period, text, position, negative, length, SECONDS); - setFieldValue(period, MILLIS, 0); + + if (iFieldType != SECONDS_MILLIS && iFieldType != SECONDS_OPTIONAL_MILLIS) { + // Handle common case. + setFieldValue(period, iFieldType, parseInt(text, position, length)); + } else if (fractPos < 0) { + setFieldValue(period, SECONDS, parseInt(text, position, length)); + setFieldValue(period, MILLIS, 0); + } else { + int wholeValue = parseInt(text, position, fractPos - position - 1); + setFieldValue(period, SECONDS, wholeValue); + + int fractLen = position + length - fractPos; + int fractValue; + if (fractLen <= 0) { + fractValue = 0; } else { - if (dp > 0) { - position = parseField(period, text, position, negative, dp, SECONDS); + if (fractLen >= 3) { + fractValue = parseInt(text, fractPos, 3); } else { - setFieldValue(period, SECONDS, 0); + fractValue = parseInt(text, fractPos, fractLen); + if (fractLen == 1) { + fractValue *= 100; + } else { + fractValue *= 10; + } } - position++; // skip dp - int millisLength = length - 1 - dp; - if (millisLength > 3) { - position = parseField(period, text, position, false, 3, MILLIS); - position += (millisLength - 3); - } else if (millisLength == 0) { - setFieldValue(period, MILLIS, 0); - } else { - position = parseField(period, text, position, false, millisLength, MILLIS); + if (wholeValue < 0) { + fractValue = -fractValue; } } - } else { - position = parseField(period, text, position, negative, length, iFieldType); + + setFieldValue(period, MILLIS, fractValue); } + position += length; + if (position >= 0 && iSuffix != null) { position = iSuffix.parse(text, position); } return position; } - private int parseField( - ReadWritablePeriod period, String text, int position, - boolean negative, int length, int type) { - - int value; - if (length >= 9) { - // Since value may exceed max, use stock parser which checks - // for this. - value = Integer.parseInt - (text.substring(position, position += length)); - } else { - int i = position; - if (negative) { - i++; + /** + * @param text text to parse + * @param position position in text + * @param length exact count of characters to parse + * @return parsed int value + */ + private int parseInt(String text, int position, int length) { + if (length >= 10) { + // Since value may exceed max, use stock parser which checks for this. + return Integer.parseInt(text.substring(position, position + length)); + } + if (length <= 0) { + return 0; + } + int value = text.charAt(position++); + length--; + boolean negative; + if (value == '-') { + if (--length < 0) { + return 0; } - value = text.charAt(i++) - '0'; - position += length; - while (i < position) { - value = ((value << 3) + (value << 1)) + text.charAt(i++) - '0'; - } - if (negative) { - value = -value; - } + negative = true; + value = text.charAt(position++); + } else { + negative = false; } - - setFieldValue(period, type, value); - return position; + value -= '0'; + while (length-- > 0) { + value = ((value << 3) + (value << 1)) + text.charAt(position++) - '0'; + } + return negative ? -value : value; } /** @@ -1221,7 +1388,7 @@ return Long.MAX_VALUE; } - int value; + long value; switch (iFieldType) { default: @@ -1254,7 +1421,7 @@ case SECONDS_OPTIONAL_MILLIS: int seconds = period.get(DurationFieldType.seconds()); int millis = period.get(DurationFieldType.millis()); - value = seconds * DateTimeConstants.MILLIS_PER_SECOND + millis; + value = (seconds * (long) DateTimeConstants.MILLIS_PER_SECOND) + millis; break; } @@ -1265,7 +1432,7 @@ return Long.MAX_VALUE; case PRINT_ZERO_RARELY_LAST: if (isZero(period) && iFieldFormatters[iFieldType] == this) { - for (int i = iFieldType + 1; i < 10; i++) { + for (int i = iFieldType + 1; i <= MAX_FIELD; i++) { if (isSupported(type, i) && iFieldFormatters[i] != null) { return Long.MAX_VALUE; } @@ -1276,7 +1443,9 @@ break; case PRINT_ZERO_RARELY_FIRST: if (isZero(period) && iFieldFormatters[iFieldType] == this) { - for (int i = Math.min(iFieldType, 8) - 1; i >= 0; i++) { + int i = Math.min(iFieldType, 8); // line split out for IBM JDK + i--; // see bug 1660490 + for (; i >= 0 && i <= MAX_FIELD; i--) { if (isSupported(type, i) && iFieldFormatters[i] != null) { return Long.MAX_VALUE; } @@ -1368,33 +1537,33 @@ * Handles a simple literal piece of text. */ static class Literal - extends BasePeriodFormatter - implements PeriodFormatter { + implements PeriodPrinter, PeriodParser { static final Literal EMPTY = new Literal(""); private final String iText; Literal(String text) { iText = text; } - public int countFieldsToPrint(ReadablePeriod period, int stopAt) { + public int countFieldsToPrint(ReadablePeriod period, int stopAt, Locale locale) { return 0; } - public int calculatePrintedLength(ReadablePeriod period) { + public int calculatePrintedLength(ReadablePeriod period, Locale locale) { return iText.length(); } - public void printTo(StringBuffer buf, ReadablePeriod period) { + public void printTo(StringBuffer buf, ReadablePeriod period, Locale locale) { buf.append(iText); } - public void printTo(Writer out, ReadablePeriod period) throws IOException { + public void printTo(Writer out, ReadablePeriod period, Locale locale) throws IOException { out.write(iText); } - public int parseInto(ReadWritablePeriod period, - String periodStr, int position) { + public int parseInto( + ReadWritablePeriod period, String periodStr, + int position, Locale locale) { if (periodStr.regionMatches(true, position, iText, 0, iText.length())) { return position + iText.length(); } @@ -1408,126 +1577,178 @@ * For example, the 'T' in the ISO8601 standard. */ static class Separator - extends BasePeriodFormatter - implements PeriodFormatter { + implements PeriodPrinter, PeriodParser { private final String iText; private final String iFinalText; + private final String[] iParsedForms; private final boolean iUseBefore; private final boolean iUseAfter; - private BasePeriodFormatter iBefore; - private BasePeriodFormatter iAfter; + private final PeriodPrinter iBeforePrinter; + private volatile PeriodPrinter iAfterPrinter; + private final PeriodParser iBeforeParser; + private volatile PeriodParser iAfterParser; - Separator(String text, String finalText, BasePeriodFormatter before, boolean useBefore, boolean useAfter) { + Separator(String text, String finalText, String[] variants, + PeriodPrinter beforePrinter, PeriodParser beforeParser, + boolean useBefore, boolean useAfter) { iText = text; iFinalText = finalText; - iBefore = before; + + if ((finalText == null || text.equals(finalText)) && + (variants == null || variants.length == 0)) { + + iParsedForms = new String[] {text}; + } else { + // Filter and reverse sort the parsed forms. + TreeSet parsedSet = new TreeSet(String.CASE_INSENSITIVE_ORDER); + parsedSet.add(text); + parsedSet.add(finalText); + if (variants != null) { + for (int i=variants.length; --i>=0; ) { + parsedSet.add(variants[i]); + } + } + ArrayList parsedList = new ArrayList(parsedSet); + Collections.reverse(parsedList); + iParsedForms = parsedList.toArray(new String[parsedList.size()]); + } + + iBeforePrinter = beforePrinter; + iBeforeParser = beforeParser; iUseBefore = useBefore; iUseAfter = useAfter; } - public int countFieldsToPrint(ReadablePeriod period, int stopAt) { - int sum = iBefore.countFieldsToPrint(period, stopAt); + public int countFieldsToPrint(ReadablePeriod period, int stopAt, Locale locale) { + int sum = iBeforePrinter.countFieldsToPrint(period, stopAt, locale); if (sum < stopAt) { - sum += iAfter.countFieldsToPrint(period, stopAt); + sum += iAfterPrinter.countFieldsToPrint(period, stopAt, locale); } return sum; } - public int calculatePrintedLength(ReadablePeriod period) { - BasePeriodFormatter before = iBefore; - BasePeriodFormatter after = iAfter; + public int calculatePrintedLength(ReadablePeriod period, Locale locale) { + PeriodPrinter before = iBeforePrinter; + PeriodPrinter after = iAfterPrinter; - int sum = before.calculatePrintedLength(period) - + after.calculatePrintedLength(period); + int sum = before.calculatePrintedLength(period, locale) + + after.calculatePrintedLength(period, locale); if (iUseBefore) { - if (before.countFieldsToPrint(period, 1) > 0) { + if (before.countFieldsToPrint(period, 1, locale) > 0) { if (iUseAfter) { - int afterCount = after.countFieldsToPrint(period, 2); + int afterCount = after.countFieldsToPrint(period, 2, locale); if (afterCount > 0) { sum += (afterCount > 1 ? iText : iFinalText).length(); } } else { sum += iText.length(); } } - } else if (iUseAfter && after.countFieldsToPrint(period, 1) > 0) { + } else if (iUseAfter && after.countFieldsToPrint(period, 1, locale) > 0) { sum += iText.length(); } return sum; } - public void printTo(StringBuffer buf, ReadablePeriod period) { - BasePeriodFormatter before = iBefore; - BasePeriodFormatter after = iAfter; + public void printTo(StringBuffer buf, ReadablePeriod period, Locale locale) { + PeriodPrinter before = iBeforePrinter; + PeriodPrinter after = iAfterPrinter; - before.printTo(buf, period); + before.printTo(buf, period, locale); if (iUseBefore) { - if (before.countFieldsToPrint(period, 1) > 0) { + if (before.countFieldsToPrint(period, 1, locale) > 0) { if (iUseAfter) { - int afterCount = after.countFieldsToPrint(period, 2); + int afterCount = after.countFieldsToPrint(period, 2, locale); if (afterCount > 0) { buf.append(afterCount > 1 ? iText : iFinalText); } } else { buf.append(iText); } } - } else if (iUseAfter && after.countFieldsToPrint(period, 1) > 0) { + } else if (iUseAfter && after.countFieldsToPrint(period, 1, locale) > 0) { buf.append(iText); } - after.printTo(buf, period); + after.printTo(buf, period, locale); } - public void printTo(Writer out, ReadablePeriod period) throws IOException { - BasePeriodFormatter before = iBefore; - BasePeriodFormatter after = iAfter; + public void printTo(Writer out, ReadablePeriod period, Locale locale) throws IOException { + PeriodPrinter before = iBeforePrinter; + PeriodPrinter after = iAfterPrinter; - before.printTo(out, period); + before.printTo(out, period, locale); if (iUseBefore) { - if (before.countFieldsToPrint(period, 1) > 0) { + if (before.countFieldsToPrint(period, 1, locale) > 0) { if (iUseAfter) { - int afterCount = after.countFieldsToPrint(period, 2); + int afterCount = after.countFieldsToPrint(period, 2, locale); if (afterCount > 0) { out.write(afterCount > 1 ? iText : iFinalText); } } else { out.write(iText); } } - } else if (iUseAfter && after.countFieldsToPrint(period, 1) > 0) { + } else if (iUseAfter && after.countFieldsToPrint(period, 1, locale) > 0) { out.write(iText); } - after.printTo(out, period); + after.printTo(out, period, locale); } - public int parseInto(ReadWritablePeriod period, - String periodStr, int position) { - final int oldPos = position; + public int parseInto( + ReadWritablePeriod period, String periodStr, + int position, Locale locale) { + int oldPos = position; + position = iBeforeParser.parseInto(period, periodStr, position, locale); - position = iBefore.parseInto(period, periodStr, position); if (position < 0) { return position; } + + boolean found = false; if (position > oldPos) { - // Since position advanced, this separator is - // allowed. Optionally parse it. - if (periodStr.regionMatches(true, position, iText, 0, iText.length())) { - position += iText.length(); - } else if (iText != iFinalText && periodStr.regionMatches - (true, position, iFinalText, 0, iFinalText.length())) { - position += iFinalText.length(); + // Consume this separator. + String[] parsedForms = iParsedForms; + int length = parsedForms.length; + for (int i=0; i < length; i++) { + String parsedForm = parsedForms[i]; + if ((parsedForm == null || parsedForm.length() == 0) || + periodStr.regionMatches + (true, position, parsedForm, 0, parsedForm.length())) { + + position += (parsedForm == null ? 0 : parsedForm.length()); + found = true; + break; + } } } - position = iAfter.parseInto(period, periodStr, position); + + oldPos = position; + position = iAfterParser.parseInto(period, periodStr, position, locale); + + if (position < 0) { + return position; + } + + if (found && position == oldPos) { + // Separator should not have been supplied. + return ~oldPos; + } + + if (position > oldPos && !found && !iUseBefore) { + // Separator was required. + return ~oldPos; + } + return position; } - Separator finish(BasePeriodFormatter after) { - iAfter = after; + Separator finish(PeriodPrinter afterPrinter, PeriodParser afterParser) { + iAfterPrinter = afterPrinter; + iAfterParser = afterParser; return this; } } @@ -1537,63 +1758,111 @@ * Composite implementation that merges other fields to create a full pattern. */ static class Composite - extends BasePeriodFormatter - implements PeriodFormatter { + implements PeriodPrinter, PeriodParser { - private final BasePeriodFormatter[] iFormatters; + private final PeriodPrinter[] iPrinters; + private final PeriodParser[] iParsers; - Composite(List formatters) { - iFormatters = (BasePeriodFormatter[]) formatters.toArray( - new BasePeriodFormatter[formatters.size()]); + Composite(List elementPairs) { + List printerList = new ArrayList(); + List parserList = new ArrayList(); + + decompose(elementPairs, printerList, parserList); + + if (printerList.size() <= 0) { + iPrinters = null; + } else { + iPrinters = printerList.toArray( + new PeriodPrinter[printerList.size()]); + } + + if (parserList.size() <= 0) { + iParsers = null; + } else { + iParsers = parserList.toArray( + new PeriodParser[parserList.size()]); + } } - public int countFieldsToPrint(ReadablePeriod period, int stopAt) { + public int countFieldsToPrint(ReadablePeriod period, int stopAt, Locale locale) { int sum = 0; - BasePeriodFormatter[] printers = iFormatters; + PeriodPrinter[] printers = iPrinters; for (int i=printers.length; sum < stopAt && --i>=0; ) { - sum += printers[i].countFieldsToPrint(period); + sum += printers[i].countFieldsToPrint(period, Integer.MAX_VALUE, locale); } return sum; } - public int calculatePrintedLength(ReadablePeriod period) { + public int calculatePrintedLength(ReadablePeriod period, Locale locale) { int sum = 0; - BasePeriodFormatter[] printers = iFormatters; + PeriodPrinter[] printers = iPrinters; for (int i=printers.length; --i>=0; ) { - sum += printers[i].calculatePrintedLength(period); + sum += printers[i].calculatePrintedLength(period, locale); } return sum; } - public void printTo(StringBuffer buf, ReadablePeriod period) { - BasePeriodFormatter[] printers = iFormatters; + public void printTo(StringBuffer buf, ReadablePeriod period, Locale locale) { + PeriodPrinter[] printers = iPrinters; int len = printers.length; for (int i=0; i= 0; i++) { - position = parsers[i].parseInto(period, periodStr, position); + position = parsers[i].parseInto(period, periodStr, position, locale); } return position; } + + private void decompose(List elementPairs, List printerList, List parserList) { + int size = elementPairs.size(); + for (int i=0; i list, Object[] array) { + if (array != null) { + for (int i=0; i. For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.format; -import org.joda.time.Period; -import org.joda.time.PeriodType; -import org.joda.time.MutablePeriod; +import java.util.Locale; + import org.joda.time.ReadWritablePeriod; /** - * Defines an interface for parsing textual representations of time periods. + * Internal interface for parsing textual representations of time periods. *

            - * Note: This interface represents a view onto {@link BasePeriodFormatter}. - * All implementations must extend BasePeriodFormatter. + * Application users will rarely use this class directly. Instead, you + * will use one of the factory classes to create a {@link PeriodFormatter}. + *

            + * The factory classes are:
            + * - {@link PeriodFormatterBuilder}
            + * - {@link PeriodFormat}
            + * - {@link ISOPeriodFormat}
            * * @author Brian S O'Neill + * @author Stephen Colebourne * @since 1.0 * @see PeriodFormatter * @see PeriodFormatterBuilder @@ -85,30 +52,11 @@ * @param period a period that will be modified * @param periodStr text to parse * @param position position to start parsing from + * @param locale the locale to use for parsing * @return new position, if negative, parse failed. Apply complement * operator (~) to get position of failure * @throws IllegalArgumentException if any field is out of range */ - int parseInto(ReadWritablePeriod period, String periodStr, int position); + int parseInto(ReadWritablePeriod period, String periodStr, int position, Locale locale); - /** - * Parses a period from the given text, returning a new Period. - * - * @param type defines which fields may be parsed - * @param periodStr text to parse - * @return parsed value in a Period object - * @throws IllegalArgumentException if any field is out of range - */ - Period parsePeriod(PeriodType type, String periodStr); - - /** - * Parses a period from the given text, returning a new MutablePeriod. - * - * @param type defines which fields may be parsed - * @param periodStr text to parse - * @return parsed value in a MutablePeriod object - * @throws IllegalArgumentException if any field is out of range - */ - MutablePeriod parseMutablePeriod(PeriodType type, String periodStr); - } Index: 3rdParty_sources/joda-time/org/joda/time/format/PeriodPrinter.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/format/PeriodPrinter.java (.../PeriodPrinter.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/format/PeriodPrinter.java (.../PeriodPrinter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,70 +1,39 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.format; import java.io.IOException; import java.io.Writer; +import java.util.Locale; import org.joda.time.ReadablePeriod; /** - * Defines an interface for creating textual representations of time periods. + * Internal interface for printing textual representations of time periods. *

            - * Note: This interface represents a view onto {@link BasePeriodFormatter}. - * All implementations must extend BasePeriodFormatter. + * Application users will rarely use this class directly. Instead, you + * will use one of the factory classes to create a {@link PeriodFormatter}. + *

            + * The factory classes are:
            + * - {@link PeriodFormatterBuilder}
            + * - {@link PeriodFormat}
            + * - {@link ISOPeriodFormat}
            * * @author Brian S O'Neill + * @author Stephen Colebourne * @since 1.0 * @see PeriodFormatter * @see PeriodFormatterBuilder @@ -73,27 +42,42 @@ public interface PeriodPrinter { /** + * Returns the exact number of characters produced for the given period. + * + * @param period the period to use + * @param locale the locale to use + * @return the estimated length + */ + int calculatePrintedLength(ReadablePeriod period, Locale locale); + + /** + * Returns the amount of fields from the given period that this printer + * will print. + * + * @param period the period to use + * @param stopAt stop counting at this value, enter a number ≥ 256 to count all + * @param locale the locale to use + * @return amount of fields printed + */ + int countFieldsToPrint(ReadablePeriod period, int stopAt, Locale locale); + + //----------------------------------------------------------------------- + /** * Prints a ReadablePeriod to a StringBuffer. * * @param buf the formatted period is appended to this buffer * @param period the period to format + * @param locale the locale to use */ - void printTo(StringBuffer buf, ReadablePeriod period); + void printTo(StringBuffer buf, ReadablePeriod period, Locale locale); /** * Prints a ReadablePeriod to a Writer. * * @param out the formatted period is written out * @param period the period to format + * @param locale the locale to use */ - void printTo(Writer out, ReadablePeriod period) throws IOException; + void printTo(Writer out, ReadablePeriod period, Locale locale) throws IOException; - /** - * Prints a ReadablePeriod to a new String. - * - * @param period the period to format - * @return the printed result - */ - String print(ReadablePeriod period); - } Index: 3rdParty_sources/joda-time/org/joda/time/format/messages.properties =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/format/messages.properties (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/format/messages.properties (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,22 @@ +PeriodFormat.space=\ +PeriodFormat.comma=, +PeriodFormat.commandand=,and +PeriodFormat.commaspaceand=, and +PeriodFormat.commaspace=, +PeriodFormat.spaceandspace=\ and +PeriodFormat.year=\ year +PeriodFormat.years=\ years +PeriodFormat.month=\ month +PeriodFormat.months=\ months +PeriodFormat.week=\ week +PeriodFormat.weeks=\ weeks +PeriodFormat.day=\ day +PeriodFormat.days=\ days +PeriodFormat.hour=\ hour +PeriodFormat.hours=\ hours +PeriodFormat.minute=\ minute +PeriodFormat.minutes=\ minutes +PeriodFormat.second=\ second +PeriodFormat.seconds=\ seconds +PeriodFormat.millisecond=\ millisecond +PeriodFormat.milliseconds=\ milliseconds Index: 3rdParty_sources/joda-time/org/joda/time/format/messages_de.properties =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/format/messages_de.properties (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/format/messages_de.properties (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,22 @@ +PeriodFormat.space=\ +PeriodFormat.comma=, +PeriodFormat.commandand=,und +PeriodFormat.commaspaceand=, und +PeriodFormat.commaspace=, +PeriodFormat.spaceandspace=\ und +PeriodFormat.year=\ Jahr +PeriodFormat.years=\ Jahre +PeriodFormat.month=\ Monat +PeriodFormat.months=\ Monate +PeriodFormat.week=\ Woche +PeriodFormat.weeks=\ Wochen +PeriodFormat.day=\ Tag +PeriodFormat.days=\ Tage +PeriodFormat.hour=\ Stunde +PeriodFormat.hours=\ Stunden +PeriodFormat.minute=\ Minute +PeriodFormat.minutes=\ Minuten +PeriodFormat.second=\ Sekunde +PeriodFormat.seconds=\ Sekunden +PeriodFormat.millisecond=\ Millisekunde +PeriodFormat.milliseconds=\ Millisekunden Index: 3rdParty_sources/joda-time/org/joda/time/format/messages_en.properties =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/format/messages_en.properties (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/format/messages_en.properties (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1 @@ \ No newline at end of file Index: 3rdParty_sources/joda-time/org/joda/time/format/messages_es.properties =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/format/messages_es.properties (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/format/messages_es.properties (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,22 @@ +PeriodFormat.space=\ +PeriodFormat.comma=, +PeriodFormat.commandand=,y +PeriodFormat.commaspaceand=, y +PeriodFormat.commaspace=, +PeriodFormat.spaceandspace=\ y +PeriodFormat.year=\ a�o +PeriodFormat.years=\ a�os +PeriodFormat.month=\ mes +PeriodFormat.months=\ meses +PeriodFormat.week=\ semana +PeriodFormat.weeks=\ semanas +PeriodFormat.day=\ dia +PeriodFormat.days=\ dias +PeriodFormat.hour=\ hora +PeriodFormat.hours=\ horas +PeriodFormat.minute=\ minuto +PeriodFormat.minutes=\ minutos +PeriodFormat.second=\ segundo +PeriodFormat.seconds=\ segundos +PeriodFormat.millisecond=\ milisegundo +PeriodFormat.milliseconds=\ milisegundos Index: 3rdParty_sources/joda-time/org/joda/time/format/messages_fr.properties =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/format/messages_fr.properties (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/format/messages_fr.properties (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,22 @@ +PeriodFormat.space=\ +PeriodFormat.comma=, +PeriodFormat.commandand=,et +PeriodFormat.commaspaceand=, et +PeriodFormat.commaspace=, +PeriodFormat.spaceandspace=\ et +PeriodFormat.year=\ ann�e +PeriodFormat.years=\ ann�es +PeriodFormat.month=\ mois +PeriodFormat.months=\ mois +PeriodFormat.week=\ semaine +PeriodFormat.weeks=\ semaines +PeriodFormat.day=\ jour +PeriodFormat.days=\ jours +PeriodFormat.hour=\ heure +PeriodFormat.hours=\ heures +PeriodFormat.minute=\ minute +PeriodFormat.minutes=\ minutes +PeriodFormat.second=\ seconde +PeriodFormat.seconds=\ secondes +PeriodFormat.millisecond=\ milliseconde +PeriodFormat.milliseconds=\ millisecondes Index: 3rdParty_sources/joda-time/org/joda/time/format/messages_nl.properties =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/format/messages_nl.properties (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/format/messages_nl.properties (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,22 @@ +PeriodFormat.space=\ +PeriodFormat.comma=, +PeriodFormat.commandand=,en +PeriodFormat.commaspaceand=, en +PeriodFormat.commaspace=, +PeriodFormat.spaceandspace=\ en +PeriodFormat.year=\ jaar +PeriodFormat.years=\ jaar +PeriodFormat.month=\ maand +PeriodFormat.months=\ maanden +PeriodFormat.week=\ week +PeriodFormat.weeks=\ weken +PeriodFormat.day=\ dag +PeriodFormat.days=\ dagen +PeriodFormat.hour=\ uur +PeriodFormat.hours=\ uur +PeriodFormat.minute=\ minuut +PeriodFormat.minutes=\ minuten +PeriodFormat.second=\ seconde +PeriodFormat.seconds=\ seconden +PeriodFormat.millisecond=\ milliseconde +PeriodFormat.milliseconds=\ milliseconden Index: 3rdParty_sources/joda-time/org/joda/time/format/messages_pt.properties =================================================================== diff -u --- 3rdParty_sources/joda-time/org/joda/time/format/messages_pt.properties (revision 0) +++ 3rdParty_sources/joda-time/org/joda/time/format/messages_pt.properties (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,22 @@ +PeriodFormat.space=\ +PeriodFormat.comma=, +PeriodFormat.commandand=,e +PeriodFormat.commaspaceand=, e +PeriodFormat.commaspace=, +PeriodFormat.spaceandspace=\ e +PeriodFormat.year=\ ano +PeriodFormat.years=\ anos +PeriodFormat.month=\ m�s +PeriodFormat.months=\ meses +PeriodFormat.week=\ semana +PeriodFormat.weeks=\ semanas +PeriodFormat.day=\ dia +PeriodFormat.days=\ dias +PeriodFormat.hour=\ hora +PeriodFormat.hours=\ horas +PeriodFormat.minute=\ minuto +PeriodFormat.minutes=\ minutos +PeriodFormat.second=\ segundo +PeriodFormat.seconds=\ segundos +PeriodFormat.millisecond=\ milissegundo +PeriodFormat.milliseconds=\ milissegundos Index: 3rdParty_sources/joda-time/org/joda/time/format/package.html =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/format/package.html (.../package.html) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/format/package.html (.../package.html) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -4,57 +4,19 @@ org.joda.time.format package Index: 3rdParty_sources/joda-time/org/joda/time/overview.html =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/overview.html (.../overview.html) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/overview.html (.../overview.html) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -4,57 +4,19 @@ org.joda.time package @@ -70,9 +32,9 @@ package while the format package will be of interest for formatting.

            -Joda-Time is standalone and has no dependencies other than JDK 1.3. -(The jar file may work on JDK 1.2, but it is untested.) -It is licenced under an Apache/BSD style licence. +Joda-Time is standalone and has no dependencies other than JDK 1.5. +(The jar file may work on older JDK versions, but it is untested.) +It is licensed under the Apache License Version 2.0.

            \ No newline at end of file Index: 3rdParty_sources/joda-time/org/joda/time/package.html =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/package.html (.../package.html) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/package.html (.../package.html) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -4,57 +4,19 @@ org.joda.time package @@ -163,7 +125,7 @@ grouped into a Chronology. The chronology represents all the information to convert from a millisecond value to human understandable fields in a specific calendar system. Chronologies are provided for ISO, -Gregorian/Julian (GJ), Coptic and Buddhist. +Gregorian/Julian (GJ), Buddhist, Coptic and Ethiopic. More implementations are sought from the community.

            @@ -185,30 +147,21 @@

            Partials

            Partials are like instants, except they do not completely specify a point in -time. The main interface is ReadablePartial, and implementations -include TimeOfDay (contains hour, minute, second, and millis) and -YearMonthDay. +time. The main interface is ReadablePartial.

            -The API of a partial is remarkably similar to an instant, however there are -internal differences. DateTime and Instant store a -long millisecond value internally and calculate field values on demand. The -partial classes work the other way around, storing field values internally -and providing a means to resolve to a millisecond value on demand. +The main implementations are: +

              +
            • LocalTime - A class storing a local time without a date
            • +
            • LocalDate - A class storing a local date without a time
            • +
            • LocalDateTime - A class storing a local datetime
            • +
            • Partial - A class storing any combination of datetime fields, such as dayOfMonth and dayOfWeek
            • +
            +For consistency, the API of each partial class is similar to that of an instant class.

            -Since a partial does not represent a specific point in time, it must be -resolved to create a full instant. For example, a TimeOfDay -might represent 12:30. To convert to a DateTime requires the -specification of a date, and is performed using the resolve -methods of ReadablePartial. For example, -

            -    new TimeOfDay("12:30").resolveDateTime(new DateTime("2004-06-07T06:00"));
            -
            -equals -
            -    new DateTime("2004-06-07T12:30");
            -
            +All partial implementations represent a local time, in other words without a time zone. +Thus, to convert a partial to an instant (which does contain a time zone) requires adding a zone.

            Formatting

            Index: 3rdParty_sources/joda-time/org/joda/time/tz/CachedDateTimeZone.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/tz/CachedDateTimeZone.java (.../CachedDateTimeZone.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/tz/CachedDateTimeZone.java (.../CachedDateTimeZone.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2012 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.tz; @@ -63,6 +25,7 @@ * CachedDateTimeZone is thread-safe and immutable. * * @author Brian S O'Neill + * @since 1.0 */ public class CachedDateTimeZone extends DateTimeZone { @@ -118,21 +81,13 @@ private final DateTimeZone iZone; - private transient Info[] iInfoCache; + private final Info[] iInfoCache = new Info[cInfoCacheMask + 1]; private CachedDateTimeZone(DateTimeZone zone) { super(zone.getID()); iZone = zone; - iInfoCache = new Info[cInfoCacheMask + 1]; } - private void readObject(java.io.ObjectInputStream in) - throws java.io.IOException, ClassNotFoundException - { - in.defaultReadObject(); - iInfoCache = new Info[cInfoCacheMask + 1]; - } - /** * Returns the DateTimeZone being wrapped. */ Index: 3rdParty_sources/joda-time/org/joda/time/tz/DateTimeZoneBuilder.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/tz/DateTimeZoneBuilder.java (.../DateTimeZoneBuilder.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/tz/DateTimeZoneBuilder.java (.../DateTimeZoneBuilder.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2010 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.tz; @@ -60,15 +22,20 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.text.DateFormatSymbols; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; +import java.util.Locale; import java.util.Set; import org.joda.time.Chronology; +import org.joda.time.DateTime; import org.joda.time.DateTimeUtils; import org.joda.time.DateTimeZone; +import org.joda.time.Period; +import org.joda.time.PeriodType; import org.joda.time.chrono.ISOChronology; /** @@ -79,10 +46,42 @@ *

            * DateTimeZoneBuilder itself is mutable and not thread-safe, but the * DateTimeZone objects that it builds are thread-safe and immutable. + *

            + * It is intended that {@link ZoneInfoCompiler} be used to read time zone data + * files, indirectly calling DateTimeZoneBuilder. The following complex + * example defines the America/Los_Angeles time zone, with all historical + * transitions: + * + *

            + * DateTimeZone America_Los_Angeles = new DateTimeZoneBuilder()
            + *     .addCutover(-2147483648, 'w', 1, 1, 0, false, 0)
            + *     .setStandardOffset(-28378000)
            + *     .setFixedSavings("LMT", 0)
            + *     .addCutover(1883, 'w', 11, 18, 0, false, 43200000)
            + *     .setStandardOffset(-28800000)
            + *     .addRecurringSavings("PDT", 3600000, 1918, 1919, 'w',  3, -1, 7, false, 7200000)
            + *     .addRecurringSavings("PST",       0, 1918, 1919, 'w', 10, -1, 7, false, 7200000)
            + *     .addRecurringSavings("PWT", 3600000, 1942, 1942, 'w',  2,  9, 0, false, 7200000)
            + *     .addRecurringSavings("PPT", 3600000, 1945, 1945, 'u',  8, 14, 0, false, 82800000)
            + *     .addRecurringSavings("PST",       0, 1945, 1945, 'w',  9, 30, 0, false, 7200000)
            + *     .addRecurringSavings("PDT", 3600000, 1948, 1948, 'w',  3, 14, 0, false, 7200000)
            + *     .addRecurringSavings("PST",       0, 1949, 1949, 'w',  1,  1, 0, false, 7200000)
            + *     .addRecurringSavings("PDT", 3600000, 1950, 1966, 'w',  4, -1, 7, false, 7200000)
            + *     .addRecurringSavings("PST",       0, 1950, 1961, 'w',  9, -1, 7, false, 7200000)
            + *     .addRecurringSavings("PST",       0, 1962, 1966, 'w', 10, -1, 7, false, 7200000)
            + *     .addRecurringSavings("PST",       0, 1967, 2147483647, 'w', 10, -1, 7, false, 7200000)
            + *     .addRecurringSavings("PDT", 3600000, 1967, 1973, 'w', 4, -1,  7, false, 7200000)
            + *     .addRecurringSavings("PDT", 3600000, 1974, 1974, 'w', 1,  6,  0, false, 7200000)
            + *     .addRecurringSavings("PDT", 3600000, 1975, 1975, 'w', 2, 23,  0, false, 7200000)
            + *     .addRecurringSavings("PDT", 3600000, 1976, 1986, 'w', 4, -1,  7, false, 7200000)
            + *     .addRecurringSavings("PDT", 3600000, 1987, 2147483647, 'w', 4, 1, 7, true, 7200000)
            + *     .toDateTimeZone("America/Los_Angeles", true);
            + * 
            * * @author Brian S O'Neill * @see ZoneInfoCompiler * @see ZoneInfoProvider + * @since 1.0 */ public class DateTimeZoneBuilder { /** @@ -221,26 +220,26 @@ } // List of RuleSets. - private final ArrayList iRuleSets; + private final ArrayList iRuleSets; public DateTimeZoneBuilder() { - iRuleSets = new ArrayList(10); + iRuleSets = new ArrayList(10); } /** * Adds a cutover for added rules. The standard offset at the cutover * defaults to 0. Call setStandardOffset afterwards to change it. * - * @param year year of cutover + * @param year the year of cutover * @param mode 'u' - cutover is measured against UTC, 'w' - against wall - * offset, 's' - against standard offset. - * @param dayOfMonth if negative, set to ((last day of month) - ~dayOfMonth). - * For example, if -1, set to last day of month - * @param dayOfWeek if 0, ignore - * @param advanceDayOfWeek if dayOfMonth does not fall on dayOfWeek, advance to - * dayOfWeek when true, retreat when false. - * @param millisOfDay additional precision for specifying time of day of - * cutover + * offset, 's' - against standard offset + * @param monthOfYear the month from 1 (January) to 12 (December) + * @param dayOfMonth if negative, set to ((last day of month) - ~dayOfMonth). + * For example, if -1, set to last day of month + * @param dayOfWeek from 1 (Monday) to 7 (Sunday), if 0 then ignore + * @param advanceDayOfWeek if dayOfMonth does not fall on dayOfWeek, advance to + * dayOfWeek when true, retreat when false. + * @param millisOfDay additional precision for specifying time of day of cutover */ public DateTimeZoneBuilder addCutover(int year, char mode, @@ -250,10 +249,10 @@ boolean advanceDayOfWeek, int millisOfDay) { - OfYear ofYear = new OfYear - (mode, monthOfYear, dayOfMonth, dayOfWeek, advanceDayOfWeek, millisOfDay); if (iRuleSets.size() > 0) { - RuleSet lastRuleSet = (RuleSet)iRuleSets.get(iRuleSets.size() - 1); + OfYear ofYear = new OfYear + (mode, monthOfYear, dayOfMonth, dayOfWeek, advanceDayOfWeek, millisOfDay); + RuleSet lastRuleSet = iRuleSets.get(iRuleSets.size() - 1); lastRuleSet.setUpperLimit(year, ofYear); } iRuleSets.add(new RuleSet()); @@ -263,6 +262,7 @@ /** * Sets the standard offset to use for newly added rules until the next * cutover is added. + * @param standardOffset the standard offset in millis */ public DateTimeZoneBuilder setStandardOffset(int standardOffset) { getLastRuleSet().setStandardOffset(standardOffset); @@ -280,22 +280,22 @@ /** * Add a recurring daylight saving time rule. * - * @param nameKey name key of new rule - * @param saveMillis milliseconds to add to standard offset - * @param fromYear First year that rule is in effect. MIN_VALUE indicates - * beginning of time. - * @param toYear Last year (inclusive) that rule is in effect. MAX_VALUE - * indicates end of time. - * @param mode 'u' - transitions are calculated against UTC, 'w' - - * transitions are calculated against wall offset, 's' - transitions are - * calculated against standard offset. - * @param dayOfMonth if negative, set to ((last day of month) - ~dayOfMonth). - * For example, if -1, set to last day of month - * @param dayOfWeek if 0, ignore - * @param advanceDayOfWeek if dayOfMonth does not fall on dayOfWeek, advance to - * dayOfWeek when true, retreat when false. - * @param millisOfDay additional precision for specifying time of day of - * transitions + * @param nameKey the name key of new rule + * @param saveMillis the milliseconds to add to standard offset + * @param fromYear the first year that rule is in effect, MIN_VALUE indicates + * beginning of time + * @param toYear the last year (inclusive) that rule is in effect, MAX_VALUE + * indicates end of time + * @param mode 'u' - transitions are calculated against UTC, 'w' - + * transitions are calculated against wall offset, 's' - transitions are + * calculated against standard offset + * @param monthOfYear the month from 1 (January) to 12 (December) + * @param dayOfMonth if negative, set to ((last day of month) - ~dayOfMonth). + * For example, if -1, set to last day of month + * @param dayOfWeek from 1 (Monday) to 7 (Sunday), if 0 then ignore + * @param advanceDayOfWeek if dayOfMonth does not fall on dayOfWeek, advance to + * dayOfWeek when true, retreat when false. + * @param millisOfDay additional precision for specifying time of day of transitions */ public DateTimeZoneBuilder addRecurringSavings(String nameKey, int saveMillis, int fromYear, int toYear, @@ -320,22 +320,23 @@ if (iRuleSets.size() == 0) { addCutover(Integer.MIN_VALUE, 'w', 1, 1, 0, false, 0); } - return (RuleSet)iRuleSets.get(iRuleSets.size() - 1); + return iRuleSets.get(iRuleSets.size() - 1); } /** * Processes all the rules and builds a DateTimeZone. * - * @param id time zone id to assign + * @param id time zone id to assign + * @param outputID true if the zone id should be output */ - public DateTimeZone toDateTimeZone(String id) { + public DateTimeZone toDateTimeZone(String id, boolean outputID) { if (id == null) { throw new IllegalArgumentException(); } // Discover where all the transitions occur and store the results in // these lists. - ArrayList transitions = new ArrayList(); + ArrayList transitions = new ArrayList(); // Tail zone picks up remaining transitions in the form of an endless // DST cycle. @@ -346,7 +347,7 @@ int ruleSetCount = iRuleSets.size(); for (int i=0; i transitions, Transition tr) { int size = transitions.size(); if (size == 0) { transitions.add(tr); return true; } - Transition last = (Transition)transitions.get(size - 1); + Transition last = transitions.get(size - 1); if (!tr.isTransitionFrom(last)) { return false; } @@ -415,7 +416,7 @@ // replace last transition with new one. int offsetForLast = 0; if (size >= 2) { - offsetForLast = ((Transition)transitions.get(size - 2)).getWallOffset(); + offsetForLast = transitions.get(size - 2).getWallOffset(); } int offsetForNew = last.getWallOffset(); @@ -435,25 +436,27 @@ * Encodes a built DateTimeZone to the given stream. Call readFrom to * decode the data into a DateTimeZone object. * - * @param out output stream to receive encoded DateTimeZone. + * @param out the output stream to receive the encoded DateTimeZone + * @since 1.5 (parameter added) */ - public void writeTo(OutputStream out) throws IOException { + public void writeTo(String zoneID, OutputStream out) throws IOException { if (out instanceof DataOutput) { - writeTo((DataOutput)out); + writeTo(zoneID, (DataOutput)out); } else { - writeTo((DataOutput)new DataOutputStream(out)); + writeTo(zoneID, (DataOutput)new DataOutputStream(out)); } } /** * Encodes a built DateTimeZone to the given stream. Call readFrom to * decode the data into a DateTimeZone object. * - * @param out output stream to receive encoded DateTimeZone. + * @param out the output stream to receive the encoded DateTimeZone + * @since 1.5 (parameter added) */ - public void writeTo(DataOutput out) throws IOException { - // The zone id is not written out, so the empty string is okay. - DateTimeZone zone = toDateTimeZone(""); + public void writeTo(String zoneID, DataOutput out) throws IOException { + // pass false so zone id is not written out + DateTimeZone zone = toDateTimeZone(zoneID, false); if (zone instanceof FixedDateTimeZone) { out.writeByte('F'); // 'F' for fixed @@ -792,6 +795,14 @@ out.writeUTF(iNameKey); writeMillis(out, iSaveMillis); } + + Recurrence rename(String nameKey) { + return new Recurrence(iOfYear, nameKey, iSaveMillis); + } + + Recurrence renameAppend(String appendNameKey) { + return rename((iNameKey + appendNameKey).intern()); + } } /** @@ -939,7 +950,7 @@ } private int iStandardOffset; - private ArrayList iRules; + private ArrayList iRules; // Optional. private String iInitialNameKey; @@ -950,7 +961,7 @@ private OfYear iUpperOfYear; RuleSet() { - iRules = new ArrayList(10); + iRules = new ArrayList(10); iUpperYear = Integer.MAX_VALUE; } @@ -959,7 +970,7 @@ */ RuleSet(RuleSet rs) { iStandardOffset = rs.iStandardOffset; - iRules = new ArrayList(rs.iRules); + iRules = new ArrayList(rs.iRules); iInitialNameKey = rs.iInitialNameKey; iInitialSaveMillis = rs.iInitialSaveMillis; iUpperYear = rs.iUpperYear; @@ -1004,7 +1015,7 @@ } // Make a copy before we destroy the rules. - ArrayList copy = new ArrayList(iRules); + ArrayList copy = new ArrayList(iRules); // Iterate through all the transitions until firstMillis is // reached. Use the name key and savings for whatever rule reaches @@ -1028,9 +1039,7 @@ // Find first rule without savings. This way a more // accurate nameKey is found even though no rule // extends to the RuleSet's lower limit. - Iterator it = copy.iterator(); - while (it.hasNext()) { - Rule rule = (Rule)it.next(); + for (Rule rule : copy) { if (rule.getSaveMillis() == 0) { first = new Transition(firstMillis, rule, iStandardOffset); break; @@ -1076,9 +1085,9 @@ Rule nextRule = null; long nextMillis = Long.MAX_VALUE; - Iterator it = iRules.iterator(); + Iterator it = iRules.iterator(); while (it.hasNext()) { - Rule rule = (Rule)it.next(); + Rule rule = it.next(); long next = rule.next(instant, iStandardOffset, saveMillis); if (next <= instant) { it.remove(); @@ -1130,8 +1139,8 @@ */ public DSTZone buildTailZone(String id) { if (iRules.size() == 2) { - Rule startRule = (Rule)iRules.get(0); - Rule endRule = (Rule)iRules.get(1); + Rule startRule = iRules.get(0); + Rule endRule = iRules.get(1); if (startRule.getToYear() == Integer.MAX_VALUE && endRule.getToYear() == Integer.MAX_VALUE) { @@ -1158,9 +1167,9 @@ Recurrence.readFrom(in), Recurrence.readFrom(in)); } - private final int iStandardOffset; - private final Recurrence iStartRecurrence; - private final Recurrence iEndRecurrence; + final int iStandardOffset; + final Recurrence iStartRecurrence; + final Recurrence iEndRecurrence; DSTZone(String id, int standardOffset, Recurrence startRecurrence, Recurrence endRecurrence) { @@ -1203,6 +1212,9 @@ } catch (IllegalArgumentException e) { // Overflowed. start = instant; + } catch (ArithmeticException e) { + // Overflowed. + start = instant; } try { @@ -1215,6 +1227,9 @@ } catch (IllegalArgumentException e) { // Overflowed. end = instant; + } catch (ArithmeticException e) { + // Overflowed. + end = instant; } return (start > end) ? end : start; @@ -1241,6 +1256,9 @@ } catch (IllegalArgumentException e) { // Overflowed. start = instant; + } catch (ArithmeticException e) { + // Overflowed. + start = instant; } try { @@ -1253,6 +1271,9 @@ } catch (IllegalArgumentException e) { // Overflowed. end = instant; + } catch (ArithmeticException e) { + // Overflowed. + end = instant; } return ((start > end) ? start : end) - 1; @@ -1292,6 +1313,9 @@ } catch (IllegalArgumentException e) { // Overflowed. start = instant; + } catch (ArithmeticException e) { + // Overflowed. + start = instant; } try { @@ -1300,6 +1324,9 @@ } catch (IllegalArgumentException e) { // Overflowed. end = instant; + } catch (ArithmeticException e) { + // Overflowed. + end = instant; } return (start > end) ? startRecurrence : endRecurrence; @@ -1349,60 +1376,132 @@ (id, transitions, wallOffsets, standardOffsets, nameKeys, tailZone); } - // All array fields have the same length. - - private final long[] iTransitions; - - private final int[] iWallOffsets; - private final int[] iStandardOffsets; - private final String[] iNameKeys; - - private final DSTZone iTailZone; - - PrecalculatedZone(String id, long[] transitions, int[] wallOffsets, - int[] standardOffsets, String[] nameKeys, DSTZone tailZone) - { - super(id); - iTransitions = transitions; - iWallOffsets = wallOffsets; - iStandardOffsets = standardOffsets; - iNameKeys = nameKeys; - iTailZone = tailZone; - } - /** - * @param tailZone optional zone for getting info beyond precalculated - * tables. + * Factory to create instance from builder. + * + * @param id the zone id + * @param outputID true if the zone id should be output + * @param transitions the list of Transition objects + * @param tailZone optional zone for getting info beyond precalculated tables */ - PrecalculatedZone(String id, ArrayList transitions, DSTZone tailZone) { - super(id); - + static PrecalculatedZone create(String id, boolean outputID, ArrayList transitions, + DSTZone tailZone) { int size = transitions.size(); if (size == 0) { throw new IllegalArgumentException(); } - iTransitions = new long[size]; - iWallOffsets = new int[size]; - iStandardOffsets = new int[size]; - iNameKeys = new String[size]; + long[] trans = new long[size]; + int[] wallOffsets = new int[size]; + int[] standardOffsets = new int[size]; + String[] nameKeys = new String[size]; Transition last = null; for (int i=0; i 4 && p.getMonths() < 8 && + curNameKey.equals(zoneNameData[2]) && + curNameKey.equals(zoneNameData[4])) { + + if (ZoneInfoCompiler.verbose()) { + System.out.println("Fixing duplicate name key - " + nextNameKey); + System.out.println(" - " + new DateTime(trans[i], chrono) + + " - " + new DateTime(trans[i + 1], chrono)); + } + if (curOffset > nextOffset) { + nameKeys[i] = (curNameKey + "-Summer").intern(); + } else if (curOffset < nextOffset) { + nameKeys[i + 1] = (nextNameKey + "-Summer").intern(); + i++; + } + } + } + + if (tailZone != null) { + if (tailZone.iStartRecurrence.getNameKey() + .equals(tailZone.iEndRecurrence.getNameKey())) { + if (ZoneInfoCompiler.verbose()) { + System.out.println("Fixing duplicate recurrent name key - " + + tailZone.iStartRecurrence.getNameKey()); + } + if (tailZone.iStartRecurrence.getSaveMillis() > 0) { + tailZone = new DSTZone( + tailZone.getID(), + tailZone.iStandardOffset, + tailZone.iStartRecurrence.renameAppend("-Summer"), + tailZone.iEndRecurrence); + } else { + tailZone = new DSTZone( + tailZone.getID(), + tailZone.iStandardOffset, + tailZone.iStartRecurrence, + tailZone.iEndRecurrence.renameAppend("-Summer")); + } + } + } + + return new PrecalculatedZone + ((outputID ? id : ""), trans, wallOffsets, standardOffsets, nameKeys, tailZone); + } + + // All array fields have the same length. + + private final long[] iTransitions; + + private final int[] iWallOffsets; + private final int[] iStandardOffsets; + private final String[] iNameKeys; + + private final DSTZone iTailZone; + + /** + * Constructor used ONLY for valid input, loaded via static methods. + */ + private PrecalculatedZone(String id, long[] transitions, int[] wallOffsets, + int[] standardOffsets, String[] nameKeys, DSTZone tailZone) + { + super(id); + iTransitions = transitions; + iWallOffsets = wallOffsets; + iStandardOffsets = standardOffsets; + iNameKeys = nameKeys; iTailZone = tailZone; } @@ -1539,7 +1638,7 @@ int size = iTransitions.length; // Create unique string pool. - Set poolSet = new HashSet(); + Set poolSet = new HashSet(); for (int i=0; i it = poolSet.iterator(); for (int i=0; it.hasNext(); i++) { - pool[i] = (String)it.next(); + pool[i] = it.next(); } // Write out the pool. Index: 3rdParty_sources/joda-time/org/joda/time/tz/DefaultNameProvider.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/tz/DefaultNameProvider.java (.../DefaultNameProvider.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/tz/DefaultNameProvider.java (.../DefaultNameProvider.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,73 +1,40 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2011 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.tz; import java.text.DateFormatSymbols; import java.util.HashMap; import java.util.Locale; +import java.util.Map; +import org.joda.time.DateTimeUtils; + /** * The default name provider acquires localized names from * {@link DateFormatSymbols java.text.DateFormatSymbols}. *

            * DefaultNameProvider is thread-safe and immutable. * * @author Brian S O'Neill + * @since 1.0 */ +@SuppressWarnings("unchecked") public class DefaultNameProvider implements NameProvider { // locale -> (id -> (nameKey -> [shortName, name])) - private HashMap iByLocaleCache = createCache(); + private HashMap>> iByLocaleCache = createCache(); public DefaultNameProvider() { } @@ -87,25 +54,45 @@ return null; } - HashMap byIdCache = (HashMap)iByLocaleCache.get(locale); + Map> byIdCache = iByLocaleCache.get(locale); if (byIdCache == null) { iByLocaleCache.put(locale, byIdCache = createCache()); } - HashMap byNameKeyCache = (HashMap)byIdCache.get(id); + Map byNameKeyCache = byIdCache.get(id); if (byNameKeyCache == null) { byIdCache.put(id, byNameKeyCache = createCache()); - String[][] zoneStrings = new DateFormatSymbols(locale).getZoneStrings(); - for (int i=0; i. For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.tz; @@ -61,6 +23,7 @@ * FixedDateTimeZone is thread-safe and immutable. * * @author Brian S O'Neill + * @since 1.0 */ public final class FixedDateTimeZone extends DateTimeZone { @@ -106,17 +69,37 @@ return instant; } + /** + * Override to return the correct timzone instance. + * @since 1.5 + */ + public java.util.TimeZone toTimeZone() { + String id = getID(); + if (id.length() == 6 && (id.startsWith("+") || id.startsWith("-"))) { + // standard format offset [+-]hh:mm + // our ID is without any prefix, so we need to add the GMT back + return java.util.TimeZone.getTimeZone("GMT" + getID()); + } + // unusual offset, so setup a SimpleTimeZone as best we can + return new java.util.SimpleTimeZone(iWallOffset, getID()); + } + public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof FixedDateTimeZone) { - FixedDateTimeZone other = (FixedDateTimeZone)obj; + FixedDateTimeZone other = (FixedDateTimeZone) obj; return getID().equals(other.getID()) && iStandardOffset == other.iStandardOffset && iWallOffset == other.iWallOffset; } return false; } + + public int hashCode() { + return getID().hashCode() + 37 * iStandardOffset + 31 * iWallOffset; + } + } Index: 3rdParty_sources/joda-time/org/joda/time/tz/NameProvider.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/tz/NameProvider.java (.../NameProvider.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/tz/NameProvider.java (.../NameProvider.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2005 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.tz; @@ -59,6 +21,7 @@ * Service provider factory for localized time zone names. * * @author Brian S O'Neill + * @since 1.0 */ public interface NameProvider { /** Index: 3rdParty_sources/joda-time/org/joda/time/tz/Provider.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/tz/Provider.java (.../Provider.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/tz/Provider.java (.../Provider.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,67 +1,32 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.tz; import java.util.Set; + import org.joda.time.DateTimeZone; /** * Service provider factory for time zones. * * @author Brian S O'Neill + * @since 1.0 */ public interface Provider { + /** * Retrieves a DateTimeZone for the given id. All providers must at * least support id "UTC". @@ -74,5 +39,6 @@ * Returns an unmodifiable set of ids. All providers must at least * support id "UTC". */ - Set getAvailableIDs(); + Set getAvailableIDs(); + } Index: 3rdParty_sources/joda-time/org/joda/time/tz/UTCProvider.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/tz/UTCProvider.java (.../UTCProvider.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/tz/UTCProvider.java (.../UTCProvider.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,60 +1,23 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.tz; import java.util.Collections; import java.util.Set; + import org.joda.time.DateTimeZone; /** @@ -88,7 +51,7 @@ /** * Returns a singleton collection containing only "UTC". */ - public Set getAvailableIDs() { + public Set getAvailableIDs() { return Collections.singleton("UTC"); } Index: 3rdParty_sources/joda-time/org/joda/time/tz/ZoneInfoCompiler.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/tz/ZoneInfoCompiler.java (.../ZoneInfoCompiler.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/tz/ZoneInfoCompiler.java (.../ZoneInfoCompiler.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,60 +1,21 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2010 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.tz; import java.io.BufferedReader; -import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; @@ -65,22 +26,23 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.StringTokenizer; import java.util.TreeMap; +import java.util.Map.Entry; import org.joda.time.Chronology; import org.joda.time.DateTime; import org.joda.time.DateTimeField; import org.joda.time.DateTimeZone; +import org.joda.time.LocalDate; import org.joda.time.MutableDateTime; -import org.joda.time.format.DateTimeParser; -import org.joda.time.format.ISODateTimeFormat; -import org.joda.time.chrono.LenientChronology; import org.joda.time.chrono.ISOChronology; +import org.joda.time.chrono.LenientChronology; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; /** * Compiles Olson ZoneInfo database files into binary files for each time zone @@ -96,20 +58,36 @@ * may be safely invoked by multiple threads. * * @author Brian S O'Neill + * @since 1.0 */ public class ZoneInfoCompiler { static DateTimeOfYear cStartOfYear; static Chronology cLenientISO; + static ThreadLocal cVerbose = new ThreadLocal(); + static { + cVerbose.set(Boolean.FALSE); + } + /** + * Gets a flag indicating that verbose logging is required. + * @return true to log verbosely + */ + public static boolean verbose() { + return cVerbose.get(); + } + + //----------------------------------------------------------------------- + /** * Launches the ZoneInfoCompiler tool. * *

                  * Usage: java org.joda.time.tz.ZoneInfoCompiler <options> <source files>
                  * where possible options include:
                  *   -src <directory>    Specify where to read source files
                  *   -dst <directory>    Specify where to write generated files
            +     *   -verbose            Output verbosely (default false)
                  * 
            */ public static void main(String[] args) throws Exception { @@ -120,6 +98,7 @@ File inputDir = null; File outputDir = null; + boolean verbose = false; int i; for (i=0; i Specify where to read source files"); System.out.println(" -dst Specify where to write generated files"); + System.out.println(" -verbose Output verbosely (default false)"); } static DateTimeOfYear getStartOfYear() { @@ -178,18 +161,16 @@ /** * @param zimap maps string ids to DateTimeZone objects. */ - static void writeZoneInfoMap(DataOutputStream dout, Map zimap) throws IOException { + static void writeZoneInfoMap(DataOutputStream dout, Map zimap) throws IOException { // Build the string pool. - Map idToIndex = new HashMap(zimap.size()); - TreeMap indexToId = new TreeMap(); + Map idToIndex = new HashMap(zimap.size()); + TreeMap indexToId = new TreeMap(); - Iterator it = zimap.entrySet().iterator(); short count = 0; - while (it.hasNext()) { - Map.Entry entry = (Map.Entry)it.next(); + for (Entry entry : zimap.entrySet()) { String id = (String)entry.getKey(); if (!idToIndex.containsKey(id)) { - Short index = new Short(count); + Short index = Short.valueOf(count); idToIndex.put(id, index); indexToId.put(index, id); if (++count == 0) { @@ -198,7 +179,7 @@ } id = ((DateTimeZone)entry.getValue()).getID(); if (!idToIndex.containsKey(id)) { - Short index = new Short(count); + Short index = Short.valueOf(count); idToIndex.put(id, index); indexToId.put(index, id); if (++count == 0) { @@ -209,45 +190,20 @@ // Write the string pool, ordered by index. dout.writeShort(indexToId.size()); - it = indexToId.values().iterator(); - while (it.hasNext()) { - dout.writeUTF((String)it.next()); + for (String id : indexToId.values()) { + dout.writeUTF(id); } // Write the mappings. dout.writeShort(zimap.size()); - it = zimap.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = (Map.Entry)it.next(); - String id = (String)entry.getKey(); - dout.writeShort(((Short)idToIndex.get(id)).shortValue()); - id = ((DateTimeZone)entry.getValue()).getID(); - dout.writeShort(((Short)idToIndex.get(id)).shortValue()); + for (Entry entry : zimap.entrySet()) { + String id = entry.getKey(); + dout.writeShort(idToIndex.get(id).shortValue()); + id = entry.getValue().getID(); + dout.writeShort(idToIndex.get(id).shortValue()); } } - /** - * @param zimap gets filled with string id to string id mappings - */ - static void readZoneInfoMap(DataInputStream din, Map zimap) throws IOException { - // Read the string pool. - int size = din.readUnsignedShort(); - String[] pool = new String[size]; - for (int i=0; i transitions = new ArrayList(); while (true) { long next = tz.nextTransition(millis); @@ -352,7 +307,7 @@ return false; } - transitions.add(new Long(millis)); + transitions.add(Long.valueOf(millis)); offset = nextOffset; key = nextKey; @@ -371,7 +326,7 @@ millis = prev; - long trans = ((Long)transitions.get(i)).longValue(); + long trans = transitions.get(i).longValue(); if (trans - 1 != millis) { System.out.println("*r* Error in " + tz.getID() + " " @@ -388,18 +343,18 @@ } // Maps names to RuleSets. - private Map iRuleSets; + private Map iRuleSets; // List of Zone objects. - private List iZones; + private List iZones; // List String pairs to link. - private List iLinks; + private List iLinks; public ZoneInfoCompiler() { - iRuleSets = new HashMap(); - iZones = new ArrayList(); - iLinks = new ArrayList(); + iRuleSets = new HashMap(); + iZones = new ArrayList(); + iLinks = new ArrayList(); } /** @@ -408,7 +363,7 @@ * @param outputDir optional directory to write compiled data files to * @param sources optional list of source files to parse */ - public Map compile(File outputDir, File[] sources) throws IOException { + public Map compile(File outputDir, File[] sources) throws IOException { if (sources != null) { for (int i=0; i map = new TreeMap(); + System.out.println("Writing zoneinfo files"); for (int i=0; i 0) { System.out.println("Cannot find time zone '" + id + @@ -484,11 +445,14 @@ OutputStream out = new FileOutputStream(file); DataOutputStream dout = new DataOutputStream(out); - // Sort and filter out any duplicates that match case. - Map zimap = new TreeMap(String.CASE_INSENSITIVE_ORDER); - zimap.putAll(map); - writeZoneInfoMap(dout, zimap); - dout.close(); + try { + // Sort and filter out any duplicates that match case. + Map zimap = new TreeMap(String.CASE_INSENSITIVE_ORDER); + zimap.putAll(map); + writeZoneInfoMap(dout, zimap); + } finally { + dout.close(); + } } return map; @@ -498,7 +462,8 @@ Zone zone = null; String line; while ((line = in.readLine()) != null) { - if (line.length() == 0 || line.charAt(0) == '#') { + String trimmed = line.trim(); + if (trimmed.length() == 0 || trimmed.charAt(0) == '#') { continue; } @@ -528,7 +493,7 @@ String token = st.nextToken(); if (token.equalsIgnoreCase("Rule")) { Rule r = new Rule(st); - RuleSet rs = (RuleSet)iRuleSets.get(r.iName); + RuleSet rs = iRuleSets.get(r.iName); if (rs == null) { rs = new RuleSet(r); iRuleSets.put(r.iName, rs); @@ -551,7 +516,7 @@ } } - private static class DateTimeOfYear { + static class DateTimeOfYear { public final int iMonthOfYear; public final int iDayOfMonth; public final int iDayOfWeek; @@ -612,7 +577,17 @@ if (st.hasMoreTokens()) { str = st.nextToken(); zoneChar = parseZoneChar(str.charAt(str.length() - 1)); - millis = parseTime(str); + if (str.equals("24:00")) { + LocalDate date = (day == -1 ? + new LocalDate(2001, month, 1).plusMonths(1) : + new LocalDate(2001, month, day).plusDays(1)); + advance = (day != -1); + month = date.getMonthOfYear(); + day = date.getDayOfMonth(); + dayOfWeek = ((dayOfWeek - 1 + 1) % 7) + 1; + } else { + millis = parseTime(str); + } } } } @@ -735,15 +710,15 @@ } private static class RuleSet { - private List iRules; + private List iRules; RuleSet(Rule rule) { - iRules = new ArrayList(); + iRules = new ArrayList(); iRules.add(rule); } void addRule(Rule rule) { - if (!(rule.iName.equals(((Rule)iRules.get(0)).iName))) { + if (!(rule.iName.equals(iRules.get(0).iName))) { throw new IllegalArgumentException("Rule name mismatch"); } iRules.add(rule); @@ -754,7 +729,7 @@ */ public void addRecurring(DateTimeZoneBuilder builder, String nameFormat) { for (int i=0; i ruleSets) { addToBuilder(this, builder, ruleSets); } private static void addToBuilder(Zone zone, DateTimeZoneBuilder builder, - Map ruleSets) + Map ruleSets) { for (; zone != null; zone = zone.iNext) { builder.setStandardOffset(zone.iOffsetMillis); @@ -831,7 +808,7 @@ builder.setFixedSavings(zone.iFormat, saveMillis); } catch (Exception e) { - RuleSet rs = (RuleSet)ruleSets.get(zone.iRules); + RuleSet rs = ruleSets.get(zone.iRules); if (rs == null) { throw new IllegalArgumentException ("Rules not found: " + zone.iRules); Index: 3rdParty_sources/joda-time/org/joda/time/tz/ZoneInfoProvider.java =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/tz/ZoneInfoProvider.java (.../ZoneInfoProvider.java) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/tz/ZoneInfoProvider.java (.../ZoneInfoProvider.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,55 +1,17 @@ /* - * Joda Software License, Version 1.0 + * Copyright 2001-2009 Stephen Colebourne * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Copyright (c) 2001-2004 Stephen Colebourne. - * All rights reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Joda project (http://www.joda.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "Joda" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact licence@joda.org. - * - * 5. Products derived from this software may not be called "Joda", - * nor may "Joda" appear in their name, without prior written - * permission of the Joda project. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JODA AUTHORS OR THE PROJECT - * 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Joda project and was originally - * created by Stephen Colebourne . For more - * information on the Joda project, please see . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.joda.time.tz; @@ -59,10 +21,10 @@ import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReference; -import java.util.Collections; import java.util.Map; import java.util.Set; -import java.util.TreeMap; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; import org.joda.time.DateTimeZone; @@ -73,30 +35,19 @@ * ZoneInfoProvider is thread-safe and publicly immutable. * * @author Brian S O'Neill + * @since 1.0 */ public class ZoneInfoProvider implements Provider { - private static Map loadZoneInfoMap(InputStream in) throws IOException { - Map map = new TreeMap(String.CASE_INSENSITIVE_ORDER); - DataInputStream din = new DataInputStream(in); - try { - ZoneInfoCompiler.readZoneInfoMap(din, map); - } finally { - try { - din.close(); - } catch (IOException e) { - } - } - map.put("UTC", new SoftReference(DateTimeZone.UTC)); - return map; - } + /** The directory where the files are held. */ private final File iFileDir; + /** The resource path. */ private final String iResourcePath; + /** The class loader to use. */ private final ClassLoader iLoader; + /** Maps ids to strings or SoftReferences to DateTimeZones. */ + private final Map iZoneInfoMap; - // Maps ids to strings or SoftReferences to DateTimeZones. - private final Map iZoneInfoMap; - /** * ZoneInfoProvider searches the given directory for compiled data files. * @@ -172,12 +123,16 @@ iZoneInfoMap = loadZoneInfoMap(openResource("ZoneInfoMap")); } + //----------------------------------------------------------------------- /** * If an error is thrown while loading zone data, uncaughtException is * called to log the error and null is returned for this and all future * requests. + * + * @param id the id to load + * @return the loaded zone */ - public synchronized DateTimeZone getZone(String id) { + public DateTimeZone getZone(String id) { if (id == null) { return null; } @@ -192,8 +147,10 @@ return loadZoneData(id); } - if (obj instanceof SoftReference) { - DateTimeZone tz = (DateTimeZone)((SoftReference)obj).get(); + if (obj instanceof SoftReference) { + @SuppressWarnings("unchecked") + SoftReference ref = (SoftReference) obj; + DateTimeZone tz = ref.get(); if (tz != null) { return tz; } @@ -205,19 +162,35 @@ return getZone((String)obj); } - public synchronized Set getAvailableIDs() { - return Collections.unmodifiableSet(iZoneInfoMap.keySet()); + /** + * Gets a list of all the available zone ids. + * + * @return the zone ids + */ + public Set getAvailableIDs() { + // Return a copy of the keys rather than an umodifiable collection. + // This prevents ConcurrentModificationExceptions from being thrown by + // some JVMs if zones are opened while this set is iterated over. + return new TreeSet(iZoneInfoMap.keySet()); } /** - * Called if an exception is thrown from getZone while loading zone - * data. + * Called if an exception is thrown from getZone while loading zone data. + * + * @param ex the exception */ - protected void uncaughtException(Exception e) { + protected void uncaughtException(Exception ex) { Thread t = Thread.currentThread(); - t.getThreadGroup().uncaughtException(t, e); + t.getThreadGroup().uncaughtException(t, ex); } + /** + * Opens a resource from file or classpath. + * + * @param name the name to open + * @return the input stream + * @throws IOException if an error occurs + */ private InputStream openResource(String name) throws IOException { InputStream in; if (iFileDir != null) { @@ -230,35 +203,89 @@ in = ClassLoader.getSystemResourceAsStream(path); } if (in == null) { - StringBuffer buf = new StringBuffer(40); - buf.append("Resource not found: \""); - buf.append(path); - buf.append("\" ClassLoader: "); - buf.append(iLoader != null ? iLoader.toString() : "system"); + StringBuffer buf = new StringBuffer(40) + .append("Resource not found: \"") + .append(path) + .append("\" ClassLoader: ") + .append(iLoader != null ? iLoader.toString() : "system"); throw new IOException(buf.toString()); } } return in; } + /** + * Loads the time zone data for one id. + * + * @param id the id to load + * @return the zone + */ private DateTimeZone loadZoneData(String id) { InputStream in = null; try { in = openResource(id); DateTimeZone tz = DateTimeZoneBuilder.readFrom(in, id); - iZoneInfoMap.put(id, new SoftReference(tz)); + iZoneInfoMap.put(id, new SoftReference(tz)); return tz; - } catch (IOException e) { - uncaughtException(e); + } catch (IOException ex) { + uncaughtException(ex); iZoneInfoMap.remove(id); return null; } finally { try { if (in != null) { in.close(); } - } catch (IOException e) { + } catch (IOException ex) { } } } + + //----------------------------------------------------------------------- + /** + * Loads the zone info map. + * + * @param in the input stream + * @return the map + */ + private static Map loadZoneInfoMap(InputStream in) throws IOException { + Map map = new ConcurrentHashMap(); + DataInputStream din = new DataInputStream(in); + try { + readZoneInfoMap(din, map); + } finally { + try { + din.close(); + } catch (IOException ex) { + } + } + map.put("UTC", new SoftReference(DateTimeZone.UTC)); + return map; + } + + /** + * Reads the zone info map from file. + * + * @param din the input stream + * @param zimap gets filled with string id to string id mappings + */ + private static void readZoneInfoMap(DataInputStream din, Map zimap) throws IOException { + // Read the string pool. + int size = din.readUnsignedShort(); + String[] pool = new String[size]; + for (int i=0; iorg.joda.time.tz package Index: 3rdParty_sources/joda-time/org/joda/time/tz/src/Readme.txt =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/tz/src/Readme.txt (.../Readme.txt) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/tz/src/Readme.txt (.../Readme.txt) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,2 +1,2 @@ The data files in this directory were obtained from the public tz database, -http://www.twinsun.com/tz/tz-link.htm, version 2004g. +http://www.twinsun.com/tz/tz-link.htm, version 2011n. Index: 3rdParty_sources/joda-time/org/joda/time/tz/src/africa =================================================================== diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- 3rdParty_sources/joda-time/org/joda/time/tz/src/africa (.../africa) (revision 4e266757c429613d78b0fd2914d40d77a447daad) +++ 3rdParty_sources/joda-time/org/joda/time/tz/src/africa (.../africa) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -1,23 +1,26 @@ -# @(#)africa 7.36 +#
            +# @(#)africa	8.33
            +# This file is in the public domain, so clarified as of
            +# 2009-05-17 by Arthur David Olson.
             
             # This data is by no means authoritative; if you think you know better,
             # go ahead and edit the file (and please send any changes to
             # tz@elsie.nci.nih.gov for general use in the future).
             
            -# From Paul Eggert  (1999-03-22):
            +# From Paul Eggert (2006-03-22):
             #
             # A good source for time zone historical data outside the U.S. is
            -# Thomas G. Shanks, The International Atlas (5th edition),
            -# San Diego: ACS Publications, Inc. (1999).
            +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
            +# San Diego: ACS Publications, Inc. (2003).
             #
             # Gwillim Law writes that a good source
             # for recent time zone data is the International Air Transport
             # Association's Standard Schedules Information Manual (IATA SSIM),
             # published semiannually.  Law sent in several helpful summaries
             # of the IATA's data after 1990.
             #
            -# Except where otherwise noted, Shanks is the source for entries through 1990,
            -# and IATA SSIM is the source for entries after 1990.
            +# Except where otherwise noted, Shanks & Pottenger is the source for
            +# entries through 1990, and IATA SSIM is the source for entries afterwards.
             #
             # Another source occasionally used is Edward W. Whitman, World Time Differences,
             # Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
            @@ -28,7 +31,7 @@
             #
             # Previous editions of this database used WAT, CAT, SAT, and EAT
             # for +0:00 through +3:00, respectively,
            -# but Mark R V Murray  reports that
            +# but Mark R V Murray reports that
             # `SAST' is the official abbreviation for +2:00 in the country of South Africa,
             # `CAT' is commonly used for +2:00 in countries north of South Africa, and
             # `WAT' is probably the best name for +1:00, as the common phrase for
            @@ -55,7 +58,7 @@
             # I invented the following abbreviations; corrections are welcome!
             #	 2:00	WAST	West Africa Summer Time
             #	 2:30	BEAT	British East Africa Time (no longer used)
            -#	 2:44:45 BEAUT	British East Africa Unified Time (no longer used)
            +#	 2:45	BEAUT	British East Africa Unified Time (no longer used)
             #	 3:00	CAST	Central Africa Summer Time (no longer used)
             #	 3:00	SAST	South Africa Summer Time (no longer used)
             #	 3:00	EAT	East Africa Time
            @@ -64,7 +67,7 @@
             # Algeria
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Algeria	1916	only	-	Jun	14	23:00s	1:00	S
            -Rule	Algeria	1916	1919	-	Oct	Sun<=7	23:00s	0	-
            +Rule	Algeria	1916	1919	-	Oct	Sun>=1	23:00s	0	-
             Rule	Algeria	1917	only	-	Mar	24	23:00s	1:00	S
             Rule	Algeria	1918	only	-	Mar	 9	23:00s	1:00	S
             Rule	Algeria	1919	only	-	Mar	 1	23:00s	1:00	S
            @@ -74,7 +77,7 @@
             Rule	Algeria	1921	only	-	Jun	21	23:00s	0	-
             Rule	Algeria	1939	only	-	Sep	11	23:00s	1:00	S
             Rule	Algeria	1939	only	-	Nov	19	 1:00	0	-
            -Rule	Algeria	1944	1945	-	Apr	Mon<=7	 2:00	1:00	S
            +Rule	Algeria	1944	1945	-	Apr	Mon>=1	 2:00	1:00	S
             Rule	Algeria	1944	only	-	Oct	 8	 2:00	0	-
             Rule	Algeria	1945	only	-	Sep	16	 1:00	0	-
             Rule	Algeria	1971	only	-	Apr	25	23:00s	1:00	S
            @@ -85,7 +88,8 @@
             Rule	Algeria	1978	only	-	Sep	22	 3:00	0	-
             Rule	Algeria	1980	only	-	Apr	25	 0:00	1:00	S
             Rule	Algeria	1980	only	-	Oct	31	 2:00	0	-
            -# Shanks gives 0:09 for Paris Mean Time; go with Howse's more precise 0:09:21.
            +# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
            +# more precise 0:09:21.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Africa/Algiers	0:12:12 -	LMT	1891 Mar 15 0:01
             			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
            @@ -105,7 +109,8 @@
             			1:00	-	WAT
             
             # Benin
            -# Whitman says they switched to 1:00 in 1946, not 1934; go with Shanks.
            +# Whitman says they switched to 1:00 in 1946, not 1934;
            +# go with Shanks & Pottenger.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Africa/Porto-Novo	0:10:28	-	LMT	1912
             			0:00	-	GMT	1934 Feb 26
            @@ -129,7 +134,7 @@
             			2:00	-	CAT
             
             # Cameroon
            -# Whitman says they switched to 1:00 in 1920; go with Shanks.
            +# Whitman says they switched to 1:00 in 1920; go with Shanks & Pottenger.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Africa/Douala	0:38:48	-	LMT	1912
             			1:00	-	WAT
            @@ -207,9 +212,123 @@
             Rule	Egypt	1990	1994	-	May	 1	1:00	1:00	S
             # IATA (after 1990) says transitions are at 0:00.
             # Go with IATA starting in 1995, except correct 1995 entry from 09-30 to 09-29.
            -Rule	Egypt	1995	max	-	Apr	lastFri	 0:00s	1:00	S
            -Rule	Egypt	1995	max	-	Sep	lastThu	23:00s	0	-
             
            +# From Alexander Krivenyshev (2011-04-20):
            +# "...Egypt's interim cabinet decided on Wednesday to cancel daylight
            +# saving time after a poll posted on its website showed the majority of
            +# Egyptians would approve the cancellation."
            +#
            +# Egypt to cancel daylight saving time
            +# 
            +# http://www.almasryalyoum.com/en/node/407168
            +# 
            +# or
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_egypt04.html
            +# 
            +Rule	Egypt	1995	2010	-	Apr	lastFri	 0:00s	1:00	S
            +Rule	Egypt	1995	2005	-	Sep	lastThu	23:00s	0	-
            +# From Steffen Thorsen (2006-09-19):
            +# The Egyptian Gazette, issue 41,090 (2006-09-18), page 1, reports:
            +# Egypt will turn back clocks by one hour at the midnight of Thursday
            +# after observing the daylight saving time since May.
            +# http://news.gom.com.eg/gazette/pdf/2006/09/18/01.pdf
            +Rule	Egypt	2006	only	-	Sep	21	23:00s	0	-
            +# From Dirk Losch (2007-08-14):
            +# I received a mail from an airline which says that the daylight
            +# saving time in Egypt will end in the night of 2007-09-06 to 2007-09-07.
            +# From Jesper Norgaard Welen (2007-08-15): [The following agree:]
            +# http://www.nentjes.info/Bill/bill5.htm 
            +# http://www.timeanddate.com/worldclock/city.html?n=53
            +# From Steffen Thorsen (2007-09-04): The official information...:
            +# http://www.sis.gov.eg/En/EgyptOnline/Miscellaneous/000002/0207000000000000001580.htm
            +Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
            +# From Abdelrahman Hassan (2007-09-06):
            +# Due to the Hijri (lunar Islamic calendar) year being 11 days shorter
            +# than the year of the Gregorian calendar, Ramadan shifts earlier each
            +# year. This year it will be observed September 13 (September is quite
            +# hot in Egypt), and the idea is to make fasting easier for workers by
            +# shifting business hours one hour out of daytime heat. Consequently,
            +# unless discontinued, next DST may end Thursday 28 August 2008.
            +# From Paul Eggert (2007-08-17):
            +# For lack of better info, assume the new rule is last Thursday in August.
            +
            +# From Petr Machata (2009-04-06):
            +# The following appeared in Red Hat bugzilla[1] (edited):
            +#
            +# > $ zdump -v /usr/share/zoneinfo/Africa/Cairo | grep 2009
            +# > /usr/share/zoneinfo/Africa/Cairo  Thu Apr 23 21:59:59 2009 UTC = Thu =
            +# Apr 23
            +# > 23:59:59 2009 EET isdst=0 gmtoff=7200
            +# > /usr/share/zoneinfo/Africa/Cairo  Thu Apr 23 22:00:00 2009 UTC = Fri =
            +# Apr 24
            +# > 01:00:00 2009 EEST isdst=1 gmtoff=10800
            +# > /usr/share/zoneinfo/Africa/Cairo  Thu Aug 27 20:59:59 2009 UTC = Thu =
            +# Aug 27
            +# > 23:59:59 2009 EEST isdst=1 gmtoff=10800
            +# > /usr/share/zoneinfo/Africa/Cairo  Thu Aug 27 21:00:00 2009 UTC = Thu =
            +# Aug 27
            +# > 23:00:00 2009 EET isdst=0 gmtoff=7200
            +#
            +# > end date should be Thu Sep 24 2009 (Last Thursday in September at 23:59=
            +# :59)
            +# > http://support.microsoft.com/kb/958729/
            +#
            +# timeanddate[2] and another site I've found[3] also support that.
            +#
            +# [1] 
            +# https://bugzilla.redhat.com/show_bug.cgi?id=492263
            +# 
            +# [2] 
            +# http://www.timeanddate.com/worldclock/clockchange.html?n=53
            +# 
            +# [3] 
            +# http://wwp.greenwichmeantime.com/time-zone/africa/egypt/
            +# 
            +
            +# From Arthur David Olson (2009-04-20):
            +# In 2009 (and for the next several years), Ramadan ends before the fourth
            +# Thursday in September; Egypt is expected to revert to the last Thursday
            +# in September.
            +
            +# From Steffen Thorsen (2009-08-11):
            +# We have been able to confirm the August change with the Egyptian Cabinet 
            +# Information and Decision Support Center:
            +# 
            +# http://www.timeanddate.com/news/time/egypt-dst-ends-2009.html
            +# 
            +# 
            +# The Middle East News Agency
            +# 
            +# http://www.mena.org.eg/index.aspx
            +# 
            +# also reports "Egypt starts winter time on August 21"
            +# today in article numbered "71, 11/08/2009 12:25 GMT." 
            +# Only the title above is available without a subscription to their service,
            +# and can be found by searching for "winter" in their search engine
            +# (at least today).
            +
            +# From Alexander Krivenyshev (2010-07-20):
            +# According to News from Egypt -  Al-Masry Al-Youm Egypt's cabinet has
            +# decided that Daylight Saving Time will not be used in Egypt during
            +# Ramadan.
            +#
            +# Arabic translation:
            +# "Clocks to go back during Ramadan--and then forward again"
            +# 
            +# http://www.almasryalyoum.com/en/news/clocks-go-back-during-ramadan-and-then-forward-again
            +# 
            +# or
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_egypt02.html
            +# 
            +
            +Rule	Egypt	2008	only	-	Aug	lastThu	23:00s	0	-
            +Rule	Egypt	2009	only	-	Aug	20	23:00s	0	-
            +Rule	Egypt	2010	only	-	Aug	11	0:00	0	-
            +Rule	Egypt	2010	only	-	Sep	10	0:00	1:00	S
            +Rule	Egypt	2010	only	-	Sep	lastThu	23:00s	0	-
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Africa/Cairo	2:05:00 -	LMT	1900 Oct
             			2:00	Egypt	EE%sT
            @@ -222,15 +341,15 @@
             
             # Eritrea
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone	Africa/Asmera	2:35:32 -	LMT	1870
            -			2:35:32	-	AMT	1890	      # Asmera Mean Time
            +Zone	Africa/Asmara	2:35:32 -	LMT	1870
            +			2:35:32	-	AMT	1890	      # Asmara Mean Time
             			2:35:20	-	ADMT	1936 May 5    # Adis Dera MT
             			3:00	-	EAT
             
             # Ethiopia
            -# From Paul Eggert (1997-10-05):
            -# Shanks writes that Ethiopia had six narrowly-spaced time zones between
            -# 1870 and 1890, and that they merged to 38E50 (2:35:20) in 1890.
            +# From Paul Eggert (2006-03-22):
            +# Shanks & Pottenger write that Ethiopia had six narrowly-spaced time zones
            +# between 1870 and 1890, and that they merged to 38E50 (2:35:20) in 1890.
             # We'll guess that 38E50 is for Adis Dera.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Africa/Addis_Ababa	2:34:48 -	LMT	1870
            @@ -251,7 +370,8 @@
             
             # Ghana
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -# Whitman says DST was observed from 1931 to ``the present''; go with Shanks.
            +# Whitman says DST was observed from 1931 to ``the present'';
            +# go with Shanks & Pottenger.
             Rule	Ghana	1936	1942	-	Sep	 1	0:00	0:20	GHST
             Rule	Ghana	1936	1942	-	Dec	31	0:00	0	GMT
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            @@ -276,7 +396,7 @@
             Zone	Africa/Nairobi	2:27:16	-	LMT	1928 Jul
             			3:00	-	EAT	1930
             			2:30	-	BEAT	1940
            -			2:44:45	-	BEAUT	1960
            +			2:45	-	BEAUT	1960
             			3:00	-	EAT
             
             # Lesotho
            @@ -287,13 +407,14 @@
             			2:00	-	SAST
             
             # Liberia
            -# From Paul Eggert  (2001-07-17):
            +# From Paul Eggert (2006-03-22):
             # In 1972 Liberia was the last country to switch
             # from a UTC offset that was not a multiple of 15 or 20 minutes.
             # Howse reports that it was in honor of their president's birthday.
            -# Shanks reports the date as May 1, whereas Howse reports Jan; go with Shanks.
            -# For Liberia before 1972, Shanks reports -0:44, whereas Howse and Whitman
            -# each report -0:44:30; go with the more precise figure.
            +# Shank & Pottenger report the date as May 1, whereas Howse reports Jan;
            +# go with Shanks & Pottenger.
            +# For Liberia before 1972, Shanks & Pottenger report -0:44, whereas Howse and
            +# Whitman each report -0:44:30; go with the more precise figure.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Africa/Monrovia	-0:43:08 -	LMT	1882
             			-0:43:08 -	MMT	1919 Mar # Monrovia Mean Time
            @@ -317,13 +438,13 @@
             Rule	Libya	1986	only	-	Apr	 4	0:00	1:00	S
             Rule	Libya	1986	only	-	Oct	 3	0:00	0	-
             Rule	Libya	1987	1989	-	Apr	 1	0:00	1:00	S
            -Rule	Libya	1987	1990	-	Oct	 1	0:00	0	-
            +Rule	Libya	1987	1989	-	Oct	 1	0:00	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Africa/Tripoli	0:52:44 -	LMT	1920
             			1:00	Libya	CE%sT	1959
             			2:00	-	EET	1982
             			1:00	Libya	CE%sT	1990 May  4
            -# The following entries are all from Shanks;
            +# The following entries are from Shanks & Pottenger;
             # the IATA SSIM data contain some obvious errors.
             			2:00	-	EET	1996 Sep 30
             			1:00	-	CET	1997 Apr  4
            @@ -348,9 +469,6 @@
             			 0:00	-	GMT	1934 Feb 26
             			-1:00	-	WAT	1960 Jun 20
             			 0:00	-	GMT
            -# no longer different from Bamako, but too famous to omit
            -Zone	Africa/Timbuktu	-0:12:04 -	LMT	1912
            -			 0:00	-	GMT
             
             # Mauritania
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            @@ -360,9 +478,110 @@
             			 0:00	-	GMT
             
             # Mauritius
            +
            +# From Steffen Thorsen (2008-06-25):
            +# Mauritius plans to observe DST from 2008-11-01 to 2009-03-31 on a trial
            +# basis....
            +# It seems that Mauritius observed daylight saving time from 1982-10-10 to 
            +# 1983-03-20 as well, but that was not successful....
            +# http://www.timeanddate.com/news/time/mauritius-daylight-saving-time.html
            +
            +# From Alex Krivenyshev (2008-06-25):
            +# http://economicdevelopment.gov.mu/portal/site/Mainhomepage/menuitem.a42b24128104d9845dabddd154508a0c/?content_id=0a7cee8b5d69a110VgnVCM1000000a04a8c0RCRD
            +
            +# From Arthur David Olson (2008-06-30):
            +# The www.timeanddate.com article cited by Steffen Thorsen notes that "A
            +# final decision has yet to be made on the times that daylight saving
            +# would begin and end on these dates." As a place holder, use midnight.
            +
            +# From Paul Eggert (2008-06-30):
            +# Follow Thorsen on DST in 1982/1983, instead of Shanks & Pottenger.
            +
            +# From Steffen Thorsen (2008-07-10):
            +# According to
            +# 
            +# http://www.lexpress.mu/display_article.php?news_id=111216
            +# 
            +# (in French), Mauritius will start and end their DST a few days earlier
            +# than previously announced (2008-11-01 to 2009-03-31).  The new start
            +# date is 2008-10-26 at 02:00 and the new end date is 2009-03-27 (no time
            +# given, but it is probably at either 2 or 3 wall clock time).
            +# 
            +# A little strange though, since the article says that they moved the date 
            +# to align itself with Europe and USA which also change time on that date, 
            +# but that means they have not paid attention to what happened in 
            +# USA/Canada last year (DST ends first Sunday in November). I also wonder 
            +# why that they end on a Friday, instead of aligning with Europe which 
            +# changes two days later.
            +
            +# From Alex Krivenyshev (2008-07-11):
            +# Seems that English language article "The revival of daylight saving
            +# time:  Energy conservation?"-# No. 16578 (07/11/2008) was originally
            +# published on Monday, June 30, 2008...
            +#
            +# I guess that article in French "Le gouvernement avance l'introduction
            +# de l'heure d'ete" stating that DST in Mauritius starting on October 26
            +# and ending on March 27, 2009 is the most recent one.
            +# ...
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_mauritius02.html
            +# 
            +
            +# From Riad M. Hossen Ally (2008-08-03):
            +# The Government of Mauritius weblink
            +# 
            +# http://www.gov.mu/portal/site/pmosite/menuitem.4ca0efdee47462e7440a600248a521ca/?content_id=4728ca68b2a5b110VgnVCM1000000a04a8c0RCRD
            +# 
            +# Cabinet Decision of July 18th, 2008 states as follows:
            +#
            +# 4. ...Cabinet has agreed to the introduction into the National Assembly
            +# of the Time Bill which provides for the introduction of summer time in
            +# Mauritius. The summer time period which will be of one hour ahead of
            +# the standard time, will be aligned with that in Europe and the United
            +# States of America. It will start at two o'clock in the morning on the
            +# last Sunday of October and will end at two o'clock in the morning on
            +# the last Sunday of March the following year. The summer time for the
            +# year 2008 - 2009 will, therefore, be effective as from 26 October 2008
            +# and end on 29 March 2009.
            +
            +# From Ed Maste (2008-10-07):
            +# THE TIME BILL (No. XXVII of 2008) Explanatory Memorandum states the
            +# beginning / ending of summer time is 2 o'clock standard time in the
            +# morning of the last Sunday of October / last Sunday of March.
            +# 
            +# http://www.gov.mu/portal/goc/assemblysite/file/bill2708.pdf
            +# 
            +
            +# From Steffen Thorsen (2009-06-05):
            +# According to several sources, Mauritius will not continue to observe
            +# DST the coming summer...
            +#
            +# Some sources, in French:
            +# 
            +# http://www.defimedia.info/news/946/Rashid-Beebeejaun-:-%C2%AB-L%E2%80%99heure-d%E2%80%99%C3%A9t%C3%A9-ne-sera-pas-appliqu%C3%A9e-cette-ann%C3%A9e-%C2%BB
            +# 
            +# 
            +# http://lexpress.mu/Story/3398~Beebeejaun---Les-objectifs-d-%C3%A9conomie-d-%C3%A9nergie-de-l-heure-d-%C3%A9t%C3%A9-ont-%C3%A9t%C3%A9-atteints-
            +# 
            +#
            +# Our wrap-up:
            +# 
            +# http://www.timeanddate.com/news/time/mauritius-dst-will-not-repeat.html
            +# 
            +
            +# From Arthur David Olson (2009-07-11):
            +# The "mauritius-dst-will-not-repeat" wrapup includes this: 
            +# "The trial ended on March 29, 2009, when the clocks moved back by one hour
            +# at 2am (or 02:00) local time..."
            +
            +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            +Rule Mauritius	1982	only	-	Oct	10	0:00	1:00	S
            +Rule Mauritius	1983	only	-	Mar	21	0:00	0	-
            +Rule Mauritius	2008	only	-	Oct	lastSun	2:00	1:00	S
            +Rule Mauritius	2009	only	-	Mar	lastSun	2:00	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Indian/Mauritius	3:50:00 -	LMT	1907		# Port Louis
            -			4:00	-	MUT	# Mauritius Time
            +			4:00 Mauritius	MU%sT	# Mauritius Time
             # Agalega Is, Rodriguez
             # no information; probably like Indian/Mauritius
             
            @@ -373,7 +592,184 @@
             
             # Morocco
             # See the `europe' file for Spanish Morocco (Africa/Ceuta).
            +
            +# From Alex Krivenyshev (2008-05-09):
            +# Here is an article that Morocco plan to introduce Daylight Saving Time between
            +# 1 June, 2008 and 27 September, 2008.
            +#
            +# "... Morocco is to save energy by adjusting its clock during summer so it will
            +# be one hour ahead of GMT between 1 June and 27 September, according to
            +# Communication Minister and Gov ernment Spokesman, Khalid Naciri...."
            +#
            +# 
            +# http://www.worldtimezone.net/dst_news/dst_news_morocco01.html
            +# 
            +# OR
            +# 
            +# http://en.afrik.com/news11892.html
            +# 
            +
            +# From Alex Krivenyshev (2008-05-09):
            +# The Morocco time change can be confirmed on Morocco web site Maghreb Arabe Presse:
            +# 
            +# http://www.map.ma/eng/sections/box3/morocco_shifts_to_da/view
            +# 
            +#
            +# Morocco shifts to daylight time on June 1st through September 27, Govt.
            +# spokesman.
            +
            +# From Patrice Scattolin (2008-05-09):
            +# According to this article:
            +# 
            +# http://www.avmaroc.com/actualite/heure-dete-comment-a127896.html
            +# 
            +# (and republished here:
            +# 
            +# http://www.actu.ma/heure-dete-comment_i127896_0.html
            +# 
            +# )
            +# the changes occurs at midnight:
            +#
            +# saturday night may 31st at midnight (which in french is to be
            +# intrepreted as the night between saturday and sunday)
            +# sunday night the 28th  at midnight
            +#
            +# Seeing that the 28th is monday, I am guessing that she intends to say
            +# the midnight of the 28th which is the midnight between sunday and
            +# monday, which jives with other sources that say that it's inclusive
            +# june1st to sept 27th.
            +#
            +# The decision was taken by decree *2-08-224 *but I can't find the decree
            +# published on the web.
            +#
            +# It's also confirmed here:
            +# 
            +# http://www.maroc.ma/NR/exeres/FACF141F-D910-44B0-B7FA-6E03733425D1.htm
            +# 
            +# on a government portal as being  between june 1st and sept 27th (not yet
            +# posted in english).
            +#
            +# The following google query will generate many relevant hits:
            +# 
            +# http://www.google.com/search?hl=en&q=Conseil+de+gouvernement+maroc+heure+avance&btnG=Search
            +# 
            +
            +# From Alex Krivenyshev (2008-05-09):
            +# Is Western Sahara (part which administrated by Morocco) going to follow
            +# Morocco DST changes?  Any information?  What about other part of
            +# Western Sahara - under administration of POLISARIO Front (also named
            +# SADR Saharawi Arab Democratic Republic)?
            +
            +# From Arthur David Olson (2008-05-09):
            +# XXX--guess that it is only Morocco for now; guess only 2008 for now.
            +
            +# From Steffen Thorsen (2008-08-27):
            +# Morocco will change the clocks back on the midnight between August 31 
            +# and September 1. They originally planned to observe DST to near the end 
            +# of September:
            +#
            +# One article about it (in French):
            +# 
            +# http://www.menara.ma/fr/Actualites/Maroc/Societe/ci.retour_a_l_heure_gmt_a_partir_du_dimanche_31_aout_a_minuit_officiel_.default
            +# 
            +#
            +# We have some further details posted here:
            +# 
            +# http://www.timeanddate.com/news/time/morocco-ends-dst-early-2008.html
            +# 
            +
            +# From Steffen Thorsen (2009-03-17):
            +# Morocco will observe DST from 2009-06-01 00:00 to 2009-08-21 00:00 according
            +# to many sources, such as
            +# 
            +# http://news.marweb.com/morocco/entertainment/morocco-daylight-saving.html
            +# 
            +# 
            +# http://www.medi1sat.ma/fr/depeche.aspx?idp=2312
            +# 
            +# (French)
            +#
            +# Our summary:
            +# 
            +# http://www.timeanddate.com/news/time/morocco-starts-dst-2009.html
            +# 
            +
            +# From Alexander Krivenyshev (2009-03-17):
            +# Here is a link to official document from Royaume du Maroc Premier Ministre,
            +# Ministere de la Modernisation des Secteurs Publics
            +#
            +# Under Article 1 of Royal Decree No. 455-67 of Act 23 safar 1387 (2 june 1967)
            +# concerning the amendment of the legal time, the Ministry of Modernization of
            +# Public Sectors announced that the official time in the Kingdom will be
            +# advanced 60 minutes from Sunday 31 May 2009 at midnight.
            +#
            +# 
            +# http://www.mmsp.gov.ma/francais/Actualites_fr/PDF_Actualites_Fr/HeureEte_FR.pdf
            +# 
            +#
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_morocco03.html
            +# 
            +
            +# From Steffen Thorsen (2010-04-13):
            +# Several news media in Morocco report that the Ministry of Modernization
            +# of Public Sectors has announced that Morocco will have DST from
            +# 2010-05-02 to 2010-08-08.
            +#
            +# Example:
            +# 
            +# http://www.lavieeco.com/actualites/4099-le-maroc-passera-a-l-heure-d-ete-gmt1-le-2-mai.html
            +# 
            +# (French)
            +# Our page:
            +# 
            +# http://www.timeanddate.com/news/time/morocco-starts-dst-2010.html
            +# 
            +
            +# From Dan Abitol (2011-03-30):
            +# ...Rules for Africa/Casablanca are the following (24h format)
            +# The 3rd april 2011 at 00:00:00, [it] will be 3rd april 1:00:00
            +# The 31th july 2011 at 00:59:59,  [it] will be 31th July 00:00:00
            +# ...Official links of change in morocco
            +# The change was broadcast on the FM Radio
            +# I ve called ANRT (telecom regulations in Morocco) at
            +# +212.537.71.84.00
            +# 
            +# http://www.anrt.net.ma/fr/
            +# 
            +# They said that
            +# 
            +# http://www.map.ma/fr/sections/accueil/l_heure_legale_au_ma/view
            +# 
            +# is the official publication to look at.
            +# They said that the decision was already taken.
            +#
            +# More articles in the press
            +# 
            +# http://www.yabiladi.com/articles/details/5058/secret-l-heure-d-ete-maroc-lev
            +# 
            +# e.html
            +# 
            +# http://www.lematin.ma/Actualite/Express/Article.asp?id=148923
            +# 
            +# 
            +# http://www.lavieeco.com/actualite/Le-Maroc-passe-sur-GMT%2B1-a-partir-de-dim
            +# anche-prochain-5538.html
            +# 
            +
            +# From Petr Machata (2011-03-30):
            +# They have it written in English here:
            +# 
            +# http://www.map.ma/eng/sections/home/morocco_to_spring_fo/view
            +# 
            +#
            +# It says there that "Morocco will resume its standard time on July 31,
            +# 2011 at midnight." Now they don't say whether they mean midnight of
            +# wall clock time (i.e. 11pm UTC), but that's what I would assume. It has
            +# also been like that in the past.
            +
             # RULE	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            +
             Rule	Morocco	1939	only	-	Sep	12	 0:00	1:00	S
             Rule	Morocco	1939	only	-	Nov	19	 0:00	0	-
             Rule	Morocco	1940	only	-	Feb	25	 0:00	1:00	S
            @@ -389,11 +785,19 @@
             Rule	Morocco	1977	only	-	Sep	28	 0:00	0	-
             Rule	Morocco	1978	only	-	Jun	 1	 0:00	1:00	S
             Rule	Morocco	1978	only	-	Aug	 4	 0:00	0	-
            +Rule	Morocco	2008	only	-	Jun	 1	 0:00	1:00	S
            +Rule	Morocco	2008	only	-	Sep	 1	 0:00	0	-
            +Rule	Morocco	2009	only	-	Jun	 1	 0:00	1:00	S
            +Rule	Morocco	2009	only	-	Aug	 21	 0:00	0	-
            +Rule	Morocco	2010	only	-	May	 2	 0:00	1:00	S
            +Rule	Morocco	2010	only	-	Aug	 8	 0:00	0	-
            +Rule	Morocco	2011	only	-	Apr	 3	 0:00	1:00	S
            +Rule	Morocco	2011	only	-	Jul	 31	 0	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Africa/Casablanca	-0:30:20 -	LMT	1913 Oct 26
             			 0:00	Morocco	WE%sT	1984 Mar 16
             			 1:00	-	CET	1986
            -			 0:00	-	WET
            +			 0:00	Morocco	WE%sT
             # Western Sahara
             Zone Africa/El_Aaiun	-0:52:48 -	LMT	1934 Jan
             			-1:00	-	WAT	1976 Apr 14
            @@ -405,8 +809,22 @@
             			2:00	-	CAT
             
             # Namibia
            -# The 1994-04-03 transition is from Shanks.
            -# Shanks reports no DST after 1998-04; go with IATA.
            +# The 1994-04-03 transition is from Shanks & Pottenger.
            +# Shanks & Pottenger report no DST after 1998-04; go with IATA.
            +
            +# From Petronella Sibeene (2007-03-30) in
            +# :
            +# While the entire country changes its time, Katima Mulilo and other
            +# settlements in Caprivi unofficially will not because the sun there
            +# rises and sets earlier compared to other regions.  Chief of
            +# Forecasting Riaan van Zyl explained that the far eastern parts of
            +# the country are close to 40 minutes earlier in sunrise than the rest
            +# of the country.
            +# 
            +# From Paul Eggert (2007-03-31):
            +# Apparently the Caprivi Strip informally observes Botswana time, but
            +# we have no details.  In the meantime people there can use Africa/Gaborone.
            +
             # RULE	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Namibia	1994	max	-	Sep	Sun>=1	2:00	1:00	S
             Rule	Namibia	1995	max	-	Apr	Sun>=1	2:00	0	-
            @@ -490,7 +908,7 @@
             
             # Sierra Leone
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -# Whitman gives Mar 31 - Aug 31 for 1931 on; go with Shanks.
            +# Whitman gives Mar 31 - Aug 31 for 1931 on; go with Shanks & Pottenger.
             Rule	SL	1935	1942	-	Jun	 1	0:00	0:40	SLST
             Rule	SL	1935	1942	-	Oct	 1	0:00	0	WAT
             Rule	SL	1957	1962	-	Jun	 1	0:00	1:00	SLST
            @@ -539,6 +957,11 @@
             			2:00	Sudan	CA%sT	2000 Jan 15 12:00
             			3:00	-	EAT
             
            +# South Sudan
            +Zone	Africa/Juba	2:06:24 -	LMT	1931
            +			2:00	Sudan	CA%sT	2000 Jan 15 12:00
            +			3:00	-	EAT
            +
             # Swaziland
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Africa/Mbabane	2:04:24 -	LMT	1903 Mar
            @@ -548,7 +971,7 @@
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Africa/Dar_es_Salaam 2:37:08 -	LMT	1931
             			3:00	-	EAT	1948
            -			2:44:45	-	BEAUT	1961
            +			2:45	-	BEAUT	1961
             			3:00	-	EAT
             
             # Togo
            @@ -557,6 +980,83 @@
             			0:00	-	GMT
             
             # Tunisia
            +
            +# From Gwillim Law (2005-04-30):
            +# My correspondent, Risto Nykanen, has alerted me to another adoption of DST,
            +# this time in Tunisia.  According to Yahoo France News
            +# , in a story attributed to AP
            +# and dated 2005-04-26, "Tunisia has decided to advance its official time by
            +# one hour, starting on Sunday, May 1.  Henceforth, Tunisian time will be
            +# UTC+2 instead of UTC+1.  The change will take place at 23:00 UTC next
            +# Saturday."  (My translation)
            +#
            +# From Oscar van Vlijmen (2005-05-02):
            +# LaPresse, the first national daily newspaper ...
            +# 
            +# ... DST for 2005: on: Sun May 1 0h standard time, off: Fri Sept. 30,
            +# 1h standard time.
            +#
            +# From Atef Loukil (2006-03-28):
            +# The daylight saving time will be the same each year:
            +# Beginning      : the last Sunday of March at 02:00
            +# Ending         : the last Sunday of October at 03:00 ...
            +# http://www.tap.info.tn/en/index.php?option=com_content&task=view&id=1188&Itemid=50
            +
            +# From Steffen Thorsen (2009-03-16):
            +# According to several news sources, Tunisia will not observe DST this year.
            +# (Arabic)
            +# 
            +# http://www.elbashayer.com/?page=viewn&nid=42546
            +# 
            +# 
            +# http://www.babnet.net/kiwidetail-15295.asp
            +# 
            +#
            +# We have also confirmed this with the US embassy in Tunisia.
            +# We have a wrap-up about this on the following page:
            +# 
            +# http://www.timeanddate.com/news/time/tunisia-cancels-dst-2009.html
            +# 
            +
            +# From Alexander Krivenyshev (2009-03-17):
            +# Here is a link to Tunis Afrique Presse News Agency
            +#
            +# Standard time to be kept the whole year long (tap.info.tn):
            +#
            +# (in English)
            +# 
            +# http://www.tap.info.tn/en/index.php?option=com_content&task=view&id=26813&Itemid=157
            +# 
            +#
            +# (in Arabic)
            +# 
            +# http://www.tap.info.tn/ar/index.php?option=com_content&task=view&id=61240&Itemid=1
            +# 
            +
            +# From Arthur David Olson (2009--3-18):
            +# The Tunis Afrique Presse News Agency notice contains this: "This measure is due to the fact
            +# that the fasting month of ramadan coincides with the period concerned by summer time.
            +# Therefore, the standard time will be kept unchanged the whole year long."
            +# So foregoing DST seems to be an exception (albeit one that may be repeated in the  future).
            +
            +# From Alexander Krivenyshev (2010-03-27):
            +# According to some news reports Tunis confirmed not to use DST in 2010
            +#
            +# (translation):
            +# "The Tunisian government has decided to abandon DST, which was scheduled on
            +# Sunday...
            +# Tunisian authorities had suspended the DST for the first time last year also
            +# coincided with the month of Ramadan..."
            +#
            +# (in Arabic)
            +# 
            +# http://www.moheet.com/show_news.aspx?nid=358861&pg=1
            +# 
            +# http://www.almadenahnews.com/newss/news.php?c=118&id=38036
            +# or
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_tunis02.html
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Tunisia	1939	only	-	Apr	15	23:00s	1:00	S
             Rule	Tunisia	1939	only	-	Nov	18	23:00s	0	-
            @@ -579,8 +1079,14 @@
             Rule	Tunisia	1988	1990	-	Sep	lastSun	 0:00s	0	-
             Rule	Tunisia	1989	only	-	Mar	26	 0:00s	1:00	S
             Rule	Tunisia	1990	only	-	May	 1	 0:00s	1:00	S
            -# Shanks gives 0:09 for Paris Mean Time; go with Howse's more precise 0:09:21.
            -# Shanks says the 1911 switch occurred on Mar 9; go with Howse's Mar 11.
            +Rule	Tunisia	2005	only	-	May	 1	 0:00s	1:00	S
            +Rule	Tunisia	2005	only	-	Sep	30	 1:00s	0	-
            +Rule	Tunisia	2006	2008	-	Mar	lastSun	 2:00s	1:00	S
            +Rule	Tunisia	2006	2008	-	Oct	lastSun	 2:00s	0	-
            +
            +# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
            +# more precise 0:09:21.
            +# Shanks & Pottenger say the 1911 switch was on Mar 9; go with Howse's Mar 11.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Africa/Tunis	0:40:44 -	LMT	1881 May 12
             			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
            @@ -591,7 +1097,7 @@
             Zone	Africa/Kampala	2:09:40 -	LMT	1928 Jul
             			3:00	-	EAT	1930
             			2:30	-	BEAT	1948
            -			2:44:45	-	BEAUT	1957
            +			2:45	-	BEAUT	1957
             			3:00	-	EAT
             
             # Zambia
            Index: 3rdParty_sources/joda-time/org/joda/time/tz/src/antarctica
            ===================================================================
            diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/joda-time/org/joda/time/tz/src/antarctica	(.../antarctica)	(revision 4e266757c429613d78b0fd2914d40d77a447daad)
            +++ 3rdParty_sources/joda-time/org/joda/time/tz/src/antarctica	(.../antarctica)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -1,4 +1,7 @@
            -# @(#)antarctica	7.23
            +# 
            +# @(#)antarctica	8.9
            +# This file is in the public domain, so clarified as of
            +# 2009-05-17 by Arthur David Olson.
             
             # From Paul Eggert (1999-11-15):
             # To keep things manageable, we list only locations occupied year-round; see
            @@ -16,36 +19,59 @@
             # I made up all time zone abbreviations mentioned here; corrections welcome!
             # FORMAT is `zzz' and GMTOFF is 0 for locations while uninhabited.
             
            -# These rules are stolen from the `europe' file.
            -# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -Rule	RussAQ	1981	1984	-	Apr	 1	 0:00	1:00	S
            -Rule	RussAQ	1981	1983	-	Oct	 1	 0:00	0	-
            -Rule	RussAQ	1984	1991	-	Sep	lastSun	 2:00s	0	-
            -Rule	RussAQ	1985	1991	-	Mar	lastSun	 2:00s	1:00	S
            -Rule	RussAQ	1992	only	-	Mar	lastSat	 23:00	1:00	S
            -Rule	RussAQ	1992	only	-	Sep	lastSat	 23:00	0	-
            -Rule	RussAQ	1993	max	-	Mar	lastSun	 2:00s	1:00	S
            -Rule	RussAQ	1993	1995	-	Sep	lastSun	 2:00s	0	-
            -Rule	RussAQ	1996	max	-	Oct	lastSun	 2:00s	0	-
            -
             # These rules are stolen from the `southamerica' file.
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	ArgAQ	1964	1966	-	Mar	 1	0:00	0	-
             Rule	ArgAQ	1964	1966	-	Oct	15	0:00	1:00	S
            -Rule	ArgAQ	1967	only	-	Apr	 1	0:00	0	-
            -Rule	ArgAQ	1967	1968	-	Oct	Sun<=7	0:00	1:00	S
            -Rule	ArgAQ	1968	1969	-	Apr	Sun<=7	0:00	0	-
            +Rule	ArgAQ	1967	only	-	Apr	 2	0:00	0	-
            +Rule	ArgAQ	1967	1968	-	Oct	Sun>=1	0:00	1:00	S
            +Rule	ArgAQ	1968	1969	-	Apr	Sun>=1	0:00	0	-
             Rule	ArgAQ	1974	only	-	Jan	23	0:00	1:00	S
             Rule	ArgAQ	1974	only	-	May	 1	0:00	0	-
            -Rule	ArgAQ	1974	1976	-	Oct	Sun<=7	0:00	1:00	S
            -Rule	ArgAQ	1975	1977	-	Apr	Sun<=7	0:00	0	-
            -Rule	ChileAQ	1966	1997	-	Oct	Sun>=9	0:00	1:00	S
            -Rule	ChileAQ	1967	1998	-	Mar	Sun>=9	0:00	0	-
            -Rule	ChileAQ	1998	only	-	Sep	27	0:00	1:00	S
            -Rule	ChileAQ	1999	only	-	Apr	 4	0:00	0	-
            -Rule	ChileAQ	1999	max	-	Oct	Sun>=9	0:00	1:00	S
            -Rule	ChileAQ	2000	max	-	Mar	Sun>=9	0:00	0	-
            +Rule	ChileAQ	1972	1986	-	Mar	Sun>=9	3:00u	0	-
            +Rule	ChileAQ	1974	1987	-	Oct	Sun>=9	4:00u	1:00	S
            +Rule	ChileAQ	1987	only	-	Apr	12	3:00u	0	-
            +Rule	ChileAQ	1988	1989	-	Mar	Sun>=9	3:00u	0	-
            +Rule	ChileAQ	1988	only	-	Oct	Sun>=1	4:00u	1:00	S
            +Rule	ChileAQ	1989	only	-	Oct	Sun>=9	4:00u	1:00	S
            +Rule	ChileAQ	1990	only	-	Mar	18	3:00u	0	-
            +Rule	ChileAQ	1990	only	-	Sep	16	4:00u	1:00	S
            +Rule	ChileAQ	1991	1996	-	Mar	Sun>=9	3:00u	0	-
            +Rule	ChileAQ	1991	1997	-	Oct	Sun>=9	4:00u	1:00	S
            +Rule	ChileAQ	1997	only	-	Mar	30	3:00u	0	-
            +Rule	ChileAQ	1998	only	-	Mar	Sun>=9	3:00u	0	-
            +Rule	ChileAQ	1998	only	-	Sep	27	4:00u	1:00	S
            +Rule	ChileAQ	1999	only	-	Apr	 4	3:00u	0	-
            +Rule	ChileAQ	1999	max	-	Oct	Sun>=9	4:00u	1:00	S
            +Rule	ChileAQ	2000	max	-	Mar	Sun>=9	3:00u	0	-
             
            +# These rules are stolen from the `australasia' file.
            +Rule	AusAQ	1917	only	-	Jan	 1	0:01	1:00	-
            +Rule	AusAQ	1917	only	-	Mar	25	2:00	0	-
            +Rule	AusAQ	1942	only	-	Jan	 1	2:00	1:00	-
            +Rule	AusAQ	1942	only	-	Mar	29	2:00	0	-
            +Rule	AusAQ	1942	only	-	Sep	27	2:00	1:00	-
            +Rule	AusAQ	1943	1944	-	Mar	lastSun	2:00	0	-
            +Rule	AusAQ	1943	only	-	Oct	 3	2:00	1:00	-
            +Rule	ATAQ	1967	only	-	Oct	Sun>=1	2:00s	1:00	-
            +Rule	ATAQ	1968	only	-	Mar	lastSun	2:00s	0	-
            +Rule	ATAQ	1968	1985	-	Oct	lastSun	2:00s	1:00	-
            +Rule	ATAQ	1969	1971	-	Mar	Sun>=8	2:00s	0	-
            +Rule	ATAQ	1972	only	-	Feb	lastSun	2:00s	0	-
            +Rule	ATAQ	1973	1981	-	Mar	Sun>=1	2:00s	0	-
            +Rule	ATAQ	1982	1983	-	Mar	lastSun	2:00s	0	-
            +Rule	ATAQ	1984	1986	-	Mar	Sun>=1	2:00s	0	-
            +Rule	ATAQ	1986	only	-	Oct	Sun>=15	2:00s	1:00	-
            +Rule	ATAQ	1987	1990	-	Mar	Sun>=15	2:00s	0	-
            +Rule	ATAQ	1987	only	-	Oct	Sun>=22	2:00s	1:00	-
            +Rule	ATAQ	1988	1990	-	Oct	lastSun	2:00s	1:00	-
            +Rule	ATAQ	1991	1999	-	Oct	Sun>=1	2:00s	1:00	-
            +Rule	ATAQ	1991	2005	-	Mar	lastSun	2:00s	0	-
            +Rule	ATAQ	2000	only	-	Aug	lastSun	2:00s	1:00	-
            +Rule	ATAQ	2001	max	-	Oct	Sun>=1	2:00s	1:00	-
            +Rule	ATAQ	2006	only	-	Apr	Sun>=1	2:00s	0	-
            +Rule	ATAQ	2007	only	-	Mar	lastSun	2:00s	0	-
            +Rule	ATAQ	2008	max	-	Apr	Sun>=1	2:00s	0	-
             
             # Argentina - year-round bases
             # Belgrano II, Confin Coast, -770227-0343737, since 1972-02-05
            @@ -59,7 +85,7 @@
             # Australia - territories
             # Heard Island, McDonald Islands (uninhabited)
             #	previously sealers and scientific personnel wintered
            -#	
            +#	
             #	Margaret Turner reports
             #	 (1999-09-30) that they're UTC+5, with no DST;
             #	presumably this is when they have visitors.
            @@ -69,15 +95,70 @@
             # Davis, Vestfold Hills, -6835+07759, since 1957-01-13
             #	(except 1964-11 - 1969-02)
             # Mawson, Holme Bay, -6736+06253, since 1954-02-13
            +
            +# From Steffen Thorsen (2009-03-11):
            +# Three Australian stations in Antarctica have changed their time zone:
            +# Casey moved from UTC+8 to UTC+11
            +# Davis moved from UTC+7 to UTC+5
            +# Mawson moved from UTC+6 to UTC+5
            +# The changes occurred on 2009-10-18 at 02:00 (local times).
            +#
            +# Government source: (Australian Antarctic Division)
            +# 
            +# http://www.aad.gov.au/default.asp?casid=37079
            +# 
            +#
            +# We have more background information here:
            +# 
            +# http://www.timeanddate.com/news/time/antarctica-new-times.html
            +# 
            +
            +# From Steffen Thorsen (2010-03-10):
            +# We got these changes from the Australian Antarctic Division:
            +# - Macquarie Island will stay on UTC+11 for winter and therefore not
            +# switch back from daylight savings time when other parts of Australia do
            +# on 4 April.
            +#
            +# - Casey station reverted to its normal time of UTC+8 on 5 March 2010.
            +# The change to UTC+11 is being considered as a regular summer thing but
            +# has not been decided yet.
            +#
            +# - Davis station will revert to its normal time of UTC+7 at 10 March 2010
            +# 20:00 UTC.
            +#
            +# - Mawson station stays on UTC+5.
            +#
            +# In addition to the Rule changes for Casey/Davis, it means that Macquarie
            +# will no longer be like Hobart and will have to have its own Zone created.
            +#
            +# Background:
            +# 
            +# http://www.timeanddate.com/news/time/antartica-time-changes-2010.html
            +# 
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Antarctica/Casey	0	-	zzz	1969
            -			8:00	-	WST	# Western (Aus) Standard Time
            +			8:00	-	WST	2009 Oct 18 2:00
            +						# Western (Aus) Standard Time
            +			11:00	-	CAST	2010 Mar 5 2:00
            +						# Casey Time
            +			8:00	-	WST
             Zone Antarctica/Davis	0	-	zzz	1957 Jan 13
             			7:00	-	DAVT	1964 Nov # Davis Time
             			0	-	zzz	1969 Feb
            +			7:00	-	DAVT	2009 Oct 18 2:00
            +			5:00	-	DAVT	2010 Mar 10 20:00u
             			7:00	-	DAVT
             Zone Antarctica/Mawson	0	-	zzz	1954 Feb 13
            -			6:00	-	MAWT	# Mawson Time
            +			6:00	-	MAWT	2009 Oct 18 2:00
            +						# Mawson Time
            +			5:00	-	MAWT
            +Zone Antarctica/Macquarie 0	-	zzz	1911
            +			10:00	-	EST	1916 Oct 1 2:00
            +			10:00	1:00	EST	1917 Feb
            +			10:00	AusAQ	EST	1967
            +			10:00	ATAQ	EST	2010 Apr 4 3:00
            +			11:00	-	MIST	# Macquarie Island Time
             # References:
             # 
             # Casey Weather (1998-02-26)
            @@ -90,23 +171,23 @@
             # 
             
             # Brazil - year-round base
            -# Ferraz, King George Island, since 1983/4
            +# Comandante Ferraz, King George Island, -6205+05824, since 1983/4
             
             # Chile - year-round bases and towns
             # Escudero, South Shetland Is, -621157-0585735, since 1994
            -# Frei, King George Island, -6214-05848, since 1969-03-07
            -# O'Higgins, Antarctic Peninsula, -6319-05704, since 1948-02
            -# Prat, -6230-05941
            -# Villa Las Estrellas (a town), King George Island, since 1984-04-09
            +# Presidente Eduadro Frei, King George Island, -6214-05848, since 1969-03-07
            +# General Bernardo O'Higgins, Antarctic Peninsula, -6319-05704, since 1948-02
            +# Capitan Arturo Prat, -6230-05941
            +# Villa Las Estrellas (a town), around the Frei base, since 1984-04-09
             # These locations have always used Santiago time; use TZ='America/Santiago'.
             
             # China - year-round bases
            -# Great Wall, King George Island, since 1985-02-20
            -# Zhongshan, Larsemann Hills, Prydz Bay, since 1989-02-26
            +# Great Wall, King George Island, -6213-05858, since 1985-02-20
            +# Zhongshan, Larsemann Hills, Prydz Bay, -6922+07623, since 1989-02-26
             
             # France - year-round bases
             #
            -# From Antoine Leca  (1997-01-20):
            +# From Antoine Leca (1997-01-20):
             # Time data are from Nicole Pailleau at the IFRTP
             # (French Institute for Polar Research and Technology).
             # She confirms that French Southern Territories and Terre Adelie bases
            @@ -139,25 +220,22 @@
             			0	-	zzz	1956 Nov
             			10:00	-	DDUT	# Dumont-d'Urville Time
             # Reference:
            -# 
            -# Support and Development of Polar Research and Technology (1997-02-03)
            +# 
            +# Dumont d'Urville Station (2005-12-05)
             # 
             
            -
             # Germany - year-round base
            -# Georg von Neumayer
            +# Georg von Neumayer, -7039-00815
             
             # India - year-round base
            -# Dakshin Gangotri
            +# Dakshin Gangotri, -7005+01200
             
             # Japan - year-round bases
            -# Dome Fuji
            -# Syowa
            +# Dome Fuji, -7719+03942
            +# Syowa, -690022+0393524
             #
             # From Hideyuki Suzuki (1999-02-06):
            -# In all Japanese stations, +0300 is used as the standard time.  [See]
            -# [reference in Japanese]
            -# and information from KAMO Hiroyasu .
            +# In all Japanese stations, +0300 is used as the standard time.
             #
             # Syowa station, which is the first antarctic station of Japan,
             # was established on 1957-01-29.  Since Syowa station is still the main
            @@ -171,7 +249,7 @@
             # 
             
             # S Korea - year-round base
            -# King Sejong, King George Island, since 1988
            +# King Sejong, King George Island, -6213-05847, since 1988
             
             # New Zealand - claims
             # Balleny Islands (never inhabited)
            @@ -185,10 +263,12 @@
             Rule	NZAQ	1974	only	-	Nov	 3	2:00s	1:00	D
             Rule	NZAQ	1975	1988	-	Oct	lastSun	2:00s	1:00	D
             Rule	NZAQ	1989	only	-	Oct	 8	2:00s	1:00	D
            -Rule	NZAQ	1990	max	-	Oct	Sun>=1	2:00s	1:00	D
            +Rule	NZAQ	1990	2006	-	Oct	Sun>=1	2:00s	1:00	D
             Rule	NZAQ	1975	only	-	Feb	23	2:00s	0	S
             Rule	NZAQ	1976	1989	-	Mar	Sun>=1	2:00s	0	S
            -Rule	NZAQ	1990	max	-	Mar	Sun>=15	2:00s	0	S
            +Rule	NZAQ	1990	2007	-	Mar	Sun>=15	2:00s	0	S
            +Rule	NZAQ	2007	max	-	Sep	lastSun	2:00s	1:00	D
            +Rule	NZAQ	2008	max	-	Apr	Sun>=1	2:00s	0	S
             
             # Norway - territories
             # Bouvet (never inhabited)
            @@ -202,7 +282,8 @@
             # Russia - year-round bases
             # Bellingshausen, King George Island, -621159-0585337, since 1968-02-22
             # Mirny, Davis coast, -6633+09301, since 1956-02
            -# Molodezhnaya, Alasheyev Bay, year-round from 1962-02 to 1999-07-01
            +# Molodezhnaya, Alasheyev Bay, -6740+04551,
            +#	year-round from 1962-02 to 1999-07-01
             # Novolazarevskaya, Queen Maud Land, -7046+01150,
             #	year-round from 1960/61 to 1992
             
            @@ -234,8 +315,8 @@
             			6:00	-	VOST	# Vostok time
             
             # S Africa - year-round bases
            -# Marion Island
            -# Sanae
            +# Marion Island, -4653+03752
            +# Sanae, -7141-00250
             
             # UK
             #
            @@ -270,7 +351,7 @@
             #
             # Palmer, Anvers Island, since 1965 (moved 2 miles in 1968)
             #
            -# From Ethan Dicks  (1996-10-06):
            +# From Ethan Dicks (1996-10-06):
             # It keeps the same time as Punta Arenas, Chile, because, just like us
             # and the South Pole, that's the other end of their supply line....
             # I verified with someone who was there that since 1980,
            @@ -295,7 +376,7 @@
             # Normally it wouldn't have a separate entry, since it's like the
             # larger Antarctica/McMurdo since 1970, but it's too famous to omit.
             #
            -# From Chris Carrier <72157.3334@CompuServe.COM> (1996-06-27):
            +# From Chris Carrier (1996-06-27):
             # Siple, the first commander of the South Pole station,
             # stated that he would have liked to have kept GMT at the station,
             # but that he found it more convenient to keep GMT+12
            Index: 3rdParty_sources/joda-time/org/joda/time/tz/src/asia
            ===================================================================
            diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/joda-time/org/joda/time/tz/src/asia	(.../asia)	(revision 4e266757c429613d78b0fd2914d40d77a447daad)
            +++ 3rdParty_sources/joda-time/org/joda/time/tz/src/asia	(.../asia)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -1,23 +1,25 @@
            -# @(#)asia	7.77
            +# @(#)asia	8.69
            +# This file is in the public domain, so clarified as of
            +# 2009-05-17 by Arthur David Olson.
             
             # This data is by no means authoritative; if you think you know better,
             # go ahead and edit the file (and please send any changes to
             # tz@elsie.nci.nih.gov for general use in the future).
             
            -# From Paul Eggert  (1999-03-22):
            +# From Paul Eggert (2006-03-22):
             #
             # A good source for time zone historical data outside the U.S. is
            -# Thomas G. Shanks, The International Atlas (5th edition),
            -# San Diego: ACS Publications, Inc. (1999).
            +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
            +# San Diego: ACS Publications, Inc. (2003).
             #
             # Gwillim Law writes that a good source
             # for recent time zone data is the International Air Transport
             # Association's Standard Schedules Information Manual (IATA SSIM),
             # published semiannually.  Law sent in several helpful summaries
             # of the IATA's data after 1990.
             #
            -# Except where otherwise noted, Shanks is the source for entries through 1990,
            -# and IATA SSIM is the source for entries after 1990.
            +# Except where otherwise noted, Shanks & Pottenger is the source for
            +# entries through 1990, and IATA SSIM is the source for entries afterwards.
             #
             # Another source occasionally used is Edward W. Whitman, World Time Differences,
             # Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
            @@ -43,8 +45,8 @@
             #	8:00 CST	China
             #	9:00 CJT	Central Japanese Time (1896/1937)*
             #	9:00 EIT	east Indonesia
            -#	9:00 JST	Japan
            -#	9:00 KST	Korea
            +#	9:00 JST  JDT	Japan
            +#	9:00 KST  KDT	Korea
             #	9:30 CST	(Australian) Central Standard Time
             #
             # See the `europe' file for Russia and Turkey in Asia.
            @@ -60,6 +62,7 @@
             # These rules are stolen from the `europe' file.
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	EUAsia	1981	max	-	Mar	lastSun	 1:00u	1:00	S
            +Rule	EUAsia	1979	1995	-	Sep	lastSun	 1:00u	0	-
             Rule	EUAsia	1996	max	-	Oct	lastSun	 1:00u	0	-
             Rule E-EurAsia	1981	max	-	Mar	lastSun	 0:00	1:00	S
             Rule E-EurAsia	1979	1995	-	Sep	lastSun	 0:00	0	-
            @@ -74,18 +77,23 @@
             Rule RussiaAsia	1993	1995	-	Sep	lastSun	 2:00s	0	-
             Rule RussiaAsia	1996	max	-	Oct	lastSun	 2:00s	0	-
             
            +# From Arthur David Olson (2011-06-15):
            +# While Russia abandoned DST in 2011, Armenia may choose to
            +# follow Russia's "old" rules.
            +
             # Afghanistan
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Kabul	4:36:48 -	LMT	1890
             			4:00	-	AFT	1945
             			4:30	-	AFT
             
             # Armenia
            -# From Paul Eggert (1999-10-29):
            -# Shanks has Yerevan switching to 3:00 (with Russian DST) in spring 1991,
            -# then to 4:00 with no DST in fall 1995, then readopting Russian DST in 1997.
            -# Go with Shanks, even when he disagrees with others.  Edgar Der-Danieliantz
            -#  reported (1996-05-04) that Yerevan probably wouldn't use DST
            +# From Paul Eggert (2006-03-22):
            +# Shanks & Pottenger have Yerevan switching to 3:00 (with Russian DST)
            +# in spring 1991, then to 4:00 with no DST in fall 1995, then
            +# readopting Russian DST in 1997.  Go with Shanks & Pottenger, even
            +# when they disagree with others.  Edgar Der-Danieliantz
            +# reported (1996-05-04) that Yerevan probably wouldn't use DST
             # in 1996, though it did use DST in 1995.  IATA SSIM (1991/1998) reports that
             # Armenia switched from 3:00 to 4:00 in 1998 and observed DST after 1991,
             # but started switching at 3:00s in 1998.
            @@ -99,15 +107,18 @@
             			4:00 RussiaAsia	AM%sT
             
             # Azerbaijan
            +# From Rustam Aliyev of the Azerbaijan Internet Forum (2005-10-23):
            +# According to the resolution of Cabinet of Ministers, 1997
            +# Resolution available at: http://aif.az/docs/daylight_res.pdf
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -Rule	Azer	1997	max	-	Mar	lastSun	 1:00	1:00	S
            -Rule	Azer	1997	max	-	Oct	lastSun	 1:00	0	-
            +Rule	Azer	1997	max	-	Mar	lastSun	 4:00	1:00	S
            +Rule	Azer	1997	max	-	Oct	lastSun	 5:00	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Baku	3:19:24 -	LMT	1924 May  2
             			3:00	-	BAKT	1957 Mar    # Baku Time
             			4:00 RussiaAsia BAK%sT	1991 Mar 31 2:00s
             			3:00	1:00	BAKST	1991 Aug 30 # independence
            -			3:00 RussiaAsia	AZ%sT	1992 Sep lastSun 2:00s
            +			3:00 RussiaAsia	AZ%sT	1992 Sep lastSat 23:00
             			4:00	-	AZT	1996 # Azerbaijan time
             			4:00	EUAsia	AZ%sT	1997
             			4:00	Azer	AZ%sT
            @@ -119,14 +130,118 @@
             			3:00	-	AST
             
             # Bangladesh
            +# From Alexander Krivenyshev (2009-05-13):
            +# According to newspaper Asian Tribune (May 6, 2009) Bangladesh may introduce
            +# Daylight Saving Time from June 16 to Sept 30
            +#
            +# Bangladesh to introduce daylight saving time likely from June 16
            +# 
            +# http://www.asiantribune.com/?q=node/17288
            +# 
            +# or
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_bangladesh02.html
            +# 
            +#
            +# "... Bangladesh government has decided to switch daylight saving time from
            +# June
            +# 16 till September 30 in a bid to ensure maximum use of daylight to cope with
            +# crippling power crisis. "
            +#
            +# The switch will remain in effect from June 16 to Sept 30 (2009) but if
            +# implemented the next year, it will come in force from April 1, 2010
            +
            +# From Steffen Thorsen (2009-06-02):
            +# They have finally decided now, but changed the start date to midnight between
            +# the 19th and 20th, and they have not set the end date yet.
            +#
            +# Some sources:
            +# 
            +# http://in.reuters.com/article/southAsiaNews/idINIndia-40017620090601
            +# 
            +# 
            +# http://bdnews24.com/details.php?id=85889&cid=2
            +# 
            +#
            +# Our wrap-up:
            +# 
            +# http://www.timeanddate.com/news/time/bangladesh-daylight-saving-2009.html
            +# 
            +
            +# From A. N. M. Kamrus Saadat (2009-06-15):
            +# Finally we've got the official mail regarding DST start time where DST start 
            +# time is mentioned as Jun 19 2009, 23:00 from BTRC (Bangladesh 
            +# Telecommunication Regulatory Commission). 
            +#
            +# No DST end date has been announced yet.
            +
            +# From Alexander Krivenyshev (2009-09-25):
            +# Bangladesh won't go back to Standard Time from October 1, 2009, 
            +# instead it will continue DST measure till the cabinet makes a fresh decision. 
            +#
            +# Following report by same newspaper-"The Daily Star Friday":
            +# "DST change awaits cabinet decision-Clock won't go back by 1-hr from Oct 1"
            +# 
            +# http://www.thedailystar.net/newDesign/news-details.php?nid=107021
            +# 
            +# or
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_bangladesh04.html
            +# 
            +
            +# From Steffen Thorsen (2009-10-13):
            +# IANS (Indo-Asian News Service) now reports:
            +# Bangladesh has decided that the clock advanced by an hour to make 
            +# maximum use of daylight hours as an energy saving measure would 
            +# "continue for an indefinite period."
            +#
            +# One of many places where it is published:
            +# 
            +# http://www.thaindian.com/newsportal/business/bangladesh-to-continue-indefinitely-with-advanced-time_100259987.html
            +# 
            +
            +# From Alexander Krivenyshev (2009-12-24):
            +# According to Bangladesh newspaper "The Daily Star,"
            +# Bangladesh will change its clock back to Standard Time on Dec 31, 2009.
            +#
            +# Clock goes back 1-hr on Dec 31 night.
            +# 
            +# http://www.thedailystar.net/newDesign/news-details.php?nid=119228
            +# 
            +# and
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_bangladesh05.html
            +# 
            +#
            +# "...The government yesterday decided to put the clock back by one hour
            +# on December 31 midnight and the new time will continue until March 31,
            +# 2010 midnight. The decision came at a cabinet meeting at the Prime
            +# Minister's Office last night..."
            +
            +# From Alexander Krivenyshev (2010-03-22):
            +# According to Bangladesh newspaper "The Daily Star,"
            +# Cabinet cancels Daylight Saving Time 
            +# 
            +# http://www.thedailystar.net/newDesign/latest_news.php?nid=22817
            +# 
            +# or
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_bangladesh06.html
            +# 
            +
            +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            +Rule	Dhaka	2009	only	-	Jun	19	23:00	1:00	S
            +Rule	Dhaka	2009	only	-	Dec	31	23:59	0	-
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Dhaka	6:01:40 -	LMT	1890
             			5:53:20	-	HMT	1941 Oct    # Howrah Mean Time?
             			6:30	-	BURT	1942 May 15 # Burma Time
             			5:30	-	IST	1942 Sep
             			6:30	-	BURT	1951 Sep 30
             			6:00	-	DACT	1971 Mar 26 # Dacca Time
            -			6:00	-	BDT	# Bangladesh Time
            +			6:00	-	BDT	2009
            +			6:00	Dhaka	BD%sT
             
             # Bhutan
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            @@ -137,8 +252,12 @@
             # British Indian Ocean Territory
             # Whitman and the 1995 CIA time zone map say 5:00, but the
             # 1997 and later maps say 6:00.  Assume the switch occurred in 1996.
            +# We have no information as to when standard time was introduced;
            +# assume it occurred in 1907, the same year as Mauritius (which
            +# then contained the Chagos Archipelago).
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone	Indian/Chagos	5:00	-	IOT	1996 # BIOT Time
            +Zone	Indian/Chagos	4:49:40	-	LMT	1907
            +			5:00	-	IOT	1996 # BIOT Time
             			6:00	-	IOT
             
             # Brunei
            @@ -186,83 +305,293 @@
             # CHINA               8 H  AHEAD OF UTC  ALL OF CHINA, INCL TAIWAN
             # CHINA               9 H  AHEAD OF UTC  APR 17 - SEP 10
             
            -# From Paul Eggert  (1995-12-19):
            -# Shanks writes that China has had a single time zone since 1980 May 1,
            -# observing summer DST from 1986 through 1991; this contradicts Devine's
            +# From Paul Eggert (2006-03-22):
            +# Shanks & Pottenger write that China (except for Hong Kong and Macau)
            +# has had a single time zone since 1980 May 1, observing summer DST
            +# from 1986 through 1991; this contradicts Devine's
             # note about Time magazine, though apparently _something_ happened in 1986.
            -# Go with Shanks for now.  I made up names for the other pre-1980 time zones.
            +# Go with Shanks & Pottenger for now.  I made up names for the other
            +# pre-1980 time zones.
             
            -# From Shanks:
            +# From Shanks & Pottenger:
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Shang	1940	only	-	Jun	 3	0:00	1:00	D
             Rule	Shang	1940	1941	-	Oct	 1	0:00	0	S
             Rule	Shang	1941	only	-	Mar	16	0:00	1:00	D
            -Rule	PRC	1949	only	-	Jan	 1	0:00	0	S
             Rule	PRC	1986	only	-	May	 4	0:00	1:00	D
             Rule	PRC	1986	1991	-	Sep	Sun>=11	0:00	0	S
             Rule	PRC	1987	1991	-	Apr	Sun>=10	0:00	1:00	D
            -#
            -# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -#
            +
             # From Anthony Fok (2001-12-20):
             # BTW, I did some research on-line and found some info regarding these five
             # historic timezones from some Taiwan websites.  And yes, there are official
            -# Chinese names for these locales (before 1949):
            +# Chinese names for these locales (before 1949).
            +#
            +# From Jesper Norgaard Welen (2006-07-14):
            +# I have investigated the timezones around 1970 on the
            +# http://www.astro.com/atlas site [with provinces and county
            +# boundaries summarized below]....  A few other exceptions were two
            +# counties on the Sichuan side of the Xizang-Sichuan border,
            +# counties Dege and Baiyu which lies on the Sichuan side and are
            +# therefore supposed to be GMT+7, Xizang region being GMT+6, but Dege
            +# county is GMT+8 according to astro.com while Baiyu county is GMT+6
            +# (could be true), for the moment I am assuming that those two
            +# counties are mistakes in the astro.com data.
            +
            +# From Paul Eggert (2008-02-11):
            +# I just now checked Google News for western news sources that talk
            +# about China's single time zone, and couldn't find anything before 1986
            +# talking about China being in one time zone.  (That article was: Jim
            +# Mann, "A clumsy embrace for another western custom: China on daylight
            +# time--sort of", Los Angeles Times, 1986-05-05.  By the way, this
            +# article confirms the tz database's data claiming that China began
            +# observing daylight saving time in 1986.
            +#
            +# From Thomas S. Mullaney (2008-02-11):
            +# I think you're combining two subjects that need to treated 
            +# separately: daylight savings (which, you're correct, wasn't 
            +# implemented until the 1980s) and the unified time zone centered near 
            +# Beijing (which was implemented in 1949). Briefly, there was also a 
            +# "Lhasa Time" in Tibet and "Urumqi Time" in Xinjiang. The first was 
            +# ceased, and the second eventually recognized (again, in the 1980s).
            +#
            +# From Paul Eggert (2008-06-30):
            +# There seems to be a good chance China switched to a single time zone in 1949
            +# rather than in 1980 as Shanks & Pottenger have it, but we don't have a
            +# reliable documentary source saying so yet, so for now we still go with
            +# Shanks & Pottenger.
            +
            +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             # Changbai Time ("Long-white Time", Long-white = Heilongjiang area)
            +# Heilongjiang (except Mohe county), Jilin
             Zone	Asia/Harbin	8:26:44	-	LMT	1928 # or Haerbin
             			8:30	-	CHAT	1932 Mar # Changbai Time
             			8:00	-	CST	1940
             			9:00	-	CHAT	1966 May
             			8:30	-	CHAT	1980 May
             			8:00	PRC	C%sT
             # Zhongyuan Time ("Central plain Time")
            +# most of China
             Zone	Asia/Shanghai	8:05:52	-	LMT	1928
             			8:00	Shang	C%sT	1949
             			8:00	PRC	C%sT
             # Long-shu Time (probably due to Long and Shu being two names of that area)
            +# Guangxi, Guizhou, Hainan, Ningxia, Sichuan, Shaanxi, and Yunnan;
            +# most of Gansu; west Inner Mongolia; west Qinghai; and the Guangdong
            +# counties Deqing, Enping, Kaiping, Luoding, Taishan, Xinxing,
            +# Yangchun, Yangjiang, Yu'nan, and Yunfu.
             Zone	Asia/Chongqing	7:06:20	-	LMT	1928 # or Chungking
             			7:00	-	LONT	1980 May # Long-shu Time
             			8:00	PRC	C%sT
             # Xin-zang Time ("Xinjiang-Tibet Time")
            +# The Gansu counties Aksay, Anxi, Dunhuang, Subei; west Qinghai;
            +# the Guangdong counties  Xuwen, Haikang, Suixi, Lianjiang,
            +# Zhanjiang, Wuchuan, Huazhou, Gaozhou, Maoming, Dianbai, and Xinyi;
            +# east Tibet, including Lhasa, Chamdo, Shigaise, Jimsar, Shawan and Hutubi;
            +# east Xinjiang, including Urumqi, Turpan, Karamay, Korla, Minfeng, Jinghe,
            +# Wusu, Qiemo, Xinyan, Wulanwusu, Jinghe, Yumin, Tacheng, Tuoli, Emin,
            +# Shihezi, Changji, Yanqi, Heshuo, Tuokexun, Tulufan, Shanshan, Hami,
            +# Fukang, Kuitun, Kumukuli, Miquan, Qitai, and Turfan.
             Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
             			6:00	-	URUT	1980 May # Urumqi Time
             			8:00	PRC	C%sT
             # Kunlun Time
            +# West Tibet, including Pulan, Aheqi, Shufu, Shule;
            +# West Xinjiang, including Aksu, Atushi, Yining, Hetian, Cele, Luopu, Nileke,
            +# Zhaosu, Tekesi, Gongliu, Chabuchaer, Huocheng, Bole, Pishan, Suiding,
            +# and Yarkand.
            +
            +# From Luther Ma (2009-10-17):
            +# Almost all (>99.9%) ethnic Chinese (properly ethnic Han) living in
            +# Xinjiang use Chinese Standard Time. Some are aware of Xinjiang time,
            +# but have no need of it. All planes, trains, and schools function on
            +# what is called "Beijing time." When Han make an appointment in Chinese
            +# they implicitly use Beijing time.
            +#
            +# On the other hand, ethnic Uyghurs, who make up about half the
            +# population of Xinjiang, typically use "Xinjiang time" which is two
            +# hours behind Beijing time, or UTC +0600. The government of the Xinjiang
            +# Uyghur Autonomous Region, (XAUR, or just Xinjiang for short) as well as
            +# local governments such as the Urumqi city government use both times in
            +# publications, referring to what is popularly called Xinjiang time as
            +# "Urumqi time." When Uyghurs make an appointment in the Uyghur language
            +# they almost invariably use Xinjiang time.
            +#
            +# (Their ethnic Han compatriots would typically have no clue of its
            +# widespread use, however, because so extremely few of them are fluent in
            +# Uyghur, comparable to the number of Anglo-Americans fluent in Navajo.)
            +#
            +# (...As with the rest of China there was a brief interval ending in 1990
            +# or 1991 when summer time was in use.  The confusion was severe, with
            +# the province not having dual times but four times in use at the same
            +# time. Some areas remained on standard Xinjiang time or Beijing time and
            +# others moving their clocks ahead.)
            +#
            +# ...an example of an official website using of Urumqi time.
            +#
            +# The first few lines of the Google translation of
            +# 
            +# http://www.fjysgl.gov.cn/show.aspx?id=2379&cid=39
            +# 
            +# (retrieved 2009-10-13)
            +# > Urumqi fire seven people are missing the alleged losses of at least
            +# > 500 million yuan
            +# >
            +# > (Reporter Dong Liu) the day before 20:20 or so (Urumqi Time 18:20),
            +# > Urumqi City Department of International Plaza Luther Qiantang River
            +# > burst fire. As of yesterday, 18:30, Urumqi City Fire officers and men
            +# > have worked continuously for 22 hours...
            +
            +# From Luther Ma (2009-11-19):
            +# With the risk of being redundant to previous answers these are the most common
            +# English "transliterations" (w/o using non-English symbols):
            +#
            +# 1. Wulumuqi...
            +# 2. Kashi...
            +# 3. Urumqi...
            +# 4. Kashgar...
            +# ...
            +# 5. It seems that Uyghurs in Urumqi has been using Xinjiang since at least the
            +# 1960's. I know of one Han, now over 50, who grew up in the surrounding
            +# countryside and used Xinjiang time as a child.
            +#
            +# 6. Likewise for Kashgar and the rest of south Xinjiang I don't know of any
            +# start date for Xinjiang time.
            +#
            +# Without having access to local historical records, nor the ability to legally
            +# publish them, I would go with October 1, 1949, when Xinjiang became the Uyghur
            +# Autonomous Region under the PRC. (Before that Uyghurs, of course, would also
            +# not be using Beijing time, but some local time.)
            +
             Zone	Asia/Kashgar	5:03:56	-	LMT	1928 # or Kashi or Kaxgar
             			5:30	-	KAST	1940	 # Kashgar Time
             			5:00	-	KAST	1980 May
             			8:00	PRC	C%sT
             
            +
            +# From Lee Yiu Chung (2009-10-24):
            +# I found there are some mistakes for the...DST rule for Hong
            +# Kong. [According] to the DST record from Hong Kong Observatory (actually,
            +# it is not [an] observatory, but the official meteorological agency of HK,
            +# and also serves as the official timing agency), there are some missing
            +# and incorrect rules. Although the exact switch over time is missing, I
            +# think 3:30 is correct. The official DST record for Hong Kong can be
            +# obtained from
            +# 
            +# http://www.hko.gov.hk/gts/time/Summertime.htm
            +# .
            +
            +# From Arthur David Olson (2009-10-28):
            +# Here are the dates given at
            +# 
            +# http://www.hko.gov.hk/gts/time/Summertime.htm
            +# 
            +# as of 2009-10-28:
            +# Year        Period
            +# 1941        1 Apr to 30 Sep
            +# 1942        Whole year 
            +# 1943        Whole year
            +# 1944        Whole year
            +# 1945        Whole year
            +# 1946        20 Apr to 1 Dec
            +# 1947        13 Apr to 30 Dec
            +# 1948        2 May to 31 Oct
            +# 1949        3 Apr to 30 Oct
            +# 1950        2 Apr to 29 Oct
            +# 1951        1 Apr to 28 Oct
            +# 1952        6 Apr to 25 Oct
            +# 1953        5 Apr to 1 Nov
            +# 1954        21 Mar to 31 Oct
            +# 1955        20 Mar to 6 Nov
            +# 1956        18 Mar to 4 Nov
            +# 1957        24 Mar to 3 Nov
            +# 1958        23 Mar to 2 Nov
            +# 1959        22 Mar to 1 Nov
            +# 1960        20 Mar to 6 Nov
            +# 1961        19 Mar to 5 Nov
            +# 1962        18 Mar to 4 Nov
            +# 1963        24 Mar to 3 Nov
            +# 1964        22 Mar to 1 Nov
            +# 1965        18 Apr to 17 Oct
            +# 1966        17 Apr to 16 Oct
            +# 1967        16 Apr to 22 Oct
            +# 1968        21 Apr to 20 Oct
            +# 1969        20 Apr to 19 Oct
            +# 1970        19 Apr to 18 Oct
            +# 1971        18 Apr to 17 Oct
            +# 1972        16 Apr to 22 Oct
            +# 1973        22 Apr to 21 Oct
            +# 1973/74     30 Dec 73 to 20 Oct 74
            +# 1975        20 Apr to 19 Oct
            +# 1976        18 Apr to 17 Oct
            +# 1977        Nil
            +# 1978        Nil
            +# 1979        13 May to 21 Oct
            +# 1980 to Now Nil
            +# The page does not give start or end times of day.
            +# The page does not give a start date for 1942.
            +# The page does not givw an end date for 1945.
            +# The Japanese occupation of Hong Kong began on 1941-12-25.
            +# The Japanese surrender of Hong Kong was signed 1945-09-15.
            +# For lack of anything better, use start of those days as the transition times.
            +
             # Hong Kong (Xianggang)
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            +Rule	HK	1941	only	-	Apr	1	3:30	1:00	S
            +Rule	HK	1941	only	-	Sep	30	3:30	0	-
             Rule	HK	1946	only	-	Apr	20	3:30	1:00	S
             Rule	HK	1946	only	-	Dec	1	3:30	0	-
             Rule	HK	1947	only	-	Apr	13	3:30	1:00	S
             Rule	HK	1947	only	-	Dec	30	3:30	0	-
             Rule	HK	1948	only	-	May	2	3:30	1:00	S
            -Rule	HK	1948	1952	-	Oct	lastSun	3:30	0	-
            +Rule	HK	1948	1951	-	Oct	lastSun	3:30	0	-
            +Rule	HK	1952	only	-	Oct	25	3:30	0	-
             Rule	HK	1949	1953	-	Apr	Sun>=1	3:30	1:00	S
             Rule	HK	1953	only	-	Nov	1	3:30	0	-
             Rule	HK	1954	1964	-	Mar	Sun>=18	3:30	1:00	S
             Rule	HK	1954	only	-	Oct	31	3:30	0	-
             Rule	HK	1955	1964	-	Nov	Sun>=1	3:30	0	-
            -Rule	HK	1965	1977	-	Apr	Sun>=16	3:30	1:00	S
            -Rule	HK	1965	1977	-	Oct	Sun>=16	3:30	0	-
            -Rule	HK	1979	1980	-	May	Sun>=8	3:30	1:00	S
            -Rule	HK	1979	1980	-	Oct	Sun>=16	3:30	0	-
            +Rule	HK	1965	1976	-	Apr	Sun>=16	3:30	1:00	S
            +Rule	HK	1965	1976	-	Oct	Sun>=16	3:30	0	-
            +Rule	HK	1973	only	-	Dec	30	3:30	1:00	S
            +Rule	HK	1979	only	-	May	Sun>=8	3:30	1:00	S
            +Rule	HK	1979	only	-	Oct	Sun>=16	3:30	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Hong_Kong	7:36:36 -	LMT	1904 Oct 30
            +			8:00	HK	HK%sT	1941 Dec 25
            +			9:00	-	JST	1945 Sep 15
             			8:00	HK	HK%sT
             
            -
             ###############################################################################
             
             # Taiwan
             
            -# Shanks writes that Taiwan observed DST during 1945, when it
            +# Shanks & Pottenger write that Taiwan observed DST during 1945, when it
             # was still controlled by Japan.  This is hard to believe, but we don't
             # have any other information.
             
            +# From smallufo (2010-04-03):
            +# According to Taiwan's CWB,
            +# 
            +# http://www.cwb.gov.tw/V6/astronomy/cdata/summert.htm
            +# 
            +# Taipei has DST in 1979 between July 1st and Sep 30.
            +
            +# From Arthur David Olson (2010-04-07):
            +# Here's Google's translation of the table at the bottom of the "summert.htm" page:
            +# Decade 	                                                    Name                      Start and end date
            +# Republic of China 34 years to 40 years (AD 1945-1951 years) Summer Time               May 1 to September 30 
            +# 41 years of the Republic of China (AD 1952)                 Daylight Saving Time      March 1 to October 31 
            +# Republic of China 42 years to 43 years (AD 1953-1954 years) Daylight Saving Time      April 1 to October 31 
            +# In the 44 years to 45 years (AD 1955-1956 years)            Daylight Saving Time      April 1 to September 30 
            +# Republic of China 46 years to 48 years (AD 1957-1959)       Summer Time               April 1 to September 30 
            +# Republic of China 49 years to 50 years (AD 1960-1961)       Summer Time               June 1 to September 30 
            +# Republic of China 51 years to 62 years (AD 1962-1973 years) Stop Summer Time 
            +# Republic of China 63 years to 64 years (1974-1975 AD)       Daylight Saving Time      April 1 to September 30 
            +# Republic of China 65 years to 67 years (1976-1978 AD)       Stop Daylight Saving Time 
            +# Republic of China 68 years (AD 1979)                        Daylight Saving Time      July 1 to September 30 
            +# Republic of China since 69 years (AD 1980)                  Stop Daylight Saving Time
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Taiwan	1945	1951	-	May	1	0:00	1:00	D
             Rule	Taiwan	1945	1951	-	Oct	1	0:00	0	S
            @@ -273,8 +602,9 @@
             Rule	Taiwan	1960	1961	-	Jun	1	0:00	1:00	D
             Rule	Taiwan	1974	1975	-	Apr	1	0:00	1:00	D
             Rule	Taiwan	1974	1975	-	Oct	1	0:00	0	S
            -Rule	Taiwan	1980	only	-	Jun	30	0:00	1:00	D
            -Rule	Taiwan	1980	only	-	Sep	30	0:00	0	S
            +Rule	Taiwan	1979	only	-	Jun	30	0:00	1:00	D
            +Rule	Taiwan	1979	only	-	Sep	30	0:00	0	S
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Taipei	8:06:00 -	LMT	1896 # or Taibei or T'ai-pei
             			8:00	Taiwan	C%sT
            @@ -325,26 +655,37 @@
             Link	Asia/Nicosia	Europe/Nicosia
             
             # Georgia
            -# From Paul Eggert  (1994-11-19):
            +# From Paul Eggert (1994-11-19):
             # Today's _Economist_ (p 60) reports that Georgia moved its clocks forward
             # an hour recently, due to a law proposed by Zurab Murvanidze,
             # an MP who went on a hunger strike for 11 days to force discussion about it!
             # We have no details, but we'll guess they didn't move the clocks back in fall.
             #
            -# From Mathew Englander , quoting AP (1996-10-23 13:05-04):
            +# From Mathew Englander, quoting AP (1996-10-23 13:05-04):
             # Instead of putting back clocks at the end of October, Georgia
             # will stay on daylight savings time this winter to save energy,
             # President Eduard Shevardnadze decreed Wednesday.
             #
             # From the BBC via Joseph S. Myers (2004-06-27):
            -#  	
            +#
             # Georgia moved closer to Western Europe on Sunday...  The former Soviet
             # republic has changed its time zone back to that of Moscow.  As a result it
             # is now just four hours ahead of Greenwich Mean Time, rather than five hours
             # ahead.  The switch was decreed by the pro-Western president of Georgia,
             # Mikhail Saakashvili, who said the change was partly prompted by the process
             # of integration into Europe.
             
            +# From Teimuraz Abashidze (2005-11-07):
            +# Government of Georgia ... decided to NOT CHANGE daylight savings time on
            +# [Oct.] 30, as it was done before during last more than 10 years.
            +# Currently, we are in fact GMT +4:00, as before 30 October it was GMT
            +# +3:00.... The problem is, there is NO FORMAL LAW or governmental document
            +# about it.  As far as I can find, I was told, that there is no document,
            +# because we just DIDN'T ISSUE document about switching to winter time....
            +# I don't know what can be done, especially knowing that some years ago our
            +# DST rules where changed THREE TIMES during one month.
            +
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Tbilisi	2:59:16 -	LMT	1880
             			2:59:16	-	TBMT	1924 May  2 # Tbilisi Mean Time
            @@ -356,10 +697,13 @@
             			4:00 E-EurAsia	GE%sT	1996 Oct lastSun
             			4:00	1:00	GEST	1997 Mar lastSun
             			4:00 E-EurAsia	GE%sT	2004 Jun 27
            -			3:00 RussiaAsia	GE%sT
            +			3:00 RussiaAsia	GE%sT	2005 Mar lastSun 2:00
            +			4:00	-	GET
             
             # East Timor
             
            +# See Indonesia for the 1945 transition.
            +
             # From Joao Carrascalao, brother of the former governor of East Timor, in
             # 
             # East Timor may be late for its millennium
            @@ -383,49 +727,62 @@
             
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Dili	8:22:20 -	LMT	1912
            -			8:00	-	TPT	1942 Feb 21 23:00 # E Timor Time
            -			9:00	-	JST	1945 Aug
            -			9:00	-	TPT	1976 May  3
            +			8:00	-	TLT	1942 Feb 21 23:00 # E Timor Time
            +			9:00	-	JST	1945 Sep 23
            +			9:00	-	TLT	1976 May  3
             			8:00	-	CIT	2000 Sep 17 00:00
            -			9:00	-	TPT
            +			9:00	-	TLT
             
             # India
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone	Asia/Calcutta	5:53:28 -	LMT	1880	# Kolkata
            +Zone	Asia/Kolkata	5:53:28 -	LMT	1880	# Kolkata
             			5:53:20	-	HMT	1941 Oct    # Howrah Mean Time?
             			6:30	-	BURT	1942 May 15 # Burma Time
             			5:30	-	IST	1942 Sep
             			5:30	1:00	IST	1945 Oct 15
             			5:30	-	IST
            -# The following are like Asia/Calcutta:
            +# The following are like Asia/Kolkata:
             #	Andaman Is
             #	Lakshadweep (Laccadive, Minicoy and Amindivi Is)
             #	Nicobar Is
             
             # Indonesia
             #
            -# From Gwillim Law (2001-05-28), overriding Shanks:
            +# From Gwillim Law (2001-05-28), overriding Shanks & Pottenger:
             # 
             # says that Indonesia's time zones changed on 1988-01-01.  Looking at some
             # time zone maps, I think that must refer to Western Borneo (Kalimantan Barat
             # and Kalimantan Tengah) switching from UTC+8 to UTC+7.
             #
            +# From Paul Eggert (2007-03-10):
            +# Here is another correction to Shanks & Pottenger.
            +# JohnTWB writes that Japanese forces did not surrender control in
            +# Indonesia until 1945-09-01 00:00 at the earliest (in Jakarta) and
            +# other formal surrender ceremonies were September 9, 11, and 13, plus
            +# September 12 for the regional surrender to Mountbatten in Singapore.
            +# These would be the earliest possible times for a change.
            +# Regimes horaires pour le monde entier, by Henri Le Corre, (Editions
            +# Traditionnelles, 1987, Paris) says that Java and Madura switched
            +# from JST to UTC+07:30 on 1945-09-23, and gives 1944-09-01 for Jayapura
            +# (Hollandia).  For now, assume all Indonesian locations other than Jayapura
            +# switched on 1945-09-23.
            +#
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Asia/Jakarta	7:07:12 -	LMT	1867 Aug 10
            -# Shanks says the next transition was at 1924 Jan 1 0:13,
            +# Shanks & Pottenger say the next transition was at 1924 Jan 1 0:13,
             # but this must be a typo.
             			7:07:12	-	JMT	1923 Dec 31 23:47:12 # Jakarta
             			7:20	-	JAVT	1932 Nov	 # Java Time
             			7:30	-	WIT	1942 Mar 23
            -			9:00	-	JST	1945 Aug
            +			9:00	-	JST	1945 Sep 23
             			7:30	-	WIT	1948 May
             			8:00	-	WIT	1950 May
             			7:30	-	WIT	1964
             			7:00	-	WIT
             Zone Asia/Pontianak	7:17:20	-	LMT	1908 May
             			7:17:20	-	PMT	1932 Nov    # Pontianak MT
             			7:30	-	WIT	1942 Jan 29
            -			9:00	-	JST	1945 Aug
            +			9:00	-	JST	1945 Sep 23
             			7:30	-	WIT	1948 May
             			8:00	-	WIT	1950 May
             			7:30	-	WIT	1964
            @@ -434,10 +791,10 @@
             Zone Asia/Makassar	7:57:36 -	LMT	1920
             			7:57:36	-	MMT	1932 Nov    # Macassar MT
             			8:00	-	CIT	1942 Feb  9
            -			9:00	-	JST	1945 Aug
            +			9:00	-	JST	1945 Sep 23
             			8:00	-	CIT
             Zone Asia/Jayapura	9:22:48 -	LMT	1932 Nov
            -			9:00	-	EIT	1944
            +			9:00	-	EIT	1944 Sep  1
             			9:30	-	CST	1964
             			9:00	-	EIT
             
            @@ -472,13 +829,52 @@
             # Thursday night of Shahrivar, but I can't give exact dates....
             # I have also changed the abbreviations to what is considered correct
             # here in Iran, IRST for regular time and IRDT for daylight saving time.
            -
            -# From Paul Eggert (2003-03-15)
            -# Go with Shanks before September 1991, and with Pournader thereafter.
            -# I used Ed Reingold's cal-persia in GNU Emacs 21.2 to check Persian dates.
            -# The Persian calendar is based on the sun, and dates after around 2050
            -# are approximate; stop after 2037 when 32-bit time_t's overflow.
             #
            +# From Roozbeh Pournader (2005-04-05):
            +# The text of the Iranian law, in effect since 1925, clearly mentions
            +# that the true solar year is the measure, and there is no arithmetic
            +# leap year calculation involved.  There has never been any serious
            +# plan to change that law....
            +#
            +# From Paul Eggert (2006-03-22):
            +# Go with Shanks & Pottenger before Sept. 1991, and with Pournader thereafter.
            +# I used Ed Reingold's cal-persia in GNU Emacs 21.2 to check Persian dates,
            +# stopping after 2037 when 32-bit time_t's overflow.
            +# That cal-persia used Birashk's approximation, which disagrees with the solar
            +# calendar predictions for the year 2025, so I corrected those dates by hand.
            +#
            +# From Oscar van Vlijmen (2005-03-30), writing about future
            +# discrepancies between cal-persia and the Iranian calendar:
            +# For 2091 solar-longitude-after yields 2091-03-20 08:40:07.7 UT for
            +# the vernal equinox and that gets so close to 12:00 some local
            +# Iranian time that the definition of the correct location needs to be
            +# known exactly, amongst other factors.  2157 is even closer:
            +# 2157-03-20 08:37:15.5 UT.  But the Gregorian year 2025 should give
            +# no interpretation problem whatsoever.  By the way, another instant
            +# in the near future where there will be a discrepancy between
            +# arithmetical and astronomical Iranian calendars will be in 2058:
            +# vernal equinox on 2058-03-20 09:03:05.9 UT.  The Java version of
            +# Reingold's/Dershowitz' calculator gives correctly the Gregorian date
            +# 2058-03-21 for 1 Farvardin 1437 (astronomical).
            +#
            +# From Steffen Thorsen (2006-03-22):
            +# Several of my users have reported that Iran will not observe DST anymore:
            +# http://www.irna.ir/en/news/view/line-17/0603193812164948.htm
            +#
            +# From Reuters (2007-09-16), with a heads-up from Jesper Norgaard Welen:
            +# ... the Guardian Council ... approved a law on Sunday to re-introduce
            +# daylight saving time ...
            +# http://uk.reuters.com/article/oilRpt/idUKBLA65048420070916
            +#
            +# From Roozbeh Pournader (2007-11-05):
            +# This is quoted from Official Gazette of the Islamic Republic of
            +# Iran, Volume 63, Number 18242, dated Tuesday 1386/6/24
            +# [2007-10-16]. I am doing the best translation I can:...
            +# The official time of the country will be moved forward for one hour
            +# on the 24 hours of the first day of the month of Farvardin and will
            +# be changed back to its previous state on the 24 hours of the
            +# thirtieth day of Shahrivar.
            +#
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Iran	1978	1980	-	Mar	21	0:00	1:00	D
             Rule	Iran	1978	only	-	Oct	21	0:00	0	S
            @@ -497,8 +893,8 @@
             Rule	Iran	2001	2003	-	Sep	22	0:00	0	S
             Rule	Iran	2004	only	-	Mar	21	0:00	1:00	D
             Rule	Iran	2004	only	-	Sep	21	0:00	0	S
            -Rule	Iran	2005	2007	-	Mar	22	0:00	1:00	D
            -Rule	Iran	2005	2007	-	Sep	22	0:00	0	S
            +Rule	Iran	2005	only	-	Mar	22	0:00	1:00	D
            +Rule	Iran	2005	only	-	Sep	22	0:00	0	S
             Rule	Iran	2008	only	-	Mar	21	0:00	1:00	D
             Rule	Iran	2008	only	-	Sep	21	0:00	0	S
             Rule	Iran	2009	2011	-	Mar	22	0:00	1:00	D
            @@ -515,10 +911,10 @@
             Rule	Iran	2020	only	-	Sep	21	0:00	0	S
             Rule	Iran	2021	2023	-	Mar	22	0:00	1:00	D
             Rule	Iran	2021	2023	-	Sep	22	0:00	0	S
            -Rule	Iran	2024	2025	-	Mar	21	0:00	1:00	D
            -Rule	Iran	2024	2025	-	Sep	21	0:00	0	S
            -Rule	Iran	2026	2027	-	Mar	22	0:00	1:00	D
            -Rule	Iran	2026	2027	-	Sep	22	0:00	0	S
            +Rule	Iran	2024	only	-	Mar	21	0:00	1:00	D
            +Rule	Iran	2024	only	-	Sep	21	0:00	0	S
            +Rule	Iran	2025	2027	-	Mar	22	0:00	1:00	D
            +Rule	Iran	2025	2027	-	Sep	22	0:00	0	S
             Rule	Iran	2028	2029	-	Mar	21	0:00	1:00	D
             Rule	Iran	2028	2029	-	Sep	21	0:00	0	S
             Rule	Iran	2030	2031	-	Mar	22	0:00	1:00	D
            @@ -539,7 +935,7 @@
             
             # Iraq
             #
            -# From Jonathan Lennox  (2000-06-12):
            +# From Jonathan Lennox (2000-06-12):
             # An article in this week's Economist ("Inside the Saddam-free zone", p. 50 in
             # the U.S. edition) on the Iraqi Kurds contains a paragraph:
             # "The three northern provinces ... switched their clocks this spring and
            @@ -553,6 +949,21 @@
             #
             # So we'll ignore the Economist's claim.
             
            +# From Steffen Thorsen (2008-03-10):
            +# The cabinet in Iraq abolished DST last week, according to the following
            +# news sources (in Arabic):
            +# 
            +# http://www.aljeeran.net/wesima_articles/news-20080305-98602.html
            +# 
            +# 
            +# http://www.aswataliraq.info/look/article.tpl?id=2047&IdLanguage=17&IdPublication=4&NrArticle=71743&NrIssue=1&NrSection=10
            +# 
            +#
            +# We have published a short article in English about the change:
            +# 
            +# http://www.timeanddate.com/news/time/iraq-dumps-daylight-saving.html
            +# 
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Iraq	1982	only	-	May	1	0:00	1:00	D
             Rule	Iraq	1982	1984	-	Oct	1	0:00	0	S
            @@ -561,9 +972,10 @@
             Rule	Iraq	1985	1990	-	Sep	lastSun	1:00s	0	S
             Rule	Iraq	1986	1990	-	Mar	lastSun	1:00s	1:00	D
             # IATA SSIM (1991/1996) says Apr 1 12:01am UTC; guess the `:01' is a typo.
            -# Shanks says Iraq did not observe DST 1992/1997 or 1999 on; ignore this.
            -Rule	Iraq	1991	max	-	Apr	 1	3:00s	1:00	D
            -Rule	Iraq	1991	max	-	Oct	 1	3:00s	0	S
            +# Shanks & Pottenger say Iraq did not observe DST 1992/1997; ignore this.
            +#
            +Rule	Iraq	1991	2007	-	Apr	 1	3:00s	1:00	D
            +Rule	Iraq	1991	2007	-	Oct	 1	3:00s	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Baghdad	2:57:40	-	LMT	1890
             			2:57:36	-	BMT	1918	    # Baghdad Mean Time?
            @@ -595,7 +1007,7 @@
             # high on my favorite-country list (and not only because my wife's
             # family is from India).
             
            -# From Shanks:
            +# From Shanks & Pottenger:
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Zion	1940	only	-	Jun	 1	0:00	1:00	D
             Rule	Zion	1942	1944	-	Nov	 1	0:00	0	S
            @@ -638,8 +1050,9 @@
             Rule	Zion	1988	only	-	Apr	 9	0:00	1:00	D
             Rule	Zion	1988	only	-	Sep	 3	0:00	0	S
             
            -# From Ephraim Silverberg 
            -# (1997-03-04, 1998-03-16, 1998-12-28, 2000-01-17 and 2000-07-25):
            +# From Ephraim Silverberg
            +# (1997-03-04, 1998-03-16, 1998-12-28, 2000-01-17, 2000-07-25, 2004-12-22,
            +# and 2005-02-17):
             
             # According to the Office of the Secretary General of the Ministry of
             # Interior, there is NO set rule for Daylight-Savings/Standard time changes.
            @@ -690,13 +1103,13 @@
             # time, Haim Ramon.  The official announcement regarding 1996-1998
             # (with the dates for 1997-1998 no longer being relevant) can be viewed at:
             #
            -#   ftp://ftp.huji.ac.il/pub/tz/announcements/1996-1998.ramon.ps.gz
            +#   ftp://ftp.cs.huji.ac.il/pub/tz/announcements/1996-1998.ramon.ps.gz
             #
             # The dates for 1997-1998 were altered by his successor, Rabbi Eli Suissa.
             #
             # The official announcements for the years 1997-1999 can be viewed at:
             #
            -#   ftp://ftp.huji.ac.il/pub/tz/announcements/YYYY.ps.gz
            +#   ftp://ftp.cs.huji.ac.il/pub/tz/announcements/YYYY.ps.gz
             #
             #       where YYYY is the relevant year.
             
            @@ -716,12 +1129,12 @@
             #
             # The official announcement for the start date of 2000 can be viewed at:
             #
            -#	ftp://ftp.huji.ac.il/pub/tz/announcements/2000-start.ps.gz
            +#	ftp://ftp.cs.huji.ac.il/pub/tz/announcements/2000-start.ps.gz
             #
             # The official announcement for the end date of 2000 and the dates
             # for the years 2001-2004 can be viewed at:
             #
            -#	ftp://ftp.huji.ac.il/pub/tz/announcements/2000-2004.ps.gz
            +#	ftp://ftp.cs.huji.ac.il/pub/tz/announcements/2000-2004.ps.gz
             
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Zion	2000	only	-	Apr	14	2:00	1:00	D
            @@ -735,72 +1148,115 @@
             Rule	Zion	2004	only	-	Apr	 7	1:00	1:00	D
             Rule	Zion	2004	only	-	Sep	22	1:00	0	S
             
            -# From Paul Eggert (2000-07-25):
            -# Here are guesses for rules after 2004.
            -# They are probably wrong, but they are more likely than no DST at all.
            -# Rule	NAME    FROM    TO      TYPE    IN      ON      AT      SAVE    LETTER/S
            -Rule	Zion	2005	max	-	Apr	 1	1:00	1:00	D
            -Rule	Zion	2005	max	-	Oct	 1	1:00	0	S
            +# The proposed law agreed upon by the Knesset Interior Committee on
            +# 2005-02-14 is that, for 2005 and beyond, DST starts at 02:00 the
            +# last Friday before April 2nd (i.e. the last Friday in March or April
            +# 1st itself if it falls on a Friday) and ends at 02:00 on the Saturday
            +# night _before_ the fast of Yom Kippur.
            +#
            +# Those who can read Hebrew can view the announcement at:
            +#
            +#	ftp://ftp.cs.huji.ac.il/pub/tz/announcements/2005+beyond.ps
             
            +# From Paul Eggert (2005-02-22):
            +# I used Ephraim Silverberg's dst-israel.el program
            +#  (2005-02-20)
            +# along with Ed Reingold's cal-hebrew in GNU Emacs 21.4,
            +# to generate the transitions in this list.
            +# (I replaced "lastFri" with "Fri>=26" by hand.)
            +# The spring transitions below all correspond to the following Rule:
            +#
            +# Rule	Zion	2005	max	-	Mar	Fri>=26	2:00	1:00	D
            +#
            +# but older zic implementations (e.g., Solaris 8) do not support
            +# "Fri>=26" to mean April 1 in years like 2005, so for now we list the
            +# springtime transitions explicitly.
            +
            +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            +Rule	Zion	2005	only	-	Apr	 1	2:00	1:00	D
            +Rule	Zion	2005	only	-	Oct	 9	2:00	0	S
            +Rule	Zion	2006	2010	-	Mar	Fri>=26	2:00	1:00	D
            +Rule	Zion	2006	only	-	Oct	 1	2:00	0	S
            +Rule	Zion	2007	only	-	Sep	16	2:00	0	S
            +Rule	Zion	2008	only	-	Oct	 5	2:00	0	S
            +Rule	Zion	2009	only	-	Sep	27	2:00	0	S
            +Rule	Zion	2010	only	-	Sep	12	2:00	0	S
            +Rule	Zion	2011	only	-	Apr	 1	2:00	1:00	D
            +Rule	Zion	2011	only	-	Oct	 2	2:00	0	S
            +Rule	Zion	2012	2015	-	Mar	Fri>=26	2:00	1:00	D
            +Rule	Zion	2012	only	-	Sep	23	2:00	0	S
            +Rule	Zion	2013	only	-	Sep	 8	2:00	0	S
            +Rule	Zion	2014	only	-	Sep	28	2:00	0	S
            +Rule	Zion	2015	only	-	Sep	20	2:00	0	S
            +Rule	Zion	2016	only	-	Apr	 1	2:00	1:00	D
            +Rule	Zion	2016	only	-	Oct	 9	2:00	0	S
            +Rule	Zion	2017	2021	-	Mar	Fri>=26	2:00	1:00	D
            +Rule	Zion	2017	only	-	Sep	24	2:00	0	S
            +Rule	Zion	2018	only	-	Sep	16	2:00	0	S
            +Rule	Zion	2019	only	-	Oct	 6	2:00	0	S
            +Rule	Zion	2020	only	-	Sep	27	2:00	0	S
            +Rule	Zion	2021	only	-	Sep	12	2:00	0	S
            +Rule	Zion	2022	only	-	Apr	 1	2:00	1:00	D
            +Rule	Zion	2022	only	-	Oct	 2	2:00	0	S
            +Rule	Zion	2023	2032	-	Mar	Fri>=26	2:00	1:00	D
            +Rule	Zion	2023	only	-	Sep	24	2:00	0	S
            +Rule	Zion	2024	only	-	Oct	 6	2:00	0	S
            +Rule	Zion	2025	only	-	Sep	28	2:00	0	S
            +Rule	Zion	2026	only	-	Sep	20	2:00	0	S
            +Rule	Zion	2027	only	-	Oct	10	2:00	0	S
            +Rule	Zion	2028	only	-	Sep	24	2:00	0	S
            +Rule	Zion	2029	only	-	Sep	16	2:00	0	S
            +Rule	Zion	2030	only	-	Oct	 6	2:00	0	S
            +Rule	Zion	2031	only	-	Sep	21	2:00	0	S
            +Rule	Zion	2032	only	-	Sep	12	2:00	0	S
            +Rule	Zion	2033	only	-	Apr	 1	2:00	1:00	D
            +Rule	Zion	2033	only	-	Oct	 2	2:00	0	S
            +Rule	Zion	2034	2037	-	Mar	Fri>=26	2:00	1:00	D
            +Rule	Zion	2034	only	-	Sep	17	2:00	0	S
            +Rule	Zion	2035	only	-	Oct	 7	2:00	0	S
            +Rule	Zion	2036	only	-	Sep	28	2:00	0	S
            +Rule	Zion	2037	only	-	Sep	13	2:00	0	S
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Jerusalem	2:20:56 -	LMT	1880
             			2:20:40	-	JMT	1918	# Jerusalem Mean Time?
             			2:00	Zion	I%sT
             
            -# From Ephraim Silverberg (2003-03-23):
            -#
            -# Minister of Interior Poraz has announced that he will respect the law
            -# passed in July 2000 (proposed at the time jointly by himself and
            -# then-MK David Azulai [Shas]) fixing the dates for 2000-2004.  Hence,
            -# the dates for 2003 and 2004 remain unchanged....
            -#
            -# As far as 2005 and beyond, no dates have been set.  However, the
            -# minister has mentioned that he wishes to propose to move Israel's
            -# timezone in 2005 from GMT+2 to GMT+3 and upon that have DST during
            -# the summer months (i.e. GMT+4).  However, no legislation in this
            -# direction is expected until the latter part of 2004 which is a long
            -# time off in terms of Israeli politics.
             
            -# (2004-09-20):
            -# The latest rumour, however, is that in 2005, when the clock changes to
            -# Daylight Saving Time (date as yet unknown), the move will be a two-hour leap
            -# forward (from UTC+0200 to UTC+0400) and then, in the fall, the clock will
            -# move back only an hour to UTC+0300 thus effectively moving Israel's timezone
            -# from UTC+0200 to UTC+0300.  However, no actual draft has been put before the
            -# Knesset (Israel's Parliament) though the intention is to do so this
            -# month [2004-09].
             
            -# (2004-09-26):
            -# Even though the draft law for the above did pass the Ministerial Committee
            -# for Legislative Matters three months ago, it was voted down in today's
            -# Cabinet meeting.  The current suggestion is to keep the current timezone at
            -# UTC+0200 but have an extended period of Daylight Saving Time (UTC+0300) from
            -# the beginning of Passover holiday in the spring to after the Tabernacle
            -# holiday in the fall (i.e. the dates of which are governed by the Hebrew
            -# calendar but this means at least 184 days of DST).  However, this is only a
            -# suggestion that was raised in today's cabinet meeting and has not yet been
            -# drafted.
            -
            -
            -
             ###############################################################################
             
             # Japan
             
             # `9:00' and `JST' is from Guy Harris.
             
            -# From Paul Eggert  (1995-03-06):
            +# From Paul Eggert (1995-03-06):
             # Today's _Asahi Evening News_ (page 4) reports that Japan had
             # daylight saving between 1948 and 1951, but ``the system was discontinued
             # because the public believed it would lead to longer working hours.''
            -# Shanks writes that daylight saving in Japan during those years was as follows:
            +
            +# From Mayumi Negishi in the 2005-08-10 Japan Times
            +# :
            +# Occupation authorities imposed daylight-saving time on Japan on
            +# [1948-05-01]....  But lack of prior debate and the execution of
            +# daylight-saving time just three days after the bill was passed generated
            +# deep hatred of the concept....  The Diet unceremoniously passed a bill to
            +# dump the unpopular system in October 1951, less than a month after the San
            +# Francisco Peace Treaty was signed.  (A government poll in 1951 showed 53%
            +# of the Japanese wanted to scrap daylight-saving time, as opposed to 30% who
            +# wanted to keep it.)
            +
            +# From Paul Eggert (2006-03-22):
            +# Shanks & Pottenger write that DST in Japan during those years was as follows:
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -#Rule	Japan	1948	only	-	May	Sun>=1	2:00	1:00	D
            -#Rule	Japan	1948	1951	-	Sep	Sat>=8	2:00	0	S
            -#Rule	Japan	1949	only	-	Apr	Sun>=1	2:00	1:00	D
            -#Rule	Japan	1950	1951	-	May	Sun>=1	2:00	1:00	D
            -# but the only locations using it were US military bases.
            -# We go with Shanks and omit daylight saving in those years for Asia/Tokyo.
            +Rule	Japan	1948	only	-	May	Sun>=1	2:00	1:00	D
            +Rule	Japan	1948	1951	-	Sep	Sat>=8	2:00	0	S
            +Rule	Japan	1949	only	-	Apr	Sun>=1	2:00	1:00	D
            +Rule	Japan	1950	1951	-	May	Sun>=1	2:00	1:00	D
            +# but the only locations using it (for birth certificates, presumably, since
            +# their audience is astrologers) were US military bases.  For now, assume
            +# that for most purposes daylight-saving time was observed; otherwise, what
            +# would have been the point of the 1951 poll?
             
             # From Hideyuki Suzuki (1998-11-09):
             # 'Tokyo' usually stands for the former location of Tokyo Astronomical
            @@ -823,14 +1279,15 @@
             # I wrote "ordinance" above, but I don't know how to translate.
             # In Japanese it's "chokurei", which means ordinance from emperor.
             
            -# Shanks claims JST in use since 1896, and that a few places (e.g. Ishigaki)
            -# use +0800; go with Suzuki.  Guess that all ordinances took effect on Jan 1.
            +# Shanks & Pottenger claim JST in use since 1896, and that a few
            +# places (e.g. Ishigaki) use +0800; go with Suzuki.  Guess that all
            +# ordinances took effect on Jan 1.
             
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Tokyo	9:18:59	-	LMT	1887 Dec 31 15:00u
             			9:00	-	JST	1896
             			9:00	-	CJT	1938
            -			9:00	-	JST
            +			9:00	Japan	J%sT
             # Since 1938, all Japanese possessions have been like Asia/Tokyo.
             
             # Jordan
            @@ -848,6 +1305,51 @@
             # The decision was taken because of the increase in working hours in
             # government's departments from six to seven hours.
             #
            +# From Paul Eggert (2005-11-22):
            +# Starting 2003 transitions are from Steffen Thorsen's web site timeanddate.com.
            +#
            +# From Steffen Thorsen (2005-11-23):
            +# For Jordan I have received multiple independent user reports every year
            +# about DST end dates, as the end-rule is different every year.
            +#
            +# From Steffen Thorsen (2006-10-01), after a heads-up from Hilal Malawi:
            +# http://www.petranews.gov.jo/nepras/2006/Sep/05/4000.htm
            +# "Jordan will switch to winter time on Friday, October 27".
            +#
            +
            +# From Phil Pizzey (2009-04-02):
            +# ...I think I may have spotted an error in the timezone data for
            +# Jordan.
            +# The current (2009d) asia file shows Jordan going to daylight
            +# saving
            +# time on the last Thursday in March.
            +#
            +# Rule  Jordan      2000  max	-  Mar   lastThu     0:00s 1:00  S
            +#
            +# However timeanddate.com, which I usually find reliable, shows Jordan
            +# going to daylight saving time on the last Friday in March since 2002.
            +# Please see
            +# 
            +# http://www.timeanddate.com/worldclock/timezone.html?n=11
            +# 
            +
            +# From Steffen Thorsen (2009-04-02):
            +# This single one might be good enough, (2009-03-24, Arabic):
            +# 
            +# http://petra.gov.jo/Artical.aspx?Lng=2&Section=8&Artical=95279
            +# 
            +#
            +# Google's translation:
            +#
            +# > The Council of Ministers decided in 2002 to adopt the principle of timely
            +# > submission of the summer at 60 minutes as of midnight on the last Thursday
            +# > of the month of March of each year.
            +#
            +# So - this means the midnight between Thursday and Friday since 2002.
            +
            +# From Arthur David Olson (2009-04-06):
            +# We still have Jordan switching to DST on Thursdays in 2000 and 2001.
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Jordan	1973	only	-	Jun	6	0:00	1:00	S
             Rule	Jordan	1973	1975	-	Oct	1	0:00	0	-
            @@ -870,30 +1372,54 @@
             Rule	Jordan	1994	only	-	Sep	Fri>=15	0:00	0	-
             Rule	Jordan	1995	1998	-	Sep	Fri>=15	0:00s	0	-
             Rule	Jordan	1999	only	-	Jul	 1	0:00s	1:00	S
            -Rule	Jordan	1999	max	-	Sep	lastThu	0:00s	0	-
            -Rule	Jordan	2000	max	-	Mar	lastThu	0:00s	1:00	S
            +Rule	Jordan	1999	2002	-	Sep	lastFri	0:00s	0	-
            +Rule	Jordan	2000	2001	-	Mar	lastThu	0:00s	1:00	S
            +Rule	Jordan	2002	max	-	Mar	lastThu	24:00	1:00	S
            +Rule	Jordan	2003	only	-	Oct	24	0:00s	0	-
            +Rule	Jordan	2004	only	-	Oct	15	0:00s	0	-
            +Rule	Jordan	2005	only	-	Sep	lastFri	0:00s	0	-
            +Rule	Jordan	2006	max	-	Oct	lastFri	0:00s	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Amman	2:23:44 -	LMT	1931
             			2:00	Jordan	EE%sT
             
            +
             # Kazakhstan
            +
             # From Paul Eggert (1996-11-22):
            -# Andrew Evtichov  (1996-04-13) writes that Kazakhstan
            +# Andrew Evtichov (1996-04-13) writes that Kazakhstan
             # stayed in sync with Moscow after 1990, and that Aqtobe (formerly Aktyubinsk)
             # and Aqtau (formerly Shevchenko) are the largest cities in their zones.
             # Guess that Aqtau and Aqtobe diverged in 1995, since that's the first time
             # IATA SSIM mentions a third time zone in Kazakhstan.
            -#
            -# From Paul Eggert (2001-10-18):
            +
            +# From Paul Eggert (2006-03-22):
             # German Iofis, ELSI, Almaty (2001-10-09) reports that Kazakhstan uses
             # RussiaAsia rules, instead of switching at 00:00 as the IATA has it.
            -# Go with Shanks, who has them always using RussiaAsia rules.
            -# Also go with the following claims of Shanks:
            +# Go with Shanks & Pottenger, who have them always using RussiaAsia rules.
            +# Also go with the following claims of Shanks & Pottenger:
             #
             # - Kazakhstan did not observe DST in 1991.
             # - Qyzylorda switched from +5:00 to +6:00 on 1992-01-19 02:00.
             # - Oral switched from +5:00 to +4:00 in spring 1989.
            +
            +# 
            +# From Kazakhstan Embassy's News Bulletin #11 (2005-03-21):
            +# 
            +# The Government of Kazakhstan passed a resolution March 15 abolishing
            +# daylight saving time citing lack of economic benefits and health
            +# complications coupled with a decrease in productivity.
             #
            +# From Branislav Kojic (in Astana) via Gwillim Law (2005-06-28):
            +# ... what happened was that the former Kazakhstan Eastern time zone
            +# was "blended" with the Central zone.  Therefore, Kazakhstan now has
            +# two time zones, and difference between them is one hour.  The zone
            +# closer to UTC is the former Western zone (probably still called the
            +# same), encompassing four provinces in the west: Aqtobe, Atyrau,
            +# Mangghystau, and West Kazakhstan.  The other zone encompasses
            +# everything else....  I guess that would make Kazakhstan time zones
            +# de jure UTC+5 and UTC+6 respectively.
            +
             #
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             #
            @@ -902,7 +1428,8 @@
             			5:00	-	ALMT	1930 Jun 21 # Alma-Ata Time
             			6:00 RussiaAsia ALM%sT	1991
             			6:00	-	ALMT	1992
            -			6:00 RussiaAsia	ALM%sT
            +			6:00 RussiaAsia	ALM%sT	2005 Mar 15
            +			6:00	-	ALMT
             # Qyzylorda (aka Kyzylorda, Kizilorda, Kzyl-Orda, etc.)
             Zone	Asia/Qyzylorda	4:21:52 -	LMT	1924 May  2
             			4:00	-	KIZT	1930 Jun 21 # Kizilorda Time
            @@ -912,7 +1439,8 @@
             			5:00 RussiaAsia	KIZ%sT	1991
             			5:00	-	KIZT	1991 Dec 16 # independence
             			5:00	-	QYZT	1992 Jan 19 2:00
            -			6:00 RussiaAsia	QYZ%sT
            +			6:00 RussiaAsia	QYZ%sT	2005 Mar 15
            +			6:00	-	QYZT
             # Aqtobe (aka Aktobe, formerly Akt'ubinsk)
             Zone	Asia/Aqtobe	3:48:40	-	LMT	1924 May  2
             			4:00	-	AKTT	1930 Jun 21 # Aktyubinsk Time
            @@ -921,7 +1449,8 @@
             			6:00	-	AKTT	1982 Apr  1
             			5:00 RussiaAsia	AKT%sT	1991
             			5:00	-	AKTT	1991 Dec 16 # independence
            -			5:00 RussiaAsia	AQT%sT	# Aqtobe Time
            +			5:00 RussiaAsia	AQT%sT	2005 Mar 15 # Aqtobe Time
            +			5:00	-	AQTT
             # Mangghystau
             # Aqtau was not founded until 1963, but it represents an inhabited region,
             # so include time stamps before 1963.
            @@ -933,7 +1462,8 @@
             			5:00 RussiaAsia	SHE%sT	1991
             			5:00	-	SHET	1991 Dec 16 # independence
             			5:00 RussiaAsia	AQT%sT	1995 Mar lastSun 2:00 # Aqtau Time
            -			4:00 RussiaAsia	AQT%sT
            +			4:00 RussiaAsia	AQT%sT	2005 Mar 15
            +			5:00	-	AQTT
             # West Kazakhstan
             Zone	Asia/Oral	3:25:24	-	LMT	1924 May  2 # or Ural'sk
             			4:00	-	URAT	1930 Jun 21 # Ural'sk time
            @@ -943,37 +1473,51 @@
             			5:00 RussiaAsia	URA%sT	1989 Mar 26 2:00
             			4:00 RussiaAsia	URA%sT	1991
             			4:00	-	URAT	1991 Dec 16 # independence
            -			4:00 RussiaAsia	ORA%sT	# Oral Time
            +			4:00 RussiaAsia	ORA%sT	2005 Mar 15 # Oral Time
            +			5:00	-	ORAT
             
             # Kyrgyzstan (Kirgizstan)
            -# Transitions through 1991 are from Shanks.
            +# Transitions through 1991 are from Shanks & Pottenger.
            +
            +# From Paul Eggert (2005-08-15):
            +# According to an article dated today in the Kyrgyzstan Development Gateway
            +# 
            +# Kyrgyzstan is canceling the daylight saving time system.  I take the article
            +# to mean that they will leave their clocks at 6 hours ahead of UTC.
            +# From Malik Abdugaliev (2005-09-21):
            +# Our government cancels daylight saving time 6th of August 2005.
            +# From 2005-08-12 our GMT-offset is +6, w/o any daylight saving.
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -Rule	Kirgiz	1992	1996	-	Apr	Sun>=7	0:00s	1:00	S
            -Rule	Kirgiz	1992	1996	-	Sep	lastSun	0:00	0	-
            -Rule	Kirgiz	1997	max	-	Mar	lastSun	2:30	1:00	S
            -Rule	Kirgiz	1997	max	-	Oct	lastSun	2:30	0	-
            +Rule	Kyrgyz	1992	1996	-	Apr	Sun>=7	0:00s	1:00	S
            +Rule	Kyrgyz	1992	1996	-	Sep	lastSun	0:00	0	-
            +Rule	Kyrgyz	1997	2005	-	Mar	lastSun	2:30	1:00	S
            +Rule	Kyrgyz	1997	2004	-	Oct	lastSun	2:30	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Bishkek	4:58:24 -	LMT	1924 May  2
             			5:00	-	FRUT	1930 Jun 21 # Frunze Time
             			6:00 RussiaAsia FRU%sT	1991 Mar 31 2:00s
             			5:00	1:00	FRUST	1991 Aug 31 2:00 # independence
            -			5:00	Kirgiz	KG%sT		    # Kirgizstan Time
            +			5:00	Kyrgyz	KG%sT	2005 Aug 12    # Kyrgyzstan Time
            +			6:00	-	KGT
             
             ###############################################################################
             
             # Korea (North and South)
             
            -# From Guy Harris:
            -# According to someone at the Korean Times in San Francisco,
            -# Daylight Savings Time was not observed until 1987.  He did not know
            -# at what time of day DST starts or ends.
            +# From Annie I. Bang (2006-07-10) in
            +# :
            +# The Ministry of Commerce, Industry and Energy has already
            +# commissioned a research project [to reintroduce DST] and has said
            +# the system may begin as early as 2008....  Korea ran a daylight
            +# saving program from 1949-61 but stopped it during the 1950-53 Korean War.
             
            -# From Shanks:
            +# From Shanks & Pottenger:
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	ROK	1960	only	-	May	15	0:00	1:00	D
             Rule	ROK	1960	only	-	Sep	13	0:00	0	S
            -Rule	ROK	1987	1988	-	May	Sun<=14	0:00	1:00	D
            -Rule	ROK	1987	1988	-	Oct	Sun<=14	0:00	0	S
            +Rule	ROK	1987	1988	-	May	Sun>=8	0:00	1:00	D
            +Rule	ROK	1987	1988	-	Oct	Sun>=8	0:00	0	S
             
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Seoul	8:27:52	-	LMT	1890
            @@ -996,6 +1540,14 @@
             
             # Kuwait
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            +# From the Arab Times (2007-03-14):
            +# The Civil Service Commission (CSC) has approved a proposal forwarded
            +# by MP Ahmad Baqer on implementing the daylight saving time (DST) in
            +# Kuwait starting from April until the end of Sept this year, reports Al-Anba.
            +# .
            +# From Paul Eggert (2007-03-29):
            +# We don't know the details, or whether the approval means it'll happen,
            +# so for now we assume no DST.
             Zone	Asia/Kuwait	3:11:56 -	LMT	1950
             			3:00	-	AST
             
            @@ -1056,8 +1608,8 @@
             			7:30	-	MALT	1982 Jan  1
             			8:00	-	MYT	# Malaysia Time
             # Sabah & Sarawak
            -# From Paul Eggert (2003-11-01):
            -# The data here are mostly from Shanks, but the 1942, 1945 and 1982
            +# From Paul Eggert (2006-03-22):
            +# The data here are mostly from Shanks & Pottenger, but the 1942, 1945 and 1982
             # transition dates are from Mok Ly Yng.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Asia/Kuching	7:21:20	-	LMT	1926 Mar
            @@ -1075,8 +1627,8 @@
             
             # Mongolia
             
            -# Shanks says that Mongolia has three time zones, but usno1995 and the CIA map
            -# Standard Time Zones of the World (1997-01)
            +# Shanks & Pottenger say that Mongolia has three time zones, but
            +# usno1995 and the CIA map Standard Time Zones of the World (2005-03)
             # both say that it has just one.
             
             # From Oscar van Vlijmen (1999-12-11):
            @@ -1116,7 +1668,7 @@
             #
             # [The province of Selenge is omitted from the above lists.]
             
            -# From Ganbold Ts., Ulaanbaatar  (2004-04-17):
            +# From Ganbold Ts., Ulaanbaatar (2004-04-17):
             # Daylight saving occurs at 02:00 local time last Saturday of March.
             # It will change back to normal at 02:00 local time last Saturday of
             # September.... As I remember this rule was changed in 2001.
            @@ -1125,18 +1677,85 @@
             # For now, assume Rives McDow's informant got confused about Friday vs
             # Saturday, and that his 2001 dates should have 1 added to them.
             
            +# From Paul Eggert (2005-07-26):
            +# We have wildly conflicting information about Mongolia's time zones.
            +# Bill Bonnet (2005-05-19) reports that the US Embassy in Ulaanbaatar says
            +# there is only one time zone and that DST is observed, citing Microsoft
            +# Windows XP as the source.  Risto Nykanen (2005-05-16) reports that
            +# travelmongolia.org says there are two time zones (UTC+7, UTC+8) with no DST.
            +# Oscar van Vlijmen (2005-05-20) reports that the Mongolian Embassy in
            +# Washington, DC says there are two time zones, with DST observed.
            +# He also found
            +# 
            +# which also says that there is DST, and which has a comment by "Toddius"
            +# (2005-03-31 06:05 +0700) saying "Mongolia actually has 3.5 time zones.
            +# The West (OLGII) is +7 GMT, most of the country is ULAT is +8 GMT
            +# and some Eastern provinces are +9 GMT but Sukhbaatar Aimag is SUHK +8.5 GMT.
            +# The SUKH timezone is new this year, it is one of the few things the
            +# parliament passed during the tumultuous winter session."
            +# For now, let's ignore this information, until we have more confirmation.
            +
            +# From Ganbold Ts. (2007-02-26):
            +# Parliament of Mongolia has just changed the daylight-saving rule in February.
            +# They decided not to adopt daylight-saving time....
            +# http://www.mongolnews.mn/index.php?module=unuudur&sec=view&id=15742
            +
            +# From Deborah Goldsmith (2008-03-30):
            +# We received a bug report claiming that the tz database UTC offset for
            +# Asia/Choibalsan (GMT+09:00) is incorrect, and that it should be GMT
            +# +08:00 instead. Different sources appear to disagree with the tz
            +# database on this, e.g.:
            +#
            +# 
            +# http://www.timeanddate.com/worldclock/city.html?n=1026
            +# 
            +# 
            +# http://www.worldtimeserver.com/current_time_in_MN.aspx
            +# 
            +#
            +# both say GMT+08:00.
            +
            +# From Steffen Thorsen (2008-03-31):
            +# eznis airways, which operates several domestic flights, has a flight
            +# schedule here:
            +# 
            +# http://www.eznis.com/Container.jsp?id=112
            +# 
            +# (click the English flag for English)
            +#
            +# There it appears that flights between Choibalsan and Ulaanbatar arrive
            +# about 1:35 - 1:50 hours later in local clock time, no matter the
            +# direction, while Ulaanbaatar-Khvod takes 2 hours in the Eastern
            +# direction and 3:35 back, which indicates that Ulaanbatar and Khvod are
            +# in different time zones (like we know about), while Choibalsan and
            +# Ulaanbatar are in the same time zone (correction needed).
            +
            +# From Arthur David Olson (2008-05-19):
            +# Assume that Choibalsan is indeed offset by 8:00.
            +# XXX--in the absence of better information, assume that transition
            +# was at the start of 2008-03-31 (the day of Steffen Thorsen's report);
            +# this is almost surely wrong.
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Mongol	1983	1984	-	Apr	1	0:00	1:00	S
             Rule	Mongol	1983	only	-	Oct	1	0:00	0	-
            -# IATA SSIM says 1990s switches occurred at 00:00, but Shanks (1995) lists
            -# them at 02:00s, and McDow says the 2001 switches also occurred at 02:00.
            -# Also, IATA SSIM (1996-09) says 1996-10-25.  Go with Shanks through 1998.
            -Rule	Mongol	1985	1998	-	Mar	lastSun	2:00s	1:00	S
            -Rule	Mongol	1984	1998	-	Sep	lastSun	2:00s	0	-
            +# Shanks & Pottenger and IATA SSIM say 1990s switches occurred at 00:00,
            +# but McDow says the 2001 switches occurred at 02:00.  Also, IATA SSIM
            +# (1996-09) says 1996-10-25.  Go with Shanks & Pottenger through 1998.
            +#
            +# Shanks & Pottenger say that the Sept. 1984 through Sept. 1990 switches
            +# in Choibalsan (more precisely, in Dornod and Sukhbaatar) took place
            +# at 02:00 standard time, not at 00:00 local time as in the rest of
            +# the country.  That would be odd, and possibly is a result of their
            +# correction of 02:00 (in the previous edition) not being done correctly
            +# in the latest edition; so ignore it for now.
            +
            +Rule	Mongol	1985	1998	-	Mar	lastSun	0:00	1:00	S
            +Rule	Mongol	1984	1998	-	Sep	lastSun	0:00	0	-
             # IATA SSIM (1999-09) says Mongolia no longer observes DST.
             Rule	Mongol	2001	only	-	Apr	lastSat	2:00	1:00	S
            -Rule	Mongol	2001	max	-	Sep	lastSat	2:00	0	-
            -Rule	Mongol	2002	max	-	Mar	lastSat	2:00	1:00	S
            +Rule	Mongol	2001	2006	-	Sep	lastSat	2:00	0	-
            +Rule	Mongol	2002	2006	-	Mar	lastSat	2:00	1:00	S
             
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             # Hovd, a.k.a. Chovd, Dund-Us, Dzhargalant, Khovd, Jirgalanta
            @@ -1152,11 +1771,12 @@
             Zone	Asia/Choibalsan	7:38:00 -	LMT	1905 Aug
             			7:00	-	ULAT	1978
             			8:00	-	ULAT	1983 Apr
            -			9:00	Mongol	CHO%sT	# Choibalsan Time
            +			9:00	Mongol	CHO%sT	2008 Mar 31 # Choibalsan Time
            +			8:00	Mongol	CHO%sT
             
             # Nepal
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone	Asia/Katmandu	5:41:16 -	LMT	1920
            +Zone	Asia/Kathmandu	5:41:16 -	LMT	1920
             			5:30	-	IST	1986
             			5:45	-	NPT	# Nepal Time
             
            @@ -1202,10 +1822,152 @@
             # The minister told a news conference that the experiment had rather
             # shown 8 per cent higher consumption of electricity.
             
            +# From Alex Krivenyshev (2008-05-15):
            +# 
            +# Here is an article that Pakistan plan to introduce Daylight Saving Time 
            +# on June 1, 2008 for 3 months.
            +# 
            +# "... The federal cabinet on Wednesday announced a new conservation plan to help 
            +# reduce load shedding by approving the closure of commercial centres at 9pm and 
            +# moving clocks forward by one hour for the next three months. 
            +# ...."
            +# 
            +# 
            +# http://www.worldtimezone.net/dst_news/dst_news_pakistan01.html
            +# 
            +# OR
            +# 
            +# http://www.dailytimes.com.pk/default.asp?page=2008%5C05%5C15%5Cstory_15-5-2008_pg1_4
            +# 
             
            +# From Arthur David Olson (2008-05-19):
            +# XXX--midnight transitions is a guess; 2008 only is a guess.
            +
            +# From Alexander Krivenyshev (2008-08-28):
            +# Pakistan government has decided to keep the watches one-hour advanced
            +# for another 2 months--plan to return to Standard Time on October 31
            +# instead of August 31.
            +#
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_pakistan02.html
            +# 
            +# OR
            +# 
            +# http://dailymailnews.com/200808/28/news/dmbrn03.html
            +# 
            +
            +# From Alexander Krivenyshev (2009-04-08):
            +# Based on previous media reports that "... proposed plan to
            +# advance clocks by one hour from May 1 will cause disturbance
            +# to the working schedules rather than bringing discipline in
            +# official working."
            +# 
            +# http://www.thenews.com.pk/daily_detail.asp?id=171280
            +# 
            +#
            +# recent news that instead of May 2009 - Pakistan plan to
            +# introduce DST from April 15, 2009
            +#
            +# FYI: Associated Press Of Pakistan
            +# April 08, 2009
            +# Cabinet okays proposal to advance clocks by one hour from April 15
            +# 
            +# http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=73043&Itemid=1
            +# 
            +#
            +# or
            +#
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_pakistan05.html
            +# 
            +#
            +# ....
            +# The Federal Cabinet on Wednesday approved the proposal to
            +# advance clocks in the country by one hour from April 15 to
            +# conserve energy"
            +
            +# From Steffen Thorsen (2009-09-17):
            +# "The News International," Pakistan reports that: "The Federal
            +# Government has decided to restore the previous time by moving the
            +# clocks backward by one hour from October 1. A formal announcement to
            +# this effect will be made after the Prime Minister grants approval in
            +# this regard." 
            +# 
            +# http://www.thenews.com.pk/updates.asp?id=87168
            +# 
            +
            +# From Alexander Krivenyshev (2009-09-28):
            +# According to Associated Press Of Pakistan, it is confirmed that
            +# Pakistan clocks across the country would be turned back by an hour from October
            +# 1, 2009.
            +#
            +# "Clocks to go back one hour from 1 Oct"
            +# 
            +# http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=86715&Itemid=2
            +# 
            +# or
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_pakistan07.htm
            +# 
            +
            +# From Steffen Thorsen (2009-09-29):
            +# Alexander Krivenyshev wrote:
            +# > According to Associated Press Of Pakistan, it is confirmed that
            +# > Pakistan clocks across the country would be turned back by an hour from October
            +# > 1, 2009.
            +#
            +# Now they seem to have changed their mind, November 1 is the new date:
            +# 
            +# http://www.thenews.com.pk/top_story_detail.asp?Id=24742
            +# 
            +# "The country's clocks will be reversed by one hour on November 1.
            +# Officials of Federal Ministry for Interior told this to Geo News on
            +# Monday."
            +#
            +# And more importantly, it seems that these dates will be kept every year:
            +# "It has now been decided that clocks will be wound forward by one hour
            +# on April 15 and reversed by an hour on November 1 every year without
            +# obtaining prior approval, the officials added."
            +#
            +# We have confirmed this year's end date with both with the Ministry of
            +# Water and Power and the Pakistan Electric Power Company:
            +# 
            +# http://www.timeanddate.com/news/time/pakistan-ends-dst09.html
            +# 
            +
            +# From Christoph Goehre (2009-10-01):
            +# [T]he German Consulate General in Karachi reported me today that Pakistan
            +# will go back to standard time on 1st of November.
            +
            +# From Steffen Thorsen (2010-03-26):
            +# Steffen Thorsen wrote:
            +# > On Thursday (2010-03-25) it was announced that DST would start in
            +# > Pakistan on 2010-04-01.
            +# >
            +# > Then today, the president said that they might have to revert the
            +# > decision if it is not supported by the parliament. So at the time
            +# > being, it seems unclear if DST will be actually observed or not - but
            +# > April 1 could be a more likely date than April 15.
            +# Now, it seems that the decision to not observe DST in final:
            +#
            +# "Govt Withdraws Plan To Advance Clocks"
            +# 
            +# http://www.apakistannews.com/govt-withdraws-plan-to-advance-clocks-172041
            +# 
            +#
            +# "People laud PM's announcement to end DST"
            +# 
            +# http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=99374&Itemid=2
            +# 
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule Pakistan	2002	only	-	Apr	Sun>=2	0:01	1:00	S
             Rule Pakistan	2002	only	-	Oct	Sun>=2	0:01	0	-
            +Rule Pakistan	2008	only	-	Jun	1	0:00	1:00	S
            +Rule Pakistan	2008	only	-	Nov	1	0:00	0	-
            +Rule Pakistan	2009	only	-	Apr	15	0:00	1:00	S
            +Rule Pakistan	2009	only	-	Nov	1	0:00	0	-
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Karachi	4:28:12 -	LMT	1907
             			5:30	-	IST	1942 Sep
            @@ -1216,7 +1978,7 @@
             
             # Palestine
             
            -# From Amos Shapir  (1998-02-15):
            +# From Amos Shapir (1998-02-15):
             #
             # From 1917 until 1948-05-15, all of Palestine, including the parts now
             # known as the Gaza Strip and the West Bank, was under British rule.
            @@ -1258,8 +2020,8 @@
             # I guess more info may be available from the PA's web page (if/when they
             # have one).
             
            -# From Paul Eggert (1998-02-25):
            -# Shanks writes that Gaza did not observe DST until 1957, but we'll go
            +# From Paul Eggert (2006-03-22):
            +# Shanks & Pottenger write that Gaza did not observe DST until 1957, but go
             # with Shapir and assume that it observed DST from 1940 through 1947,
             # and that it used Jordanian rules starting in 1996.
             # We don't yet need a separate entry for the West Bank, since
            @@ -1288,7 +2050,191 @@
             # For now, let's assume that the spring switch was at 24:00,
             # and that they switch at 0:00 on the 3rd Fridays of April and October.
             
            +# From Paul Eggert (2005-11-22):
            +# Starting 2004 transitions are from Steffen Thorsen's web site timeanddate.com.
            +
            +# From Steffen Thorsen (2005-11-23):
            +# A user from Gaza reported that Gaza made the change early because of
            +# the Ramadan.  Next year Ramadan will be even earlier, so I think
            +# there is a good chance next year's end date will be around two weeks
            +# earlier--the same goes for Jordan.
            +
            +# From Steffen Thorsen (2006-08-17):
            +# I was informed by a user in Bethlehem that in Bethlehem it started the
            +# same day as Israel, and after checking with other users in the area, I
            +# was informed that they started DST one day after Israel.  I was not
            +# able to find any authoritative sources at the time, nor details if
            +# Gaza changed as well, but presumed Gaza to follow the same rules as
            +# the West Bank.
            +
            +# From Steffen Thorsen (2006-09-26):
            +# according to the Palestine News Network (2006-09-19):
            +# http://english.pnn.ps/index.php?option=com_content&task=view&id=596&Itemid=5
            +# > The Council of Ministers announced that this year its winter schedule
            +# > will begin early, as of midnight Thursday.  It is also time to turn
            +# > back the clocks for winter.  Friday will begin an hour late this week.
            +# I guess it is likely that next year's date will be moved as well,
            +# because of the Ramadan.
            +
            +# From Jesper Norgaard Welen (2007-09-18):
            +# According to Steffen Thorsen's web site the Gaza Strip and the rest of the
            +# Palestinian territories left DST early on 13.th. of September at 2:00.
            +
            +# From Paul Eggert (2007-09-20):
            +# My understanding is that Gaza and the West Bank disagree even over when
            +# the weekend is (Thursday+Friday versus Friday+Saturday), so I'd be a bit
            +# surprised if they agreed about DST.  But for now, assume they agree.
            +# For lack of better information, predict that future changes will be
            +# the 2nd Thursday of September at 02:00.
            +
            +# From Alexander Krivenyshev (2008-08-28):
            +# Here is an article, that Mideast running on different clocks at Ramadan.
            +#
            +# Gaza Strip (as Egypt) ended DST at midnight Thursday (Aug 28, 2008), while
            +# the West Bank will end Daylight Saving Time at midnight Sunday (Aug 31, 2008).
            +#
            +# 
            +# http://www.guardian.co.uk/world/feedarticle/7759001
            +# 
            +# 
            +# http://www.abcnews.go.com/International/wireStory?id=5676087
            +# 
            +# or
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_gazastrip01.html
            +# 
            +
            +# From Alexander Krivenyshev (2009-03-26):
            +# According to the Palestine News Network (arabic.pnn.ps), Palestinian
            +# government decided to start Daylight Time on Thursday night March
            +# 26 and continue until the night of 27 September 2009.
            +#
            +# (in Arabic)
            +# 
            +# http://arabic.pnn.ps/index.php?option=com_content&task=view&id=50850
            +# 
            +#
            +# or
            +# (English translation)
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_westbank01.html
            +# 
            +
            +# From Steffen Thorsen (2009-08-31):
            +# Palestine's Council of Ministers announced that they will revert back to
            +# winter time on Friday, 2009-09-04.
            +#
            +# One news source:
            +# 
            +# http://www.safa.ps/ara/?action=showdetail&seid=4158
            +# 
            +# (Palestinian press agency, Arabic),
            +# Google translate: "Decided that the Palestinian government in Ramallah
            +# headed by Salam Fayyad, the start of work in time for the winter of
            +# 2009, starting on Friday approved the fourth delay Sept. clock sixty
            +# minutes per hour as of Friday morning."
            +#
            +# We are not sure if Gaza will do the same, last year they had a different
            +# end date, we will keep this page updated:
            +# 
            +# http://www.timeanddate.com/news/time/westbank-gaza-dst-2009.html
            +# 
            +
            +# From Alexander Krivenyshev (2009-09-02):
            +# Seems that Gaza Strip will go back to Winter Time same date as West Bank.
            +#
            +# According to Palestinian Ministry Of Interior, West Bank and Gaza Strip plan
            +# to change time back to Standard time on September 4, 2009.
            +#
            +# "Winter time unite the West Bank and Gaza"
            +# (from Palestinian National Authority):
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_gazastrip02.html
            +# 
            +
            +# From Alexander Krivenyshev (2010-03-19):
            +# According to Voice of Palestine DST will last for 191 days, from March
            +# 26, 2010 till "the last Sunday before the tenth day of Tishri
            +# (October), each year" (October 03, 2010?)
            +#
            +# 
            +# http://palvoice.org/forums/showthread.php?t=245697
            +# 
            +# (in Arabic)
            +# or
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_westbank03.html
            +# 
            +
            +# From Steffen Thorsen (2010-03-24):
            +# ...Ma'an News Agency reports that Hamas cabinet has decided it will
            +# start one day later, at 12:01am. Not sure if they really mean 12:01am or
            +# noon though:
            +#
            +# 
            +# http://www.maannews.net/eng/ViewDetails.aspx?ID=271178
            +# 
            +# (Ma'an News Agency)
            +# "At 12:01am Friday, clocks in Israel and the West Bank will change to
            +# 1:01am, while Gaza clocks will change at 12:01am Saturday morning."
            +
            +# From Steffen Thorsen (2010-08-11):
            +# According to several sources, including
            +# 
            +# http://www.maannews.net/eng/ViewDetails.aspx?ID=306795
            +# 
            +# the clocks were set back one hour at 2010-08-11 00:00:00 local time in 
            +# Gaza and the West Bank.
            +# Some more background info:
            +# 
            +# http://www.timeanddate.com/news/time/westbank-gaza-end-dst-2010.html
            +# 
            +
            +# From Steffen Thorsen (2011-08-26):
            +# Gaza and the West Bank did go back to standard time in the beginning of
            +# August, and will now enter daylight saving time again on 2011-08-30
            +# 00:00 (so two periods of DST in 2011). The pause was because of
            +# Ramadan.
            +#
            +# 
            +# http://www.maannews.net/eng/ViewDetails.aspx?ID=416217
            +# 
            +# Additional info:
            +# 
            +# http://www.timeanddate.com/news/time/palestine-dst-2011.html
            +# 
            +
            +# From Alexander Krivenyshev (2011-08-27):
            +# According to the article in The Jerusalem Post:
            +# "...Earlier this month, the Palestinian government in the West Bank decided to
            +# move to standard time for 30 days, during Ramadan. The Palestinians in the
            +# Gaza Strip accepted the change and also moved their clocks one hour back.
            +# The Hamas government said on Saturday that it won't observe summertime after
            +# the Muslim feast of Id al-Fitr, which begins on Tuesday..."
            +# ...
            +# 
            +# http://www.jpost.com/MiddleEast/Article.aspx?id=235650
            +# 
            +# or
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_gazastrip05.html
            +# 
             # The rules for Egypt are stolen from the `africa' file.
            +
            +# From Steffen Thorsen (2011-09-30):
            +# West Bank did end Daylight Saving Time this morning/midnight (2011-09-30 
            +# 00:00).
            +# So West Bank and Gaza now have the same time again.
            +#
            +# Many sources, including:
            +# 
            +# http://www.maannews.net/eng/ViewDetails.aspx?ID=424808
            +# 
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule EgyptAsia	1957	only	-	May	10	0:00	1:00	S
             Rule EgyptAsia	1957	1958	-	Oct	 1	0:00	0	-
            @@ -1297,17 +2243,45 @@
             Rule EgyptAsia	1959	1965	-	Sep	30	3:00	0	-
             Rule EgyptAsia	1966	only	-	Oct	 1	3:00	0	-
             
            -Rule Palestine	1999	max	-	Apr	Fri>=15	0:00	1:00	S
            -Rule Palestine	1999	max	-	Oct	Fri>=15	0:00	0	-
            +Rule Palestine	1999	2005	-	Apr	Fri>=15	0:00	1:00	S
            +Rule Palestine	1999	2003	-	Oct	Fri>=15	0:00	0	-
            +Rule Palestine	2004	only	-	Oct	 1	1:00	0	-
            +Rule Palestine	2005	only	-	Oct	 4	2:00	0	-
            +Rule Palestine	2006	2008	-	Apr	 1	0:00	1:00	S
            +Rule Palestine	2006	only	-	Sep	22	0:00	0	-
            +Rule Palestine	2007	only	-	Sep	Thu>=8	2:00	0	-
            +Rule Palestine	2008	only	-	Aug	lastFri	0:00	0	-
            +Rule Palestine	2009	only	-	Mar	lastFri	0:00	1:00	S
            +Rule Palestine	2009	only	-	Sep	Fri>=1	2:00	0	-
            +Rule Palestine	2010	only	-	Mar	lastSat	0:01	1:00	S
            +Rule Palestine	2010	only	-	Aug	11	0:00	0	-
             
            +# From Arthur David Olson (2011-09-20):
            +# 2011 transitions per http://www.timeanddate.com as of 2011-09-20.
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Gaza	2:17:52	-	LMT	1900 Oct
             			2:00	Zion	EET	1948 May 15
             			2:00 EgyptAsia	EE%sT	1967 Jun  5
             			2:00	Zion	I%sT	1996
             			2:00	Jordan	EE%sT	1999
            -			2:00 Palestine	EE%sT
            +			2:00 Palestine	EE%sT	2011 Apr  2 12:01
            +			2:00	1:00	EEST	2011 Aug  1
            +			2:00	-	EET
             
            +Zone	Asia/Hebron	2:20:23	-	LMT	1900 Oct
            +			2:00	Zion	EET	1948 May 15
            +			2:00 EgyptAsia	EE%sT	1967 Jun  5
            +			2:00	Zion	I%sT	1996
            +			2:00	Jordan	EE%sT	1999
            +			2:00 Palestine	EE%sT	2008 Aug
            +			2:00 	1:00	EEST	2008 Sep
            +			2:00 Palestine	EE%sT	2011 Apr  1 12:01
            +			2:00	1:00	EEST	2011 Aug  1
            +			2:00	-	EET	2011 Aug 30
            +			2:00	1:00	EEST	2011 Sep 30 3:00
            +			2:00	-	EET
            +
             # Paracel Is
             # no information
             
            @@ -1316,7 +2290,21 @@
             # Philippines, issued a proclamation announcing that 1844-12-30 was to
             # be immediately followed by 1845-01-01.  Robert H. van Gent has a
             # transcript of the decree in .
            -# The rest of this data is from Shanks.
            +# The rest of the data are from Shanks & Pottenger.
            +
            +# From Paul Eggert (2006-04-25):
            +# Tomorrow's Manila Standard reports that the Philippines Department of
            +# Trade and Industry is considering adopting DST this June when the
            +# rainy season begins.  See
            +# .
            +# For now, we'll ignore this, since it's not definite and we lack details.
            +#
            +# From Jesper Norgaard Welen (2006-04-26):
            +# ... claims that Philippines had DST last time in 1990:
            +# http://story.philippinetimes.com/p.x/ct/9/id/145be20cc6b121c0/cid/3e5bbccc730d258c/
            +# [a story dated 2006-04-25 by Cris Larano of Dow Jones Newswires,
            +# but no details]
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Phil	1936	only	-	Nov	1	0:00	1:00	S
             Rule	Phil	1937	only	-	Feb	1	0:00	0	-
            @@ -1376,6 +2364,49 @@
             # With effect from 12.30 a.m. on 26th October 1996
             # Sri Lanka will be six (06) hours ahead of GMT.
             
            +# From Jesper Norgaard Welen (2006-04-14), quoting Sri Lanka News Online
            +#  (2006-04-13):
            +# 0030 hrs on April 15, 2006 (midnight of April 14, 2006 +30 minutes)
            +# at present, become 2400 hours of April 14, 2006 (midnight of April 14, 2006).
            +
            +# From Peter Apps and Ranga Sirila of Reuters (2006-04-12) in:
            +# 
            +# [The Tamil Tigers] never accepted the original 1996 time change and simply
            +# kept their clocks set five and a half hours ahead of Greenwich Mean
            +# Time (GMT), in line with neighbor India.
            +# From Paul Eggert (2006-04-18):
            +# People who live in regions under Tamil control can use [TZ='Asia/Kolkata'],
            +# as that zone has agreed with the Tamil areas since our cutoff date of 1970.
            +
            +# From K Sethu (2006-04-25):
            +# I think the abbreviation LKT originated from the world of computers at
            +# the time of or subsequent to the time zone changes by SL Government
            +# twice in 1996 and probably SL Government or its standardization
            +# agencies never declared an abbreviation as a national standard.
            +#
            +# I recollect before the recent change the government annoucemments
            +# mentioning it as simply changing Sri Lanka Standard Time or Sri Lanka
            +# Time and no mention was made about the abbreviation.
            +#
            +# If we look at Sri Lanka Department of Government's "Official News
            +# Website of Sri Lanka" ... http://www.news.lk/ we can see that they
            +# use SLT as abbreviation in time stamp at the beginning of each news
            +# item....
            +#
            +# Within Sri Lanka I think LKT is well known among computer users and
            +# adminsitrators.  In my opinion SLT may not be a good choice because the
            +# nation's largest telcom / internet operator Sri Lanka Telcom is well
            +# known by that abbreviation - simply as SLT (there IP domains are
            +# slt.lk and sltnet.lk).
            +#
            +# But if indeed our government has adopted SLT as standard abbreviation
            +# (that we have not known so far) then  it is better that it be used for
            +# all computers.
            +
            +# From Paul Eggert (2006-04-25):
            +# One possibility is that we wait for a bit for the dust to settle down
            +# and then see what people actually say in practice.
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Colombo	5:19:24 -	LMT	1880
             			5:19:32	-	MMT	1906	# Moratuwa Mean Time
            @@ -1384,7 +2415,8 @@
             			5:30	1:00	IST	1945 Oct 16 2:00
             			5:30	-	IST	1996 May 25 0:00
             			6:30	-	LKT	1996 Oct 26 0:30
            -			6:00	-	LKT
            +			6:00	-	LKT	2006 Apr 15 0:30
            +			5:30	-	IST
             
             # Syria
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            @@ -1419,17 +2451,138 @@
             # IATA SSIM (1998-02) says 1998-04-02;
             # (1998-09) says 1999-03-29 and 1999-09-29; (1999-02) says 1999-04-02,
             # 2000-04-02, and 2001-04-02; (1999-09) says 2000-03-31 and 2001-03-31;
            -# ignore all these claims and go with Shanks.
            +# (2006) says 2006-03-31 and 2006-09-22;
            +# for now ignore all these claims and go with Shanks & Pottenger,
            +# except for the 2006-09-22 claim (which seems right for Ramadan).
             Rule	Syria	1994	1996	-	Apr	 1	0:00	1:00	S
            -Rule	Syria	1994	max	-	Oct	 1	0:00	0	-
            +Rule	Syria	1994	2005	-	Oct	 1	0:00	0	-
             Rule	Syria	1997	1998	-	Mar	lastMon	0:00	1:00	S
            -Rule	Syria	1999	max	-	Apr	 1	0:00	1:00	S
            +Rule	Syria	1999	2006	-	Apr	 1	0:00	1:00	S
            +# From Stephen Colebourne (2006-09-18):
            +# According to IATA data, Syria will change DST on 21st September [21:00 UTC]
            +# this year [only]....  This is probably related to Ramadan, like Egypt.
            +Rule	Syria	2006	only	-	Sep	22	0:00	0	-
            +# From Paul Eggert (2007-03-29):
            +# Today the AP reported "Syria will switch to summertime at midnight Thursday."
            +# http://www.iht.com/articles/ap/2007/03/29/africa/ME-GEN-Syria-Time-Change.php
            +Rule	Syria	2007	only	-	Mar	lastFri	0:00	1:00	S
            +# From Jesper Norgard (2007-10-27):
            +# The sister center ICARDA of my work CIMMYT is confirming that Syria DST will
            +# not take place 1.st November at 0:00 o'clock but 1.st November at 24:00 or
            +# rather Midnight between Thursday and Friday. This does make more sence than
            +# having it between Wednesday and Thursday (two workdays in Syria) since the
            +# weekend in Syria is not Saturday and Sunday, but Friday and Saturday. So now
            +# it is implemented at midnight of the last workday before weekend...
            +# 
            +# From Steffen Thorsen (2007-10-27):
            +# Jesper Norgaard Welen wrote:
            +# 
            +# > "Winter local time in Syria will be observed at midnight of Thursday 1
            +# > November 2007, and the clock will be put back 1 hour."
            +# 
            +# I found confirmation on this in this gov.sy-article (Arabic):
            +# http://wehda.alwehda.gov.sy/_print_veiw.asp?FileName=12521710520070926111247
            +# 
            +# which using Google's translate tools says:
            +# Council of Ministers also approved the commencement of work on 
            +# identifying the winter time as of Friday, 2/11/2007 where the 60th 
            +# minute delay at midnight Thursday 1/11/2007.
            +Rule	Syria	2007	only	-	Nov	 Fri>=1	0:00	0	-
            +
            +# From Stephen Colebourne (2008-03-17):
            +# For everyone's info, I saw an IATA time zone change for [Syria] for
            +# this month (March 2008) in the last day or so...This is the data IATA
            +# are now using:
            +# Country     Time Standard   --- DST Start ---   --- DST End ---  DST
            +# Name        Zone Variation   Time    Date        Time    Date
            +# Variation
            +# Syrian Arab
            +# Republic    SY    +0200      2200  03APR08       2100  30SEP08   +0300
            +#                              2200  02APR09       2100  30SEP09   +0300
            +#                              2200  01APR10       2100  30SEP10   +0300
            +
            +# From Arthur David Olson (2008-03-17):
            +# Here's a link to English-language coverage by the Syrian Arab News
            +# Agency (SANA)...
            +# 
            +# http://www.sana.sy/eng/21/2008/03/11/165173.htm
            +# ...which reads (in part) "The Cabinet approved the suggestion of the
            +# Ministry of Electricity to begin daylight savings time on Friday April
            +# 4th, advancing clocks one hour ahead on midnight of Thursday April 3rd."
            +# Since Syria is two hours east of UTC, the 2200 and 2100 transition times
            +# shown above match up with midnight in Syria.
            +
            +# From Arthur David Olson (2008-03-18):
            +# My buest guess at a Syrian rule is "the Friday nearest April 1";
            +# coding that involves either using a "Mar Fri>=29" construct that old time zone
            +# compilers can't handle  or having multiple Rules (a la Israel).
            +# For now, use "Apr Fri>=1", and go with IATA on a uniform Sep 30 end.
            +
            +# From Steffen Thorsen (2008-10-07):
            +# Syria has now officially decided to end DST on 2008-11-01 this year,
            +# according to the following article in the Syrian Arab News Agency (SANA).
            +#
            +# The article is in Arabic, and seems to tell that they will go back to
            +# winter time on 2008-11-01 at 00:00 local daylight time (delaying/setting
            +# clocks back 60 minutes).
            +#
            +# 
            +# http://sana.sy/ara/2/2008/10/07/195459.htm
            +# 
            +
            +# From Steffen Thorsen (2009-03-19):
            +# Syria will start DST on 2009-03-27 00:00 this year according to many sources,
            +# two examples:
            +#
            +# 
            +# http://www.sana.sy/eng/21/2009/03/17/217563.htm
            +# 
            +# (English, Syrian Arab News # Agency)
            +# 
            +# http://thawra.alwehda.gov.sy/_View_news2.asp?FileName=94459258720090318012209
            +# 
            +# (Arabic, gov-site)
            +#
            +# We have not found any sources saying anything about when DST ends this year.
            +#
            +# Our summary
            +# 
            +# http://www.timeanddate.com/news/time/syria-dst-starts-march-27-2009.html
            +# 
            +
            +# From Steffen Thorsen (2009-10-27):
            +# The Syrian Arab News Network on 2009-09-29 reported that Syria will 
            +# revert back to winter (standard) time on midnight between Thursday 
            +# 2009-10-29 and Friday 2009-10-30:
            +# 
            +# http://www.sana.sy/ara/2/2009/09/29/247012.htm (Arabic)
            +# 
            +
            +# From Arthur David Olson (2009-10-28):
            +# We'll see if future DST switching times turn out to be end of the last
            +# Thursday of the month or the start of the last Friday of the month or
            +# something else. For now, use the start of the last Friday.
            +
            +# From Steffen Thorsen (2010-03-17):
            +# The "Syrian News Station" reported on 2010-03-16 that the Council of
            +# Ministers has decided that Syria will start DST on midnight Thursday
            +# 2010-04-01: (midnight between Thursday and Friday):
            +# 
            +# http://sns.sy/sns/?path=news/read/11421 (Arabic)
            +# 
            +
            +Rule	Syria	2008	only	-	Apr	Fri>=1	0:00	1:00	S
            +Rule	Syria	2008	only	-	Nov	1	0:00	0	-
            +Rule	Syria	2009	only	-	Mar	lastFri	0:00	1:00	S
            +Rule	Syria	2010	max	-	Apr	Fri>=1	0:00	1:00	S
            +Rule	Syria	2009	max	-	Oct	lastFri	0:00	0	-
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Damascus	2:25:12 -	LMT	1920	# Dimashq
             			2:00	Syria	EE%sT
             
             # Tajikistan
            -# From Shanks.
            +# From Shanks & Pottenger.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Dushanbe	4:35:12 -	LMT	1924 May  2
             			5:00	-	DUST	1930 Jun 21 # Dushanbe Time
            @@ -1444,13 +2597,13 @@
             			7:00	-	ICT
             
             # Turkmenistan
            -# From Shanks.
            +# From Shanks & Pottenger.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Asia/Ashgabat	3:53:32 -	LMT	1924 May  2 # or Ashkhabad
             			4:00	-	ASHT	1930 Jun 21 # Ashkhabad Time
             			5:00 RussiaAsia	ASH%sT	1991 Mar 31 2:00
             			4:00 RussiaAsia	ASH%sT	1991 Oct 27 # independence
            -			4:00 RussiaAsia TM%sT	1992 Jan 19 2:00
            +			4:00 RussiaAsia	TM%sT	1992 Jan 19 2:00
             			5:00	-	TMT
             
             # United Arab Emirates
            @@ -1464,26 +2617,26 @@
             			4:00	-	SAMT	1930 Jun 21 # Samarkand Time
             			5:00	-	SAMT	1981 Apr  1
             			5:00	1:00	SAMST	1981 Oct  1
            -			6:00 RussiaAsia TAS%sT	1991 Mar 31 2:00 # Tashkent Time
            -			5:00 RussiaAsia	TAS%sT	1991 Sep  1 # independence
            +			6:00	-	TAST	1982 Apr  1 # Tashkent Time
            +			5:00 RussiaAsia	SAM%sT	1991 Sep  1 # independence
             			5:00 RussiaAsia	UZ%sT	1992
            -			5:00 RussiaAsia	UZ%sT	1993
             			5:00	-	UZT
             Zone	Asia/Tashkent	4:37:12 -	LMT	1924 May  2
             			5:00	-	TAST	1930 Jun 21 # Tashkent Time
            -			6:00 RussiaAsia TAS%sT	1991 Mar 31 2:00s
            +			6:00 RussiaAsia	TAS%sT	1991 Mar 31 2:00
             			5:00 RussiaAsia	TAS%sT	1991 Sep  1 # independence
             			5:00 RussiaAsia	UZ%sT	1992
            -			5:00 RussiaAsia	UZ%sT	1993
             			5:00	-	UZT
             
             # Vietnam
            -# From Paul Eggert  (1993-11-18):
            -# Saigon's official name is Thanh-Pho Ho Chi Minh, but it's too long.
            -# We'll stick with the traditional name for now.
            -# From Shanks:
            +
            +# From Arthur David Olson (2008-03-18):
            +# The English-language name of Vietnam's most populous city is "Ho Chi Min City";
            +# we use Ho_Chi_Minh below to avoid a name of more than 14 characters.
            +
            +# From Shanks & Pottenger:
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone	Asia/Saigon	7:06:40 -	LMT	1906 Jun  9
            +Zone	Asia/Ho_Chi_Minh	7:06:40 -	LMT	1906 Jun  9
             			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
             			7:00	-	ICT	1912 May
             			8:00	-	ICT	1931 May
            Index: 3rdParty_sources/joda-time/org/joda/time/tz/src/australasia
            ===================================================================
            diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/joda-time/org/joda/time/tz/src/australasia	(.../australasia)	(revision 4e266757c429613d78b0fd2914d40d77a447daad)
            +++ 3rdParty_sources/joda-time/org/joda/time/tz/src/australasia	(.../australasia)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -1,4 +1,8 @@
            -# @(#)australasia	7.69
            +# 
            +# @(#)australasia	8.29
            +# This file is in the public domain, so clarified as of
            +# 2009-05-17 by Arthur David Olson.
            +
             # This file also includes Pacific islands.
             
             # Notes are at the end of this file
            @@ -27,18 +31,27 @@
             			 9:00	-	CST	1899 May
             			 9:30	Aus	CST
             # Western Australia
            +#
            +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            +Rule	AW	1974	only	-	Oct	lastSun	2:00s	1:00	-
            +Rule	AW	1975	only	-	Mar	Sun>=1	2:00s	0	-
            +Rule	AW	1983	only	-	Oct	lastSun	2:00s	1:00	-
            +Rule	AW	1984	only	-	Mar	Sun>=1	2:00s	0	-
            +Rule	AW	1991	only	-	Nov	17	2:00s	1:00	-
            +Rule	AW	1992	only	-	Mar	Sun>=1	2:00s	0	-
            +Rule	AW	2006	only	-	Dec	 3	2:00s	1:00	-
            +Rule	AW	2007	2009	-	Mar	lastSun	2:00s	0	-
            +Rule	AW	2007	2008	-	Oct	lastSun	2:00s	1:00	-
             Zone Australia/Perth	 7:43:24 -	LMT	1895 Dec
             			 8:00	Aus	WST	1943 Jul
            -			 8:00	-	WST	1974 Oct lastSun 2:00s
            -			 8:00	1:00	WST	1975 Mar Sun>=1 2:00s
            -			 8:00	-	WST	1983 Oct lastSun 2:00s
            -			 8:00	1:00	WST	1984 Mar Sun>=1 2:00s
            -			 8:00	-	WST	1991 Nov 17 2:00s
            -			 8:00	1:00	WST	1992 Mar Sun>=1 2:00s
            -			 8:00	-	WST
            +			 8:00	AW	WST
            +Zone Australia/Eucla	 8:35:28 -	LMT	1895 Dec
            +			 8:45	Aus	CWST	1943 Jul
            +			 8:45	AW	CWST
            +
             # Queensland
             #
            -# From Alex Livingston  (1996-11-01):
            +# From Alex Livingston (1996-11-01):
             # I have heard or read more than once that some resort islands off the coast
             # of Queensland chose to keep observing daylight-saving time even after
             # Queensland ceased to.
            @@ -68,23 +81,31 @@
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	AS	1971	1985	-	Oct	lastSun	2:00s	1:00	-
             Rule	AS	1986	only	-	Oct	19	2:00s	1:00	-
            -Rule	AS	1987	max	-	Oct	lastSun	2:00s	1:00	-
            +Rule	AS	1987	2007	-	Oct	lastSun	2:00s	1:00	-
             Rule	AS	1972	only	-	Feb	27	2:00s	0	-
             Rule	AS	1973	1985	-	Mar	Sun>=1	2:00s	0	-
            -Rule	AS	1986	1989	-	Mar	Sun>=15	2:00s	0	-
            -Rule	AS	1990	only	-	Mar	Sun>=18	2:00s	0	-
            -Rule	AS	1991	only	-	Mar	Sun>=1	2:00s	0	-
            -Rule	AS	1992	only	-	Mar	Sun>=18	2:00s	0	-
            -Rule	AS	1993	only	-	Mar	Sun>=1	2:00s	0	-
            -Rule	AS	1994	only	-	Mar	Sun>=18	2:00s	0	-
            -Rule	AS	1995	max	-	Mar	lastSun	2:00s	0	-
            +Rule	AS	1986	1990	-	Mar	Sun>=15	2:00s	0	-
            +Rule	AS	1991	only	-	Mar	3	2:00s	0	-
            +Rule	AS	1992	only	-	Mar	22	2:00s	0	-
            +Rule	AS	1993	only	-	Mar	7	2:00s	0	-
            +Rule	AS	1994	only	-	Mar	20	2:00s	0	-
            +Rule	AS	1995	2005	-	Mar	lastSun	2:00s	0	-
            +Rule	AS	2006	only	-	Apr	2	2:00s	0	-
            +Rule	AS	2007	only	-	Mar	lastSun	2:00s	0	-
            +Rule	AS	2008	max	-	Apr	Sun>=1	2:00s	0	-
            +Rule	AS	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Australia/Adelaide	9:14:20 -	LMT	1895 Feb
             			9:00	-	CST	1899 May
             			9:30	Aus	CST	1971
             			9:30	AS	CST
             
             # Tasmania
            +#
            +# From Paul Eggert (2005-08-16):
            +# 
            +# says King Island didn't observe DST from WWII until late 1971.
            +#
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	AT	1967	only	-	Oct	Sun>=1	2:00s	1:00	-
             Rule	AT	1968	only	-	Mar	lastSun	2:00s	0	-
            @@ -99,15 +120,23 @@
             Rule	AT	1987	only	-	Oct	Sun>=22	2:00s	1:00	-
             Rule	AT	1988	1990	-	Oct	lastSun	2:00s	1:00	-
             Rule	AT	1991	1999	-	Oct	Sun>=1	2:00s	1:00	-
            -Rule	AT	1991	max	-	Mar	lastSun	2:00s	0	-
            +Rule	AT	1991	2005	-	Mar	lastSun	2:00s	0	-
             Rule	AT	2000	only	-	Aug	lastSun	2:00s	1:00	-
             Rule	AT	2001	max	-	Oct	Sun>=1	2:00s	1:00	-
            +Rule	AT	2006	only	-	Apr	Sun>=1	2:00s	0	-
            +Rule	AT	2007	only	-	Mar	lastSun	2:00s	0	-
            +Rule	AT	2008	max	-	Apr	Sun>=1	2:00s	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Australia/Hobart	9:49:16	-	LMT	1895 Sep
             			10:00	-	EST	1916 Oct 1 2:00
             			10:00	1:00	EST	1917 Feb
             			10:00	Aus	EST	1967
             			10:00	AT	EST
            +Zone Australia/Currie	9:35:28	-	LMT	1895 Sep
            +			10:00	-	EST	1916 Oct 1 2:00
            +			10:00	1:00	EST	1917 Feb
            +			10:00	Aus	EST	1971 Jul
            +			10:00	AT	EST
             
             # Victoria
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            @@ -118,9 +147,13 @@
             Rule	AV	1986	1987	-	Oct	Sun>=15	2:00s	1:00	-
             Rule	AV	1988	1999	-	Oct	lastSun	2:00s	1:00	-
             Rule	AV	1991	1994	-	Mar	Sun>=1	2:00s	0	-
            -Rule	AV	1995	max	-	Mar	lastSun	2:00s	0	-
            +Rule	AV	1995	2005	-	Mar	lastSun	2:00s	0	-
             Rule	AV	2000	only	-	Aug	lastSun	2:00s	1:00	-
            -Rule	AV	2001	max	-	Oct	lastSun	2:00s	1:00	-
            +Rule	AV	2001	2007	-	Oct	lastSun	2:00s	1:00	-
            +Rule	AV	2006	only	-	Apr	Sun>=1	2:00s	0	-
            +Rule	AV	2007	only	-	Mar	lastSun	2:00s	0	-
            +Rule	AV	2008	max	-	Apr	Sun>=1	2:00s	0	-
            +Rule	AV	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Australia/Melbourne 9:39:52 -	LMT	1895 Feb
             			10:00	Aus	EST	1971
            @@ -137,9 +170,13 @@
             Rule	AN	1986	only	-	Oct	19	2:00s	1:00	-
             Rule	AN	1987	1999	-	Oct	lastSun	2:00s	1:00	-
             Rule	AN	1990	1995	-	Mar	Sun>=1	2:00s	0	-
            -Rule	AN	1996	max	-	Mar	lastSun	2:00s	0	-
            +Rule	AN	1996	2005	-	Mar	lastSun	2:00s	0	-
             Rule	AN	2000	only	-	Aug	lastSun	2:00s	1:00	-
            -Rule	AN	2001	max	-	Oct	lastSun	2:00s	1:00	-
            +Rule	AN	2001	2007	-	Oct	lastSun	2:00s	1:00	-
            +Rule	AN	2006	only	-	Apr	Sun>=1	2:00s	0	-
            +Rule	AN	2007	only	-	Mar	lastSun	2:00s	0	-
            +Rule	AN	2008	max	-	Apr	Sun>=1	2:00s	0	-
            +Rule	AN	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Australia/Sydney	10:04:52 -	LMT	1895 Feb
             			10:00	Aus	EST	1971
            @@ -160,9 +197,13 @@
             Rule	LH	1986	only	-	Oct	19	2:00	0:30	-
             Rule	LH	1987	1999	-	Oct	lastSun	2:00	0:30	-
             Rule	LH	1990	1995	-	Mar	Sun>=1	2:00	0	-
            -Rule	LH	1996	max	-	Mar	lastSun	2:00	0	-
            +Rule	LH	1996	2005	-	Mar	lastSun	2:00	0	-
             Rule	LH	2000	only	-	Aug	lastSun	2:00	0:30	-
            -Rule	LH	2001	max	-	Oct	lastSun	2:00	0:30	-
            +Rule	LH	2001	2007	-	Oct	lastSun	2:00	0:30	-
            +Rule	LH	2006	only	-	Apr	Sun>=1	2:00	0	-
            +Rule	LH	2007	only	-	Mar	lastSun	2:00	0	-
            +Rule	LH	2008	max	-	Apr	Sun>=1	2:00	0	-
            +Rule	LH	2008	max	-	Oct	Sun>=1	2:00	0:30	-
             Zone Australia/Lord_Howe 10:36:20 -	LMT	1895 Feb
             			10:00	-	EST	1981 Mar
             			10:30	LH	LHST
            @@ -171,24 +212,24 @@
             #
             # Ashmore Is, Cartier
             # no indigenous inhabitants; only seasonal caretakers
            -# like Australia/Perth, says Turner
            +# no times are set
             #
             # Coral Sea Is
             # no indigenous inhabitants; only meteorologists
            -# no information
            +# no times are set
             #
             # Macquarie
             # permanent occupation (scientific station) since 1948;
             # sealing and penguin oil station operated 1888/1917
            -# like Australia/Hobart, says Turner
            +# like Australia/Hobart
             
             # Christmas
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Indian/Christmas	7:02:52 -	LMT	1895 Feb
             			7:00	-	CXT	# Christmas Island Time
             
             # Cook Is
            -# From Shanks:
            +# From Shanks & Pottenger:
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Cook	1978	only	-	Nov	12	0:00	0:30	HS
             Rule	Cook	1979	1991	-	Mar	Sun>=1	0:00	0	-
            @@ -199,14 +240,97 @@
             			-10:00	Cook	CK%sT
             
             # Cocos
            -# From USNO (1989):
            +# These islands were ruled by the Ross family from about 1830 to 1978.
            +# We don't know when standard time was introduced; for now, we guess 1900.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone	Indian/Cocos	6:30	-	CCT	# Cocos Islands Time
            +Zone	Indian/Cocos	6:27:40	-	LMT	1900
            +			6:30	-	CCT	# Cocos Islands Time
             
             # Fiji
            +# From Alexander Krivenyshev (2009-11-10):
            +# According to Fiji Broadcasting Corporation,  Fiji plans to re-introduce DST
            +# from November 29th 2009  to April 25th 2010.
            +#
            +# "Daylight savings to commence this month"
            +# 
            +# http://www.radiofiji.com.fj/fullstory.php?id=23719
            +# 
            +# or
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_fiji01.html
            +# 
            +
            +# From Steffen Thorsen (2009-11-10):
            +# The Fiji Government has posted some more details about the approved
            +# amendments:
            +# 
            +# http://www.fiji.gov.fj/publish/page_16198.shtml
            +# 
            +
            +# From Steffen Thorsen (2010-03-03):
            +# The Cabinet in Fiji has decided to end DST about a month early, on
            +# 2010-03-28 at 03:00.
            +# The plan is to observe DST again, from 2010-10-24 to sometime in March
            +# 2011 (last Sunday a good guess?).
            +#
            +# Official source:
            +# 
            +# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=1096:3310-cabinet-approves-change-in-daylight-savings-dates&catid=49:cabinet-releases&Itemid=166
            +# 
            +#
            +# A bit more background info here:
            +# 
            +# http://www.timeanddate.com/news/time/fiji-dst-ends-march-2010.html
            +# 
            +
            +# From Alexander Krivenyshev (2010-10-24):
            +# According to Radio Fiji and Fiji Times online, Fiji will end DST 3 
            +# weeks earlier than expected - on March 6, 2011, not March 27, 2011...
            +# Here is confirmation from Government of the Republic of the Fiji Islands, 
            +# Ministry of Information (fiji.gov.fj) web site:
            +# 
            +# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=2608:daylight-savings&catid=71:press-releases&Itemid=155
            +# 
            +# or
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_fiji04.html
            +# 
            +
            +# From Steffen Thorsen (2011-10-03):
            +# Now the dates have been confirmed, and at least our start date 
            +# assumption was correct (end date was one week wrong).
            +#
            +# 
            +# www.fiji.gov.fj/index.php?option=com_content&view=article&id=4966:daylight-saving-starts-in-fiji&catid=71:press-releases&Itemid=155
            +# 
            +# which says
            +# Members of the public are reminded to change their time to one hour in 
            +# advance at 2am to 3am on October 23, 2011 and one hour back at 3am to 
            +# 2am on February 26 next year.
            +
            +# From Ken Rylander (2011-10-24)
            +# Another change to the Fiji DST end date. In the TZ database the end date for
            +# Fiji DST 2012, is currently Feb 26. This has been changed to Jan 22.
            +#
            +# 
            +# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=5017:amendments-to-daylight-savings&catid=71:press-releases&Itemid=155
            +# 
            +# states:
            +#
            +# The end of daylight saving scheduled initially for the 26th of February 2012
            +# has been brought forward to the 22nd of January 2012.
            +# The commencement of daylight saving will remain unchanged and start
            +# on the  23rd of October, 2011.
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Fiji	1998	1999	-	Nov	Sun>=1	2:00	1:00	S
             Rule	Fiji	1999	2000	-	Feb	lastSun	3:00	0	-
            +Rule	Fiji	2009	only	-	Nov	29	2:00	1:00	S
            +Rule	Fiji	2010	only	-	Mar	lastSun	3:00	0	-
            +Rule	Fiji	2010	only	-	Oct	24	2:00	1:00	S
            +Rule	Fiji	2011	only	-	Mar	Sun>=1	3:00	0	-
            +Rule	Fiji	2011	only	-	Oct	23	2:00	1:00	S
            +Rule	Fiji	2012	only	-	Jan	22	3:00	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Pacific/Fiji	11:53:40 -	LMT	1915 Oct 26	# Suva
             			12:00	Fiji	FJ%sT	# Fiji Time
            @@ -262,13 +386,10 @@
             
             # Micronesia
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone Pacific/Yap	9:12:32	-	LMT	1901		# Colonia
            -			9:00	-	YAPT	1969 Oct	# Yap Time
            -			10:00	-	YAPT
            -Zone Pacific/Truk	10:07:08 -	LMT	1901
            -			10:00	-	TRUT			# Truk Time
            -Zone Pacific/Ponape	10:32:52 -	LMT	1901		# Kolonia
            -			11:00	-	PONT			# Ponape Time
            +Zone Pacific/Chuuk	10:07:08 -	LMT	1901
            +			10:00	-	CHUT			# Chuuk Time
            +Zone Pacific/Pohnpei	10:32:52 -	LMT	1901		# Kolonia
            +			11:00	-	PONT			# Pohnpei Time
             Zone Pacific/Kosrae	10:51:56 -	LMT	1901
             			11:00	-	KOST	1969 Oct	# Kosrae Time
             			12:00	-	KOST	1999
            @@ -287,7 +408,7 @@
             Rule	NC	1977	1978	-	Dec	Sun>=1	0:00	1:00	S
             Rule	NC	1978	1979	-	Feb	27	0:00	0	-
             Rule	NC	1996	only	-	Dec	 1	2:00s	1:00	S
            -# Shanks says the following was at 2:00; go with IATA.
            +# Shanks & Pottenger say the following was at 2:00; go with IATA.
             Rule	NC	1997	only	-	Mar	 2	2:00s	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Pacific/Noumea	11:05:48 -	LMT	1912 Jan 13
            @@ -318,10 +439,14 @@
             Rule	Chatham	1976	1989	-	Mar	Sun>=1	2:45s	0	S
             Rule	NZ	1989	only	-	Oct	Sun>=8	2:00s	1:00	D
             Rule	Chatham	1989	only	-	Oct	Sun>=8	2:45s	1:00	D
            -Rule	NZ	1990	max	-	Oct	Sun>=1	2:00s	1:00	D
            -Rule	Chatham	1990	max	-	Oct	Sun>=1	2:45s	1:00	D
            -Rule	NZ	1990	max	-	Mar	Sun>=15	2:00s	0	S
            -Rule	Chatham	1990	max	-	Mar	Sun>=15	2:45s	0	S
            +Rule	NZ	1990	2006	-	Oct	Sun>=1	2:00s	1:00	D
            +Rule	Chatham	1990	2006	-	Oct	Sun>=1	2:45s	1:00	D
            +Rule	NZ	1990	2007	-	Mar	Sun>=15	2:00s	0	S
            +Rule	Chatham	1990	2007	-	Mar	Sun>=15	2:45s	0	S
            +Rule	NZ	2007	max	-	Sep	lastSun	2:00s	1:00	D
            +Rule	Chatham	2007	max	-	Sep	lastSun	2:45s	1:00	D
            +Rule	NZ	2008	max	-	Apr	Sun>=1	2:00s	0	S
            +Rule	Chatham	2008	max	-	Apr	Sun>=1	2:45s	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Pacific/Auckland	11:39:04 -	LMT	1868 Nov  2
             			11:30	NZ	NZ%sT	1946 Jan  1
            @@ -381,11 +506,125 @@
             			-11:00	-	BST	1983 Nov 30	# B=Bering
             			-11:00	-	SST			# S=Samoa
             
            -# W Samoa
            +# Samoa
            +
            +# From Steffen Thorsen (2009-10-16):
            +# We have been in contact with the government of Samoa again, and received
            +# the following info:
            +#
            +# "Cabinet has now approved Daylight Saving to be effected next year
            +# commencing from the last Sunday of September 2010 and conclude first
            +# Sunday of April 2011."
            +#
            +# Background info:
            +# 
            +# http://www.timeanddate.com/news/time/samoa-dst-plan-2009.html
            +# 
            +#
            +# Samoa's Daylight Saving Time Act 2009 is available here, but does not
            +# contain any dates:
            +# 
            +# http://www.parliament.gov.ws/documents/acts/Daylight%20Saving%20Act%20%202009%20%28English%29%20-%20Final%207-7-091.pdf
            +# 
            +
            +# From Laupue Raymond Hughes (2010-10-07):
            +# Please see
            +# 
            +# http://www.mcil.gov.ws
            +# ,
            +# the Ministry of Commerce, Industry and Labour (sideframe) "Last Sunday
            +# September 2010 (26/09/10) - adjust clocks forward from 12:00 midnight
            +# to 01:00am and First Sunday April 2011 (03/04/11) - adjust clocks
            +# backwards from 1:00am to 12:00am"
            +
            +# From Laupue Raymond Hughes (2011-03-07):
            +# I believe this will be posted shortly on the website
            +# 
            +# www.mcil.gov.ws
            +# 
            +#
            +# PUBLIC NOTICE ON DAYLIGHT SAVING TIME
            +#
            +# Pursuant to the Daylight Saving Act 2009 and Cabinets decision,
            +# businesses and the general public are hereby advised that daylight
            +# saving time is on the first Saturday of April 2011 (02/04/11).
            +#
            +# The public is therefore advised that when the standard time strikes
            +# the hour of four oclock (4.00am or 0400 Hours) on the 2nd April 2011,
            +# then all instruments used to measure standard time are to be
            +# adjusted/changed to three oclock (3:00am or 0300Hrs).
            +#
            +# Margaret Fruean ACTING CHIEF EXECUTIVE OFFICER MINISTRY OF COMMERCE,
            +# INDUSTRY AND LABOUR 28th February 2011
            +
            +# From David Zuelke (2011-05-09):
            +# Subject: Samoa to move timezone from east to west of international date line
            +# 
            +# 
            +# http://www.morningstar.co.uk/uk/markets/newsfeeditem.aspx?id=138501958347963
            +# 
            +
            +# From Mark Sim-Smith (2011-08-17):
            +# I have been in contact with Leilani Tuala Warren from the Samoa Law
            +# Reform Commission, and she has sent me a copy of the Bill that she
            +# confirmed has been passed...Most of the sections are about maps rather
            +# than the time zone change, but I'll paste the relevant bits below. But
            +# the essence is that at midnight 29 Dec (UTC-11 I suppose), Samoa
            +# changes from UTC-11 to UTC+13:
            +#
            +# International Date Line Bill 2011
            +#
            +# AN ACT to provide for the change to standard time in Samoa and to make
            +# consequential amendments to the position of the International Date
            +# Line, and for related purposes.
            +#
            +# BE IT ENACTED by the Legislative Assembly of Samoa in Parliament
            +# assembled as follows:
            +#
            +# 1. Short title and commencement-(1) This Act may be cited as the
            +# International Date Line Act 2011. (2) Except for section 5(3) this Act
            +# commences at 12 o'clock midnight, on Thursday 29th December 2011. (3)
            +# Section 5(3) commences on the date of assent by the Head of State.
            +#
            +# [snip]
            +#
            +# 3. Interpretation - [snip] "Samoa standard time" in this Act and any
            +# other statute of Samoa which refers to 'Samoa standard time' means the
            +# time 13 hours in advance of Co-ordinated Universal Time.
            +#
            +# 4. Samoa standard time - (1) Upon the commencement of this Act, Samoa
            +# standard time shall be set at 13 hours in advance of Co-ordinated
            +# Universal Time for the whole of Samoa. (2) All references to Samoa's
            +# time zone and to Samoa standard time in Samoa in all legislation and
            +# instruments after the commencement of this Act shall be references to
            +# Samoa standard time as provided for in this Act. (3) Nothing in this
            +# Act affects the provisions of the Daylight Saving Act 2009, except that
            +# it defines Samoa standard time....
            +
            +# From Laupue Raymond Hughes (2011-09-02):
            +# 
            +# http://www.mcil.gov.ws/mcil_publications.html
            +# 
            +#
            +# here is the official website publication for Samoa DST and dateline change
            +#
            +# DST
            +# Year	End	Time	Start	Time
            +# 2011	- - -	- - -	24 September	3:00am to 4:00am
            +# 2012	01 April	4:00am to 3:00am	- - -	- - -
            +#
            +# Dateline Change skip Friday 30th Dec 2011
            +# Thursday 29th December 2011	23:59:59 Hours
            +# Saturday 31st December 2011	00:00:00 Hours
             Zone Pacific/Apia	 12:33:04 -	LMT	1879 Jul  5
             			-11:26:56 -	LMT	1911
             			-11:30	-	SAMT	1950		# Samoa Time
            -			-11:00	-	WST			# W Samoa Time
            +			-11:00	-	WST	2010 Sep 26
            +			-11:00	1:00	WSDT	2011 Apr 2 4:00
            +			-11:00	-	WST	2011 Sep 24 3:00
            +			-11:00	1:00	WSDT	2011 Dec 30
            +			 13:00	1:00	WSDT	2012 Apr 1 4:00
            +			 13:00	-	WST
             
             # Solomon Is
             # excludes Bougainville, for which see Papua New Guinea
            @@ -419,11 +658,20 @@
             # US minor outlying islands
             
             # Howland, Baker
            -# uninhabited since World War II
            -# no information; was probably like Pacific/Pago_Pago
            +# Howland was mined for guano by American companies 1857-1878 and British
            +# 1886-1891; Baker was similar but exact dates are not known.
            +# Inhabited by civilians 1935-1942; U.S. military bases 1943-1944;
            +# uninhabited thereafter.
            +# Howland observed Hawaii Standard Time (UTC-10:30) in 1937;
            +# see page 206 of Elgen M. Long and Marie K. Long,
            +# Amelia Earhart: the Mystery Solved, Simon & Schuster (2000).
            +# So most likely Howland and Baker observed Hawaii Time from 1935
            +# until they were abandoned after the war.
             
             # Jarvis
            -# uninhabited since 1958
            +# Mined for guano by American companies 1857-1879 and British 1883?-1891?.
            +# Inhabited by civilians 1935-1942; IGY scientific base 1957-1958;
            +# uninhabited thereafter.
             # no information; was probably like Pacific/Kiritimati
             
             # Johnston
            @@ -434,6 +682,17 @@
             # uninhabited
             
             # Midway
            +#
            +# From Mark Brader (2005-01-23):
            +# [Fallacies and Fantasies of Air Transport History, by R.E.G. Davies,
            +# published 1994 by Paladwr Press, McLean, VA, USA; ISBN 0-9626483-5-3]
            +# reproduced a Pan American Airways timeables from 1936, for their weekly
            +# "Orient Express" flights between San Francisco and Manila, and connecting
            +# flights to Chicago and the US East Coast.  As it uses some time zone
            +# designations that I've never seen before:....
            +# Fri. 6:30A Lv. HONOLOLU (Pearl Harbor), H.I.   H.L.T. Ar. 5:30P Sun.
            +#  "   3:00P Ar. MIDWAY ISLAND . . . . . . . . . M.L.T. Lv. 6:00A  "
            +#
             Zone Pacific/Midway	-11:49:28 -	LMT	1901
             			-11:00	-	NST	1956 Jun  3
             			-11:00	1:00	NDT	1956 Sep  2
            @@ -475,19 +734,19 @@
             # go ahead and edit the file (and please send any changes to
             # tz@elsie.nci.nih.gov for general use in the future).
             
            -# From Paul Eggert  (1999-10-29):
            +# From Paul Eggert (2006-03-22):
             # A good source for time zone historical data outside the U.S. is
            -# Thomas G. Shanks, The International Atlas (5th edition),
            -# San Diego: ACS Publications, Inc. (1999).
            +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
            +# San Diego: ACS Publications, Inc. (2003).
             #
             # Gwillim Law writes that a good source
             # for recent time zone data is the International Air Transport
             # Association's Standard Schedules Information Manual (IATA SSIM),
             # published semiannually.  Law sent in several helpful summaries
             # of the IATA's data after 1990.
             #
            -# Except where otherwise noted, Shanks is the source for entries through 1990,
            -# and IATA SSIM is the source for entries after 1990.
            +# Except where otherwise noted, Shanks & Pottenger is the source for
            +# entries through 1990, and IATA SSIM is the source for entries afterwards.
             #
             # Another source occasionally used is Edward W. Whitman, World Time Differences,
             # Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
            @@ -502,6 +761,7 @@
             #		std dst
             #		LMT	Local Mean Time
             #	  8:00	WST WST	Western Australia
            +#	  8:45	CWST CWST Central Western Australia*
             #	  9:00	JST	Japan
             #	  9:30	CST CST	Central Australia
             #	 10:00	EST EST	Eastern Australia
            @@ -521,10 +781,16 @@
             
             # Australia
             
            -# 
            -# Australia's Daylight Saving Times
            -# , by Margaret Turner, summarizes daylight saving issues in Australia.
            +# From Paul Eggert (2005-12-08):
            +# 
            +# Implementation Dates of Daylight Saving Time within Australia
            +#  summarizes daylight saving issues in Australia.
             
            +# From Arthur David Olson (2005-12-12):
            +# 
            +# Lawlink NSW:Daylight Saving in New South Wales
            +#  covers New South Wales in particular.
            +
             # From John Mackin (1991-03-06):
             # We in Australia have _never_ referred to DST as `daylight' time.
             # It is called `summer' time.  Now by a happy coincidence, `summer'
            @@ -549,6 +815,12 @@
             #	WST	for any place operating at a GMTOFF of 8:00
             #	EST	for any place operating at a GMTOFF of 10:00
             
            +# From Chuck Soper (2006-06-01):
            +# I recently found this Australian government web page on time zones:
            +# 
            +# And this government web page lists time zone names and abbreviations:
            +# 
            +
             # From Paul Eggert (2001-04-05), summarizing a long discussion about "EST"
             # versus "AEST" etc.:
             #
            @@ -631,14 +903,14 @@
             #   understood in Australia.
             
             # From Paul Eggert (1995-12-19):
            -# Shanks reports 2:00 for all autumn changes in Australia and New Zealand.
            -# Mark Prior  writes that his newspaper
            +# Shanks & Pottenger report 2:00 for all autumn changes in Australia and NZ.
            +# Mark Prior writes that his newspaper
             # reports that NSW's fall 1995 change will occur at 2:00,
             # but Robert Elz says it's been 3:00 in Victoria since 1970
             # and perhaps the newspaper's `2:00' is referring to standard time.
             # For now we'll continue to assume 2:00s for changes since 1960.
             
            -# From Eric Ulevik  (1998-01-05):
            +# From Eric Ulevik (1998-01-05):
             #
             # Here are some URLs to Australian time legislation. These URLs are stable,
             # and should probably be included in the data file. There are probably more
            @@ -657,6 +929,24 @@
             # Standard Time Act, 1898
             # 
             
            +# From David Grosz (2005-06-13):
            +# It was announced last week that Daylight Saving would be extended by
            +# one week next year to allow for the 2006 Commonwealth Games.
            +# Daylight Saving is now to end for next year only on the first Sunday
            +# in April instead of the last Sunday in March.
            +#
            +# From Gwillim Law (2005-06-14):
            +# I did some Googling and found that all of those states (and territory) plan
            +# to extend DST together in 2006.
            +# ACT: http://www.cmd.act.gov.au/mediareleases/fileread.cfm?file=86.txt
            +# New South Wales: http://www.thecouriermail.news.com.au/common/story_page/0,5936,15538869%255E1702,00.html
            +# South Australia: http://www.news.com.au/story/0,10117,15555031-1246,00.html
            +# Tasmania: http://www.media.tas.gov.au/release.php?id=14772
            +# Victoria: I wasn't able to find anything separate, but the other articles
            +# allude to it.
            +# But not Queensland
            +# http://www.news.com.au/story/0,10117,15564030-1248,00.html.
            +
             # Northern Territory
             
             # From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
            @@ -744,65 +1034,59 @@
             # From Arthur David Olson (1992-03-08):
             # The chosen rules the union of the 1971/1972 change and the 1989-1992 changes.
             
            +# From Christopher Hunt (2006-11-21), after an advance warning
            +# from Jesper Norgaard Welen (2006-11-01):
            +# WA are trialing DST for three years.
            +# 
            +
             # From Rives McDow (2002-04-09):
             # The most interesting region I have found consists of three towns on the
            -# southern coast of Australia, population 10 at last report, along with
            -# 50,000 sheep, about 100 kilometers long and 40 kilometers into the
            -# continent.  The primary town is Madura, with the other towns being
            -# Mundrabilla and Eucla.  According to the sheriff of Madura, the
            -# residents got tired of having to change the time so often, as they are
            -# located in a strip overlapping the border of South Australia and Western
            -# Australia.  South Australia observes daylight saving time; Western
            +# southern coast....  South Australia observes daylight saving time; Western
             # Australia does not.  The two states are one and a half hours apart.  The
             # residents decided to forget about this nonsense of changing the clock so
             # much and set the local time 20 hours and 45 minutes from the
             # international date line, or right in the middle of the time of South
            -# Australia and Western Australia.  As it only affects about 10 people and
            -# tourists staying at the Madura Motel, it has never really made as big an
            -# impact as Broken Hill.  However, as tourist visiting there or anyone
            -# calling the local sheriff will attest, they do keep time in this way.
            +# Australia and Western Australia....
             #
             # From Paul Eggert (2002-04-09):
             # This is confirmed by the section entitled
             # "What's the deal with time zones???" in
            -# ,
            -# which says a few other things:
            +# .
             #
            -# * Border Village, SA also is 45 minutes ahead of Perth.
            -# * The locals call this time zone "central W.A. Time" (presumably "CWAT").
            -# * The locals also call Western Australia time "Perth time".
            +# From Alex Livingston (2006-12-07):
            +# ... it was just on four years ago that I drove along the Eyre Highway,
            +# which passes through eastern Western Australia close to the southern
            +# coast of the continent.
             #
            -# It's not clear from context whether everyone in Western Australia
            -# knows of this naming convention, or whether it's just the people in
            -# this subregion.
            +# I paid particular attention to the time kept there. There can be no
            +# dispute that UTC+08:45 was considered "the time" from the border
            +# village just inside the border with South Australia to as far west
            +# as just east of Caiguna. There can also be no dispute that Eucla is
            +# the largest population centre in this zone....
            +#
            +# Now that Western Australia is observing daylight saving, the
            +# question arose whether this part of the state would follow suit. I
            +# just called the border village and confirmed that indeed they have,
            +# meaning that they are now observing UTC+09:45.
            +#
            +# (2006-12-09):
            +# I personally doubt that either experimentation with daylight saving
            +# in WA or its introduction in SA had anything to do with the genesis
            +# of this time zone.  My hunch is that it's been around since well
            +# before 1975.  I remember seeing it noted on road maps decades ago.
             
            -# South Australia, Tasmania, Victoria
            +# From Paul Eggert (2006-12-15):
            +# For lack of better info, assume the tradition dates back to the
            +# introduction of standard time in 1895.
             
            -# From Arthur David Olson (1992-03-08):
            -# The rules from version 7.1 follow.
            -# There are lots of differences between these rules and
            -# the Shepherd et al. rules.  Since the Shepherd et al. rules
            -# and Bradley White's newspaper article are in agreement on
            -# current DST ending dates, no worries.
            +
            +# southeast Australia
             #
            -# Rule	Oz	1971	1985	-	Oct	lastSun	2:00	1:00	-
            -# Rule	Oz	1986	max	-	Oct	Sun<=24	2:00	1:00	-
            -# Rule	Oz	1972	only	-	Feb	27	3:00	0	-
            -# Rule	Oz	1973	1986	-	Mar	Sun>=1	3:00	0	-
            -# Rule	Oz	1987	max	-	Mar	Sun<=21	3:00	0	-
            -# Zone	Australia/Tasmania	10:00	Oz	EST
            -# Zone	Australia/South		9:30	Oz	CST
            -# Zone	Australia/Victoria	10:00	Oz	EST	1985 Oct lastSun 2:00
            -#				10:00	1:00	EST	1986 Mar Sun<=21 3:00
            -#				10:00	Oz	EST
            +# From Paul Eggert (2007-07-23):
            +# Starting autumn 2008 Victoria, NSW, South Australia, Tasmania and the ACT
            +# end DST the first Sunday in April and start DST the first Sunday in October.
            +# http://www.theage.com.au/news/national/daylight-savings-to-span-six-months/2007/06/27/1182623966703.html
             
            -# From Robert Elz (1991-03-06):
            -# I believe that the current start date for DST is "lastSun" in Oct...
            -# that changed Oct 89.  That is, we're back to the
            -# original rule, and that rule currently applies in all the states
            -# that have dst, incl Qld.  (Certainly it was true in Vic).
            -# The file I'm including says that happened in 1988, I think
            -# that's incorrect, but I'm not 100% certain.
             
             # South Australia
             
            @@ -819,7 +1103,7 @@
             # ...
             # Rule	 AS	1971	max	-	Oct	lastSun	2:00	1:00	D
             # Rule	 AS	1972	1985	-	Mar	Sun>=1	3:00	0	C
            -# Rule	 AS	1986	1990	-	Mar	Sun<=21	3:00	0	C
            +# Rule	 AS	1986	1990	-	Mar	Sun>=15	3:00	0	C
             # Rule	 AS	1991	max	-	Mar	Sun>=1	3:00	0	C
             
             # From Bradley White (1992-03-11):
            @@ -843,11 +1127,14 @@
             # 1994 was at +0930 as John Connolly's customer seems to assert, then I can
             # only conclude that the actual rule is more complicated....
             
            -# From John Warburton  (1994-10-07):
            +# From John Warburton (1994-10-07):
             # The new Daylight Savings dates for South Australia ...
             # was gazetted in the Government Hansard on Sep 26 1994....
             # start on last Sunday in October and end in last sunday in March.
             
            +# From Paul Eggert (2007-07-23):
            +# See "southeast Australia" above for 2008 and later.
            +
             # Tasmania
             
             # The rules for 1967 through 1991 were reported by George Shepherd
            @@ -870,6 +1157,9 @@
             # Sim Alam (2000-07-03) reported a legal citation for the 2000/2001 rules:
             # http://www.thelaw.tas.gov.au/fragview/42++1968+GS3A@EN+2000070300
             
            +# From Paul Eggert (2007-07-23):
            +# See "southeast Australia" above for 2008 and later.
            +
             # Victoria
             
             # The rules for 1971 through 1991 were reported by George Shepherd
            @@ -899,11 +1189,14 @@
             # [1] http://www.hup.harvard.edu/catalog/HEISUN.html
             # [2] http://www.shrine.org.au
             
            +# From Paul Eggert (2007-07-23):
            +# See "southeast Australia" above for 2008 and later.
            +
             # New South Wales
             
             # From Arthur David Olson:
             # New South Wales and subjurisdictions have their own ideas of a fun time.
            -# Based on law library research by John Mackin (john@basser.cs.su.oz),
            +# Based on law library research by John Mackin,
             # who notes:
             #	In Australia, time is not legislated federally, but rather by the
             #	individual states.  Thus, while such terms as ``Eastern Standard Time''
            @@ -912,18 +1205,7 @@
             #	legislation.  This is very important to understand.
             #	I have researched New South Wales time only...
             
            -# From Paul Eggert (1999-09-27):
            -# The Information Service of the Australian National Standards Commission
            -# 
            -# Daylight Saving
            -#  page (1995-04) has an excellent overall history of Australian DST.
            -# The Community Relations Division of the NSW Attorney General's Department
            -# publishes a history of daylight saving in NSW.  See:
            -# 
            -# Lawlink NSW: Daylight Saving in New South Wales
            -# 
            -
            -# From Eric Ulevik  (1999-05-26):
            +# From Eric Ulevik (1999-05-26):
             # DST will start in NSW on the last Sunday of August, rather than the usual
             # October in 2000.  [See: Matthew Moore,
             # 
            @@ -976,6 +1258,9 @@
             # The Queensland Premier Peter Beattie is encouraging northern NSW
             # towns to use Queensland time.
             
            +# From Paul Eggert (2007-07-23):
            +# See "southeast Australia" above for 2008 and later.
            +
             # Yancowinna
             
             # From John Mackin (1989-01-04):
            @@ -1000,7 +1285,7 @@
             # Lord Howe Island
             
             # From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
            -# LHI...		[ Courtesy of Pauline Van Winsen.. pauline@Aus ]
            +# LHI...		[ Courtesy of Pauline Van Winsen ]
             #					[ Dec 1990 ]
             # Lord Howe Island is located off the New South Wales coast, and is half an
             # hour ahead of NSW time.
            @@ -1011,7 +1296,7 @@
             # Lord Howe Island Board (controlling authority for the Island) is
             # seeking the community's views on various options for summer time
             # arrangements on the Island, e.g. advance clocks by 1 full hour
            -# instead of only 30 minutes.  Dependant on the wishes of residents
            +# instead of only 30 minutes.  [Dependent] on the wishes of residents
             # the Board may approach the NSW government to change the existing
             # arrangements.  The starting date for summer time on the Island will
             # however always coincide with the rest of NSW.
            @@ -1023,10 +1308,34 @@
             # shown on clocks on LHI. I guess this means that for 30 minutes at the start
             # of DST, LHI is actually 1 hour ahead of the rest of NSW.
             
            -# From Paul Eggert (2001-02-09):
            -# For Lord Howe dates we use Shanks through 1989, and Lonergan thereafter.
            -# For times we use Lonergan.
            +# From Paul Eggert (2006-03-22):
            +# For Lord Howe dates we use Shanks & Pottenger through 1989, and
            +# Lonergan thereafter.  For times we use Lonergan.
             
            +# From Paul Eggert (2007-07-23):
            +# See "southeast Australia" above for 2008 and later.
            +
            +# From Steffen Thorsen (2009-04-28):
            +# According to the official press release, South Australia's extended daylight 
            +# saving period will continue with the same rules as used during the 2008-2009 
            +# summer (southern hemisphere).
            +# 
            +# From
            +# 
            +# http://www.safework.sa.gov.au/uploaded_files/DaylightDatesSet.pdf
            +# 
            +# The extended daylight saving period that South Australia has been trialling 
            +# for over the last year is now set to be ongoing.
            +# Daylight saving will continue to start on the first Sunday in October each 
            +# year and finish on the first Sunday in April the following year.
            +# Industrial Relations Minister, Paul Caica, says this provides South Australia 
            +# with a consistent half hour time difference with NSW, Victoria, Tasmania and 
            +# the ACT for all 52 weeks of the year...
            +# 
            +# We have a wrap-up here:
            +# 
            +# http://www.timeanddate.com/news/time/south-australia-extends-dst.html
            +# 
             ###############################################################################
             
             # New Zealand
            @@ -1040,7 +1349,7 @@
             # From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
             # # The Country of New Zealand   (Australia's east island -) Gee they hate that!
             # #				   or is Australia the west island of N.Z.
            -# #	[ courtesy of Geoff Tribble.. Geofft@Aus.. Auckland N.Z. ]
            +# #	[ courtesy of Geoff Tribble.. Auckland N.Z. ]
             # #				[ Nov 1990 ]
             # ...
             # Rule	NZ      1974    1988	-	Oct	lastSun	2:00	1:00	D
            @@ -1056,21 +1365,27 @@
             # rather than the October 1 value.
             
             # From Paul Eggert (1995-12-19);
            -# Shanks reports 2:00 for all autumn changes in Australia and New Zealand.
            -# Robert Uzgalis  writes that the New Zealand Daylight
            +# Shank & Pottenger report 2:00 for all autumn changes in Australia and NZ.
            +# Robert Uzgalis writes that the New Zealand Daylight
             # Savings Time Order in Council dated 1990-06-18 specifies 2:00 standard
             # time on both the first Sunday in October and the third Sunday in March.
             # As with Australia, we'll assume the tradition is 2:00s, not 2:00.
             #
            -# From Paul Eggert (2003-05-26):
            +# From Paul Eggert (2006-03-22):
             # The Department of Internal Affairs (DIA) maintains a brief history,
             # as does Carol Squires; see tz-link.htm for the full references.
            -# Use these sources in preference to Shanks.
            +# Use these sources in preference to Shanks & Pottenger.
             #
             # For Chatham, IATA SSIM (1991/1999) gives the NZ rules but with
             # transitions at 2:45 local standard time; this confirms that Chatham
             # is always exactly 45 minutes ahead of Auckland.
             
            +# From Colin Sharples (2007-04-30):
            +# DST will now start on the last Sunday in September, and end on the
            +# first Sunday in April.  The changes take effect this year, meaning
            +# that DST will begin on 2007-09-30 2008-04-06.
            +# http://www.dia.govt.nz/diawebsite.nsf/wpg_URL/Services-Daylight-Saving-Daylight-saving-to-be-extended
            +
             ###############################################################################
             
             
            @@ -1107,7 +1422,7 @@
             
             # From Paul Eggert (1996-01-22):
             # Today's _Wall Street Journal_ (page 1) reports that Kiribati
            -# ``declared it the same day throught the country as of Jan. 1, 1995''
            +# ``declared it the same day [throughout] the country as of Jan. 1, 1995''
             # as part of the competition to be first into the 21st century.
             
             
            @@ -1136,12 +1451,12 @@
             
             # Micronesia
             
            -# Alan Eugene Davis  writes (1996-03-16),
            +# Alan Eugene Davis writes (1996-03-16),
             # ``I am certain, having lived there for the past decade, that "Truk"
             # (now properly known as Chuuk) ... is in the time zone GMT+10.''
             #
            -# Shanks writes that Truk switched from UTC+10 to UTC+11 on 1978-10-01;
            -# ignore this for now.
            +# Shanks & Pottenger write that Truk switched from UTC+10 to UTC+11
            +# on 1978-10-01; ignore this for now.
             
             # From Paul Eggert (1999-10-29):
             # The Federated States of Micronesia Visitors Board writes in
            @@ -1234,8 +1549,8 @@
             # on the World Day of Prayer, you would be the first people on Earth
             # to say your prayers in the morning."
             
            -# From Paul Eggert (1999-08-12):
            -# Shanks says the transition was on 1968-10-01; go with Mundell.
            +# From Paul Eggert (2006-03-22):
            +# Shanks & Pottenger say the transition was on 1968-10-01; go with Mundell.
             
             # From Eric Ulevik (1999-05-03):
             # Tonga's director of tourism, who is also secretary of the National Millenium
            @@ -1244,11 +1559,11 @@
             # October to March, which has won approval in principle from the Tongan
             # Government.
             
            -# From Steffen Thorsen [straen@thorsen.priv.no] (1999-09-09):
            +# From Steffen Thorsen (1999-09-09):
             # * Tonga will introduce DST in November
             #
            -# I was given this link by John Letts :
            -# 
            +# I was given this link by John Letts:
            +# 
             # http://news.bbc.co.uk/hi/english/world/asia-pacific/newsid_424000/424764.stm
             # 
             #
            @@ -1257,8 +1572,8 @@
             # of UTC as well, but as far as I know Fiji will only be 13 hours ahead
             # (12 + 1 hour DST).
             
            -# From Arthur David Olson [arthur_david_olson@nih.gov] (1999-09-20):
            -# According to 
             # http://www.tongaonline.com/news/sept1799.html
             # :
             # "Daylight Savings Time will take effect on Oct. 2 through April 15, 2000
            @@ -1327,12 +1642,30 @@
             # mapmakers redrew the IDL following the boundary of Kiribati.  Even that line
             # has a rather arbitrary nature.  The straight-line boundaries between Pacific
             # island nations that are shown on many maps are based on an international
            -# convention, but are not legally binding national borders.
            -#
            -# An Anglo-French Conference on Time-Keeping at Sea (June, 1917) agreed that
            -# legal time on the high seas would be zone time, i.e., the standard time at
            -# the nearest meridian that is a multiple of fifteen degrees.  The date is
            +# convention, but are not legally binding national borders.... The date is
             # governed by the IDL; therefore, even on the high seas, there may be some
             # places as late as fourteen hours later than UTC.  And, since the IDL is not
             # an international standard, there are some places on the high seas where the
             # correct date is ambiguous.
            +
            +# From Wikipedia  (2005-08-31):
            +# Before 1920, all ships kept local apparent time on the high seas by setting
            +# their clocks at night or at the morning sight so that, given the ship's
            +# speed and direction, it would be 12 o'clock when the Sun crossed the ship's
            +# meridian (12 o'clock = local apparent noon).  During 1917, at the
            +# Anglo-French Conference on Time-keeping at Sea, it was recommended that all
            +# ships, both military and civilian, should adopt hourly standard time zones
            +# on the high seas.  Whenever a ship was within the territorial waters of any
            +# nation it would use that nation's standard time.  The captain was permitted
            +# to change his ship's clocks at a time of his choice following his ship's
            +# entry into another zone time--he often chose midnight.  These zones were
            +# adopted by all major fleets between 1920 and 1925 but not by many
            +# independent merchant ships until World War II.
            +
            +# From Paul Eggert, using references suggested by Oscar van Vlijmen
            +# (2005-03-20):
            +#
            +# The American Practical Navigator (2002)
            +# 
            +# talks only about the 180-degree meridian with respect to ships in
            +# international waters; it ignores the international date line.
            Index: 3rdParty_sources/joda-time/org/joda/time/tz/src/backward
            ===================================================================
            diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/joda-time/org/joda/time/tz/src/backward	(.../backward)	(revision 4e266757c429613d78b0fd2914d40d77a447daad)
            +++ 3rdParty_sources/joda-time/org/joda/time/tz/src/backward	(.../backward)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -1,28 +1,42 @@
            -# @(#)backward	7.26
            +# 
            +# @(#)backward	8.11
            +# This file is in the public domain, so clarified as of
            +# 2009-05-17 by Arthur David Olson.
             
             # This file provides links between current names for time zones
             # and their old names.  Many names changed in late 1993.
             
            +Link	Africa/Asmara		Africa/Asmera
            +Link	Africa/Bamako		Africa/Timbuktu
            +Link	America/Argentina/Catamarca	America/Argentina/ComodRivadavia
             Link	America/Adak		America/Atka
             Link	America/Argentina/Buenos_Aires	America/Buenos_Aires
             Link	America/Argentina/Catamarca	America/Catamarca
            +Link	America/Atikokan	America/Coral_Harbour
             Link	America/Argentina/Cordoba	America/Cordoba
             Link	America/Tijuana		America/Ensenada
            -Link	America/Indianapolis	America/Fort_Wayne
            +Link	America/Indiana/Indianapolis	America/Fort_Wayne
            +Link	America/Indiana/Indianapolis	America/Indianapolis
             Link	America/Argentina/Jujuy	America/Jujuy
             Link	America/Indiana/Knox	America/Knox_IN
            +Link	America/Kentucky/Louisville	America/Louisville
             Link	America/Argentina/Mendoza	America/Mendoza
             Link	America/Rio_Branco	America/Porto_Acre
            -Link	America/Cordoba		America/Rosario
            +Link	America/Argentina/Cordoba	America/Rosario
             Link	America/St_Thomas	America/Virgin
             Link	Asia/Ashgabat		Asia/Ashkhabad
             Link	Asia/Chongqing		Asia/Chungking
             Link	Asia/Dhaka		Asia/Dacca
            +Link	Asia/Kathmandu		Asia/Katmandu
            +Link	Asia/Kolkata		Asia/Calcutta
             Link	Asia/Macau		Asia/Macao
            -Link	Asia/Makassar		Asia/Ujung_Pandang
             Link	Asia/Jerusalem		Asia/Tel_Aviv
            +Link	Asia/Ho_Chi_Minh	Asia/Saigon
             Link	Asia/Thimphu		Asia/Thimbu
            +Link	Asia/Makassar		Asia/Ujung_Pandang
             Link	Asia/Ulaanbaatar	Asia/Ulan_Bator
            +Link	Atlantic/Faroe		Atlantic/Faeroe
            +Link	Europe/Oslo		Atlantic/Jan_Mayen
             Link	Australia/Sydney	Australia/ACT
             Link	Australia/Sydney	Australia/Canberra
             Link	Australia/Lord_Howe	Australia/LHI
            @@ -34,7 +48,7 @@
             Link	Australia/Melbourne	Australia/Victoria
             Link	Australia/Perth		Australia/West
             Link	Australia/Broken_Hill	Australia/Yancowinna
            -Link	America/Porto_Acre	Brazil/Acre
            +Link	America/Rio_Branco	Brazil/Acre
             Link	America/Noronha		Brazil/DeNoronha
             Link	America/Sao_Paulo	Brazil/East
             Link	America/Manaus		Brazil/West
            @@ -52,13 +66,14 @@
             Link	America/Havana		Cuba
             Link	Africa/Cairo		Egypt
             Link	Europe/Dublin		Eire
            +Link	Europe/London		Europe/Belfast
             Link	Europe/Chisinau		Europe/Tiraspol
             Link	Europe/London		GB
             Link	Europe/London		GB-Eire
            -Link	Etc/GMT+0		GMT+0
            -Link	Etc/GMT-0		GMT-0
            -Link	Etc/GMT0		GMT0
            -Link	Etc/Greenwich		Greenwich
            +Link	Etc/GMT			GMT+0
            +Link	Etc/GMT			GMT-0
            +Link	Etc/GMT			GMT0
            +Link	Etc/GMT			Greenwich
             Link	Asia/Hong_Kong		Hongkong
             Link	Atlantic/Reykjavik	Iceland
             Link	Asia/Tehran		Iran
            @@ -70,13 +85,16 @@
             Link	America/Tijuana		Mexico/BajaNorte
             Link	America/Mazatlan	Mexico/BajaSur
             Link	America/Mexico_City	Mexico/General
            -Link	America/Shiprock	Navajo
             Link	Pacific/Auckland	NZ
             Link	Pacific/Chatham		NZ-CHAT
            +Link	America/Denver		Navajo
            +Link	Asia/Shanghai		PRC
             Link	Pacific/Pago_Pago	Pacific/Samoa
            +Link	Pacific/Chuuk		Pacific/Yap
            +Link	Pacific/Chuuk		Pacific/Truk
            +Link	Pacific/Pohnpei		Pacific/Ponape
             Link	Europe/Warsaw		Poland
             Link	Europe/Lisbon		Portugal
            -Link	Asia/Shanghai		PRC
             Link	Asia/Taipei		ROC
             Link	Asia/Seoul		ROK
             Link	Asia/Singapore		Singapore
            @@ -86,7 +104,7 @@
             Link	America/Adak		US/Aleutian
             Link	America/Phoenix		US/Arizona
             Link	America/Chicago		US/Central
            -Link	America/Indianapolis	US/East-Indiana
            +Link	America/Indiana/Indianapolis	US/East-Indiana
             Link	America/New_York	US/Eastern
             Link	Pacific/Honolulu	US/Hawaii
             Link	America/Indiana/Knox	US/Indiana-Starke
            @@ -95,6 +113,6 @@
             Link	America/Los_Angeles	US/Pacific
             Link	Pacific/Pago_Pago	US/Samoa
             Link	Etc/UTC			UTC
            -Link	Etc/Universal		Universal
            +Link	Etc/UTC			Universal
             Link	Europe/Moscow		W-SU
            -Link	Etc/Zulu		Zulu
            +Link	Etc/UTC			Zulu
            Index: 3rdParty_sources/joda-time/org/joda/time/tz/src/etcetera
            ===================================================================
            diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/joda-time/org/joda/time/tz/src/etcetera	(.../etcetera)	(revision 4e266757c429613d78b0fd2914d40d77a447daad)
            +++ 3rdParty_sources/joda-time/org/joda/time/tz/src/etcetera	(.../etcetera)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -1,10 +1,14 @@
            -# @(#)etcetera	7.11
            +# 
            +# @(#)etcetera	8.3
            +# This file is in the public domain, so clarified as of
            +# 2009-05-17 by Arthur David Olson.
             
             # These entries are mostly present for historical reasons, so that
             # people in areas not otherwise covered by the tz files could "zic -l"
             # to a time zone that was right for their area.  These days, the
            -# tz files cover almost all the inhabited world, so there's little
            -# need now for the entries that are not on UTC.
            +# tz files cover almost all the inhabited world, and the only practical
            +# need now for the entries that are not on UTC are for ships at sea
            +# that cannot use POSIX TZ settings.
             
             Zone	Etc/GMT		0	-	GMT
             Zone	Etc/UTC		0	-	UTC
            @@ -32,8 +36,7 @@
             # (i.e. west of Greenwich) even though many people would expect it to
             # mean 4 hours ahead of UTC (i.e. east of Greenwich).
             #
            -# In the draft 5 of POSIX 1003.1-200x, the angle bracket notation
            -# (which is not yet supported by the tz code) allows for
            +# In the draft 5 of POSIX 1003.1-200x, the angle bracket notation allows for
             # TZ='+4'; if you want time zone abbreviations conforming to
             # ISO 8601 you can use TZ='<-0400>+4'.  Thus the commonly-expected
             # offset is kept within the angle bracket (and is used for display)
            Index: 3rdParty_sources/joda-time/org/joda/time/tz/src/europe
            ===================================================================
            diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/joda-time/org/joda/time/tz/src/europe	(.../europe)	(revision 4e266757c429613d78b0fd2914d40d77a447daad)
            +++ 3rdParty_sources/joda-time/org/joda/time/tz/src/europe	(.../europe)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -1,22 +1,25 @@
            -# @(#)europe	7.90
            +# 
            +# @(#)europe	8.40
            +# This file is in the public domain, so clarified as of
            +# 2009-05-17 by Arthur David Olson.
             
             # This data is by no means authoritative; if you think you know better,
             # go ahead and edit the file (and please send any changes to
             # tz@elsie.nci.nih.gov for general use in the future).
             
            -# From Paul Eggert  (1999-10-29):
            +# From Paul Eggert (2006-03-22):
             # A good source for time zone historical data outside the U.S. is
            -# Thomas G. Shanks, The International Atlas (5th edition),
            -# San Diego: ACS Publications, Inc. (1999).
            +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
            +# San Diego: ACS Publications, Inc. (2003).
             #
             # Gwillim Law writes that a good source
             # for recent time zone data is the International Air Transport
             # Association's Standard Schedules Information Manual (IATA SSIM),
             # published semiannually.  Law sent in several helpful summaries
             # of the IATA's data after 1990.
             #
            -# Except where otherwise noted, Shanks is the source for entries through 1991,
            -# and IATA SSIM is the source for entries afterwards.
            +# Except where otherwise noted, Shanks & Pottenger is the source for
            +# entries through 1991, and IATA SSIM is the source for entries afterwards.
             #
             # Other sources occasionally used include:
             #
            @@ -55,7 +58,7 @@
             # A reliable and entertaining source about time zones, especially in Britain,
             # Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
             
            -# From Peter Ilieve  (1994-12-04),
            +# From Peter Ilieve (1994-12-04),
             # The original six [EU members]: Belgium, France, (West) Germany, Italy,
             # Luxembourg, the Netherlands.
             # Plus, from 1 Jan 73: Denmark, Ireland, United Kingdom.
            @@ -81,7 +84,7 @@
             
             # Britain (United Kingdom) and Ireland (Eire)
             
            -# From Peter Ilieve  (1994-07-06):
            +# From Peter Ilieve (1994-07-06):
             #
             # On 17 Jan 1994 the Independent, a UK quality newspaper, had a piece about
             # historical vistas along the Thames in west London. There was a photo
            @@ -102,7 +105,7 @@
             #
             # [This yields GMTOFF = -0:01:15 for London LMT in the 18th century.]
             
            -# From Paul Eggert  (1993-11-18):
            +# From Paul Eggert (1993-11-18):
             #
             # Howse writes that Britain was the first country to use standard time.
             # The railways cared most about the inconsistencies of local mean time,
            @@ -143,7 +146,7 @@
             # A monument to Willett was unveiled on 1927-05-21, in an open space in
             # a 45-acre wood near Chislehurst, Kent that was purchased by popular
             # subscription and open to the public.  On the south face of the monolith,
            -# designed by G. W. Miller, is the the William Willett Memorial Sundial,
            +# designed by G. W. Miller, is the...William Willett Memorial Sundial,
             # which is permanently set to Summer Time.
             
             # From Winston Churchill (1934-04-28):
            @@ -168,12 +171,12 @@
             # known as "British" Summer Time in all parts of the United Kingdom.
             
             # Date: 4 Jan 89 08:57:25 GMT (Wed)
            -# From: Jonathan Leffler 
            +# From: Jonathan Leffler
             # [British Summer Time] is fixed annually by Act of Parliament.
             # If you can predict what Parliament will do, you should be in
             # politics making a fortune, not computing.
             
            -# From Chris Carrier <72157.3334@CompuServe.COM> (1996-06-14):
            +# From Chris Carrier (1996-06-14):
             # I remember reading in various wartime issues of the London Times the
             # acronym BDST for British Double Summer Time.  Look for the published
             # time of sunrise and sunset in The Times, when BDST was in effect, and
            @@ -204,27 +207,28 @@
             # and follows the more usual convention of putting the location name first,
             # so we use `BDST'.
             
            -# Peter Ilieve  (1998-04-19) described at length
            +# Peter Ilieve (1998-04-19) described at length
             # the history of summer time legislation in the United Kingdom.
            -# Since 1998 Joseph S. Myers  has been updating
            +# Since 1998 Joseph S. Myers has been updating
             # and extending this list, which can be found in
             # 
             # History of legal time in Britain
             # 
             
            -# From Joseph S. Myers  (1998-01-06):
            +# From Joseph S. Myers (1998-01-06):
             #
             # The legal time in the UK outside of summer time is definitely GMT, not UTC;
             # see Lord Tanlaw's speech
             # 
             # (Lords Hansard 11 June 1997 columns 964 to 976)
             # .
             
            -# From Paul Eggert (2001-07-18):
            +# From Paul Eggert (2006-03-22):
             #
            -# For lack of other data, we'll follow Shanks for Eire in 1940-1948.
            +# For lack of other data, follow Shanks & Pottenger for Eire in 1940-1948.
             #
            -# Given Ilieve and Myers's data, the following claims by Shanks are incorrect:
            +# Given Ilieve and Myers's data, the following claims by Shanks & Pottenger
            +# are incorrect:
             #     * Wales did not switch from GMT to daylight saving time until
             #	1921 Apr 3, when they began to conform with the rest of Great Britain.
             # Actually, Wales was identical after 1880.
            @@ -236,25 +240,55 @@
             # Actually, that date saw the usual switch to summer time.
             # Standard time was not changed until 1968-10-27 (the clocks didn't change).
             #
            -# Here is another incorrect claim by Shanks:
            +# Here is another incorrect claim by Shanks & Pottenger:
             #     * Jersey, Guernsey, and the Isle of Man did not switch from GMT
             #	to daylight saving time until 1921 Apr 3, when they began to
             #	conform with Great Britain.
             # S.R.&O. 1916, No. 382 and HO 45/10811/312364 (quoted above) say otherwise.
             #
            -# The following claim by Shanks is possible though doubtful;
            +# The following claim by Shanks & Pottenger is possible though doubtful;
             # we'll ignore it for now.
             #     * Dublin's 1971-10-31 switch was at 02:00, even though London's was 03:00.
             #
             #
            -# Whitman says Dublin Mean Time was -0:25:21, which is more precise than Shanks.
            +# Whitman says Dublin Mean Time was -0:25:21, which is more precise than
            +# Shanks & Pottenger.
             # Perhaps this was Dunsink Observatory Time, as Dunsink Observatory
             # (8 km NW of Dublin's center) seemingly was to Dublin as Greenwich was
             # to London.  For example:
             #
             #   "Timeball on the ballast office is down.  Dunsink time."
             #   -- James Joyce, Ulysses
             
            +# From Joseph S. Myers (2005-01-26):
            +# Irish laws are available online at www.irishstatutebook.ie.  These include
            +# various relating to legal time, for example:
            +#
            +# ZZA13Y1923.html ZZA12Y1924.html ZZA8Y1925.html ZZSIV20PG1267.html
            +#
            +# ZZSI71Y1947.html ZZSI128Y1948.html ZZSI23Y1949.html ZZSI41Y1950.html
            +# ZZSI27Y1951.html ZZSI73Y1952.html
            +#
            +# ZZSI11Y1961.html ZZSI232Y1961.html ZZSI182Y1962.html
            +# ZZSI167Y1963.html ZZSI257Y1964.html ZZSI198Y1967.html
            +# ZZA23Y1968.html ZZA17Y1971.html
            +#
            +# ZZSI67Y1981.html ZZSI212Y1982.html ZZSI45Y1986.html
            +# ZZSI264Y1988.html ZZSI52Y1990.html ZZSI371Y1992.html
            +# ZZSI395Y1994.html ZZSI484Y1997.html ZZSI506Y2001.html
            +#
            +# [These are all relative to the root, e.g., the first is
            +# .]
            +#
            +# (These are those I found, but there could be more.  In any case these
            +# should allow various updates to the comments in the europe file to cover
            +# the laws applicable in Ireland.)
            +#
            +# (Note that the time in the Republic of Ireland since 1968 has been defined
            +# in terms of standard time being GMT+1 with a period of winter time when it
            +# is GMT, rather than standard time being GMT with a period of summer time
            +# being GMT+1.)
            +
             # From Paul Eggert (1999-03-28):
             # Clive Feather (, 1997-03-31)
             # reports that Folkestone (Cheriton) Shuttle Terminal uses Concession Time
            @@ -388,18 +422,14 @@
             # See EU for rules starting in 1996.
             
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone	Europe/London	-0:01:15 -	LMT	1847 Dec  1
            +Zone	Europe/London	-0:01:15 -	LMT	1847 Dec  1 0:00s
             			 0:00	GB-Eire	%s	1968 Oct 27
             			 1:00	-	BST	1971 Oct 31 2:00u
             			 0:00	GB-Eire	%s	1996
             			 0:00	EU	GMT/BST
            -Zone	Europe/Belfast	-0:23:40 -	LMT	1880 Aug  2
            -			-0:25:21 -	DMT	1916 May 21 2:00 # Dublin/Dunsink MT
            -			-0:25:21 1:00	IST	1916 Oct  1 2:00s   # Irish Summer Time
            -			 0:00	GB-Eire	%s	1968 Oct 27
            -			 1:00	-	BST	1971 Oct 31 2:00u
            -			 0:00	GB-Eire	%s	1996
            -			 0:00	EU	GMT/BST
            +Link	Europe/London	Europe/Jersey
            +Link	Europe/London	Europe/Guernsey
            +Link	Europe/London	Europe/Isle_of_Man
             Zone	Europe/Dublin	-0:25:00 -	LMT	1880 Aug  2
             			-0:25:21 -	DMT	1916 May 21 2:00
             			-0:25:21 1:00	IST	1916 Oct  1 2:00s
            @@ -416,7 +446,7 @@
             
             ###############################################################################
             
            -# Continental Europe
            +# Europe
             
             # EU rules are for the European Union, previously known as the EC, EEC,
             # Common Market, etc.
            @@ -429,7 +459,7 @@
             Rule	EU	1981	max	-	Mar	lastSun	 1:00u	1:00	S
             Rule	EU	1996	max	-	Oct	lastSun	 1:00u	0	-
             # The most recent directive covers the years starting in 2002.  See:
            -# 
             # Directive 2000/84/EC of the European Parliament and of the Council
             # of 19 January 2001 on summer-time arrangements.
             # 
            @@ -452,9 +482,48 @@
             Rule	C-Eur	1942	only	-	Nov	 2	 2:00s	0	-
             Rule	C-Eur	1943	only	-	Mar	29	 2:00s	1:00	S
             Rule	C-Eur	1943	only	-	Oct	 4	 2:00s	0	-
            -Rule	C-Eur	1944	only	-	Apr	 3	 2:00s	1:00	S
            -# Whitman gives 1944 Oct 7; go with Shanks.
            +Rule	C-Eur	1944	1945	-	Apr	Mon>=1	 2:00s	1:00	S
            +# Whitman gives 1944 Oct 7; go with Shanks & Pottenger.
             Rule	C-Eur	1944	only	-	Oct	 2	 2:00s	0	-
            +# From Jesper Norgaard Welen (2008-07-13):
            +#
            +# I found what is probably a typo of 2:00 which should perhaps be 2:00s
            +# in the C-Eur rule from tz database version 2008d (this part was
            +# corrected in version 2008d). The circumstancial evidence is simply the
            +# tz database itself, as seen below:
            +#
            +# Zone Europe/Paris 0:09:21 - LMT 1891 Mar 15  0:01
            +#    0:00 France WE%sT 1945 Sep 16  3:00
            +#
            +# Zone Europe/Monaco 0:29:32 - LMT 1891 Mar 15
            +#    0:00 France WE%sT 1945 Sep 16 3:00
            +#
            +# Zone Europe/Belgrade 1:22:00 - LMT 1884
            +#    1:00 1:00 CEST 1945 Sep 16  2:00s
            +#
            +# Rule France 1945 only - Sep 16  3:00 0 -
            +# Rule Belgium 1945 only - Sep 16  2:00s 0 -
            +# Rule Neth 1945 only - Sep 16 2:00s 0 -
            +#
            +# The rule line to be changed is:
            +#
            +# Rule C-Eur 1945 only - Sep 16  2:00 0 -
            +#
            +# It seems that Paris, Monaco, Rule France, Rule Belgium all agree on
            +# 2:00 standard time, e.g. 3:00 local time.  However there are no
            +# countries that use C-Eur rules in September 1945, so the only items
            +# affected are apparently these ficticious zones that translates acronyms
            +# CET and MET:
            +#
            +# Zone CET  1:00 C-Eur CE%sT
            +# Zone MET  1:00 C-Eur ME%sT
            +#
            +# It this is right then the corrected version would look like:
            +#
            +# Rule C-Eur 1945 only - Sep 16  2:00s 0 -
            +#
            +# A small step for mankind though 8-)
            +Rule	C-Eur	1945	only	-	Sep	16	 2:00s	0	-
             Rule	C-Eur	1977	1980	-	Apr	Sun>=1	 2:00s	1:00	S
             Rule	C-Eur	1977	only	-	Sep	lastSun	 2:00s	0	-
             Rule	C-Eur	1978	only	-	Oct	 1	 2:00s	0	-
            @@ -492,10 +561,29 @@
             #
             Rule	Russia	1992	only	-	Mar	lastSat	 23:00	1:00	S
             Rule	Russia	1992	only	-	Sep	lastSat	 23:00	0	-
            -Rule	Russia	1993	max	-	Mar	lastSun	 2:00s	1:00	S
            +Rule	Russia	1993	2010	-	Mar	lastSun	 2:00s	1:00	S
             Rule	Russia	1993	1995	-	Sep	lastSun	 2:00s	0	-
            -Rule	Russia	1996	max	-	Oct	lastSun	 2:00s	0	-
            +Rule	Russia	1996	2010	-	Oct	lastSun	 2:00s	0	-
             
            +# From Alexander Krivenyshev (2011-06-14):
            +# According to Kremlin press service, Russian President Dmitry Medvedev
            +# signed a federal law "On calculation of time" on June 9, 2011.
            +# According to the law Russia is abolishing daylight saving time.
            +# 
            +# Medvedev signed a law "On the Calculation of Time" (in russian): 
            +# 
            +# http://bmockbe.ru/events/?ID=7583
            +# 
            +# 
            +# Medvedev signed a law on the calculation of the time (in russian):
            +# 
            +# http://www.regnum.ru/news/polit/1413906.html
            +# 
            +
            +# From Arthur David Olson (2011-06-15):
            +# Take "abolishing daylight saving time" to mean that time is now considered
            +# to be standard.
            +
             # These are for backward compatibility with older versions.
             
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            @@ -507,7 +595,7 @@
             # Previous editions of this database used abbreviations like MET DST
             # for Central European Summer Time, but this didn't agree with common usage.
             
            -# From Markus Kuhn  (1996-07-12):
            +# From Markus Kuhn (1996-07-12):
             # The official German names ... are
             #
             #	Mitteleuropaeische Zeit (MEZ)         = UTC+01:00
            @@ -573,12 +661,12 @@
             
             # Austria
             
            -# From Paul Eggert (2003-02-28): Shanks gives 1918-06-16 and
            +# From Paul Eggert (2006-03-22): Shanks & Pottenger give 1918-06-16 and
             # 1945-11-18, but the Austrian Federal Office of Metrology and
             # Surveying (BEV) gives 1918-09-16 and for Vienna gives the "alleged"
             # date of 1945-04-12 with no time.  For the 1980-04-06 transition
            -# Shanks gives 02:00, the BEV 00:00.  Go with the BEV, and guess 02:00
            -# for 1945-04-12.
            +# Shanks & Pottenger give 02:00, the BEV 00:00.  Go with the BEV,
            +# and guess 02:00 for 1945-04-12.
             
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Austria	1920	only	-	Apr	 5	2:00s	1:00	S
            @@ -600,6 +688,23 @@
             			1:00	EU	CE%sT
             
             # Belarus
            +# From Yauhen Kharuzhy (2011-09-16):
            +# By latest Belarus government act Europe/Minsk timezone was changed to
            +# GMT+3 without DST (was GMT+2 with DST).
            +#
            +# Sources (Russian language):
            +# 1.
            +# 
            +# http://www.belta.by/ru/all_news/society/V-Belarusi-otmenjaetsja-perexod-na-sezonnoe-vremja_i_572952.html
            +# 
            +# 2.
            +# 
            +# http://naviny.by/rubrics/society/2011/09/16/ic_articles_116_175144/
            +# 
            +# 3.
            +# 
            +# http://news.tut.by/society/250578.html
            +# 
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Europe/Minsk	1:50:16 -	LMT	1880
             			1:50	-	MMT	1924 May 2 # Minsk Mean Time
            @@ -611,7 +716,8 @@
             			2:00	1:00	EEST	1991 Sep 29 2:00s
             			2:00	-	EET	1992 Mar 29 0:00s
             			2:00	1:00	EEST	1992 Sep 27 0:00s
            -			2:00	Russia	EE%sT
            +			2:00	Russia	EE%sT	2011 Mar 27 2:00s
            +			3:00	-	FET # Further-eastern European Time
             
             # Belgium
             #
            @@ -623,7 +729,7 @@
             #	pp 8-9.
             # LMT before 1892 was 0:17:30, according to the official journal of Belgium:
             #	Moniteur Belge, Samedi 30 Avril 1892, N.121.
            -# Thanks to Pascal Delmoitie  for these references.
            +# Thanks to Pascal Delmoitie for these references.
             # The 1918 rules are listed for completeness; they apply to unoccupied Belgium.
             # Assume Brussels switched to WET in 1918 when the armistice took effect.
             #
            @@ -678,34 +784,35 @@
             			1:00	EU	CE%sT
             
             # Bosnia and Herzegovina
            -# see Serbia and Montenegro
            +# see Serbia
             
             # Bulgaria
             #
            -# From Plamen Simenov  via Steffen Thorsen (1999-09-09):
            +# From Plamen Simenov via Steffen Thorsen (1999-09-09):
             # A document of Government of Bulgaria (No.94/1997) says:
             # EET --> EETDST is in 03:00 Local time in last Sunday of March ...
             # EETDST --> EET is in 04:00 Local time in last Sunday of October
             #
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Bulg	1979	only	-	Mar	31	23:00	1:00	S
             Rule	Bulg	1979	only	-	Oct	 1	 1:00	0	-
            -Rule	Bulg	1980	1982	-	Apr	Sat<=7	23:00	1:00	S
            +Rule	Bulg	1980	1982	-	Apr	Sat>=1	23:00	1:00	S
             Rule	Bulg	1980	only	-	Sep	29	 1:00	0	-
             Rule	Bulg	1981	only	-	Sep	27	 2:00	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Europe/Sofia	1:33:16 -	LMT	1880
             			1:56:56	-	IMT	1894 Nov 30 # Istanbul MT?
             			2:00	-	EET	1942 Nov  2  3:00
            -			1:00	C-Eur	CE%sT	1945 Apr  2  3:00
            +			1:00	C-Eur	CE%sT	1945
            +			1:00	-	CET	1945 Apr 2 3:00
             			2:00	-	EET	1979 Mar 31 23:00
             			2:00	Bulg	EE%sT	1982 Sep 26  2:00
             			2:00	C-Eur	EE%sT	1991
             			2:00	E-Eur	EE%sT	1997
             			2:00	EU	EE%sT
             
             # Croatia
            -# see Serbia and Montenegro
            +# see Serbia
             
             # Cyprus
             # Please see the `asia' file for Asia/Nicosia.
            @@ -726,7 +833,41 @@
             			1:00	Czech	CE%sT	1979
             			1:00	EU	CE%sT
             
            -# Denmark, Faeroe Islands, and Greenland
            +# Denmark, Faroe Islands, and Greenland
            +
            +# From Jesper Norgaard Welen (2005-04-26):
            +# http://www.hum.aau.dk/~poe/tid/tine/DanskTid.htm says that the law
            +# [introducing standard time] was in effect from 1894-01-01....
            +# The page http://www.retsinfo.dk/_GETDOCI_/ACCN/A18930008330-REGL
            +# confirms this, and states that the law was put forth 1893-03-29.
            +#
            +# The EU treaty with effect from 1973:
            +# http://www.retsinfo.dk/_GETDOCI_/ACCN/A19722110030-REGL
            +#
            +# This provoked a new law from 1974 to make possible summer time changes
            +# in subsequenet decrees with the law
            +# http://www.retsinfo.dk/_GETDOCI_/ACCN/A19740022330-REGL
            +#
            +# It seems however that no decree was set forward until 1980.  I have
            +# not found any decree, but in another related law, the effecting DST
            +# changes are stated explicitly to be from 1980-04-06 at 02:00 to
            +# 1980-09-28 at 02:00.  If this is true, this differs slightly from
            +# the EU rule in that DST runs to 02:00, not 03:00.  We don't know
            +# when Denmark began using the EU rule correctly, but we have only
            +# confirmation of the 1980-time, so I presume it was correct in 1981:
            +# The law is about the management of the extra hour, concerning
            +# working hours reported and effect on obligatory-rest rules (which
            +# was suspended on that night):
            +# http://www.retsinfo.dk/_GETDOCI_/ACCN/C19801120554-REGL
            +
            +# From Jesper Norgaard Welen (2005-06-11):
            +# The Herning Folkeblad (1980-09-26) reported that the night between
            +# Saturday and Sunday the clock is set back from three to two.
            +
            +# From Paul Eggert (2005-06-11):
            +# Hence the "02:00" of the 1980 law refers to standard time, not
            +# wall-clock time, and so the EU rules were in effect in 1980.
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Denmark	1916	only	-	May	14	23:00	1:00	S
             Rule	Denmark	1916	only	-	Sep	30	23:00	0	-
            @@ -739,25 +880,27 @@
             Rule	Denmark	1947	only	-	Aug	10	 2:00s	0	-
             Rule	Denmark	1948	only	-	May	 9	 2:00s	1:00	S
             Rule	Denmark	1948	only	-	Aug	 8	 2:00s	0	-
            -# Whitman also gives 1949 Apr 9 to 1949 Oct 1, and disagrees in minor ways
            -# about many of the above dates; go with Shanks.
             #
            -# For 1894, Shanks says Jan, Whitman Apr; go with Whitman.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Europe/Copenhagen	 0:50:20 -	LMT	1890
            -			 0:50:20 -	CMT	1894 Apr  # Copenhagen Mean Time
            +			 0:50:20 -	CMT	1894 Jan  1 # Copenhagen MT
             			 1:00	Denmark	CE%sT	1942 Nov  2 2:00s
             			 1:00	C-Eur	CE%sT	1945 Apr  2 2:00
             			 1:00	Denmark	CE%sT	1980
             			 1:00	EU	CE%sT
            -Zone Atlantic/Faeroe	-0:27:04 -	LMT	1908 Jan 11	# Torshavn
            +Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11	# Torshavn
             			 0:00	-	WET	1981
             			 0:00	EU	WE%sT
             #
            -# From Paul Eggert (1996-11-22):
            +# From Paul Eggert (2004-10-31):
            +# During World War II, Germany maintained secret manned weather stations in
            +# East Greenland and Franz Josef Land, but we don't know their time zones.
            +# My source for this is Wilhelm Dege's book mentioned under Svalbard.
            +#
            +# From Paul Eggert (2006-03-22):
             # Greenland joined the EU as part of Denmark, obtained home rule on 1979-05-01,
             # and left the EU on 1985-02-01.  It therefore should have been using EU
            -# rules at least through 1984.  Shanks says Scoresbysund and Godthab
            +# rules at least through 1984.  Shanks & Pottenger say Scoresbysund and Godthab
             # used C-Eur rules after 1980, but IATA SSIM (1991/1996) says they use EU
             # rules since at least 1991.  Assume EU rules since 1980.
             
            @@ -812,24 +955,28 @@
             # I heard back from someone stationed at Thule; the time change took place
             # there at 2:00 AM.
             
            -# From Paul Eggert (2001-11-19):
            -# The 1997 CIA map shows Danmarkshavn on GMT; the 1995 map as like Godthab.
            +# From Paul Eggert (2006-03-22):
            +# From 1997 on the CIA map shows Danmarkshavn on GMT;
            +# the 1995 map as like Godthab.
             # For lack of better info, assume they were like Godthab before 1996.
             # startkart.no says Thule does not observe DST, but this is clearly an error,
            -# so go with Shanks for all Thule transitions.
            +# so go with Shanks & Pottenger for Thule transitions until this year.
            +# For 2007 on assume Thule will stay in sync with US DST rules.
             #
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Thule	1991	1992	-	Mar	lastSun	2:00	1:00	D
             Rule	Thule	1991	1992	-	Sep	lastSun	2:00	0	S
            -Rule	Thule	1993	max	-	Apr	Sun>=1	2:00	1:00	D
            -Rule	Thule	1993	max	-	Oct	lastSun	2:00	0	S
            +Rule	Thule	1993	2006	-	Apr	Sun>=1	2:00	1:00	D
            +Rule	Thule	1993	2006	-	Oct	lastSun	2:00	0	S
            +Rule	Thule	2007	max	-	Mar	Sun>=8	2:00	1:00	D
            +Rule	Thule	2007	max	-	Nov	Sun>=1	2:00	0	S
             #
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Danmarkshavn -1:14:40 -	LMT	1916 Jul 28
             			-3:00	-	WGT	1980 Apr  6 2:00
             			-3:00	EU	WG%sT	1996
             			0:00	-	GMT
            -Zone America/Scoresbysund -1:29:00 -	LMT	1916 Jul 28 # Ittoqqortoormiit
            +Zone America/Scoresbysund -1:27:52 -	LMT	1916 Jul 28 # Ittoqqortoormiit
             			-2:00	-	CGT	1980 Apr  6 2:00
             			-2:00	C-Eur	CG%sT	1981 Mar 29
             			-1:00	EU	EG%sT
            @@ -840,12 +987,12 @@
             			-4:00	Thule	A%sT
             
             # Estonia
            -# From Peter Ilieve  (1994-10-15):
            +# From Peter Ilieve (1994-10-15):
             # A relative in Tallinn confirms the accuracy of the data for 1989 onwards
             # [through 1994] and gives the legal authority for it,
             # a regulation of the Government of Estonia, No. 111 of 1989....
             #
            -# From Peter Ilieve  (1996-10-28):
            +# From Peter Ilieve (1996-10-28):
             # [IATA SSIM (1992/1996) claims that the Baltic republics switch at 01:00s,
             # but a relative confirms that Estonia still switches at 02:00s, writing:]
             # ``I do not [know] exactly but there are some little different
            @@ -855,7 +1002,7 @@
             # human physiology.  It seems that Estonia maybe will not change to
             # summer time next spring.''
             
            -# From Peter Ilieve  (1998-11-04), heavily edited:
            +# From Peter Ilieve (1998-11-04), heavily edited:
             # 
             # The 1998-09-22 Estonian time law
             # 
            @@ -903,22 +1050,47 @@
             			2:00	EU	EE%sT
             
             # Finland
            -#
            -# From Hannu Strang  (25 Sep 1994 06:03:37 UTC):
            +
            +# From Hannu Strang (1994-09-25 06:03:37 UTC):
             # Well, here in Helsinki we're just changing from summer time to regular one,
             # and it's supposed to change at 4am...
            +
            +# From Janne Snabb (2010-0715):
             #
            -# From Paul Eggert  (25 Sep 1994):
            -# Shanks says Finland has switched at 02:00 standard time since 1981.
            -# Go with Strang instead.
            +# I noticed that the Finland data is not accurate for years 1981 and 1982.
            +# During these two first trial years the DST adjustment was made one hour
            +# earlier than in forthcoming years. Starting 1983 the adjustment was made
            +# according to the central European standards.
             #
            +# This is documented in Heikki Oja: Aikakirja 2007, published by The Almanac
            +# Office of University of Helsinki, ISBN 952-10-3221-9, available online (in
            +# Finnish) at
            +#
            +# 
            +# http://almanakka.helsinki.fi/aikakirja/Aikakirja2007kokonaan.pdf
            +# 
            +#
            +# Page 105 (56 in PDF version) has a handy table of all past daylight savings
            +# transitions. It is easy enough to interpret without Finnish skills.
            +#
            +# This is also confirmed by Finnish Broadcasting Company's archive at:
            +#
            +# 
            +# http://www.yle.fi/elavaarkisto/?s=s&g=1&ag=5&t=&a=3401
            +# 
            +#
            +# The news clip from 1981 says that "the time between 2 and 3 o'clock does not
            +# exist tonight."
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Finland	1942	only	-	Apr	3	0:00	1:00	S
             Rule	Finland	1942	only	-	Oct	3	0:00	0	-
            +Rule	Finland	1981	1982	-	Mar	lastSun	2:00	1:00	S
            +Rule	Finland	1981	1982	-	Sep	lastSun	3:00	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Europe/Helsinki	1:39:52 -	LMT	1878 May 31
             			1:39:52	-	HMT	1921 May    # Helsinki Mean Time
            -			2:00	Finland	EE%sT	1981 Mar 29 2:00
            +			2:00	Finland	EE%sT	1983
             			2:00	EU	EE%sT
             
             # Aaland Is
            @@ -940,7 +1112,7 @@
             
             
             #
            -# Shanks seems to use `24:00' ambiguously; we resolve it with Whitman.
            +# Shank & Pottenger seem to use `24:00' ambiguously; resolve it with Whitman.
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	France	1916	only	-	Jun	14	23:00s	1:00	S
             Rule	France	1916	1919	-	Oct	Sun>=1	23:00s	0	-
            @@ -954,7 +1126,7 @@
             Rule	France	1922	only	-	Mar	25	23:00s	1:00	S
             # DSH writes that a law of 1923-05-24 specified 3rd Sat in Apr at 23:00 to 1st
             # Sat in Oct at 24:00; and that in 1930, because of Easter, the transitions
            -# were Apr 12 and Oct 5.  Go with Shanks.
            +# were Apr 12 and Oct 5.  Go with Shanks & Pottenger.
             Rule	France	1922	1938	-	Oct	Sat>=1	23:00s	0	-
             Rule	France	1923	only	-	May	26	23:00s	1:00	S
             Rule	France	1924	only	-	Mar	29	23:00s	1:00	S
            @@ -975,17 +1147,17 @@
             Rule	France	1939	only	-	Apr	15	23:00s	1:00	S
             Rule	France	1939	only	-	Nov	18	23:00s	0	-
             Rule	France	1940	only	-	Feb	25	 2:00	1:00	S
            -# The French rules for 1941-1944 were not used in Paris, but Shanks writes
            -# that they were used in Monaco and in many French locations.
            +# The French rules for 1941-1944 were not used in Paris, but Shanks & Pottenger
            +# write that they were used in Monaco and in many French locations.
             # Le Corre writes that the upper limit of the free zone was Arneguy, Orthez,
             # Mont-de-Marsan, Bazas, Langon, Lamotte-Montravel, Marouil, La
             # Rochefoucault, Champagne-Mouton, La Roche-Posay, La Haye-Decartes,
             # Loches, Montrichard, Vierzon, Bourges, Moulins, Digoin,
             # Paray-le-Monial, Montceau-les-Mines, Chalons-sur-Saone, Arbois,
             # Dole, Morez, St-Claude, and Collognes (Haute-Savioe).
             Rule	France	1941	only	-	May	 5	 0:00	2:00	M # Midsummer
            -# Shanks says this transition occurred at Oct 6 1:00,
            -# but go with Denis.Excoffier@ens.fr (1997-12-12),
            +# Shanks & Pottenger say this transition occurred at Oct 6 1:00,
            +# but go with Denis Excoffier (1997-12-12),
             # who quotes the Ephemerides Astronomiques for 1998 from Bureau des Longitudes
             # as saying 5/10/41 22hUT.
             Rule	France	1941	only	-	Oct	 6	 0:00	1:00	S
            @@ -997,61 +1169,68 @@
             Rule	France	1944	only	-	Oct	 8	 1:00	1:00	S
             Rule	France	1945	only	-	Apr	 2	 2:00	2:00	M
             Rule	France	1945	only	-	Sep	16	 3:00	0	-
            -# Shanks gives Mar 28 2:00 and Sep 26 3:00;
            +# Shanks & Pottenger give Mar 28 2:00 and Sep 26 3:00;
             # go with Excoffier's 28/3/76 0hUT and 25/9/76 23hUT.
             Rule	France	1976	only	-	Mar	28	 1:00	1:00	S
             Rule	France	1976	only	-	Sep	26	 1:00	0	-
            -# Shanks gives 0:09 for Paris Mean Time, and Whitman gives 0:09:05,
            +# Shanks & Pottenger give 0:09:20 for Paris Mean Time, and Whitman 0:09:05,
             # but Howse quotes the actual French legislation as saying 0:09:21.
             # Go with Howse.  Howse writes that the time in France was officially based
             # on PMT-0:09:21 until 1978-08-09, when the time base finally switched to UTC.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Europe/Paris	0:09:21 -	LMT	1891 Mar 15  0:01
             			0:09:21	-	PMT	1911 Mar 11  0:01  # Paris MT
            -# Shanks gives 1940 Jun 14 0:00; go with Excoffier and Le Corre.
            +# Shanks & Pottenger give 1940 Jun 14 0:00; go with Excoffier and Le Corre.
             			0:00	France	WE%sT	1940 Jun 14 23:00
             # Le Corre says Paris stuck with occupied-France time after the liberation;
            -# go with Shanks.
            +# go with Shanks & Pottenger.
             			1:00	C-Eur	CE%sT	1944 Aug 25
             			0:00	France	WE%sT	1945 Sep 16  3:00
             			1:00	France	CE%sT	1977
             			1:00	EU	CE%sT
             
             # Germany
             
            -# From Markus Kuhn  (1998-09-29):
            +# From Markus Kuhn (1998-09-29):
             # The German time zone web site by the Physikalisch-Technische
             # Bundesanstalt contains DST information back to 1916.
             # [See tz-link.htm for the URL.]
             
             # From Joerg Schilling (2002-10-23):
            -# In 1945, Berlin was switched to Moscow Summer time (GMT+4) by 
            +# In 1945, Berlin was switched to Moscow Summer time (GMT+4) by
            +# 
             # General [Nikolai] Bersarin.
             
             # From Paul Eggert (2003-03-08):
             # 
            +# http://www.parlament-berlin.de/pds-fraktion.nsf/727459127c8b66ee8525662300459099/defc77cb784f180ac1256c2b0030274b/$FILE/bersarint.pdf
            +# 
             # says that Bersarin issued an order to use Moscow time on May 20.
             # However, Moscow did not observe daylight saving in 1945, so
             # this was equivalent to CEMT (GMT+3), not GMT+4.
             
             
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -Rule	Germany	1945	only	-	Apr	 2	2:00s	1:00	S
            -Rule	Germany	1945	only	-	May	24	2:00	2:00	M # Midsummer
            -Rule	Germany	1945	only	-	Sep	24	3:00	1:00	S
            -Rule	Germany	1945	only	-	Nov	18	2:00s	0	-
             Rule	Germany	1946	only	-	Apr	14	2:00s	1:00	S
             Rule	Germany	1946	only	-	Oct	 7	2:00s	0	-
             Rule	Germany	1947	1949	-	Oct	Sun>=1	2:00s	0	-
            -Rule	Germany	1947	only	-	Apr	 6	2:00s	1:00	S
            +# http://www.ptb.de/de/org/4/44/441/salt.htm says the following transition
            +# occurred at 3:00 MEZ, not the 2:00 MEZ given in Shanks & Pottenger.
            +# Go with the PTB.
            +Rule	Germany	1947	only	-	Apr	 6	3:00s	1:00	S
             Rule	Germany	1947	only	-	May	11	2:00s	2:00	M
             Rule	Germany	1947	only	-	Jun	29	3:00	1:00	S
             Rule	Germany	1948	only	-	Apr	18	2:00s	1:00	S
             Rule	Germany	1949	only	-	Apr	10	2:00s	1:00	S
            +
            +Rule SovietZone	1945	only	-	May	24	2:00	2:00	M # Midsummer
            +Rule SovietZone	1945	only	-	Sep	24	3:00	1:00	S
            +Rule SovietZone	1945	only	-	Nov	18	2:00s	0	-
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Europe/Berlin	0:53:28 -	LMT	1893 Apr
            -			1:00	C-Eur	CE%sT	1945 Apr 2 2:00
            +			1:00	C-Eur	CE%sT	1945 May 24 2:00
            +			1:00 SovietZone	CE%sT	1946
             			1:00	Germany	CE%sT	1980
             			1:00	EU	CE%sT
             
            @@ -1062,23 +1241,23 @@
             
             # Gibraltar
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone Europe/Gibraltar	-0:21:24 -	LMT	1880 Aug  2
            +Zone Europe/Gibraltar	-0:21:24 -	LMT	1880 Aug  2 0:00s
             			0:00	GB-Eire	%s	1957 Apr 14 2:00
             			1:00	-	CET	1982
             			1:00	EU	CE%sT
             
             # Greece
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -# Whitman gives 1932 Jul 5 - Nov 1; go with Shanks.
            +# Whitman gives 1932 Jul 5 - Nov 1; go with Shanks & Pottenger.
             Rule	Greece	1932	only	-	Jul	 7	0:00	1:00	S
             Rule	Greece	1932	only	-	Sep	 1	0:00	0	-
            -# Whitman gives 1941 Apr 25 - ?; go with Shanks.
            +# Whitman gives 1941 Apr 25 - ?; go with Shanks & Pottenger.
             Rule	Greece	1941	only	-	Apr	 7	0:00	1:00	S
            -# Whitman gives 1942 Feb 2 - ?; go with Shanks.
            +# Whitman gives 1942 Feb 2 - ?; go with Shanks & Pottenger.
             Rule	Greece	1942	only	-	Nov	 2	3:00	0	-
             Rule	Greece	1943	only	-	Mar	30	0:00	1:00	S
             Rule	Greece	1943	only	-	Oct	 4	0:00	0	-
            -# Whitman gives 1944 Oct 3 - Oct 31; go with Shanks.
            +# Whitman gives 1944 Oct 3 - Oct 31; go with Shanks & Pottenger.
             Rule	Greece	1952	only	-	Jul	 1	0:00	1:00	S
             Rule	Greece	1952	only	-	Nov	 2	0:00	0	-
             Rule	Greece	1975	only	-	Apr	12	0:00s	1:00	S
            @@ -1098,7 +1277,7 @@
             			2:00	Greece	EE%sT	1941 Apr 30
             			1:00	Greece	CE%sT	1944 Apr  4
             			2:00	Greece	EE%sT	1981
            -			# Shanks says they switched to C-Eur in 1981;
            +			# Shanks & Pottenger say it switched to C-Eur in 1981;
             			# go with EU instead, since Greece joined it on Jan 1.
             			2:00	EU	EE%sT
             
            @@ -1128,13 +1307,13 @@
             Zone	Europe/Budapest	1:16:20 -	LMT	1890 Oct
             			1:00	C-Eur	CE%sT	1918
             			1:00	Hungary	CE%sT	1941 Apr  6  2:00
            -			1:00	C-Eur	CE%sT	1945 May  1 23:00
            +			1:00	C-Eur	CE%sT	1945
             			1:00	Hungary	CE%sT	1980 Sep 28  2:00s
             			1:00	EU	CE%sT
             
             # Iceland
             #
            -# From Adam David  (1993-11-06):
            +# From Adam David (1993-11-06):
             # The name of the timezone in Iceland for system / mail / news purposes is GMT.
             #
             # (1993-12-05):
            @@ -1161,10 +1340,10 @@
             # might be a reference to the Julian calendar as opposed to Gregorian, or it
             # might mean something else (???).
             #
            -# From Paul Eggert  (1999-10-29):
            -# The Iceland Almanak, Shanks and Whitman disagree on many points.
            -# We go with the Almanak, except for one claim from Shanks, namely that
            -# Reykavik was 21W57 from 1837 to 1908, local mean time before that.
            +# From Paul Eggert (2006-03-22):
            +# The Iceland Almanak, Shanks & Pottenger, and Whitman disagree on many points.
            +# We go with the Almanak, except for one claim from Shanks & Pottenger, namely
            +# that Reykavik was 21W57 from 1837 to 1908, local mean time before that.
             #
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Iceland	1917	1918	-	Feb	19	23:00	1:00	S
            @@ -1202,15 +1381,16 @@
             # But these events all occurred before the 1970 cutoff,
             # so record only the time in Rome.
             #
            -# From Paul Eggert (1996-05-06):
            -# For Italian DST we have three sources: Shanks, Whitman, and F. Pollastri
            +# From Paul Eggert (2006-03-22):
            +# For Italian DST we have three sources: Shanks & Pottenger, Whitman, and
            +# F. Pollastri
             # 
            -# Day-light Saving Time in Italy (1996-03-14)
            +# Day-light Saving Time in Italy (2006-02-03)
             # 
             # (`FP' below), taken from an Italian National Electrotechnical Institute
             # publication. When the three sources disagree, guess who's right, as follows:
             #
            -# year	FP	Shanks (S)	Whitman (W)	Go with:
            +# year	FP	Shanks&P. (S)	Whitman (W)	Go with:
             # 1916	06-03	06-03 24:00	06-03 00:00	FP & W
             #	09-30	09-30 24:00	09-30 01:00	FP; guess 24:00s
             # 1917	04-01	03-31 24:00	03-31 00:00	FP & S
            @@ -1266,7 +1446,7 @@
             Rule	Italy	1979	only	-	Sep	30	0:00s	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Europe/Rome	0:49:56 -	LMT	1866 Sep 22
            -			0:49:56	-	RMT	1893 Nov	# Rome Mean Time
            +			0:49:56	-	RMT	1893 Nov  1 0:00s # Rome Mean
             			1:00	Italy	CE%sT	1942 Nov  2 2:00s
             			1:00	C-Eur	CE%sT	1944 Jul
             			1:00	Italy	CE%sT	1980
            @@ -1277,7 +1457,7 @@
             
             # Latvia
             
            -# From Liene Kanepe  (1998-09-17):
            +# From Liene Kanepe (1998-09-17):
             
             # I asked about this matter Scientific Secretary of the Institute of Astronomy
             # of The University of Latvia Dr. paed Mr. Ilgonis Vilks. I also searched the
            @@ -1364,7 +1544,7 @@
             # IATA SSIM (1992/1996) says Lithuania uses W-Eur rules, but since it is
             # known to be wrong about Estonia and Latvia, assume it's wrong here too.
             
            -# From Marius Gedminas  (1998-08-07):
            +# From Marius Gedminas (1998-08-07):
             # I would like to inform that in this year Lithuanian time zone
             # (Europe/Vilnius) was changed.
             
            @@ -1408,7 +1588,8 @@
             			2:00	EU	EE%sT
             
             # Luxembourg
            -# Whitman disagrees with most of these dates in minor ways; go with Shanks.
            +# Whitman disagrees with most of these dates in minor ways;
            +# go with Shanks & Pottenger.
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Lux	1916	only	-	May	14	23:00	1:00	S
             Rule	Lux	1916	only	-	Oct	 1	 1:00	0	-
            @@ -1443,7 +1624,7 @@
             			1:00	EU	CE%sT
             
             # Macedonia
            -# see Serbia and Montenegro
            +# see Serbia
             
             # Malta
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            @@ -1455,7 +1636,7 @@
             Rule	Malta	1975	1980	-	Sep	Sun>=15	2:00	0	-
             Rule	Malta	1980	only	-	Mar	31	2:00	1:00	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2	# Valletta
            +Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2 0:00s # Valletta
             			1:00	Italy	CE%sT	1942 Nov  2 2:00s
             			1:00	C-Eur	CE%sT	1945 Apr  2 2:00s
             			1:00	Italy	CE%sT	1973 Mar 31
            @@ -1464,17 +1645,52 @@
             
             # Moldova
             
            -# From Paul Eggert (2001-02-11):
            -# A previous version of this database followed Shanks, who writes that
            -# Tiraspol switched to Moscow time on 1992-01-19 at 02:00.
            +# From Paul Eggert (2006-03-22):
            +# A previous version of this database followed Shanks & Pottenger, who write
            +# that Tiraspol switched to Moscow time on 1992-01-19 at 02:00.
             # However, this is most likely an error, as Moldova declared independence
             # on 1991-08-27 (the 1992-01-19 date is that of a Russian decree).
             # In early 1992 there was large-scale interethnic violence in the area
             # and it's possible that some Russophones continued to observe Moscow time.
            -# But moldavizolit@tirastel.md and mk@tirastel.md separately reported via
            +# But [two people] separately reported via
             # Jesper Norgaard that as of 2001-01-24 Tiraspol was like Chisinau.
             # The Tiraspol entry has therefore been removed for now.
            +#
            +# From Alexander Krivenyshev (2011-10-17):
            +# Pridnestrovian Moldavian Republic (PMR, also known as
            +# "Pridnestrovie") has abolished seasonal clock change (no transition
            +# to the Winter Time).
            +#
            +# News (in Russian):
            +# 
            +# http://www.kyivpost.ua/russia/news/pridnestrove-otkazalos-ot-perehoda-na-zimnee-vremya-30954.html
            +# 
            +#
            +# 
            +# http://www.allmoldova.com/moldova-news/1249064116.html
            +# 
            +#
            +# The substance of this change (reinstatement of the Tiraspol entry)
            +# is from a patch from Petr Machata (2011-10-17)
            +#
            +# From Tim Parenti (2011-10-19)
            +# In addition, being situated at +4651+2938 would give Tiraspol
            +# a pre-1880 LMT offset of 1:58:32.
            +#
            +# (which agrees with the earlier entry that had been removed)
            +#
            +# From Alexander Krivenyshev (2011-10-26)
            +# NO need to divide Moldova into two timezones at this point.
            +# As of today, Transnistria (Pridnestrovie)- Tiraspol reversed its own
            +# decision to abolish DST this winter. 
            +# Following Moldova and neighboring Ukraine- Transnistria (Pridnestrovie)-
            +# Tiraspol will go back to winter time on October 30, 2011.
            +# News from Moldova (in russian):
            +# 
            +# http://ru.publika.md/link_317061.html
            +# 
             
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Europe/Chisinau	1:55:20 -	LMT	1880
             			1:55	-	CMT	1918 Feb 15 # Chisinau MT
            @@ -1491,14 +1707,18 @@
             			2:00	EU	EE%sT
             
             # Monaco
            -# Shanks gives 0:09 for Paris Mean Time; go with Howse's more precise 0:09:21.
            +# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
            +# more precise 0:09:21.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Europe/Monaco	0:29:32 -	LMT	1891 Mar 15
             			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
             			0:00	France	WE%sT	1945 Sep 16 3:00
             			1:00	France	CE%sT	1977
             			1:00	EU	CE%sT
             
            +# Montenegro
            +# see Serbia
            +
             # Netherlands
             
             # Howse writes that the Netherlands' railways used GMT between 1892 and 1940,
            @@ -1574,12 +1794,11 @@
             			1:00	EU	CE%sT
             
             # Norway
            +# http://met.no/met/met_lex/q_u/sommertid.html (2004-01) agrees with Shanks &
            +# Pottenger.
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -# Whitman gives 1916 May 21 - 1916 Oct 21; go with Shanks.
             Rule	Norway	1916	only	-	May	22	1:00	1:00	S
             Rule	Norway	1916	only	-	Sep	30	0:00	0	-
            -# Whitman says DST observed 1935-08-11/1942-11-01, then 1943-03-29/10-04,
            -# 1944-04-03/10-02, and 1945-04-01/10-01; go with Shanks.
             Rule	Norway	1945	only	-	Apr	 2	2:00s	1:00	S
             Rule	Norway	1945	only	-	Oct	 1	2:00s	0	-
             Rule	Norway	1959	1964	-	Mar	Sun>=15	2:00s	1:00	S
            @@ -1633,38 +1852,45 @@
             #  says that the Germans were
             # expelled on 1942-05-14.  However, small parties of Germans did return,
             # and according to Wilhelm Dege's book "War North of 80" (1954)
            -# 
            +# 
             # the German armed forces at the Svalbard weather station code-named
             # Haudegen did not surrender to the Allies until September 1945.
             #
             # All these events predate our cutoff date of 1970.  Unless we can
             # come up with more definitive info about the timekeeping during the
            -# war years it's probably best just do do the following for now:
            +# war years it's probably best just do...the following for now:
             Link	Europe/Oslo	Arctic/Longyearbyen
            -Link	Europe/Oslo	Atlantic/Jan_Mayen
             
             # Poland
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Poland	1918	1919	-	Sep	16	2:00s	0	-
             Rule	Poland	1919	only	-	Apr	15	2:00s	1:00	S
            -# Whitman gives 1944 Nov 30; go with Shanks.
            +Rule	Poland	1944	only	-	Apr	 3	2:00s	1:00	S
            +# Whitman gives 1944 Nov 30; go with Shanks & Pottenger.
             Rule	Poland	1944	only	-	Oct	 4	2:00	0	-
            -# For 1944-1948 Whitman gives the previous day; go with Shanks.
            +# For 1944-1948 Whitman gives the previous day; go with Shanks & Pottenger.
             Rule	Poland	1945	only	-	Apr	29	0:00	1:00	S
             Rule	Poland	1945	only	-	Nov	 1	0:00	0	-
            -Rule	Poland	1946	only	-	Apr	14	0:00	1:00	S
            -Rule	Poland	1946	only	-	Sep	 7	0:00	0	-
            -Rule	Poland	1947	only	-	May	 4	0:00	1:00	S
            -Rule	Poland	1947	1948	-	Oct	Sun>=1	0:00	0	-
            -Rule	Poland	1948	only	-	Apr	18	0:00	1:00	S
            -# Whitman also gives 1949 Apr 9 - 1949 Oct 1; go with Shanks.
            +# For 1946 on the source is Kazimierz Borkowski,
            +# Torun Center for Astronomy, Dept. of Radio Astronomy, Nicolaus Copernicus U.,
            +# 
            +# Thanks to Przemyslaw Augustyniak (2005-05-28) for this reference.
            +# He also gives these further references:
            +# Mon Pol nr 13, poz 162 (1995) 
            +# Druk nr 2180 (2003) 
            +Rule	Poland	1946	only	-	Apr	14	0:00s	1:00	S
            +Rule	Poland	1946	only	-	Oct	 7	2:00s	0	-
            +Rule	Poland	1947	only	-	May	 4	2:00s	1:00	S
            +Rule	Poland	1947	1949	-	Oct	Sun>=1	2:00s	0	-
            +Rule	Poland	1948	only	-	Apr	18	2:00s	1:00	S
            +Rule	Poland	1949	only	-	Apr	10	2:00s	1:00	S
             Rule	Poland	1957	only	-	Jun	 2	1:00s	1:00	S
             Rule	Poland	1957	1958	-	Sep	lastSun	1:00s	0	-
             Rule	Poland	1958	only	-	Mar	30	1:00s	1:00	S
             Rule	Poland	1959	only	-	May	31	1:00s	1:00	S
             Rule	Poland	1959	1961	-	Oct	Sun>=1	1:00s	0	-
             Rule	Poland	1960	only	-	Apr	 3	1:00s	1:00	S
            -Rule	Poland	1961	1964	-	May	Sun>=25	1:00s	1:00	S
            +Rule	Poland	1961	1964	-	May	lastSun	1:00s	1:00	S
             Rule	Poland	1962	1964	-	Sep	lastSun	1:00s	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Europe/Warsaw	1:24:00 -	LMT	1880
            @@ -1673,33 +1899,17 @@
             			2:00	Poland	EE%sT	1922 Jun
             			1:00	Poland	CE%sT	1940 Jun 23 2:00
             			1:00	C-Eur	CE%sT	1944 Oct
            -			1:00	Poland	CE%sT	1977 Apr  3 1:00
            -			1:00	W-Eur	CE%sT	1999
            -# IATA SSIM (1991/1996) gives EU rules, but the _The Warsaw Voice_
            -# 
            -# http://www.warsawvoice.com/pl/v361/NewsInBrief.shtml (1995-09-24)
            -# 
            -# says the autumn 1995 switch was at 02:00.
            -# Stick with W-Eur for now.
            -#
            -# From Marcin.Kasperski@softax.com.pl (1999-06-10):
            -# According to my colleagues someone recently decided, that Poland would
            -# follow European Union regulations, so - I think - the matter is not
            -# worth further discussion.
            -#
            -# From Paul Eggert (1999-06-10):
            -# Kasperski also writes that the government futzed with the rules in 1997
            -# or 1998 but he doesn't remember the details.  Assume they switched to
            -# EU rules in 1999.
            +			1:00	Poland	CE%sT	1977
            +			1:00	W-Eur	CE%sT	1988
             			1:00	EU	CE%sT
             
             # Portugal
             #
            -# From Rui Pedro Salgueiro  (1992-11-12):
            +# From Rui Pedro Salgueiro (1992-11-12):
             # Portugal has recently (September, 27) changed timezone
             # (from WET to MET or CET) to harmonize with EEC.
             #
            -# Martin Bruckmann  (1996-02-29) reports via Peter Ilieve
            +# Martin Bruckmann (1996-02-29) reports via Peter Ilieve
             # that Portugal is reverting to 0:00 by not moving its clocks this spring.
             # The new Prime Minister was fed up with getting up in the dark in the winter.
             #
            @@ -1714,9 +1924,9 @@
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             # DSH writes that despite Decree 1,469 (1915), the change to the clocks was not
             # done every year, depending on what Spain did, because of railroad schedules.
            -# Go with Shanks.
            +# Go with Shanks & Pottenger.
             Rule	Port	1916	only	-	Jun	17	23:00	1:00	S
            -# Whitman gives 1916 Oct 31; go with Shanks.
            +# Whitman gives 1916 Oct 31; go with Shanks & Pottenger.
             Rule	Port	1916	only	-	Nov	 1	 1:00	0	-
             Rule	Port	1917	only	-	Feb	28	23:00s	1:00	S
             Rule	Port	1917	1921	-	Oct	14	23:00s	0	-
            @@ -1732,24 +1942,23 @@
             Rule	Port	1928	only	-	Apr	14	23:00s	1:00	S
             Rule	Port	1929	only	-	Apr	20	23:00s	1:00	S
             Rule	Port	1931	only	-	Apr	18	23:00s	1:00	S
            -# Whitman gives 1931 Oct 8; go with Shanks.
            +# Whitman gives 1931 Oct 8; go with Shanks & Pottenger.
             Rule	Port	1931	1932	-	Oct	Sat>=1	23:00s	0	-
             Rule	Port	1932	only	-	Apr	 2	23:00s	1:00	S
            -# Shanks gives 1934 Apr 4; go with Whitman.
             Rule	Port	1934	only	-	Apr	 7	23:00s	1:00	S
            -# Whitman gives 1934 Oct 5; go with Shanks.
            +# Whitman gives 1934 Oct 5; go with Shanks & Pottenger.
             Rule	Port	1934	1938	-	Oct	Sat>=1	23:00s	0	-
            -# Shanks gives 1935 Apr 30; go with Whitman.
            +# Shanks & Pottenger give 1935 Apr 30; go with Whitman.
             Rule	Port	1935	only	-	Mar	30	23:00s	1:00	S
             Rule	Port	1936	only	-	Apr	18	23:00s	1:00	S
            -# Whitman gives 1937 Apr 2; go with Shanks.
            +# Whitman gives 1937 Apr 2; go with Shanks & Pottenger.
             Rule	Port	1937	only	-	Apr	 3	23:00s	1:00	S
             Rule	Port	1938	only	-	Mar	26	23:00s	1:00	S
             Rule	Port	1939	only	-	Apr	15	23:00s	1:00	S
            -# Whitman gives 1939 Oct 7; go with Shanks.
            +# Whitman gives 1939 Oct 7; go with Shanks & Pottenger.
             Rule	Port	1939	only	-	Nov	18	23:00s	0	-
             Rule	Port	1940	only	-	Feb	24	23:00s	1:00	S
            -# Shanks gives 1940 Oct 7; go with Whitman.
            +# Shanks & Pottenger give 1940 Oct 7; go with Whitman.
             Rule	Port	1940	1941	-	Oct	 5	23:00s	0	-
             Rule	Port	1941	only	-	Apr	 5	23:00s	1:00	S
             Rule	Port	1942	1945	-	Mar	Sat>=8	23:00s	1:00	S
            @@ -1763,8 +1972,8 @@
             Rule	Port	1946	only	-	Oct	Sat>=1	23:00s	0	-
             Rule	Port	1947	1949	-	Apr	Sun>=1	 2:00s	1:00	S
             Rule	Port	1947	1949	-	Oct	Sun>=1	 2:00s	0	-
            -# Shanks says DST was observed in 1950; go with Whitman.
            -# Whitman gives Oct lastSun for 1952 on; go with Shanks.
            +# Shanks & Pottenger say DST was observed in 1950; go with Whitman.
            +# Whitman gives Oct lastSun for 1952 on; go with Shanks & Pottenger.
             Rule	Port	1951	1965	-	Apr	Sun>=1	 2:00s	1:00	S
             Rule	Port	1951	1965	-	Oct	Sun>=1	 2:00s	0	-
             Rule	Port	1977	only	-	Mar	27	 0:00s	1:00	S
            @@ -1776,7 +1985,7 @@
             Rule	Port	1981	1982	-	Mar	lastSun	 1:00s	1:00	S
             Rule	Port	1983	only	-	Mar	lastSun	 2:00s	1:00	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -# Shanks says that the transition from LMT to WET occurred 1911-05-24;
            +# Shanks & Pottenger say the transition from LMT to WET occurred 1911-05-24;
             # Willett says 1912-01-01.  Go with Willett.
             Zone	Europe/Lisbon	-0:36:32 -	LMT	1884
             			-0:36:32 -	LMT	1912 Jan  1  # Lisbon Mean Time
            @@ -1829,25 +2038,26 @@
             
             # Russia
             
            -# From Paul Eggert  (1999-11-12):
            +# From Paul Eggert (2006-03-22):
             # Except for Moscow after 1919-07-01, I invented the time zone abbreviations.
             # Moscow time zone abbreviations after 1919-07-01, and Moscow rules after 1991,
            -# are from Andrey A. Chernov.  The rest is from Shanks, except we follow
            -# Chernov's report that 1992 DST transitions were Sat 23:00, not Sun 02:00s.
            +# are from Andrey A. Chernov.  The rest is from Shanks & Pottenger,
            +# except we follow Chernov's report that 1992 DST transitions were Sat
            +# 23:00, not Sun 02:00s.
             #
            -# From Stanislaw A. Kuzikowski  (1994-06-29):
            +# From Stanislaw A. Kuzikowski (1994-06-29):
             # But now it is some months since Novosibirsk is 3 hours ahead of Moscow!
             # I do not know why they have decided to make this change;
             # as far as I remember it was done exactly during winter->summer switching
             # so we (Novosibirsk) simply did not switch.
             #
            -# From Andrey A. Chernov  (1996-10-04):
            +# From Andrey A. Chernov (1996-10-04):
             # `MSK' and `MSD' were born and used initially on Moscow computers with
             # UNIX-like OSes by several developer groups (e.g. Demos group, Kiae group)....
             # The next step was the UUCP network, the Relcom predecessor
             # (used mainly for mail), and MSK/MSD was actively used there.
             #
            -# From Chris Carrier <72157.3334@CompuServe.COM> (1996-10-30):
            +# From Chris Carrier (1996-10-30):
             # According to a friend of mine who rode the Trans-Siberian Railroad from
             # Moscow to Irkutsk in 1995, public air and rail transport in Russia ...
             # still follows Moscow time, no matter where in Russia it is located.
            @@ -1875,23 +2085,24 @@
             			 1:00	C-Eur	CE%sT	1945
             			 2:00	Poland	CE%sT	1946
             			 3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
            -			 2:00	Russia	EE%sT
            +			 2:00	Russia	EE%sT	2011 Mar 27 2:00s
            +			 3:00	-	FET # Further-eastern European Time
             #
             # From Oscar van Vlijmen (2001-08-25): [This region consists of]
            -# Respublika Adygeya, Arkhangel'skaya oblast', Astrakhanskaya oblast',
            +# Respublika Adygeya, Arkhangel'skaya oblast',
             # Belgorodskaya oblast', Bryanskaya oblast', Vladimirskaya oblast',
            -# Volgogradskaya oblast', Vologodskaya oblast', Voronezhskaya oblast',
            +# Vologodskaya oblast', Voronezhskaya oblast',
             # Respublika Dagestan, Ivanovskaya oblast', Respublika Ingushetiya,
             # Kabarbino-Balkarskaya Respublika, Respublika Kalmykiya,
             # Kalyzhskaya oblast', Respublika Karachaevo-Cherkessiya,
            -# Respublika Kareliya, Kirovskaya oblast', Respublika Komi,
            +# Respublika Kareliya, Respublika Komi,
             # Kostromskaya oblast', Krasnodarskij kraj, Kurskaya oblast',
             # Leningradskaya oblast', Lipetskaya oblast', Respublika Marij El,
             # Respublika Mordoviya, Moskva, Moskovskaya oblast',
             # Murmanskaya oblast', Nenetskij avtonomnyj okrug,
             # Nizhegorodskaya oblast', Novgorodskaya oblast', Orlovskaya oblast',
             # Penzenskaya oblast', Pskovskaya oblast', Rostovskaya oblast',
            -# Ryazanskaya oblast', Sankt-Peterburg, Saratovskaya oblast',
            +# Ryazanskaya oblast', Sankt-Peterburg,
             # Respublika Severnaya Osetiya, Smolenskaya oblast',
             # Stavropol'skij kraj, Tambovskaya oblast', Respublika Tatarstan,
             # Tverskaya oblast', Tyl'skaya oblast', Ul'yanovskaya oblast',
            @@ -1904,17 +2115,36 @@
             			 2:00	-	EET	1930 Jun 21
             			 3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
             			 2:00	Russia	EE%sT	1992 Jan 19 2:00s
            -			 3:00	Russia	MSK/MSD
            +			 3:00	Russia	MSK/MSD	2011 Mar 27 2:00s
            +			 4:00	-	MSK
             #
            +# Astrakhanskaya oblast', Kirovskaya oblast', Saratovskaya oblast',
            +# Volgogradskaya oblast'.  Shanks & Pottenger say Kirov is still at +0400
            +# but Wikipedia (2006-05-09) says +0300.  Perhaps it switched after the
            +# others?  But we have no data.
            +Zone Europe/Volgograd	 2:57:40 -	LMT	1920 Jan  3
            +			 3:00	-	TSAT	1925 Apr  6 # Tsaritsyn Time
            +			 3:00	-	STAT	1930 Jun 21 # Stalingrad Time
            +			 4:00	-	STAT	1961 Nov 11
            +			 4:00	Russia	VOL%sT	1989 Mar 26 2:00s # Volgograd T
            +			 3:00	Russia	VOL%sT	1991 Mar 31 2:00s
            +			 4:00	-	VOLT	1992 Mar 29 2:00s
            +			 3:00	Russia	VOL%sT	2011 Mar 27 2:00s
            +			 4:00	-	VOLT
            +#
             # From Oscar van Vlijmen (2001-08-25): [This region consists of]
             # Samarskaya oblast', Udmyrtskaya respublika
             Zone Europe/Samara	 3:20:36 -	LMT	1919 Jul  1 2:00
            -			 3:00	-	KUYT	1930 Jun 21 # Kuybyshev
            -			 4:00	Russia	KUY%sT	1989 Mar 26 2:00s
            +			 3:00	-	SAMT	1930 Jun 21
            +			 4:00	-	SAMT	1935 Jan 27
            +			 4:00	Russia	KUY%sT	1989 Mar 26 2:00s # Kuybyshev
             			 3:00	Russia	KUY%sT	1991 Mar 31 2:00s
             			 2:00	Russia	KUY%sT	1991 Sep 29 2:00s
             			 3:00	-	KUYT	1991 Oct 20 3:00
            -			 4:00	Russia	SAM%sT	# Samara Time
            +			 4:00	Russia	SAM%sT	2010 Mar 28 2:00s # Samara Time
            +			 3:00	Russia	SAM%sT	2011 Mar 27 2:00s
            +			 4:00	-	SAMT
            +
             #
             # From Oscar van Vlijmen (2001-08-25): [This region consists of]
             # Respublika Bashkortostan, Komi-Permyatskij avtonomnyj okrug,
            @@ -1926,33 +2156,74 @@
             			 4:00	-	SVET	1930 Jun 21 # Sverdlovsk Time
             			 5:00	Russia	SVE%sT	1991 Mar 31 2:00s
             			 4:00	Russia	SVE%sT	1992 Jan 19 2:00s
            -			 5:00	Russia	YEK%sT	# Yekaterinburg Time
            +			 5:00	Russia	YEK%sT	2011 Mar 27 2:00s
            +			 6:00	-	YEKT	# Yekaterinburg Time
             #
             # From Oscar van Vlijmen (2001-08-25): [This region consists of]
             # Respublika Altaj, Altajskij kraj, Omskaya oblast'.
             Zone Asia/Omsk		 4:53:36 -	LMT	1919 Nov 14
             			 5:00	-	OMST	1930 Jun 21 # Omsk TIme
             			 6:00	Russia	OMS%sT	1991 Mar 31 2:00s
             			 5:00	Russia	OMS%sT	1992 Jan 19 2:00s
            -			 6:00	Russia	OMS%sT
            +			 6:00	Russia	OMS%sT	2011 Mar 27 2:00s
            +			 7:00	-	OMST
             #
            -# Novosibirskaya oblast'.
            +# From Paul Eggert (2006-08-19): I'm guessing about Tomsk here; it's
            +# not clear when it switched from +7 to +6.
            +# Novosibirskaya oblast', Tomskaya oblast'.
             Zone Asia/Novosibirsk	 5:31:40 -	LMT	1919 Dec 14 6:00
             			 6:00	-	NOVT	1930 Jun 21 # Novosibirsk Time
             			 7:00	Russia	NOV%sT	1991 Mar 31 2:00s
             			 6:00	Russia	NOV%sT	1992 Jan 19 2:00s
            -			 7:00	Russia	NOV%sT	1993 May 23 # says Shanks
            -			 6:00	Russia	NOV%sT
            +			 7:00	Russia	NOV%sT	1993 May 23 # say Shanks & P.
            +			 6:00	Russia	NOV%sT	2011 Mar 27 2:00s
            +			 7:00	-	NOVT
            +
            +# From Alexander Krivenyshev (2009-10-13):
            +# Kemerovo oblast' (Kemerovo region) in Russia will change current time zone on
            +# March 28, 2010:
            +# from current Russia Zone 6 - Krasnoyarsk Time Zone (KRA) UTC +0700
            +# to Russia Zone 5 - Novosibirsk Time Zone (NOV) UTC +0600
             #
            +# This is according to Government of Russia decree # 740, on September
            +# 14, 2009 "Application in the territory of the Kemerovo region the Fifth
            +# time zone." ("Russia Zone 5" or old "USSR Zone 5" is GMT +0600)
            +#
            +# Russian Government web site (Russian language)
            +# 
            +# http://www.government.ru/content/governmentactivity/rfgovernmentdecisions/archive/2009/09/14/991633.htm
            +# 
            +# or Russian-English translation by WorldTimeZone.com with reference
            +# map to local region and new Russia Time Zone map after March 28, 2010
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_russia03.html
            +# 
            +#
            +# Thus, when Russia will switch to DST on the night of March 28, 2010
            +# Kemerovo region (Kemerovo oblast') will not change the clock.
            +#
            +# As a result, Kemerovo oblast' will be in the same time zone as
            +# Novosibirsk, Omsk, Tomsk, Barnaul and Altai Republic.
            +
            +Zone Asia/Novokuznetsk	 5:48:48 -	NMT	1920 Jan  6
            +			 6:00	-	KRAT	1930 Jun 21 # Krasnoyarsk Time
            +			 7:00	Russia	KRA%sT	1991 Mar 31 2:00s
            +			 6:00	Russia	KRA%sT	1992 Jan 19 2:00s
            +			 7:00	Russia	KRA%sT	2010 Mar 28 2:00s
            +			 6:00	Russia	NOV%sT	2011 Mar 27 2:00s
            +			 7:00	-	NOVT # Novosibirsk/Novokuznetsk Time
            +
            +#
             # From Oscar van Vlijmen (2001-08-25): [This region consists of]
            -# Kemerovskaya oblast', Krasnoyarskij kraj,
            -# Tajmyrskij (Dolgano-Nenetskij) avtonomnyj okrug, Tomskaya oblast',
            +# Krasnoyarskij kraj,
            +# Tajmyrskij (Dolgano-Nenetskij) avtonomnyj okrug,
             # Respublika Tuva, Respublika Khakasiya, Evenkijskij avtonomnyj okrug.
             Zone Asia/Krasnoyarsk	 6:11:20 -	LMT	1920 Jan  6
             			 6:00	-	KRAT	1930 Jun 21 # Krasnoyarsk Time
             			 7:00	Russia	KRA%sT	1991 Mar 31 2:00s
             			 6:00	Russia	KRA%sT	1992 Jan 19 2:00s
            -			 7:00	Russia	KRA%sT
            +			 7:00	Russia	KRA%sT	2011 Mar 27 2:00s
            +			 8:00	-	KRAT
             #
             # From Oscar van Vlijmen (2001-08-25): [This region consists of]
             # Respublika Buryatiya, Irkutskaya oblast',
            @@ -1962,33 +2233,46 @@
             			 7:00	-	IRKT	1930 Jun 21 # Irkutsk Time
             			 8:00	Russia	IRK%sT	1991 Mar 31 2:00s
             			 7:00	Russia	IRK%sT	1992 Jan 19 2:00s
            -			 8:00	Russia	IRK%sT
            +			 8:00	Russia	IRK%sT	2011 Mar 27 2:00s
            +			 9:00	-	IRKT
             #
             # From Oscar van Vlijmen (2003-10-18): [This region consists of]
             # Aginskij Buryatskij avtonomnyj okrug, Amurskaya oblast',
             # [parts of] Respublika Sakha (Yakutiya), Chitinskaya oblast'.
            +
            +# From Oscar van Vlijmen (2009-11-29):
            +# ...some regions of [Russia] were merged with others since 2005...
            +# Some names were changed, no big deal, except for one instance: a new name.
            +# YAK/YAKST: UTC+9 Zabajkal'skij kraj.
            +
            +# From Oscar van Vlijmen (2009-11-29):
             # The Sakha districts are: Aldanskij, Amginskij, Anabarskij,
            -# Bulunskij, Verkhnekolymskij, Verkhnevilyujskij, Vilyujskij, Gornyj,
            +# Verkhnevilyujskij, Vilyujskij, Gornyj,
             # Zhiganskij, Kobyajskij, Lenskij, Megino-Kangalasskij, Mirninskij,
            -# Namskij, Nyurbinskij, Olenekskij, Olekminskij, Srednekolymskij,
            +# Namskij, Nyurbinskij, Olenyokskij, Olyokminskij,
             # Suntarskij, Tattinskij, Ust'-Aldanskij, Khangalasskij,
            -# Churapchinskij, Eveno-Bytantajskij.
            +# Churapchinskij, Eveno-Bytantajskij Natsional'nij.
            +
             Zone Asia/Yakutsk	 8:38:40 -	LMT	1919 Dec 15
             			 8:00	-	YAKT	1930 Jun 21 # Yakutsk Time
             			 9:00	Russia	YAK%sT	1991 Mar 31 2:00s
             			 8:00	Russia	YAK%sT	1992 Jan 19 2:00s
            -			 9:00	Russia	YAK%sT
            +			 9:00	Russia	YAK%sT	2011 Mar 27 2:00s
            +			 10:00	-	YAKT
             #
             # From Oscar van Vlijmen (2003-10-18): [This region consists of]
             # Evrejskaya avtonomnaya oblast', Khabarovskij kraj, Primorskij kraj,
             # [parts of] Respublika Sakha (Yakutiya).
            -# The Sakha districts are: Verkhoyanskij, Tomponskij, Ust'-Majskij,
            +
            +# From Oscar van Vlijmen (2009-11-29):
            +# The Sakha districts are: Bulunskij, Verkhoyanskij, Tomponskij, Ust'-Majskij,
             # Ust'-Yanskij.
             Zone Asia/Vladivostok	 8:47:44 -	LMT	1922 Nov 15
             			 9:00	-	VLAT	1930 Jun 21 # Vladivostok Time
             			10:00	Russia	VLA%sT	1991 Mar 31 2:00s
             			 9:00	Russia	VLA%sST	1992 Jan 19 2:00s
            -			10:00	Russia	VLA%sT
            +			10:00	Russia	VLA%sT	2011 Mar 27 2:00s
            +			11:00	-	VLAT
             #
             # Sakhalinskaya oblast'.
             # The Zone name should be Yuzhno-Sakhalinsk, but that's too long.
            @@ -1998,18 +2282,22 @@
             			11:00	Russia	SAK%sT	1991 Mar 31 2:00s # Sakhalin T.
             			10:00	Russia	SAK%sT	1992 Jan 19 2:00s
             			11:00	Russia	SAK%sT	1997 Mar lastSun 2:00s
            -			10:00	Russia	SAK%sT
            +			10:00	Russia	SAK%sT	2011 Mar 27 2:00s
            +			11:00	-	SAKT
             #
             # From Oscar van Vlijmen (2003-10-18): [This region consists of]
             # Magadanskaya oblast', Respublika Sakha (Yakutiya).
             # Probably also: Kuril Islands.
            -# The Sakha districts are: Abyjskij, Allaikhovskij, Momskij,
            -# Nizhnekolymskij, Ojmyakonskij.
            +
            +# From Oscar van Vlijmen (2009-11-29):
            +# The Sakha districts are: Abyjskij, Allaikhovskij, Verkhhhnekolymskij, Momskij,
            +# Nizhnekolymskij, Ojmyakonskij, Srednekolymskij.
             Zone Asia/Magadan	10:03:12 -	LMT	1924 May  2
             			10:00	-	MAGT	1930 Jun 21 # Magadan Time
             			11:00	Russia	MAG%sT	1991 Mar 31 2:00s
             			10:00	Russia	MAG%sT	1992 Jan 19 2:00s
            -			11:00	Russia	MAG%sT
            +			11:00	Russia	MAG%sT	2011 Mar 27 2:00s
            +			12:00	-	MAGT
             #
             # From Oscar van Vlijmen (2001-08-25): [This region consists of]
             # Kamchatskaya oblast', Koryakskij avtonomnyj okrug.
            @@ -2019,28 +2307,34 @@
             			11:00	-	PETT	1930 Jun 21 # P-K Time
             			12:00	Russia	PET%sT	1991 Mar 31 2:00s
             			11:00	Russia	PET%sT	1992 Jan 19 2:00s
            -			12:00	Russia	PET%sT
            +			12:00	Russia	PET%sT	2010 Mar 28 2:00s
            +			11:00	Russia	PET%sT	2011 Mar 27 2:00s
            +			12:00	-	PETT
             #
             # Chukotskij avtonomnyj okrug
             Zone Asia/Anadyr	11:49:56 -	LMT	1924 May  2
             			12:00	-	ANAT	1930 Jun 21 # Anadyr Time
             			13:00	Russia	ANA%sT	1982 Apr  1 0:00s
             			12:00	Russia	ANA%sT	1991 Mar 31 2:00s
             			11:00	Russia	ANA%sT	1992 Jan 19 2:00s
            -			12:00	Russia	ANA%sT
            +			12:00	Russia	ANA%sT	2010 Mar 28 2:00s
            +			11:00	Russia	ANA%sT	2011 Mar 27 2:00s
            +			12:00	-	ANAT
             
            -# Serbia and Montenegro
            +# Serbia
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Europe/Belgrade	1:22:00	-	LMT	1884
             			1:00	-	CET	1941 Apr 18 23:00
            -			1:00	C-Eur	CE%sT	1945 May  8  2:00s
            +			1:00	C-Eur	CE%sT	1945
            +			1:00	-	CET	1945 May 8 2:00s
             			1:00	1:00	CEST	1945 Sep 16  2:00s
            -# Metod Kozelj  reports that the legal date of
            +# Metod Kozelj reports that the legal date of
             # transition to EU rules was 1982-11-27, for all of Yugoslavia at the time.
            -# Shanks doesn't give as much detail, so go with Kozelj.
            +# Shanks & Pottenger don't give as much detail, so go with Kozelj.
             			1:00	-	CET	1982 Nov 27
             			1:00	EU	CE%sT
             Link Europe/Belgrade Europe/Ljubljana	# Slovenia
            +Link Europe/Belgrade Europe/Podgorica	# Montenegro
             Link Europe/Belgrade Europe/Sarajevo	# Bosnia and Herzegovina
             Link Europe/Belgrade Europe/Skopje	# Macedonia
             Link Europe/Belgrade Europe/Zagreb	# Croatia
            @@ -2049,32 +2343,34 @@
             Link Europe/Prague Europe/Bratislava
             
             # Slovenia
            -# see Serbia and Montenegro
            +# see Serbia
             
             # Spain
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -# For 1917-1919 Whitman gives Apr Sat>=1 - Oct Sat>=1; go with Shanks.
            +# For 1917-1919 Whitman gives Apr Sat>=1 - Oct Sat>=1;
            +# go with Shanks & Pottenger.
             Rule	Spain	1917	only	-	May	 5	23:00s	1:00	S
             Rule	Spain	1917	1919	-	Oct	 6	23:00s	0	-
             Rule	Spain	1918	only	-	Apr	15	23:00s	1:00	S
             Rule	Spain	1919	only	-	Apr	 5	23:00s	1:00	S
            -# Whitman gives 1921 Feb 28 - Oct 14; go with Shanks.
            +# Whitman gives 1921 Feb 28 - Oct 14; go with Shanks & Pottenger.
             Rule	Spain	1924	only	-	Apr	16	23:00s	1:00	S
            -# Whitman gives 1924 Oct 14; go with Shanks.
            +# Whitman gives 1924 Oct 14; go with Shanks & Pottenger.
             Rule	Spain	1924	only	-	Oct	 4	23:00s	0	-
             Rule	Spain	1926	only	-	Apr	17	23:00s	1:00	S
            -# Whitman says no DST in 1929; go with Shanks.
            +# Whitman says no DST in 1929; go with Shanks & Pottenger.
             Rule	Spain	1926	1929	-	Oct	Sat>=1	23:00s	0	-
             Rule	Spain	1927	only	-	Apr	 9	23:00s	1:00	S
             Rule	Spain	1928	only	-	Apr	14	23:00s	1:00	S
             Rule	Spain	1929	only	-	Apr	20	23:00s	1:00	S
            -# Whitman gives 1937 Jun 16, 1938 Apr 16, 1940 Apr 13; go with Shanks.
            +# Whitman gives 1937 Jun 16, 1938 Apr 16, 1940 Apr 13;
            +# go with Shanks & Pottenger.
             Rule	Spain	1937	only	-	May	22	23:00s	1:00	S
             Rule	Spain	1937	1939	-	Oct	Sat>=1	23:00s	0	-
             Rule	Spain	1938	only	-	Mar	22	23:00s	1:00	S
             Rule	Spain	1939	only	-	Apr	15	23:00s	1:00	S
             Rule	Spain	1940	only	-	Mar	16	23:00s	1:00	S
            -# Whitman says no DST 1942-1945; go with Shanks.
            +# Whitman says no DST 1942-1945; go with Shanks & Pottenger.
             Rule	Spain	1942	only	-	May	 2	22:00s	2:00	M # Midsummer
             Rule	Spain	1942	only	-	Sep	 1	22:00s	1:00	S
             Rule	Spain	1943	1946	-	Apr	Sat>=13	22:00s	2:00	M
            @@ -2101,7 +2397,7 @@
             Rule SpainAfrica 1978	only	-	Jun	 1	 0:00	1:00	S
             Rule SpainAfrica 1978	only	-	Aug	 4	 0:00	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone	Europe/Madrid	-0:14:44 -	LMT	1901
            +Zone	Europe/Madrid	-0:14:44 -	LMT	1901 Jan  1  0:00s
             			 0:00	Spain	WE%sT	1946 Sep 30
             			 1:00	Spain	CE%sT	1979
             			 1:00	EU	CE%sT
            @@ -2123,7 +2419,7 @@
             
             # Sweden
             
            -# From Ivan Nilsson (2001-04-13), superseding Shanks:
            +# From Ivan Nilsson (2001-04-13), superseding Shanks & Pottenger:
             #
             # The law "Svensk forfattningssamling 1878, no 14" about standard time in 1879:
             # From the beginning of 1879 (that is 01-01 00:00) the time for all
            @@ -2182,18 +2478,113 @@
             # mean time in preference to apparent time -- Geneva from 1780 ....
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             # From Whitman (who writes ``Midnight?''):
            -Rule	Swiss	1940	only	-	Nov	 2	0:00	1:00	S
            -Rule	Swiss	1940	only	-	Dec	31	0:00	0	-
            -# From Shanks:
            -Rule	Swiss	1941	1942	-	May	Sun>=1	2:00	1:00	S
            -Rule	Swiss	1941	1942	-	Oct	Sun>=1	0:00	0	-
            +# Rule	Swiss	1940	only	-	Nov	 2	0:00	1:00	S
            +# Rule	Swiss	1940	only	-	Dec	31	0:00	0	-
            +# From Shanks & Pottenger:
            +# Rule	Swiss	1941	1942	-	May	Sun>=1	2:00	1:00	S
            +# Rule	Swiss	1941	1942	-	Oct	Sun>=1	0:00	0	-
            +
            +# From Alois Treindl (2008-12-17):
            +# I have researched the DST usage in Switzerland during the 1940ies.
            +#
            +# As I wrote in an earlier message, I suspected the current tzdata values
            +# to be wrong. This is now verified.
            +#
            +# I have found copies of the original ruling by the Swiss Federal
            +# government, in 'Eidgen[o]ssische Gesetzessammlung 1941 and 1942' (Swiss
            +# federal law collection)...
            +#
            +# DST began on Monday 5 May 1941, 1:00 am by shifting the clocks to 2:00 am
            +# DST ended on Monday 6 Oct 1941, 2:00 am by shifting the clocks to 1:00 am.
            +#
            +# DST began on Monday, 4 May 1942 at 01:00 am
            +# DST ended on Monday, 5 Oct 1942 at 02:00 am
            +#
            +# There was no DST in 1940, I have checked the law collection carefully.
            +# It is also indicated by the fact that the 1942 entry in the law
            +# collection points back to 1941 as a reference, but no reference to any
            +# other years are made.
            +#
            +# Newspaper articles I have read in the archives on 6 May 1941 reported
            +# about the introduction of DST (Sommerzeit in German) during the previous
            +# night as an absolute novelty, because this was the first time that such
            +# a thing had happened in Switzerland.
            +#
            +# I have also checked 1916, because one book source (Gabriel, Traite de
            +# l'heure dans le monde) claims that Switzerland had DST in 1916. This is
            +# false, no official document could be found. Probably Gabriel got misled
            +# by references to Germany, which introduced DST in 1916 for the first time.
            +#
            +# The tzdata rules for Switzerland must be changed to:
            +# Rule  Swiss   1941    1942    -       May     Mon>=1  1:00    1:00    S
            +# Rule  Swiss   1941    1942    -       Oct     Mon>=1  2:00    0       -
            +#
            +# The 1940 rules must be deleted.
            +#
            +# One further detail for Switzerland, which is probably out of scope for
            +# most users of tzdata:
            +# The zone file
            +# Zone    Europe/Zurich   0:34:08 -       LMT     1848 Sep 12
            +#                          0:29:44 -       BMT     1894 Jun #Bern Mean Time
            +#                          1:00    Swiss   CE%sT   1981
            +#                          1:00    EU      CE%sT
            +# describes all of Switzerland correctly, with the exception of
            +# the Cantone Geneve (Geneva, Genf). Between 1848 and 1894 Geneve did not
            +# follow Bern Mean Time but kept its own local mean time.
            +# To represent this, an extra zone would be needed.
            +
            +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            +Rule	Swiss	1941	1942	-	May	Mon>=1	1:00	1:00	S
            +Rule	Swiss	1941	1942	-	Oct	Mon>=1	2:00	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Europe/Zurich	0:34:08 -	LMT	1848 Sep 12
             			0:29:44	-	BMT	1894 Jun # Bern Mean Time
             			1:00	Swiss	CE%sT	1981
             			1:00	EU	CE%sT
             
             # Turkey
            +
            +# From Amar Devegowda (2007-01-03):
            +# The time zone rules for Istanbul, Turkey have not been changed for years now.
            +# ... The latest rules are available at -
            +# http://www.timeanddate.com/worldclock/timezone.html?n=107
            +# From Steffen Thorsen (2007-01-03):
            +# I have been able to find press records back to 1996 which all say that
            +# DST started 01:00 local time and end at 02:00 local time.  I am not sure
            +# what happened before that.  One example for each year from 1996 to 2001:
            +# http://newspot.byegm.gov.tr/arsiv/1996/21/N4.htm
            +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING97/03/97X03X25.TXT
            +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING98/03/98X03X02.HTM
            +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING99/10/99X10X26.HTM#%2016
            +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2000/03/00X03X06.HTM#%2021
            +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2001/03/23x03x01.HTM#%2027
            +# From Paul Eggert (2007-01-03):
            +# Prefer the above source to Shanks & Pottenger for time stamps after 1990.
            +
            +# From Steffen Thorsen (2007-03-09):
            +# Starting 2007 though, it seems that they are adopting EU's 1:00 UTC
            +# start/end time, according to the following page (2007-03-07):
            +# http://www.ntvmsnbc.com/news/402029.asp
            +# The official document is located here - it is in Turkish...:
            +# http://rega.basbakanlik.gov.tr/eskiler/2007/03/20070307-7.htm
            +# I was able to locate the following seemingly official document
            +# (on a non-government server though) describing dates between 2002 and 2006:
            +# http://www.alomaliye.com/bkk_2002_3769.htm
            +
            +# From Gökdeniz Karadağ (2011-03-10):
            +# 
            +# According to the articles linked below, Turkey will change into summer
            +# time zone (GMT+3) on March 28, 2011 at 3:00 a.m. instead of March 27.
            +# This change is due to a nationwide exam on 27th.
            +# 
            +# 
            +# http://www.worldbulletin.net/?aType=haber&ArticleID=70872
            +# 
            +# Turkish:
            +# 
            +# http://www.hurriyet.com.tr/ekonomi/17230464.asp?gid=373
            +# 
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Turkey	1916	only	-	May	 1	0:00	1:00	S
             Rule	Turkey	1916	only	-	Oct	 1	0:00	0	-
            @@ -2203,7 +2594,8 @@
             Rule	Turkey	1921	only	-	Oct	 3	0:00	0	-
             Rule	Turkey	1922	only	-	Mar	26	0:00	1:00	S
             Rule	Turkey	1922	only	-	Oct	 8	0:00	0	-
            -# Whitman gives 1923 Apr 28 - Sep 16 and no DST in 1924-1925; go with Shanks.
            +# Whitman gives 1923 Apr 28 - Sep 16 and no DST in 1924-1925;
            +# go with Shanks & Pottenger.
             Rule	Turkey	1924	only	-	May	13	0:00	1:00	S
             Rule	Turkey	1924	1925	-	Oct	 1	0:00	0	-
             Rule	Turkey	1925	only	-	May	 1	0:00	1:00	S
            @@ -2212,7 +2604,8 @@
             Rule	Turkey	1940	only	-	Dec	 1	0:00	1:00	S
             Rule	Turkey	1941	only	-	Sep	21	0:00	0	-
             Rule	Turkey	1942	only	-	Apr	 1	0:00	1:00	S
            -# Whitman omits the next two transition and gives 1945 Oct 1; go with Shanks.
            +# Whitman omits the next two transition and gives 1945 Oct 1;
            +# go with Shanks & Pottenger.
             Rule	Turkey	1942	only	-	Nov	 1	0:00	0	-
             Rule	Turkey	1945	only	-	Apr	 2	0:00	1:00	S
             Rule	Turkey	1945	only	-	Oct	 8	0:00	0	-
            @@ -2246,13 +2639,19 @@
             Rule	Turkey	1983	only	-	Oct	 2	0:00	0	-
             Rule	Turkey	1985	only	-	Apr	20	0:00	1:00	S
             Rule	Turkey	1985	only	-	Sep	28	0:00	0	-
            +Rule	Turkey	1986	1990	-	Mar	lastSun	2:00s	1:00	S
            +Rule	Turkey	1986	1990	-	Sep	lastSun	2:00s	0	-
            +Rule	Turkey	1991	2006	-	Mar	lastSun	1:00s	1:00	S
            +Rule	Turkey	1991	1995	-	Sep	lastSun	1:00s	0	-
            +Rule	Turkey	1996	2006	-	Oct	lastSun	1:00s	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	Europe/Istanbul	1:55:52 -	LMT	1880
             			1:56:56	-	IMT	1910 Oct # Istanbul Mean Time?
             			2:00	Turkey	EE%sT	1978 Oct 15
             			3:00	Turkey	TR%sT	1985 Apr 20 # Turkey Time
            -			2:00	Turkey	EE%sT	1986
            -			2:00	C-Eur	EE%sT	1991
            +			2:00	Turkey	EE%sT	2007
            +			2:00	EU	EE%sT	2011 Mar 27 1:00u
            +			2:00	-	EET	2011 Mar 28 1:00u
             			2:00	EU	EE%sT
             Link	Europe/Istanbul	Asia/Istanbul	# Istanbul is in both continents.
             
            @@ -2266,8 +2665,54 @@
             # of March at 3am the time is changing to 4am and each last Sunday of
             # October the time at 4am is changing to 3am"
             
            +# From Alexander Krivenyshev (2011-09-20):
            +# On September 20, 2011 the deputies of the Verkhovna Rada agreed to
            +# abolish the transfer clock to winter time.
            +#
            +# Bill number 8330 of MP from the Party of Regions Oleg Nadoshi got
            +# approval from 266 deputies.
            +#
            +# Ukraine abolishes transter back to the winter time (in Russian)
            +# 
            +# http://news.mail.ru/politics/6861560/
            +# 
            +#
            +# The Ukrainians will no longer change the clock (in Russian)
            +# 
            +# http://www.segodnya.ua/news/14290482.html
            +# 
            +#
            +# Deputies cancelled the winter time (in Russian)
            +# 
            +# http://www.pravda.com.ua/rus/news/2011/09/20/6600616/
            +# 
            +#
            +# From Philip Pizzey (2011-10-18):
            +# Today my Ukrainian colleagues have informed me that the
            +# Ukrainian parliament have decided that they will go to winter
            +# time this year after all.
            +#
            +# From Udo Schwedt (2011-10-18):
            +# As far as I understand, the recent change to the Ukranian time zone 
            +# (Europe/Kiev) to introduce permanent daylight saving time (similar
            +# to Russia) was reverted today:
            +#
            +# 
            +# http://portal.rada.gov.ua/rada/control/en/publish/article/info_left?art_id=287324&cat_id=105995
            +# 
            +#
            +# Also reported by Alexander Bokovoy (2011-10-18) who also noted:
            +# The law documents themselves are at
            +#
            +# 
            +# http://w1.c1.rada.gov.ua/pls/zweb_n/webproc4_1?id=&pf3511=41484
            +# 
            +
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             # Most of Ukraine since 1970 has been like Kiev.
            +# "Kyiv" is the transliteration of the Ukrainian name, but
            +# "Kiev" is more common in English.
             Zone Europe/Kiev	2:02:04 -	LMT	1880
             			2:02:04	-	KMT	1924 May  2 # Kiev Mean Time
             			2:00	-	EET	1930 Jun 21
            @@ -2279,6 +2724,8 @@
             			2:00	E-Eur	EE%sT	1995
             			2:00	EU	EE%sT
             # Ruthenia used CET 1990/1991.
            +# "Uzhhorod" is the transliteration of the Ukrainian name, but
            +# "Uzhgorod" is more common in English.
             Zone Europe/Uzhgorod	1:29:12 -	LMT	1890 Oct
             			1:00	-	CET	1940
             			1:00	C-Eur	CE%sT	1944 Oct
            @@ -2291,7 +2738,10 @@
             			2:00	E-Eur	EE%sT	1995
             			2:00	EU	EE%sT
             # Zaporozh'ye and eastern Lugansk oblasts observed DST 1990/1991.
            -# Zaporozh'ye has an apostrophe, but Posix file names can't have apostrophes.
            +# "Zaporizhia" is the transliteration of the Ukrainian name, but
            +# "Zaporozh'ye" is more common in English.  Use the common English
            +# spelling, except omit the apostrophe as it is not allowed in
            +# portable Posix file names.
             Zone Europe/Zaporozhye	2:20:40 -	LMT	1880
             			2:20	-	CUT	1924 May  2 # Central Ukraine T
             			2:00	-	EET	1930 Jun 21
            @@ -2309,11 +2759,13 @@
             			3:00	Russia	MSK/MSD	1990
             			3:00	-	MSK	1990 Jul  1 2:00
             			2:00	-	EET	1992
            -# From Paul Eggert  (1999-11-12):
            +# From Paul Eggert (2006-03-22):
             # The _Economist_ (1994-05-28, p 45) reports that central Crimea switched
             # from Kiev to Moscow time sometime after the January 1994 elections.
            -# Shanks says ``date of change uncertain'', but implies that it happened
            -# sometime between the 1994 DST switches.  For now, guess it changed in May.
            +# Shanks (1999) says ``date of change uncertain'', but implies that it happened
            +# sometime between the 1994 DST switches.  Shanks & Pottenger simply say
            +# 1994-09-25 03:00, but that can't be right.  For now, guess it
            +# changed in May.
             			2:00	E-Eur	EE%sT	1994 May
             # From IATA SSIM (1994/1997), which also says that Kerch is still like Kiev.
             			3:00	E-Eur	MSK/MSD	1996 Mar 31 3:00s
            @@ -2339,8 +2791,7 @@
             
             # ...
             # Date: Wed, 28 Jan 87 16:56:27 -0100
            -# From: seismo!mcvax!cgcha!wtho (Tom Hofmann)
            -# Message-Id: <8701281556.AA22174@cgcha.uucp>
            +# From: Tom Hofmann
             # ...
             #
             # ...the European time rules are...standardized since 1981, when
            @@ -2359,11 +2810,11 @@
             #
             # Tom Hofmann, Scientific Computer Center, CIBA-GEIGY AG,
             # 4002 Basle, Switzerland
            -# UUCP: ...!mcvax!cernvax!cgcha!wtho
            +# ...
             
             # ...
             # Date: Wed, 4 Feb 87 22:35:22 +0100
            -# From: seismo!mcvax!cwi.nl!dik (Dik T. Winter)
            +# From: Dik T. Winter
             # ...
             #
             # The information from Tom Hofmann is (as far as I know) not entirely correct.
            @@ -2389,8 +2840,7 @@
             #
             # ...
             # dik t. winter, cwi, amsterdam, nederland
            -# INTERNET   : dik@cwi.nl
            -# BITNET/EARN: dik@mcvax
            +# ...
             
             # From Bob Devine (1988-01-28):
             # ...
            Index: 3rdParty_sources/joda-time/org/joda/time/tz/src/northamerica
            ===================================================================
            diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/joda-time/org/joda/time/tz/src/northamerica	(.../northamerica)	(revision 4e266757c429613d78b0fd2914d40d77a447daad)
            +++ 3rdParty_sources/joda-time/org/joda/time/tz/src/northamerica	(.../northamerica)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -1,11 +1,15 @@
            -# @(#)northamerica	7.70
            +# 
            +# @(#)northamerica	8.51
            +# This file is in the public domain, so clarified as of
            +# 2009-05-17 by Arthur David Olson.
            +
             # also includes Central America and the Caribbean
             
             # This data is by no means authoritative; if you think you know better,
             # go ahead and edit the file (and please send any changes to
             # tz@elsie.nci.nih.gov for general use in the future).
             
            -# From Paul Eggert  (1999-03-22):
            +# From Paul Eggert (1999-03-22):
             # A reliable and entertaining source about time zones is
             # Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
             
            @@ -24,12 +28,16 @@
             # His proposal was adopted by the railroads on 1883-11-18 at 12:00,
             # and the most of the country soon followed suit.
             
            -# From Paul Eggert  (1995-12-19):
            +# From Paul Eggert (2005-04-16):
            +# That 1883 transition occurred at 12:00 new time, not at 12:00 old time.
            +# See p 46 of David Prerau, Seize the daylight, Thunder's Mouth Press (2005).
            +
            +# From Paul Eggert (2006-03-22):
             # A good source for time zone historical data in the US is
             # Thomas G. Shanks, The American Atlas (5th edition),
             # San Diego: ACS Publications, Inc. (1991).
             # Make sure you have the errata sheet; the book is somewhat useless without it.
            -# It is the source for the US and Puerto Rico entries below.
            +# It is the source for most of the pre-1991 US entries below.
             
             # From Paul Eggert (2001-03-06):
             # Daylight Saving Time was first suggested as a joke by Benjamin Franklin
            @@ -48,7 +56,8 @@
             #	to push people into bed earlier, and get them up earlier, to make
             #	them healthy, wealthy and wise in spite of themselves.
             #
            -#	-- Robertson Davies, The Diary of Samuel Marchbanks (1947), XIX, Sunday
            +#	-- Robertson Davies, The diary of Samuel Marchbanks,
            +#	   Clarke, Irwin (1947), XIX, Sunday
             #
             # For more about the first ten years of DST in the United States, see
             # Robert Garland's 
            @@ -78,7 +87,7 @@
             # Time' instead of the old familiar 'Eastern War Time.'  Peace is wonderful."
             #  (August 1945) by way of confirmation.
             
            -# From Joseph Gallant , citing
            +# From Joseph Gallant citing
             # George H. Douglas, _The Early Days of Radio Broadcasting_ (1987):
             # At 7 P.M. (Eastern War Time) [on 1945-08-14], the networks were set
             # to switch to London for Attlee's address, but the American people
            @@ -105,22 +114,47 @@
             #
             # He had scored a 20-second scoop on other broadcasters.
             
            +# From Arthur David Olson (2005-08-22):
            +# Paul has been careful to use the "US" rules only in those locations
            +# that are part of the United States; this reflects the real scope of
            +# U.S. government action.  So even though the "US" rules have changed
            +# in the latest release, other countries won't be affected.
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	US	1918	1919	-	Mar	lastSun	2:00	1:00	D
             Rule	US	1918	1919	-	Oct	lastSun	2:00	0	S
             Rule	US	1942	only	-	Feb	9	2:00	1:00	W # War
             Rule	US	1945	only	-	Aug	14	23:00u	1:00	P # Peace
             Rule	US	1945	only	-	Sep	30	2:00	0	S
            -Rule	US	1967	max	-	Oct	lastSun	2:00	0	S
            +Rule	US	1967	2006	-	Oct	lastSun	2:00	0	S
             Rule	US	1967	1973	-	Apr	lastSun	2:00	1:00	D
             Rule	US	1974	only	-	Jan	6	2:00	1:00	D
             Rule	US	1975	only	-	Feb	23	2:00	1:00	D
             Rule	US	1976	1986	-	Apr	lastSun	2:00	1:00	D
            -Rule	US	1987	max	-	Apr	Sun>=1	2:00	1:00	D
            -# 
            -# H.R.177
            -#  (introduced 1999-01-06) would change April to March in the above rule.
            +Rule	US	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
            +Rule	US	2007	max	-	Mar	Sun>=8	2:00	1:00	D
            +Rule	US	2007	max	-	Nov	Sun>=1	2:00	0	S
             
            +# From Arthur David Olson, 2005-12-19
            +# We generate the files specified below to guard against old files with
            +# obsolete information being left in the time zone binary directory.
            +# We limit the list to names that have appeared in previous versions of
            +# this time zone package.
            +# We do these as separate Zones rather than as Links to avoid problems if
            +# a particular place changes whether it observes DST.
            +# We put these specifications here in the northamerica file both to
            +# increase the chances that they'll actually get compiled and to
            +# avoid the need to duplicate the US rules in another file.
            +
            +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            +Zone	EST		 -5:00	-	EST
            +Zone	MST		 -7:00	-	MST
            +Zone	HST		-10:00	-	HST
            +Zone	EST5EDT		 -5:00	US	E%sT
            +Zone	CST6CDT		 -6:00	US	C%sT
            +Zone	MST7MDT		 -7:00	US	M%sT
            +Zone	PST8PDT		 -8:00	US	P%sT
            +
             # From Bob Devine (1988-01-28):
             # ...Alaska (and Hawaii) had the timezone names changed in 1967.
             #    old			 new
            @@ -198,24 +232,60 @@
             # "Chamorro Standard Time" for time in Guam and the Northern Marianas.
             # See the file "australasia".
             
            +# From Arthur David Olson, 2005-08-09
            +# The following was signed into law on 2005-08-08.
            +#
            +# H.R. 6, Energy Policy Act of 2005, SEC. 110. DAYLIGHT SAVINGS.
            +#   (a) Amendment- Section 3(a) of the Uniform Time Act of 1966 (15
            +#   U.S.C. 260a(a)) is amended--
            +#     (1) by striking `first Sunday of April' and inserting `second
            +#     Sunday of March'; and
            +#     (2) by striking `last Sunday of October' and inserting `first
            +#     Sunday of November'.
            +#   (b) Effective Date- Subsection (a) shall take effect 1 year after the
            +#   date of enactment of this Act or March 1, 2007, whichever is later.
            +#   (c) Report to Congress- Not later than 9 months after the effective
            +#   date stated in subsection (b), the Secretary shall report to Congress
            +#   on the impact of this section on energy consumption in the United
            +#   States.
            +#   (d) Right to Revert- Congress retains the right to revert the
            +#   Daylight Saving Time back to the 2005 time schedules once the
            +#   Department study is complete.
             
             # US eastern time, represented by New York
             
             # Connecticut, Delaware, District of Columbia, most of Florida,
            -# Georgia, southeast Indiana (Clark, Dearborn, Floyd, Harrison, and
            -# Ohio counties), eastern Kentucky, Maine, Maryland, Massachusetts,
            +# Georgia, southeast Indiana (Dearborn and Ohio counties), eastern Kentucky
            +# (except America/Kentucky/Louisville below), Maine, Maryland, Massachusetts,
             # New Hampshire, New Jersey, New York, North Carolina, Ohio,
             # Pennsylvania, Rhode Island, South Carolina, eastern Tennessee,
             # Vermont, Virginia, West Virginia
             
            +# From Dave Cantor (2004-11-02):
            +# Early this summer I had the occasion to visit the Mount Washington
            +# Observatory weather station atop (of course!) Mount Washington [, NH]....
            +# One of the staff members said that the station was on Eastern Standard Time
            +# and didn't change their clocks for Daylight Saving ... so that their
            +# reports will always have times which are 5 hours behind UTC.
            +
            +# From Paul Eggert (2005-08-26):
            +# According to today's Huntsville Times
            +# 
            +# a few towns on Alabama's "eastern border with Georgia, such as Phenix City
            +# in Russell County, Lanett in Chambers County and some towns in Lee County,
            +# set their watches and clocks on Eastern time."  It quotes H.H. "Bubba"
            +# Roberts, city administrator in Phenix City. as saying "We are in the Central
            +# time zone, but we do go by the Eastern time zone because so many people work
            +# in Columbus."
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
             Rule	NYC	1920	only	-	Mar	lastSun	2:00	1:00	D
             Rule	NYC	1920	only	-	Oct	lastSun	2:00	0	S
             Rule	NYC	1921	1966	-	Apr	lastSun	2:00	1:00	D
             Rule	NYC	1921	1954	-	Sep	lastSun	2:00	0	S
             Rule	NYC	1955	1966	-	Oct	lastSun	2:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/New_York	-4:56:02 -	LMT	1883 Nov 18 12:00
            +Zone America/New_York	-4:56:02 -	LMT	1883 Nov 18 12:03:58
             			-5:00	US	E%sT	1920
             			-5:00	NYC	E%sT	1942
             			-5:00	US	E%sT	1946
            @@ -233,6 +303,18 @@
             # Nebraska, eastern North Dakota, Oklahoma, eastern South Dakota,
             # western Tennessee, most of Texas, Wisconsin
             
            +# From Larry M. Smith (2006-04-26) re Wisconsin:
            +# http://www.legis.state.wi.us/statutes/Stat0175.pdf ...
            +# is currently enforced at the 01:00 time of change.  Because the local
            +# "bar time" in the state corresponds to 02:00, a number of citations
            +# are issued for the "sale of class 'B' alcohol after prohibited
            +# hours" within the deviated hour of this change every year....
            +#
            +# From Douglas R. Bomberg (2007-03-12):
            +# Wisconsin has enacted (nearly eleventh-hour) legislation to get WI
            +# Statue 175 closer in synch with the US Congress' intent....
            +# http://www.legis.state.wi.us/2007/data/acts/07Act3.pdf
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
             Rule	Chicago	1920	only	-	Jun	13	2:00	1:00	D
             Rule	Chicago	1920	1921	-	Oct	lastSun	2:00	0	S
            @@ -241,7 +323,7 @@
             Rule	Chicago	1922	1954	-	Sep	lastSun	2:00	0	S
             Rule	Chicago	1955	1966	-	Oct	lastSun	2:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/Chicago	-5:50:36 -	LMT	1883 Nov 18 12:00
            +Zone America/Chicago	-5:50:36 -	LMT	1883 Nov 18 12:09:24
             			-6:00	US	C%sT	1920
             			-6:00	Chicago	C%sT	1936 Mar  1 2:00
             			-5:00	-	EST	1936 Nov 15 2:00
            @@ -250,15 +332,46 @@
             			-6:00	Chicago	C%sT	1967
             			-6:00	US	C%sT
             # Oliver County, ND switched from mountain to central time on 1992-10-25.
            -Zone America/North_Dakota/Center -6:45:12 - LMT	1883 Nov 18 12:00
            +Zone America/North_Dakota/Center -6:45:12 - LMT	1883 Nov 18 12:14:48
             			-7:00	US	M%sT	1992 Oct 25 02:00
             			-6:00	US	C%sT
            +# Morton County, ND, switched from mountain to central time on
            +# 2003-10-26, except for the area around Mandan which was already central time.
            +# See .
            +# Officially this switch also included part of Sioux County, and
            +# Jones, Mellette, and Todd Counties in South Dakota;
            +# but in practice these other counties were already observing central time.
            +# See .
            +Zone America/North_Dakota/New_Salem -6:45:39 - LMT 1883 Nov 18 12:14:21
            +			-7:00	US	M%sT	2003 Oct 26 02:00
            +			-6:00	US	C%sT
             
            +# From Josh Findley (2011-01-21):
            +# ...it appears that Mercer County, North Dakota, changed from the
            +# mountain time zone to the central time zone at the last transition from
            +# daylight-saving to standard time (on Nov. 7, 2010):
            +# 
            +# http://www.gpo.gov/fdsys/pkg/FR-2010-09-29/html/2010-24376.htm
            +# 
            +# 
            +# http://www.bismarcktribune.com/news/local/article_1eb1b588-c758-11df-b472-001cc4c03286.html
            +# 
            +
            +# From Andy Lipscomb (2011-01-24):
            +# ...according to the Census Bureau, the largest city is Beulah (although
            +# it's commonly referred to as Beulah-Hazen, with Hazen being the next
            +# largest city in Mercer County).  Google Maps places Beulah's city hall
            +# at 4715'51" north, 10146'40" west, which yields an offset of 6h47'07".
            +
            +Zone America/North_Dakota/Beulah -6:47:07 - LMT 1883 Nov 18 12:12:53
            +			-7:00	US	M%sT	2010 Nov  7 2:00
            +			-6:00	US	C%sT
            +
             # US mountain time, represented by Denver
             #
             # Colorado, far western Kansas, Montana, western
             # Nebraska, Nevada border (Jackpot, Owyhee, and Mountain City),
            -# New Mexico, southwestern North Dakota, far eastern Oregon,
            +# New Mexico, southwestern North Dakota,
             # western South Dakota, far western Texas (El Paso County, Hudspeth County,
             # and Pine Springs and Nickel Creek in Culberson County), Utah, Wyoming
             #
            @@ -269,7 +382,7 @@
             Rule	Denver	1965	1966	-	Apr	lastSun	2:00	1:00	D
             Rule	Denver	1965	1966	-	Oct	lastSun	2:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/Denver	-6:59:56 -	LMT	1883 Nov 18 12:00
            +Zone America/Denver	-6:59:56 -	LMT	1883 Nov 18 12:00:04
             			-7:00	US	M%sT	1920
             			-7:00	Denver	M%sT	1942
             			-7:00	US	M%sT	1946
            @@ -279,7 +392,8 @@
             # US Pacific time, represented by Los Angeles
             #
             # California, northern Idaho (Benewah, Bonner, Boundary, Clearwater,
            -# Idaho, Kootenai, Latah, Lewis, Nez Perce, and Shoshone counties),
            +# Idaho, Kootenai, Latah, Lewis, Nez Perce, and Shoshone counties,
            +# and the northern three-quarters of Idaho county),
             # most of Nevada, most of Oregon, and Washington
             #
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
            @@ -289,7 +403,7 @@
             Rule	CA	1950	1961	-	Sep	lastSun	2:00	0	S
             Rule	CA	1962	1966	-	Oct	lastSun	2:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/Los_Angeles -7:52:58 -	LMT	1883 Nov 18 12:00
            +Zone America/Los_Angeles -7:52:58 -	LMT	1883 Nov 18 12:07:02
             			-8:00	US	P%sT	1946
             			-8:00	CA	P%sT	1967
             			-8:00	US	P%sT
            @@ -312,15 +426,78 @@
             # were nearby inhabitants in some cases and for our purposes perhaps
             # it's best to simply use the official transition.
             #
            +
            +# From Steve Ferguson (2011-01-31):
            +# The author lives in Alaska and many of the references listed are only
            +# available to Alaskan residents.
            +#
            +# 
            +# http://www.alaskahistoricalsociety.org/index.cfm?section=discover%20alaska&page=Glimpses%20of%20the%20Past&viewpost=2&ContentId=98
            +# 
            +
            +# From Arthur David Olson (2011-02-01):
            +# Here's database-relevant material from the 2001 "Alaska History" article:
            +#
            +# On September 20 [1979]...DOT...officials decreed that on April 27,
            +# 1980, Juneau and other nearby communities would move to Yukon Time.
            +# Sitka, Petersburg, Wrangell, and Ketchikan, however, would remain on
            +# Pacific Time.
            +#
            +# ...on September 22, 1980, DOT Secretary Neil E. Goldschmidt rescinded the
            +# Department's September 1979 decision. Juneau and other communities in
            +# northern Southeast reverted to Pacific Time on October 26.
            +#
            +# On October 28 [1983]...the Metlakatla Indian Community Council voted
            +# unanimously to keep the reservation on Pacific Time.
            +#
            +# According to DOT official Joanne Petrie, Indian reservations are not
            +# bound to follow time zones imposed by neighboring jurisdictions.
            +#
            +# (The last is consistent with how the database now handles the Navajo
            +# Nation.)
            +
            +# From Arthur David Olson (2011-02-09):
            +# I just spoke by phone with a staff member at the Metlakatla Indian
            +# Community office (using contact information available at
            +# 
            +# http://www.commerce.state.ak.us/dca/commdb/CIS.cfm?Comm_Boro_name=Metlakatla
            +# ).
            +# It's shortly after 1:00 here on the east coast of the United States;
            +# the staffer said it was shortly after 10:00 there. When I asked whether
            +# that meant they were on Pacific time, they said no--they were on their
            +# own time. I asked about daylight saving; they said it wasn't used. I
            +# did not inquire about practices in the past.
            +
            +# From Arthur David Olson (2011-08-17):
            +# For lack of better information, assume that Metlakatla's
            +# abandonment of use of daylight saving resulted from the 1983 vote.
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Juneau	 15:02:19 -	LMT	1867 Oct 18
             			 -8:57:41 -	LMT	1900 Aug 20 12:00
             			 -8:00	-	PST	1942
             			 -8:00	US	P%sT	1946
             			 -8:00	-	PST	1969
            +			 -8:00	US	P%sT	1980 Apr 27 2:00
            +			 -9:00	US	Y%sT	1980 Oct 26 2:00	
             			 -8:00	US	P%sT	1983 Oct 30 2:00
             			 -9:00	US	Y%sT	1983 Nov 30
             			 -9:00	US	AK%sT
            +Zone America/Sitka	 14:58:47 -	LMT	1867 Oct 18
            +			 -9:01:13 -	LMT	1900 Aug 20 12:00
            +			 -8:00	-	PST	1942
            +			 -8:00	US	P%sT	1946
            +			 -8:00	-	PST	1969
            +			 -8:00	US	P%sT	1983 Oct 30 2:00
            +			 -9:00	US	Y%sT	1983 Nov 30
            +			 -9:00	US	AK%sT
            +Zone America/Metlakatla	 15:13:42 -	LMT	1867 Oct 18
            +			 -8:46:18 -	LMT	1900 Aug 20 12:00
            +			 -8:00	-	PST	1942
            +			 -8:00	US	P%sT	1946
            +			 -8:00	-	PST	1969
            +			 -8:00	US	P%sT	1983 Oct 30 2:00
            +			 -8:00	-	MeST
             Zone America/Yakutat	 14:41:05 -	LMT	1867 Oct 18
             			 -9:18:55 -	LMT	1900 Aug 20 12:00
             			 -9:00	-	YST	1942
            @@ -331,7 +508,8 @@
             Zone America/Anchorage	 14:00:24 -	LMT	1867 Oct 18
             			 -9:59:36 -	LMT	1900 Aug 20 12:00
             			-10:00	-	CAT	1942
            -			-10:00	US	CAT/CAWT 1946
            +			-10:00	US	CAT/CAWT 1945 Aug 14 23:00u
            +			-10:00	US	CAT/CAPT 1946 # Peace
             			-10:00	-	CAT	1967 Apr
             			-10:00	-	AHST	1969
             			-10:00	US	AH%sT	1983 Oct 30 2:00
            @@ -355,26 +533,72 @@
             			-11:00	US	B%sT	1983 Oct 30 2:00
             			-10:00	US	AH%sT	1983 Nov 30
             			-10:00	US	HA%sT
            +# The following switches don't quite make our 1970 cutoff.
            +#
             # Shanks writes that part of southwest Alaska (e.g. Aniak)
             # switched from -11:00 to -10:00 on 1968-09-22 at 02:00,
             # and another part (e.g. Akiak) made the same switch five weeks later.
            -# These switches don't quite make our 1970 cutoff.
            +#
            +# From David Flater (2004-11-09):
            +# In e-mail, 2004-11-02, Ray Hudson, historian/liaison to the Unalaska
            +# Historic Preservation Commission, provided this information, which
            +# suggests that Unalaska deviated from statutory time from early 1967
            +# possibly until 1983:
            +#
            +#  Minutes of the Unalaska City Council Meeting, January 10, 1967:
            +#  "Except for St. Paul and Akutan, Unalaska is the only important
            +#  location not on Alaska Standard Time.  The following resolution was
            +#  made by William Robinson and seconded by Henry Swanson:  Be it
            +#  resolved that the City of Unalaska hereby goes to Alaska Standard
            +#  Time as of midnight Friday, January 13, 1967 (1 A.M. Saturday,
            +#  January 14, Alaska Standard Time.)  This resolution was passed with
            +#  three votes for and one against."
             
             # Hawaii
            +
            +# From Arthur David Olson (2010-12-09):
            +# "Hawaiian Time" by Robert C. Schmitt and Doak C. Cox appears on pages 207-225
            +# of volume 26 of The Hawaiian Journal of History (1992). As of 2010-12-09,
            +# the article is available at
            +# 
            +# http://evols.library.manoa.hawaii.edu/bitstream/10524/239/2/JL26215.pdf
            +# 
            +# and indicates that standard time was adopted effective noon, January
            +# 13, 1896 (page 218), that in "1933, the Legislature decreed daylight
            +# saving for the period between the last Sunday of each April and the
            +# last Sunday of each September, but less than a month later repealed the
            +# act," (page 220), that year-round daylight saving time was in effect
            +# from 1942-02-09 to 1945-09-30 (page 221, with no time of day given for
            +# when clocks changed) and that clocks were changed by 30 minutes
            +# effective the second Sunday of June, 1947 (page 219, with no time of
            +# day given for when clocks changed). A footnote for the 1933 changes
            +# cites Session Laws of Hawaii 1933, "Act. 90 (approved 26 Apr. 1933)
            +# and Act 163 (approved 21 May 1933)."
            +
            +# From Arthur David Olson (2011-01-19):
            +# The following is from "Laws of the Territory of Hawaii Passed by the
            +# Seventeenth Legislature: Regular Session 1933," available (as of
            +# 2011-01-19) at American University's Pence Law Library. Page 85: "Act
            +# 90...At 2 o'clock ante meridian of the last Sunday in April of each
            +# year, the standard time of this Territory shall be advanced one
            +# hour...This Act shall take effect upon its approval. Approved this 26th
            +# day of April, A. D. 1933. LAWRENCE M JUDD, Governor of the Territory of
            +# Hawaii." Page 172:  "Act 163...Act 90 of the Session Laws of 1933 is
            +# hereby repealed...This Act shall take effect upon its approval, upon
            +# which date the standard time of this Territory shall be restored to
            +# that existing immediately prior to the taking effect of said Act 90.
            +# Approved this 21st day of May, A. D. 1933. LAWRENCE M. JUDD, Governor
            +# of the Territory of Hawaii."
             #
            -# From Arthur David Olson:
            -# And then there's Hawaii.
            -# DST was observed for one day in 1933;
            -# standard time was changed by half an hour in 1947;
            -# it's always standard as of 1986.
            -#
            -# From Paul Eggert:
            -# Shanks says the 1933 experiment lasted for three weeks.  Go with Shanks.
            -#
            -Zone Pacific/Honolulu	-10:31:26 -	LMT	1900 Jan  1 12:00
            -			-10:30	-	HST	1933 Apr 30 2:00
            -			-10:30	1:00	HDT	1933 May 21 2:00
            -			-10:30	US	H%sT	1947 Jun  8 2:00
            +# Note that 1933-05-21 was a Sunday.
            +# We're left to guess the time of day when Act 163 was approved; guess noon.
            +
            +Zone Pacific/Honolulu	-10:31:26 -	LMT	1896 Jan 13 12:00 #Schmitt&Cox
            +			-10:30	-	HST	1933 Apr 30 2:00 #Laws 1933
            +			-10:30	1:00	HDT	1933 May 21 12:00 #Laws 1933+12
            +			-10:30	-	HST	1942 Feb 09 2:00 #Schmitt&Cox+2
            +			-10:30	1:00	HDT	1945 Sep 30 2:00 #Schmitt&Cox+2
            +			-10:30	-	HST	1947 Jun  8 2:00 #Schmitt&Cox+2
             			-10:00	-	HST
             
             # Now we turn to US areas that have diverged from the consensus since 1970.
            @@ -400,7 +624,7 @@
             # Shanks says the 1944 experiment came to an end on 1944-03-17.
             # Go with the Arizona State Library instead.
             
            -Zone America/Phoenix	-7:28:18 -	LMT	1883 Nov 18 12:00
            +Zone America/Phoenix	-7:28:18 -	LMT	1883 Nov 18 11:31:42
             			-7:00	US	M%sT	1944 Jan  1 00:01
             			-7:00	-	MST	1944 Apr  1 00:01
             			-7:00	US	M%sT	1944 Oct  1 00:01
            @@ -420,11 +644,12 @@
             # Boise, Bonneville, Butte, Camas, Canyon, Caribou, Cassia, Clark,
             # Custer, Elmore, Franklin, Fremont, Gem, Gooding, Jefferson, Jerome,
             # Lemhi, Lincoln, Madison, Minidoka, Oneida, Owyhee, Payette, Power,
            -# Teton, Twin Falls, Valley, Washington counties) and eastern Oregon
            +# Teton, Twin Falls, Valley, Washington counties, and the southern
            +# quarter of Idaho county) and eastern Oregon (most of Malheur County)
             # switched four weeks late in 1974.
            -# 
            +#
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/Boise	-7:44:49 -	LMT	1883 Nov 18 12:00
            +Zone America/Boise	-7:44:49 -	LMT	1883 Nov 18 12:15:11
             			-8:00	US	P%sT	1923 May 13 2:00
             			-7:00	US	M%sT	1974
             			-7:00	-	MST	1974 Feb  3 2:00
            @@ -435,40 +660,60 @@
             # For a map of Indiana's time zone regions, see:
             # 
             # What time is it in Indiana?
            -#  (1999-04-06)
            +#  (2006-03-01)
             #
            -# From Paul Eggert (1995-12-19):
            -# Indiana generally observes either EST all year, or CST/CDT,
            -# but areas near Cincinnati and Louisville use those cities' timekeeping
            -# and in 1969 and 1970 the whole state observed daylight time;
            -# and there are other exceptions as noted below.
            -# Shanks partitions Indiana into 345 regions, each with its own time history,
            -# and writes ``Even newspaper reports present contradictory information.''
            -# Fortunately, most of the complexity occurred before our cutoff date of 1970.
            +# From Paul Eggert (2007-08-17):
            +# Since 1970, most of Indiana has been like America/Indiana/Indianapolis,
            +# with the following exceptions:
             #
            -# Since 1970, EST-only Indiana has been like America/Indianapolis,
            -# with exceptions noted below for Crawford, Starke, and Switzerland counties.
            -# The parts of Indiana not listed below have been like America/Chicago,
            -# America/Louisville, or America/New_York.
            +# - Gibson, Jasper, Lake, LaPorte, Newton, Porter, Posey, Spencer,
            +#   Vandenburgh, and Warrick counties have been like America/Chicago.
             #
            +# - Dearborn and Ohio counties have been like America/New_York.
            +#
            +# - Clark, Floyd, and Harrison counties have been like
            +#   America/Kentucky/Louisville.
            +#
            +# - Crawford, Daviess, Dubois, Knox, Martin, Perry, Pike, Pulaski, Starke,
            +#   and Switzerland counties have their own time zone histories as noted below.
            +#
            +# Shanks partitioned Indiana into 345 regions, each with its own time history,
            +# and wrote ``Even newspaper reports present contradictory information.''
            +# Those Hoosiers!  Such a flighty and changeable people!
            +# Fortunately, most of the complexity occurred before our cutoff date of 1970.
            +#
             # Other than Indianapolis, the Indiana place names are so nondescript
             # that they would be ambiguous if we left them at the `America' level.
             # So we reluctantly put them all in a subdirectory `America/Indiana'.
            -#
            -# Most of EST-only Indiana last observed DST in 1970.
             
            -# From Paul Eggert (2001-03-06), following a tip by Markus Kuhn:
            -# Pam Belluck reported in the New York Times (2001-01-31) that the
            -# Indiana Legislature is considering a bill to adopt DST statewide.
            -# Her article mentioned Vevay, whose post office observes a different
            -# time zone from Danner's Hardware across the street.
            +# From Paul Eggert (2005-08-16):
            +# http://www.mccsc.edu/time.html says that Indiana will use DST starting 2006.
             
            +# From Nathan Stratton Treadway (2006-03-30):
            +# http://www.dot.gov/affairs/dot0406.htm [3705 B]
            +# From Deborah Goldsmith (2006-01-18):
            +# http://dmses.dot.gov/docimages/pdf95/382329_web.pdf [2.9 MB]
            +# From Paul Eggert (2006-01-20):
            +# It says "DOT is relocating the time zone boundary in Indiana to move Starke,
            +# Pulaski, Knox, Daviess, Martin, Pike, Dubois, and Perry Counties from the
            +# Eastern Time Zone to the Central Time Zone.... The effective date of
            +# this rule is 2:OO a.m. EST Sunday, April 2, 2006, which is the
            +# changeover date from standard time to Daylight Saving Time."
            +# Strictly speaking, this means the affected counties will change their
            +# clocks twice that night, but this obviously is in error.  The intent
            +# is that 01:59:59 EST be followed by 02:00:00 CDT.
            +
            +# From Gwillim Law (2007-02-10):
            +# The Associated Press has been reporting that Pulaski County, Indiana is
            +# going to switch from Central to Eastern Time on March 11, 2007....
            +# http://www.indystar.com/apps/pbcs.dll/article?AID=/20070207/LOCAL190108/702070524/0/LOCAL
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
             Rule Indianapolis 1941	only	-	Jun	22	2:00	1:00	D
             Rule Indianapolis 1941	1954	-	Sep	lastSun	2:00	0	S
             Rule Indianapolis 1946	1954	-	Apr	lastSun	2:00	1:00	D
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/Indianapolis -5:44:38 - LMT 1883 Nov 18 12:00
            +Zone America/Indiana/Indianapolis -5:44:38 - LMT 1883 Nov 18 12:15:22
             			-6:00	US	C%sT	1920
             			-6:00 Indianapolis C%sT	1942
             			-6:00	US	C%sT	1946
            @@ -477,27 +722,89 @@
             			-6:00	-	CST	1958 Apr 27 2:00
             			-5:00	-	EST	1969
             			-5:00	US	E%sT	1971
            -			-5:00	-	EST
            -Link America/Indianapolis America/Indiana/Indianapolis
            +			-5:00	-	EST	2006
            +			-5:00	US	E%sT
             #
            -# Part of Crawford County, Indiana, last observed DST in 1975,
            -# and left its clocks alone in 1974.
            +# Eastern Crawford County, Indiana, left its clocks alone in 1974,
            +# as well as from 1976 through 2005.
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
             Rule	Marengo	1951	only	-	Apr	lastSun	2:00	1:00	D
             Rule	Marengo	1951	only	-	Sep	lastSun	2:00	0	S
             Rule	Marengo	1954	1960	-	Apr	lastSun	2:00	1:00	D
             Rule	Marengo	1954	1960	-	Sep	lastSun	2:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/Indiana/Marengo -5:45:23 -	LMT	1883 Nov 18 12:00
            +Zone America/Indiana/Marengo -5:45:23 -	LMT	1883 Nov 18 12:14:37
             			-6:00	US	C%sT	1951
             			-6:00	Marengo	C%sT	1961 Apr 30 2:00
             			-5:00	-	EST	1969
             			-5:00	US	E%sT	1974 Jan  6 2:00
             			-6:00	1:00	CDT	1974 Oct 27 2:00
             			-5:00	US	E%sT	1976
            -			-5:00	-	EST
            +			-5:00	-	EST	2006
            +			-5:00	US	E%sT
             #
            -# Starke County, Indiana
            +# Daviess, Dubois, Knox, and Martin Counties, Indiana,
            +# switched from eastern to central time in April 2006, then switched back
            +# in November 2007.
            +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
            +Rule Vincennes	1946	only	-	Apr	lastSun	2:00	1:00	D
            +Rule Vincennes	1946	only	-	Sep	lastSun	2:00	0	S
            +Rule Vincennes	1953	1954	-	Apr	lastSun	2:00	1:00	D
            +Rule Vincennes	1953	1959	-	Sep	lastSun	2:00	0	S
            +Rule Vincennes	1955	only	-	May	 1	0:00	1:00	D
            +Rule Vincennes	1956	1963	-	Apr	lastSun	2:00	1:00	D
            +Rule Vincennes	1960	only	-	Oct	lastSun	2:00	0	S
            +Rule Vincennes	1961	only	-	Sep	lastSun	2:00	0	S
            +Rule Vincennes	1962	1963	-	Oct	lastSun	2:00	0	S
            +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            +Zone America/Indiana/Vincennes -5:50:07 - LMT	1883 Nov 18 12:09:53
            +			-6:00	US	C%sT	1946
            +			-6:00 Vincennes	C%sT	1964 Apr 26 2:00
            +			-5:00	-	EST	1969
            +			-5:00	US	E%sT	1971
            +			-5:00	-	EST	2006 Apr  2 2:00
            +			-6:00	US	C%sT	2007 Nov  4 2:00
            +			-5:00	US	E%sT
            +#
            +# Perry County, Indiana, switched from eastern to central time in April 2006.
            +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
            +Rule Perry	1946	only	-	Apr	lastSun	2:00	1:00	D
            +Rule Perry	1946	only	-	Sep	lastSun	2:00	0	S
            +Rule Perry	1953	1954	-	Apr	lastSun	2:00	1:00	D
            +Rule Perry	1953	1959	-	Sep	lastSun	2:00	0	S
            +Rule Perry	1955	only	-	May	 1	0:00	1:00	D
            +Rule Perry	1956	1963	-	Apr	lastSun	2:00	1:00	D
            +Rule Perry	1960	only	-	Oct	lastSun	2:00	0	S
            +Rule Perry	1961	only	-	Sep	lastSun	2:00	0	S
            +Rule Perry	1962	1963	-	Oct	lastSun	2:00	0	S
            +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            +Zone America/Indiana/Tell_City -5:47:03 - LMT	1883 Nov 18 12:12:57
            +			-6:00	US	C%sT	1946
            +			-6:00 Perry	C%sT	1964 Apr 26 2:00
            +			-5:00	-	EST	1969
            +			-5:00	US	E%sT	1971
            +			-5:00	-	EST	2006 Apr  2 2:00
            +			-6:00	US	C%sT
            +#
            +# Pike County, Indiana moved from central to eastern time in 1977,
            +# then switched back in 2006, then switched back again in 2007.
            +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
            +Rule	Pike	1955	only	-	May	 1	0:00	1:00	D
            +Rule	Pike	1955	1960	-	Sep	lastSun	2:00	0	S
            +Rule	Pike	1956	1964	-	Apr	lastSun	2:00	1:00	D
            +Rule	Pike	1961	1964	-	Oct	lastSun	2:00	0	S
            +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            +Zone America/Indiana/Petersburg -5:49:07 - LMT	1883 Nov 18 12:10:53
            +			-6:00	US	C%sT	1955
            +			-6:00	Pike	C%sT	1965 Apr 25 2:00
            +			-5:00	-	EST	1966 Oct 30 2:00
            +			-6:00	US	C%sT	1977 Oct 30 2:00
            +			-5:00	-	EST	2006 Apr  2 2:00
            +			-6:00	US	C%sT	2007 Nov  4 2:00
            +			-5:00	US	E%sT
            +#
            +# Starke County, Indiana moved from central to eastern time in 1991,
            +# then switched back in 2006.
             # From Arthur David Olson (1991-10-28):
             # An article on page A3 of the Sunday, 1991-10-27 Washington Post
             # notes that Starke County switched from Central time to Eastern time as of
            @@ -509,23 +816,42 @@
             Rule	Starke	1957	1958	-	Sep	lastSun	2:00	0	S
             Rule	Starke	1959	1961	-	Oct	lastSun	2:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/Indiana/Knox -5:46:30 -	LMT	1883 Nov 18 12:00
            +Zone America/Indiana/Knox -5:46:30 -	LMT	1883 Nov 18 12:13:30
             			-6:00	US	C%sT	1947
             			-6:00	Starke	C%sT	1962 Apr 29 2:00
             			-5:00	-	EST	1963 Oct 27 2:00
             			-6:00	US	C%sT	1991 Oct 27 2:00
            -			-5:00	-	EST
            +			-5:00	-	EST	2006 Apr  2 2:00
            +			-6:00	US	C%sT
             #
            -# Switzerland County, Indiana, last observed DST in 1972.
            +# Pulaski County, Indiana, switched from eastern to central time in
            +# April 2006 and then switched back in March 2007.
            +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
            +Rule	Pulaski	1946	1960	-	Apr	lastSun	2:00	1:00	D
            +Rule	Pulaski	1946	1954	-	Sep	lastSun	2:00	0	S
            +Rule	Pulaski	1955	1956	-	Oct	lastSun	2:00	0	S
            +Rule	Pulaski	1957	1960	-	Sep	lastSun	2:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/Indiana/Vevay -5:40:16 -	LMT	1883 Nov 18 12:00
            +Zone America/Indiana/Winamac -5:46:25 - LMT	1883 Nov 18 12:13:35
            +			-6:00	US	C%sT	1946
            +			-6:00	Pulaski	C%sT	1961 Apr 30 2:00
            +			-5:00	-	EST	1969
            +			-5:00	US	E%sT	1971
            +			-5:00	-	EST	2006 Apr  2 2:00
            +			-6:00	US	C%sT	2007 Mar 11 2:00
            +			-5:00	US	E%sT
            +#
            +# Switzerland County, Indiana, did not observe DST from 1973 through 2005.
            +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            +Zone America/Indiana/Vevay -5:40:16 -	LMT	1883 Nov 18 12:19:44
             			-6:00	US	C%sT	1954 Apr 25 2:00
             			-5:00	-	EST	1969
             			-5:00	US	E%sT	1973
            -			-5:00	-	EST
            +			-5:00	-	EST	2006
            +			-5:00	US	E%sT
             
             # Part of Kentucky left its clocks alone in 1974.
            -# This also includes a part of Indiana immediately adjacent to Louisville.
            +# This also includes Clark, Floyd, and Harrison counties in Indiana.
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
             Rule Louisville	1921	only	-	May	1	2:00	1:00	D
             Rule Louisville	1921	only	-	Sep	1	2:00	0	S
            @@ -535,7 +861,7 @@
             Rule Louisville	1950	1955	-	Sep	lastSun	2:00	0	S
             Rule Louisville	1956	1960	-	Oct	lastSun	2:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/Louisville	-5:43:02 -	LMT	1883 Nov 18 12:00
            +Zone America/Kentucky/Louisville -5:43:02 -	LMT	1883 Nov 18 12:16:58
             			-6:00	US	C%sT	1921
             			-6:00 Louisville C%sT	1942
             			-6:00	US	C%sT	1946
            @@ -544,9 +870,8 @@
             			-5:00	US	E%sT	1974 Jan  6 2:00
             			-6:00	1:00	CDT	1974 Oct 27 2:00
             			-5:00	US	E%sT
            -Link America/Louisville America/Kentucky/Louisville
             #
            -# Wayne, Clinton, and Russell Counties, Kentucky
            +# Wayne County, Kentucky
             #
             # From
             # 
            @@ -572,7 +897,7 @@
             # Federal Register 65, 160 (2000-08-17), page 50154-50158.
             # 
             #
            -Zone America/Kentucky/Monticello -5:39:24 - LMT	1883 Nov 18 12:00
            +Zone America/Kentucky/Monticello -5:39:24 - LMT	1883 Nov 18 12:20:36
             			-6:00	US	C%sT	1946
             			-6:00	-	CST	1968
             			-6:00	US	C%sT	2000 Oct 29  2:00
            @@ -643,7 +968,8 @@
             			-5:00	-	EST	1975 Apr 27 2:00
             			-5:00	US	E%sT
             #
            -# The Michigan border with Wisconsin switched from EST to CST/CDT in 1973.
            +# Dickinson, Gogebic, Iron, and Menominee Counties, Michigan,
            +# switched from EST to CST/CDT in 1973.
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
             Rule Menominee	1946	only	-	Apr	lastSun	2:00	1:00	D
             Rule Menominee	1946	only	-	Sep	lastSun	2:00	0	S
            @@ -667,33 +993,22 @@
             # _Los Angeles Times_ (1998-11-10), A1, A10; it cites
             # Jimmy Skaggs, _The Great Guano Rush_ (1994).
             
            -# Old names, for S5 users
            -
            -# Link	LINK-FROM		LINK-TO
            -Link	America/New_York	EST5EDT
            -Link	America/Chicago		CST6CDT
            -Link	America/Denver		MST7MDT
            -Link	America/Los_Angeles	PST8PDT
            -Link	America/Indianapolis	EST
            -Link	America/Phoenix		MST
            -Link	Pacific/Honolulu	HST
            -
             ################################################################################
             
             
            -# From Paul Eggert  (1999-10-29):
            -# A good source for time zone historical data outside the US is
            -# Thomas G. Shanks, The International Atlas (5th edition),
            -# San Diego: ACS Publications, Inc. (1999).
            +# From Paul Eggert (2006-03-22):
            +# A good source for time zone historical data outside the U.S. is
            +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
            +# San Diego: ACS Publications, Inc. (2003).
             #
             # Gwillim Law writes that a good source
             # for recent time zone data is the International Air Transport
             # Association's Standard Schedules Information Manual (IATA SSIM),
             # published semiannually.  Law sent in several helpful summaries
             # of the IATA's data after 1990.
             #
            -# Except where otherwise noted, Shanks is the source for entries through 1990,
            -# and IATA SSIM is the source for entries after 1990.
            +# Except where otherwise noted, Shanks & Pottenger is the source for
            +# entries through 1990, and IATA SSIM is the source for entries afterwards.
             #
             # Other sources occasionally used include:
             #
            @@ -709,7 +1024,7 @@
             
             # Canada
             
            -# From Alain LaBont  (1994-11-14):
            +# From Alain LaBont (1994-11-14):
             # I post here the time zone abbreviations standardized in Canada
             # for both English and French in the CAN/CSA-Z234.4-89 standard....
             #
            @@ -738,36 +1053,87 @@
             #	T: de Terre-Neuve
             #	Y: du Yukon		Yukon
             #
            -# From Paul Eggert  (1994-11-22):
            +# From Paul Eggert (1994-11-22):
             # Alas, this sort of thing must be handled by localization software.
             
            -# Unless otherwise specified, the data for Canada are all from Shanks.
            +# Unless otherwise specified, the data for Canada are all from Shanks
            +# & Pottenger.
             
            -# From Paul Eggert (2000-10-02):
            +# From Chris Walton (2006-04-01, 2006-04-25, 2006-06-26, 2007-01-31,
            +# 2007-03-01):
            +# The British Columbia government announced yesterday that it will
            +# adjust daylight savings next year to align with changes in the
            +# U.S. and the rest of Canada....
            +# http://www2.news.gov.bc.ca/news_releases_2005-2009/2006AG0014-000330.htm
            +# ...
            +# Nova Scotia
            +# Daylight saving time will be extended by four weeks starting in 2007....
            +# http://www.gov.ns.ca/just/regulations/rg2/2006/ma1206.pdf
            +#
            +# [For New Brunswick] the new legislation dictates that the time change is to
            +# be done at 02:00 instead of 00:01.
            +# http://www.gnb.ca/0062/acts/BBA-2006/Chap-19.pdf
            +# ...
            +# Manitoba has traditionally changed the clock every fall at 03:00.
            +# As of 2006, the transition is to take place one hour earlier at 02:00.
            +# http://web2.gov.mb.ca/laws/statutes/ccsm/o030e.php
            +# ...
            +# [Alberta, Ontario, Quebec] will follow US rules.
            +# http://www.qp.gov.ab.ca/documents/spring/CH03_06.CFM
            +# http://www.e-laws.gov.on.ca/DBLaws/Source/Regs/English/2006/R06111_e.htm
            +# http://www2.publicationsduquebec.gouv.qc.ca/dynamicSearch/telecharge.php?type=5&file=2006C39A.PDF
            +# ...
            +# P.E.I. will follow US rules....
            +# http://www.assembly.pe.ca/bills/pdf_chapter/62/3/chapter-41.pdf
            +# ...
            +# Province of Newfoundland and Labrador....
            +# http://www.hoa.gov.nl.ca/hoa/bills/Bill0634.htm
            +# ...
            +# Yukon
            +# http://www.gov.yk.ca/legislation/regs/oic2006_127.pdf
            +# ...
            +# N.W.T. will follow US rules.  Whoever maintains the government web site
            +# does not seem to believe in bookmarks.  To see the news release, click the
            +# following link and search for "Daylight Savings Time Change".  Press the
            +# "Daylight Savings Time Change" link; it will fire off a popup using
            +# JavaScript.
            +# http://www.exec.gov.nt.ca/currentnews/currentPR.asp?mode=archive
            +# ...
            +# Nunavut
            +# An amendment to the Interpretation Act was registered on February 19/2007....
            +# http://action.attavik.ca/home/justice-gn/attach/2007/gaz02part2.pdf
            +
            +# From Paul Eggert (2006-04-25):
             # H. David Matthews and Mary Vincent's map
            -# 
            +# 
             # "It's about TIME", _Canadian Geographic_ (September-October 1998)
             #  contains detailed boundaries for regions observing nonstandard
             # time and daylight saving time arrangements in Canada circa 1998.
             #
            -# INMS, the Institute for National Measurement Standards in Ottawa, has
            -# 
            +# INMS, the Institute for National Measurement Standards in Ottawa, has 
             # information about standard and daylight saving time zones in Canada.
             #  (updated periodically).
             # Its unofficial information is often taken from Matthews and Vincent.
             
            +# From Paul Eggert (2006-06-27):
            +# For now, assume all of DST-observing Canada will fall into line with the
            +# new US DST rules,
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Canada	1918	only	-	Apr	14	2:00	1:00	D
             Rule	Canada	1918	only	-	Oct	31	2:00	0	S
             Rule	Canada	1942	only	-	Feb	 9	2:00	1:00	W # War
             Rule	Canada	1945	only	-	Aug	14	23:00u	1:00	P # Peace
             Rule	Canada	1945	only	-	Sep	30	2:00	0	S
             Rule	Canada	1974	1986	-	Apr	lastSun	2:00	1:00	D
            -Rule	Canada	1974	max	-	Oct	lastSun	2:00	0	S
            -Rule	Canada	1987	max	-	Apr	Sun>=1	2:00	1:00	D
            +Rule	Canada	1974	2006	-	Oct	lastSun	2:00	0	S
            +Rule	Canada	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
            +Rule	Canada	2007	max	-	Mar	Sun>=8	2:00	1:00	D
            +Rule	Canada	2007	max	-	Nov	Sun>=1	2:00	0	S
             
             
            -# Newfoundland (and far southeast Labrador)
            +# Newfoundland and Labrador
             
             # From Paul Eggert (2000-10-02):
             # Matthews and Vincent (1998) write that Labrador should use NST/NDT,
            @@ -778,20 +1144,21 @@
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	StJohns	1917	only	-	Apr	 8	2:00	1:00	D
             Rule	StJohns	1917	only	-	Sep	17	2:00	0	S
            -# Whitman gives 1919 Apr 5 and 1920 Apr 5; go with Shanks.
            +# Whitman gives 1919 Apr 5 and 1920 Apr 5; go with Shanks & Pottenger.
             Rule	StJohns	1919	only	-	May	 5	23:00	1:00	D
             Rule	StJohns	1919	only	-	Aug	12	23:00	0	S
            -# For 1931-1935 Whitman gives Apr same date; go with Shanks.
            +# For 1931-1935 Whitman gives Apr same date; go with Shanks & Pottenger.
             Rule	StJohns	1920	1935	-	May	Sun>=1	23:00	1:00	D
             Rule	StJohns	1920	1935	-	Oct	lastSun	23:00	0	S
            -# For 1936-1941 Whitman gives May Sun>=8 and Oct Sun>=1; go with Shanks.
            +# For 1936-1941 Whitman gives May Sun>=8 and Oct Sun>=1; go with Shanks &
            +# Pottenger.
             Rule	StJohns	1936	1941	-	May	Mon>=9	0:00	1:00	D
             Rule	StJohns	1936	1941	-	Oct	Mon>=2	0:00	0	S
             # Whitman gives the following transitions:
             # 1942 03-01/12-31, 1943 05-30/09-05, 1944 07-10/09-02, 1945 01-01/10-07
            -# but go with Shanks and assume they used Canadian rules.
            +# but go with Shanks & Pottenger and assume they used Canadian rules.
             # For 1946-9 Whitman gives May 5,4,9,1 - Oct 1,5,3,2, and for 1950 he gives
            -# Apr 30 - Sep 24; go with Shanks.
            +# Apr 30 - Sep 24; go with Shanks & Pottenger.
             Rule	StJohns	1946	1950	-	May	Sun>=8	2:00	1:00	D
             Rule	StJohns	1946	1950	-	Oct	Sun>=2	2:00	0	S
             Rule	StJohns	1951	1986	-	Apr	lastSun	2:00	1:00	D
            @@ -800,10 +1167,30 @@
             # From Paul Eggert (2000-10-02):
             # INMS (2000-09-12) says that, since 1988 at least, Newfoundland switches
             # at 00:01 local time.  For now, assume it started in 1987.
            +
            +# From Michael Pelley (2011-09-12):
            +# We received today, Monday, September 12, 2011, notification that the
            +# changes to the Newfoundland Standard Time Act have been proclaimed.
            +# The change in the Act stipulates that the change from Daylight Savings
            +# Time to Standard Time and from Standard Time to Daylight Savings Time
            +# now occurs at 2:00AM.
            +# ...
            +# 
            +# http://www.assembly.nl.ca/legislation/sr/annualstatutes/2011/1106.chp.htm
            +# 
            +# ...
            +# MICHAEL PELLEY  |  Manager of Enterprise Architecture - Solution Delivery
            +# Office of the Chief Information Officer
            +# Executive Council
            +# Government of Newfoundland & Labrador
            +
             Rule	StJohns	1987	only	-	Apr	Sun>=1	0:01	1:00	D
            -Rule	StJohns	1987	max	-	Oct	lastSun	0:01	0	S
            +Rule	StJohns	1987	2006	-	Oct	lastSun	0:01	0	S
             Rule	StJohns	1988	only	-	Apr	Sun>=1	0:01	2:00	DD
            -Rule	StJohns	1989	max	-	Apr	Sun>=1	0:01	1:00	D
            +Rule	StJohns	1989	2006	-	Apr	Sun>=1	0:01	1:00	D
            +Rule	StJohns	2007	2011	-	Mar	Sun>=8	0:01	1:00	D
            +Rule	StJohns	2007	2010	-	Nov	Sun>=1	0:01	0	S
            +#
             # St John's has an apostrophe, but Posix file names can't have apostrophes.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/St_Johns	-3:30:52 -	LMT	1884
            @@ -812,7 +1199,8 @@
             			-3:30:52 StJohns N%sT	1935 Mar 30
             			-3:30	StJohns	N%sT	1942 May 11
             			-3:30	Canada	N%sT	1946
            -			-3:30	StJohns	N%sT
            +			-3:30	StJohns	N%sT	2011 Nov
            +			-3:30	Canada	N%sT
             
             # most of east Labrador
             
            @@ -826,65 +1214,62 @@
             			-3:30	StJohns	N%sT	1942 May 11
             			-3:30	Canada	N%sT	1946
             			-3:30	StJohns	N%sT	1966 Mar 15 2:00
            -			-4:00	StJohns	A%sT
            +			-4:00	StJohns	A%sT	2011 Nov
            +			-4:00	Canada	A%sT
             
             
            -# west Labrador, New Brunswick, Nova Scotia, Prince Edward I
            +# west Labrador, Nova Scotia, Prince Edward I
             
            -# From Paul Eggert (1996-06-12):
            -# Shanks writes that since 1970 most of this region has been like Halifax.
            -# Many locales did not observe peacetime DST until 1972;
            +# From Paul Eggert (2006-03-22):
            +# Shanks & Pottenger write that since 1970 most of this region has been like
            +# Halifax.  Many locales did not observe peacetime DST until 1972;
             # Glace Bay, NS is the largest that we know of.
            -# Shanks also writes that Liverpool, NS was the only town in Canada to observe
            -# DST in 1971 but not 1970; for now we'll assume this is a typo.
            +# Shanks & Pottenger also write that Liverpool, NS was the only town
            +# in Canada to observe DST in 1971 but not 1970; for now we'll assume
            +# this is a typo.
             
            -# From Paul Eggert (2000-10-02):
            -# INMS (2000-09-12) says that, since 1988 at least, New Brunswick switches
            -# at 00:01 local time.  FIXME: verify and create a new Zone for this.
            -
            -
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -Rule Halifax	1916	only	-	Apr	 1	0:00	1:00	D
            -Rule Halifax	1916	only	-	Oct	 1	0:00	0	S
            -Rule Halifax	1920	only	-	May	 9	0:00	1:00	D
            -Rule Halifax	1920	only	-	Aug	29	0:00	0	S
            -Rule Halifax	1921	only	-	May	 6	0:00	1:00	D
            -Rule Halifax	1921	1922	-	Sep	 5	0:00	0	S
            -Rule Halifax	1922	only	-	Apr	30	0:00	1:00	D
            -Rule Halifax	1923	1925	-	May	Sun>=1	0:00	1:00	D
            -Rule Halifax	1923	only	-	Sep	 4	0:00	0	S
            -Rule Halifax	1924	only	-	Sep	15	0:00	0	S
            -Rule Halifax	1925	only	-	Sep	28	0:00	0	S
            -Rule Halifax	1926	only	-	May	16	0:00	1:00	D
            -Rule Halifax	1926	only	-	Sep	13	0:00	0	S
            -Rule Halifax	1927	only	-	May	 1	0:00	1:00	D
            -Rule Halifax	1927	only	-	Sep	26	0:00	0	S
            -Rule Halifax	1928	1931	-	May	Sun>=8	0:00	1:00	D
            -Rule Halifax	1928	only	-	Sep	 9	0:00	0	S
            -Rule Halifax	1929	only	-	Sep	 3	0:00	0	S
            -Rule Halifax	1930	only	-	Sep	15	0:00	0	S
            -Rule Halifax	1931	1932	-	Sep	Mon>=24	0:00	0	S
            -Rule Halifax	1932	only	-	May	 1	0:00	1:00	D
            -Rule Halifax	1933	only	-	Apr	30	0:00	1:00	D
            -Rule Halifax	1933	only	-	Oct	 2	0:00	0	S
            -Rule Halifax	1934	only	-	May	20	0:00	1:00	D
            -Rule Halifax	1934	only	-	Sep	16	0:00	0	S
            -Rule Halifax	1935	only	-	Jun	 2	0:00	1:00	D
            -Rule Halifax	1935	only	-	Sep	30	0:00	0	S
            -Rule Halifax	1936	only	-	Jun	 1	0:00	1:00	D
            -Rule Halifax	1936	only	-	Sep	14	0:00	0	S
            -Rule Halifax	1937	1938	-	May	Sun>=1	0:00	1:00	D
            -Rule Halifax	1937	1941	-	Sep	Mon>=24	0:00	0	S
            -Rule Halifax	1939	only	-	May	28	0:00	1:00	D
            -Rule Halifax	1940	1941	-	May	Sun>=1	0:00	1:00	D
            -Rule Halifax	1946	1949	-	Sep	lastSun	2:00	0	S
            -Rule Halifax	1946	1949	-	Apr	lastSun	2:00	1:00	D
            -Rule Halifax	1951	1954	-	Sep	lastSun	2:00	0	S
            -Rule Halifax	1951	1954	-	Apr	lastSun	2:00	1:00	D
            -Rule Halifax	1956	1959	-	Sep	lastSun	2:00	0	S
            -Rule Halifax	1956	1959	-	Apr	lastSun	2:00	1:00	D
            -Rule Halifax	1962	1973	-	Apr	lastSun	2:00	1:00	D
            -Rule Halifax	1962	1973	-	Oct	lastSun	2:00	0	S
            +Rule	Halifax	1916	only	-	Apr	 1	0:00	1:00	D
            +Rule	Halifax	1916	only	-	Oct	 1	0:00	0	S
            +Rule	Halifax	1920	only	-	May	 9	0:00	1:00	D
            +Rule	Halifax	1920	only	-	Aug	29	0:00	0	S
            +Rule	Halifax	1921	only	-	May	 6	0:00	1:00	D
            +Rule	Halifax	1921	1922	-	Sep	 5	0:00	0	S
            +Rule	Halifax	1922	only	-	Apr	30	0:00	1:00	D
            +Rule	Halifax	1923	1925	-	May	Sun>=1	0:00	1:00	D
            +Rule	Halifax	1923	only	-	Sep	 4	0:00	0	S
            +Rule	Halifax	1924	only	-	Sep	15	0:00	0	S
            +Rule	Halifax	1925	only	-	Sep	28	0:00	0	S
            +Rule	Halifax	1926	only	-	May	16	0:00	1:00	D
            +Rule	Halifax	1926	only	-	Sep	13	0:00	0	S
            +Rule	Halifax	1927	only	-	May	 1	0:00	1:00	D
            +Rule	Halifax	1927	only	-	Sep	26	0:00	0	S
            +Rule	Halifax	1928	1931	-	May	Sun>=8	0:00	1:00	D
            +Rule	Halifax	1928	only	-	Sep	 9	0:00	0	S
            +Rule	Halifax	1929	only	-	Sep	 3	0:00	0	S
            +Rule	Halifax	1930	only	-	Sep	15	0:00	0	S
            +Rule	Halifax	1931	1932	-	Sep	Mon>=24	0:00	0	S
            +Rule	Halifax	1932	only	-	May	 1	0:00	1:00	D
            +Rule	Halifax	1933	only	-	Apr	30	0:00	1:00	D
            +Rule	Halifax	1933	only	-	Oct	 2	0:00	0	S
            +Rule	Halifax	1934	only	-	May	20	0:00	1:00	D
            +Rule	Halifax	1934	only	-	Sep	16	0:00	0	S
            +Rule	Halifax	1935	only	-	Jun	 2	0:00	1:00	D
            +Rule	Halifax	1935	only	-	Sep	30	0:00	0	S
            +Rule	Halifax	1936	only	-	Jun	 1	0:00	1:00	D
            +Rule	Halifax	1936	only	-	Sep	14	0:00	0	S
            +Rule	Halifax	1937	1938	-	May	Sun>=1	0:00	1:00	D
            +Rule	Halifax	1937	1941	-	Sep	Mon>=24	0:00	0	S
            +Rule	Halifax	1939	only	-	May	28	0:00	1:00	D
            +Rule	Halifax	1940	1941	-	May	Sun>=1	0:00	1:00	D
            +Rule	Halifax	1946	1949	-	Apr	lastSun	2:00	1:00	D
            +Rule	Halifax	1946	1949	-	Sep	lastSun	2:00	0	S
            +Rule	Halifax	1951	1954	-	Apr	lastSun	2:00	1:00	D
            +Rule	Halifax	1951	1954	-	Sep	lastSun	2:00	0	S
            +Rule	Halifax	1956	1959	-	Apr	lastSun	2:00	1:00	D
            +Rule	Halifax	1956	1959	-	Sep	lastSun	2:00	0	S
            +Rule	Halifax	1962	1973	-	Apr	lastSun	2:00	1:00	D
            +Rule	Halifax	1962	1973	-	Oct	lastSun	2:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Halifax	-4:14:24 -	LMT	1902 Jun 15
             			-4:00	Halifax	A%sT	1918
            @@ -900,12 +1285,110 @@
             			-4:00	Halifax	A%sT	1974
             			-4:00	Canada	A%sT
             
            +# New Brunswick
             
            -# Ontario, Quebec
            +# From Paul Eggert (2007-01-31):
            +# The Time Definition Act 
            +# says they changed at 00:01 through 2006, and
            +#  makes it
            +# clear that this was the case since at least 1993.
            +# For now, assume it started in 1993.
             
            -# From Paul Eggert (1996-06-12):
            -# Shanks writes that since 1970 most of Ontario has been like Toronto,
            -# and most of Quebec has been like Montreal.
            +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            +Rule	Moncton	1933	1935	-	Jun	Sun>=8	1:00	1:00	D
            +Rule	Moncton	1933	1935	-	Sep	Sun>=8	1:00	0	S
            +Rule	Moncton	1936	1938	-	Jun	Sun>=1	1:00	1:00	D
            +Rule	Moncton	1936	1938	-	Sep	Sun>=1	1:00	0	S
            +Rule	Moncton	1939	only	-	May	27	1:00	1:00	D
            +Rule	Moncton	1939	1941	-	Sep	Sat>=21	1:00	0	S
            +Rule	Moncton	1940	only	-	May	19	1:00	1:00	D
            +Rule	Moncton	1941	only	-	May	 4	1:00	1:00	D
            +Rule	Moncton	1946	1972	-	Apr	lastSun	2:00	1:00	D
            +Rule	Moncton	1946	1956	-	Sep	lastSun	2:00	0	S
            +Rule	Moncton	1957	1972	-	Oct	lastSun	2:00	0	S
            +Rule	Moncton	1993	2006	-	Apr	Sun>=1	0:01	1:00	D
            +Rule	Moncton	1993	2006	-	Oct	lastSun	0:01	0	S
            +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            +Zone America/Moncton	-4:19:08 -	LMT	1883 Dec  9
            +			-5:00	-	EST	1902 Jun 15
            +			-4:00	Canada	A%sT	1933
            +			-4:00	Moncton	A%sT	1942
            +			-4:00	Canada	A%sT	1946
            +			-4:00	Moncton	A%sT	1973
            +			-4:00	Canada	A%sT	1993
            +			-4:00	Moncton	A%sT	2007
            +			-4:00	Canada	A%sT
            +
            +# Quebec
            +
            +# From Paul Eggert (2006-07-09):
            +# Shanks & Pottenger write that since 1970 most of Quebec has been
            +# like Montreal.
            +
            +# From Paul Eggert (2006-06-27):
            +# Matthews and Vincent (1998) also write that Quebec east of the -63
            +# meridian is supposed to observe AST, but residents as far east as
            +# Natashquan use EST/EDT, and residents east of Natashquan use AST.
            +# In "Official time in Quebec" the Quebec department of justice writes in
            +# http://www.justice.gouv.qc.ca/english/publications/generale/temps-regl-1-a.htm
            +# that "The residents of the Municipality of the
            +# Cote-Nord-du-Golfe-Saint-Laurent and the municipalities of Saint-Augustin,
            +# Bonne-Esperance and Blanc-Sablon apply the Official Time Act as it is
            +# written and use Atlantic standard time all year round. The same applies to
            +# the residents of the Native facilities along the lower North Shore."
            +# 
            +# says this common practice was codified into law as of 2007.
            +# For lack of better info, guess this practice began around 1970, contra to
            +# Shanks & Pottenger who have this region observing AST/ADT.
            +
            +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            +Rule	Mont	1917	only	-	Mar	25	2:00	1:00	D
            +Rule	Mont	1917	only	-	Apr	24	0:00	0	S
            +Rule	Mont	1919	only	-	Mar	31	2:30	1:00	D
            +Rule	Mont	1919	only	-	Oct	25	2:30	0	S
            +Rule	Mont	1920	only	-	May	 2	2:30	1:00	D
            +Rule	Mont	1920	1922	-	Oct	Sun>=1	2:30	0	S
            +Rule	Mont	1921	only	-	May	 1	2:00	1:00	D
            +Rule	Mont	1922	only	-	Apr	30	2:00	1:00	D
            +Rule	Mont	1924	only	-	May	17	2:00	1:00	D
            +Rule	Mont	1924	1926	-	Sep	lastSun	2:30	0	S
            +Rule	Mont	1925	1926	-	May	Sun>=1	2:00	1:00	D
            +# The 1927-to-1937 rules can be expressed more simply as
            +# Rule	Mont	1927	1937	-	Apr	lastSat	24:00	1:00	D
            +# Rule	Mont	1927	1937	-	Sep	lastSat	24:00	0	S
            +# The rules below avoid use of 24:00
            +# (which pre-1998 versions of zic cannot handle).
            +Rule	Mont	1927	only	-	May	1	0:00	1:00	D
            +Rule	Mont	1927	1932	-	Sep	lastSun	0:00	0	S
            +Rule	Mont	1928	1931	-	Apr	lastSun	0:00	1:00	D
            +Rule	Mont	1932	only	-	May	1	0:00	1:00	D
            +Rule	Mont	1933	1940	-	Apr	lastSun	0:00	1:00	D
            +Rule	Mont	1933	only	-	Oct	1	0:00	0	S
            +Rule	Mont	1934	1939	-	Sep	lastSun	0:00	0	S
            +Rule	Mont	1946	1973	-	Apr	lastSun	2:00	1:00	D
            +Rule	Mont	1945	1948	-	Sep	lastSun	2:00	0	S
            +Rule	Mont	1949	1950	-	Oct	lastSun	2:00	0	S
            +Rule	Mont	1951	1956	-	Sep	lastSun	2:00	0	S
            +Rule	Mont	1957	1973	-	Oct	lastSun	2:00	0	S
            +
            +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            +Zone America/Blanc-Sablon -3:48:28 -	LMT	1884
            +			-4:00	Canada	A%sT	1970
            +			-4:00	-	AST
            +Zone America/Montreal	-4:54:16 -	LMT	1884
            +			-5:00	Mont	E%sT	1918
            +			-5:00	Canada	E%sT	1919
            +			-5:00	Mont	E%sT	1942 Feb  9 2:00s
            +			-5:00	Canada	E%sT	1946
            +			-5:00	Mont	E%sT	1974
            +			-5:00	Canada	E%sT
            +
            +
            +# Ontario
            +
            +# From Paul Eggert (2006-07-09):
            +# Shanks & Pottenger write that since 1970 most of Ontario has been like
            +# Toronto.
             # Thunder Bay skipped DST in 1973.
             # Many smaller locales did not observe peacetime DST until 1974;
             # Nipigon (EST) and Rainy River (CST) are the largest that we know of.
            @@ -935,58 +1418,132 @@
             # says that Ontario east of 90W uses EST/EDT, and west of 90W uses CST/CDT.
             # Officially Atikokan is therefore on CST/CDT, and most likely this report
             # concerns a non-official time observed as a matter of local practice.
            -# For what it's worth, Shanks says that Atikokan has agreed with
            -# Rainy River ever since standard time was introduced.
            -
            +#
             # From Paul Eggert (2000-10-02):
             # Matthews and Vincent (1998) write that Atikokan, Pickle Lake, and
             # New Osnaburgh observe CST all year, that Big Trout Lake observes
             # CST/CDT, and that Upsala and Shebandowan observe EST/EDT, all in
             # violation of the official Ontario rules.
            -# They also write that Quebec east of the -63 meridian is supposed to
            -# observe AST, but residents as far east as Natashquan use EST/EDT,
            -# and residents east of Natashquan use AST.
            -# We probably need Zones for far east Quebec and for Atikokan,
            -# but we don't know when their practices started.
            +#
            +# From Paul Eggert (2006-07-09):
            +# Chris Walton (2006-07-06) mentioned an article by Stephanie MacLellan in the
            +# 2005-07-21 Chronicle-Journal, which said:
            +#
            +#	The clocks in Atikokan stay set on standard time year-round.
            +#	This means they spend about half the time on central time and
            +#	the other half on eastern time.
            +#
            +#	For the most part, the system works, Mayor Dennis Brown said.
            +#
            +#	"The majority of businesses in Atikokan deal more with Eastern
            +#	Canada, but there are some that deal with Western Canada," he
            +#	said.  "I don't see any changes happening here."
            +#
            +# Walton also writes "Supposedly Pickle Lake and Mishkeegogamang
            +# [New Osnaburgh] follow the same practice."
             
            -# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -Rule	Mont	1917	only	-	Mar	25	2:00	1:00	D
            -Rule	Mont	1917	only	-	Apr	24	0:00	0	S
            -Rule	Mont	1919	only	-	Mar	31	2:30	1:00	D
            -Rule	Mont	1919	only	-	Oct	25	2:30	0	S
            -Rule	Mont	1920	only	-	May	 2	2:30	1:00	D
            -Rule	Mont	1920	1922	-	Oct	Sun>=1	2:30	0	S
            -Rule	Mont	1921	only	-	May	 1	2:00	1:00	D
            -Rule	Mont	1922	only	-	Apr	30	2:00	1:00	D
            -Rule	Mont	1924	only	-	May	17	2:00	1:00	D
            -Rule	Mont	1924	1926	-	Sep	lastSun	2:30	0	S
            -Rule	Mont	1925	1926	-	May	Sun>=1	2:00	1:00	D
            -# The 1927-to-1937 rules can be expressed more simply as
            -# Rule	Mont	1927	1937	-	Apr	lastSat	24:00	1:00	D
            -# Rule	Mont	1927	1937	-	Sep	lastSat	24:00	0	S
            -# The rules below avoid use of 24:00
            -# (which pre-1998 versions of zic cannot handle).
            -Rule	Mont	1927	only	-	May	1	0:00	1:00	D
            -Rule	Mont	1927	1932	-	Sep	lastSun	0:00	0	S
            -Rule	Mont	1928	1931	-	Apr	lastSun	0:00	1:00	D
            -Rule	Mont	1932	only	-	May	1	0:00	1:00	D
            -Rule	Mont	1933	1940	-	Apr	lastSun	0:00	1:00	D
            -Rule	Mont	1933	only	-	Oct	1	0:00	0	S
            -Rule	Mont	1934	1939	-	Sep	lastSun	0:00	0	S
            -Rule	Mont	1946	1973	-	Apr	lastSun	2:00	1:00	D
            -Rule	Mont	1945	1948	-	Sep	lastSun	2:00	0	S
            -Rule	Mont	1949	1950	-	Oct	lastSun	2:00	0	S
            -Rule	Mont	1951	1956	-	Sep	lastSun	2:00	0	S
            -Rule	Mont	1957	1973	-	Oct	lastSun	2:00	0	S
            +# From Garry McKinnon (2006-07-14) via Chris Walton:
            +# I chatted with a member of my board who has an outstanding memory
            +# and a long history in Atikokan (and in the telecom industry) and he
            +# can say for certain that Atikokan has been practicing the current
            +# time keeping since 1952, at least.
             
            +# From Paul Eggert (2006-07-17):
            +# Shanks & Pottenger say that Atikokan has agreed with Rainy River
            +# ever since standard time was introduced, but the information from
            +# McKinnon sounds more authoritative.  For now, assume that Atikokan
            +# switched to EST immediately after WWII era daylight saving time
            +# ended.  This matches the old (less-populous) America/Coral_Harbour
            +# entry since our cutoff date of 1970, so we can move
            +# America/Coral_Harbour to the 'backward' file.
            +
            +# From Mark Brader (2010-03-06):
            +#
            +# Currently the database has:
            +#
            +# # Ontario
            +#
            +# # From Paul Eggert (2006-07-09):
            +# # Shanks & Pottenger write that since 1970 most of Ontario has been like
            +# # Toronto.
            +# # Thunder Bay skipped DST in 1973.
            +# # Many smaller locales did not observe peacetime DST until 1974;
            +# # Nipigon (EST) and Rainy River (CST) are the largest that we know of.
            +#
            +# In the (Toronto) Globe and Mail for Saturday, 1955-09-24, in the bottom
            +# right corner of page 1, it says that Toronto will return to standard
            +# time at 2 am Sunday morning (which agrees with the database), and that:
            +#
            +#     The one-hour setback will go into effect throughout most of Ontario,
            +#     except in areas like Windsor which remains on standard time all year.
            +#
            +# Windsor is, of course, a lot larger than Nipigon.
            +#
            +# I only came across this incidentally.  I don't know if Windsor began
            +# observing DST when Detroit did, or in 1974, or on some other date.
            +#
            +# By the way, the article continues by noting that:
            +#
            +#     Some cities in the United States have pushed the deadline back
            +#     three weeks and will change over from daylight saving in October.
            +
            +# From Arthur David Olson (2010-07-17):
            +#
            +# "Standard Time and Time Zones in Canada" appeared in
            +# The Journal of The Royal Astronomical Society of Canada,
            +# volume 26, number 2 (February 1932) and, as of 2010-07-17,
            +# was available at
            +# 
            +# http://adsabs.harvard.edu/full/1932JRASC..26...49S
            +# 
            +#
            +# It includes the text below (starting on page 57):
            +#
            +#   A list of the places in Canada using daylight saving time would
            +# require yearly revision. From information kindly furnished by
            +# the provincial governments and by the postmasters in many cities
            +# and towns, it is found that the following places used daylight sav-
            +# ing in 1930. The information for the province of Quebec is definite,
            +# for the other provinces only approximate:
            +#
            +# 	Province	Daylight saving time used
            +# Prince Edward Island	Not used.
            +# Nova Scotia		In Halifax only.
            +# New Brunswick		In St. John only.
            +# Quebec		In the following places:
            +# 			Montreal	Lachine
            +# 			Quebec		Mont-Royal
            +# 			Levis		Iberville
            +# 			St. Lambert	Cap de la Madeleine
            +# 			Verdun		Loretteville
            +# 			Westmount	Richmond
            +# 			Outremont	St. Jerome
            +# 			Longueuil	Greenfield Park
            +# 			Arvida		Waterloo
            +# 			Chambly-Canton	Beaulieu
            +# 			Melbourne	La Tuque
            +# 			St. Theophile	Buckingham
            +# Ontario		Used generally in the cities and towns along
            +# 			the southerly part of the province. Not
            +# 			used in the northwesterlhy part.
            +# Manitoba		Not used.
            +# Saskatchewan		In Regina only.
            +# Alberta		Not used.
            +# British Columbia	Not used.
            +#
            +#   With some exceptions, the use of daylight saving may be said to be limited
            +# to those cities and towns lying between Quebec city and Windsor, Ont.
            +
            +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Toronto	1919	only	-	Mar	30	23:30	1:00	D
             Rule	Toronto	1919	only	-	Oct	26	0:00	0	S
             Rule	Toronto	1920	only	-	May	 2	2:00	1:00	D
             Rule	Toronto	1920	only	-	Sep	26	0:00	0	S
             Rule	Toronto	1921	only	-	May	15	2:00	1:00	D
             Rule	Toronto	1921	only	-	Sep	15	2:00	0	S
             Rule	Toronto	1922	1923	-	May	Sun>=8	2:00	1:00	D
            -# Shanks says 1923-09-19; assume it's a typo and that "-16" was meant.
            +# Shanks & Pottenger say 1923-09-19; assume it's a typo and that "-16"
            +# was meant.
             Rule	Toronto	1922	1926	-	Sep	Sun>=15	2:00	0	S
             Rule	Toronto	1924	1927	-	May	Sun>=1	2:00	1:00	D
             # The 1927-to-1939 rules can be expressed more simply as
            @@ -1010,9 +1567,10 @@
             Rule	Toronto	1950	1973	-	Apr	lastSun	2:00	1:00	D
             Rule	Toronto	1950	only	-	Nov	lastSun	2:00	0	S
             Rule	Toronto	1951	1956	-	Sep	lastSun	2:00	0	S
            -# Shanks says Toronto ended DST a week early in 1971, namely on 1971-10-24,
            -# but Mark Brader wrote (2003-05-31) that he checked the 1971-10-30 issue
            -# of the Toronto Star, and it said that DST ended 1971-10-31 as usual.
            +# Shanks & Pottenger say Toronto ended DST a week early in 1971,
            +# namely on 1971-10-24, but Mark Brader wrote (2003-05-31) that this
            +# is wrong, and that he had confirmed it by checking the 1971-10-30
            +# Toronto Star, which said that DST was ending 1971-10-31 as usual.
             Rule	Toronto	1957	1973	-	Oct	lastSun	2:00	0	S
             
             # From Paul Eggert (2003-07-27):
            @@ -1034,13 +1592,6 @@
             # months for the remainder of the war years.
             
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/Montreal	-4:54:16 -	LMT	1884
            -			-5:00	Mont	E%sT	1918
            -			-5:00	Canada	E%sT	1919
            -			-5:00	Mont	E%sT	1942 Feb  9 2:00s
            -			-5:00	Canada	E%sT	1946
            -			-5:00	Mont	E%sT	1974
            -			-5:00	Canada	E%sT
             Zone America/Toronto	-5:17:32 -	LMT	1895
             			-5:00	Canada	E%sT	1919
             			-5:00	Toronto	E%sT	1942 Feb  9 2:00s
            @@ -1058,14 +1609,38 @@
             			-5:00	Canada	E%sT	1940 Sep 29
             			-5:00	1:00	EDT	1942 Feb  9 2:00s
             			-5:00	Canada	E%sT
            -Zone America/Rainy_River -6:17:56 -	LMT	1895
            +Zone America/Rainy_River -6:18:16 -	LMT	1895
             			-6:00	Canada	C%sT	1940 Sep 29
             			-6:00	1:00	CDT	1942 Feb  9 2:00s
             			-6:00	Canada	C%sT
            +Zone America/Atikokan	-6:06:28 -	LMT	1895
            +			-6:00	Canada	C%sT	1940 Sep 29
            +			-6:00	1:00	CDT	1942 Feb  9 2:00s
            +			-6:00	Canada	C%sT	1945 Sep 30 2:00
            +			-5:00	-	EST
             
             
             # Manitoba
             
            +# From Rob Douglas (2006-04-06):
            +# the old Manitoba Time Act - as amended by Bill 2, assented to
            +# March 27, 1987 ... said ...
            +# "between two o'clock Central Standard Time in the morning of
            +# the first Sunday of April of each year and two o'clock Central
            +# Standard Time in the morning of the last Sunday of October next
            +# following, one hour in advance of Central Standard Time."...
            +# I believe that the English legislation [of the old time act] had =
            +# been assented to (March 22, 1967)....
            +# Also, as far as I can tell, there was no order-in-council varying
            +# the time of Daylight Saving Time for 2005 and so the provisions of
            +# the 1987 version would apply - the changeover was at 2:00 Central
            +# Standard Time (i.e. not until 3:00 Central Daylight Time).
            +
            +# From Paul Eggert (2006-04-10):
            +# Shanks & Pottenger say Manitoba switched at 02:00 (not 02:00s)
            +# starting 1966.  Since 02:00s is clearly correct for 1967 on, assume
            +# it was also 02:00s in 1966.
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Winn	1916	only	-	Apr	23	0:00	1:00	D
             Rule	Winn	1916	only	-	Sep	17	0:00	0	S
            @@ -1088,16 +1663,13 @@
             Rule	Winn	1960	only	-	Sep	lastSun	2:00	0	S
             Rule	Winn	1963	only	-	Apr	lastSun	2:00	1:00	D
             Rule	Winn	1963	only	-	Sep	22	2:00	0	S
            -Rule	Winn	1966	1986	-	Apr	lastSun	2:00	1:00	D
            -Rule	Winn	1966	1986	-	Oct	lastSun	2:00	0	S
            -Rule	Winn	1987	max	-	Apr	Sun>=1	2:00	1:00	D
            -# From Paul Eggert (2000-10-02):
            -# INMS (2000-09-12) says that, since 1988 at least, Manitoba switches from
            -# DST at 03:00 local time.  For now, assume it started in 1987.
            -Rule	Winn	1987	max	-	Oct	lastSun	2:00s	0	S
            +Rule	Winn	1966	1986	-	Apr	lastSun	2:00s	1:00	D
            +Rule	Winn	1966	2005	-	Oct	lastSun	2:00s	0	S
            +Rule	Winn	1987	2005	-	Apr	Sun>=1	2:00s	1:00	D
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Winnipeg	-6:28:36 -	LMT	1887 Jul 16
            -			-6:00	Winn	C%sT
            +			-6:00	Winn	C%sT	2006
            +			-6:00	Canada	C%sT
             
             
             # Saskatchewan
            @@ -1116,14 +1688,14 @@
             # Willett (1914-03) notes that DST "has been in operation ... in the
             # City of Moose Jaw, Saskatchewan, for one year."
             
            -# From Paul Eggert (2000-10-02):
            -# Shanks writes that since 1970 most of this region has been like Regina.
            +# From Paul Eggert (2006-03-22):
            +# Shanks & Pottenger say that since 1970 this region has mostly been as Regina.
             # Some western towns (e.g. Swift Current) switched from MST/MDT to CST in 1972.
             # Other western towns (e.g. Lloydminster) are like Edmonton.
             # Matthews and Vincent (1998) write that Denare Beach and Creighton
             # are like Winnipeg, in violation of Saskatchewan law.
             
            -# From W. Jones  (1992-11-06):
            +# From W. Jones (1992-11-06):
             # The. . .below is based on information I got from our law library, the
             # provincial archives, and the provincial Community Services department.
             # A precise history would require digging through newspaper archives, and
            @@ -1149,6 +1721,11 @@
             # rules any more; all other districts appear to have used CST year round
             # since sometime in the 1960s.
             
            +# From Chris Walton (2006-06-26):
            +# The Saskatchewan time act which was last updated in 1996 is about 30 pages
            +# long and rather painful to read.
            +# http://www.qp.gov.sk.ca/documents/English/Statutes/Statutes/T14.pdf
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Regina	1918	only	-	Apr	14	2:00	1:00	D
             Rule	Regina	1918	only	-	Oct	31	2:00	0	S
            @@ -1203,17 +1780,18 @@
             Rule	Edm	1969	only	-	Apr	lastSun	2:00	1:00	D
             Rule	Edm	1969	only	-	Oct	lastSun	2:00	0	S
             Rule	Edm	1972	1986	-	Apr	lastSun	2:00	1:00	D
            -Rule	Edm	1972	max	-	Oct	lastSun	2:00	0	S
            -Rule	Edm	1987	max	-	Apr	Sun>=1	2:00	1:00	D
            +Rule	Edm	1972	2006	-	Oct	lastSun	2:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Edmonton	-7:33:52 -	LMT	1906 Sep
            -			-7:00	Edm	M%sT
            +			-7:00	Edm	M%sT	1987
            +			-7:00	Canada	M%sT
             
             
             # British Columbia
             
            -# From Paul Eggert (2000-10-02):
            -# Shanks writes that since 1970 most of this region has been like Vancouver.
            +# From Paul Eggert (2006-03-22):
            +# Shanks & Pottenger write that since 1970 most of this region has
            +# been like Vancouver.
             # Dawson Creek uses MST.  Much of east BC is like Edmonton.
             # Matthews and Vincent (1998) write that Creston is like Dawson Creek.
             
            @@ -1226,11 +1804,11 @@
             Rule	Vanc	1946	1986	-	Apr	lastSun	2:00	1:00	D
             Rule	Vanc	1946	only	-	Oct	13	2:00	0	S
             Rule	Vanc	1947	1961	-	Sep	lastSun	2:00	0	S
            -Rule	Vanc	1962	max	-	Oct	lastSun	2:00	0	S
            -Rule	Vanc	1987	max	-	Apr	Sun>=1	2:00	1:00	D
            +Rule	Vanc	1962	2006	-	Oct	lastSun	2:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Vancouver	-8:12:28 -	LMT	1884
            -			-8:00	Vanc	P%sT
            +			-8:00	Vanc	P%sT	1987
            +			-8:00	Canada	P%sT
             Zone America/Dawson_Creek -8:00:56 -	LMT	1884
             			-8:00	Canada	P%sT	1947
             			-8:00	Vanc	P%sT	1972 Aug 30 2:00
            @@ -1239,16 +1817,21 @@
             
             # Northwest Territories, Nunavut, Yukon
             
            -# From Paul Eggert (1999-10-29):
            +# From Paul Eggert (2006-03-22):
             # Dawson switched to PST in 1973.  Inuvik switched to MST in 1979.
            -# Mathew Englander  (1996-10-07) gives the following refs:
            +# Mathew Englander (1996-10-07) gives the following refs:
             #	* 1967. Paragraph 28(34)(g) of the Interpretation Act, S.C. 1967-68,
             #	c. 7 defines Yukon standard time as UTC-9.  This is still valid;
             #	see Interpretation Act, R.S.C. 1985, c. I-21, s. 35(1).
             #	* C.O. 1973/214 switched Yukon to PST on 1973-10-28 00:00.
             #	* O.I.C. 1980/02 established DST.
             #	* O.I.C. 1987/056 changed DST to Apr firstSun 2:00 to Oct lastSun 2:00.
            -# Shanks says Yukon's 1973-10-28 switch was at 2:00; go with Englander.
            +# Shanks & Pottenger say Yukon's 1973-10-28 switch was at 2:00; go
            +# with Englander.
            +# From Chris Walton (2006-06-26):
            +# Here is a link to the old daylight saving portion of the interpretation
            +# act which was last updated in 1987:
            +# http://www.gov.yk.ca/legislation/regs/oic1987_056.pdf
             
             # From Rives McDow (1999-09-04):
             # Nunavut ... moved ... to incorporate the whole territory into one time zone.
            @@ -1266,8 +1849,6 @@
             #  (1999) reports that Pangnirtung operates on eastern time,
             # and that Coral Harbour does not observe DST.  We don't know when
             # Pangnirtung switched to eastern time; we'll guess 1995.
            -# We'll ignore the claim about Coral Harbour for now,
            -# since we have no further info.
             
             # From Rives McDow (1999-11-08):
             # On October 31, when the rest of Nunavut went to Central time,
            @@ -1342,6 +1923,94 @@
             # more.
             # [Also see  (2001-03-09).]
             
            +# From Gwillim Law (2005-05-21):
            +# According to maps at
            +# http://inms-ienm.nrc-cnrc.gc.ca/images/time_services/TZ01SWE.jpg
            +# http://inms-ienm.nrc-cnrc.gc.ca/images/time_services/TZ01SSE.jpg
            +# (both dated 2003), and
            +# http://www.canadiangeographic.ca/Magazine/SO98/geomap.asp
            +# (from a 1998 Canadian Geographic article), the de facto and de jure time
            +# for Southampton Island (at the north end of Hudson Bay) is UTC-5 all year
            +# round.  Using Google, it's easy to find other websites that confirm this.
            +# I wasn't able to find how far back this time regimen goes, but since it
            +# predates the creation of Nunavut, it probably goes back many years....
            +# The Inuktitut name of Coral Harbour is Sallit, but it's rarely used.
            +#
            +# From Paul Eggert (2005-07-26):
            +# For lack of better information, assume that Southampton Island observed
            +# daylight saving only during wartime.
            +
            +# From Chris Walton (2007-03-01):
            +# ... the community of Resolute (located on Cornwallis Island in
            +# Nunavut) moved from Central Time to Eastern Time last November.
            +# Basically the community did not change its clocks at the end of
            +# daylight saving....
            +# http://www.nnsl.com/frames/newspapers/2006-11/nov13_06none.html
            +
            +# From Chris Walton (2011-03-21):
            +# Back in 2007 I initiated the creation of a new "zone file" for Resolute
            +# Bay. Resolute Bay is a small community located about 900km north of
            +# the Arctic Circle. The zone file was required because Resolute Bay had
            +# decided to use UTC-5 instead of UTC-6 for the winter of 2006-2007.
            +#
            +# According to new information which I received last week, Resolute Bay
            +# went back to using UTC-6 in the winter of 2007-2008...
            +#
            +# On March 11/2007 most of Canada went onto daylight saving. On March
            +# 14/2007 I phoned the Resolute Bay hamlet office to do a "time check." I
            +# talked to somebody that was both knowledgeable and helpful. I was able
            +# to confirm that Resolute Bay was still operating on UTC-5. It was
            +# explained to me that Resolute Bay had been on the Eastern Time zone
            +# (EST) in the winter, and was now back on the Central Time zone (CDT).
            +# i.e. the time zone had changed twice in the last year but the clocks
            +# had not moved. The residents had to know which time zone they were in
            +# so they could follow the correct TV schedule...
            +#
            +# On Nov 02/2008 most of Canada went onto standard time. On Nov 03/2008 I
            +# phoned the Resolute Bay hamlet office...[D]ue to the challenging nature
            +# of the phone call, I decided to seek out an alternate source of
            +# information. I found an e-mail address for somebody by the name of
            +# Stephanie Adams whose job was listed as "Inns North Support Officer for
            +# Arctic Co-operatives." I was under the impression that Stephanie lived
            +# and worked in Resolute Bay...
            +#
            +# On March 14/2011 I phoned the hamlet office again. I was told that
            +# Resolute Bay had been using Central Standard Time over the winter of
            +# 2010-2011 and that the clocks had therefore been moved one hour ahead
            +# on March 13/2011. The person I talked to was aware that Resolute Bay
            +# had previously experimented with Eastern Standard Time but he could not
            +# tell me when the practice had stopped.
            +#
            +# On March 17/2011 I searched the Web to find an e-mail address of
            +# somebody that might be able to tell me exactly when Resolute Bay went
            +# off Eastern Standard Time. I stumbled on the name "Aziz Kheraj." Aziz
            +# used to be the mayor of Resolute Bay and he apparently owns half the
            +# businesses including "South Camp Inn." This website has some info on
            +# Aziz:
            +# 
            +# http://www.uphere.ca/node/493
            +# 
            +#
            +# I sent Aziz an e-mail asking when Resolute Bay had stopped using
            +# Eastern Standard Time.
            +#
            +# Aziz responded quickly with this: "hi, The time was not changed for the
            +# 1 year only, the following year, the community went back to the old way
            +# of "spring ahead-fall behind" currently we are zulu plus 5 hrs and in
            +# the winter Zulu plus 6 hrs"
            +#
            +# This of course conflicted with everything I had ascertained in November 2008.
            +#
            +# I sent Aziz a copy of my 2008 e-mail exchange with Stephanie. Aziz
            +# responded with this: "Hi, Stephanie lives in Winnipeg. I live here, You
            +# may want to check with the weather office in Resolute Bay or do a
            +# search on the weather through Env. Canada. web site"
            +#
            +# If I had realized the Stephanie did not live in Resolute Bay I would
            +# never have contacted her.  I now believe that all the information I
            +# obtained in November 2008 should be ignored...
            +# I apologize for reporting incorrect information in 2008.
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	NT_YK	1918	only	-	Apr	14	2:00	1:00	D
             Rule	NT_YK	1918	only	-	Oct	27	2:00	0	S
            @@ -1353,39 +2022,54 @@
             Rule	NT_YK	1965	only	-	Apr	lastSun	0:00	2:00	DD
             Rule	NT_YK	1965	only	-	Oct	lastSun	2:00	0	S
             Rule	NT_YK	1980	1986	-	Apr	lastSun	2:00	1:00	D
            -Rule	NT_YK	1980	max	-	Oct	lastSun	2:00	0	S
            -Rule	NT_YK	1987	max	-	Apr	Sun>=1	2:00	1:00	D
            +Rule	NT_YK	1980	2006	-	Oct	lastSun	2:00	0	S
            +Rule	NT_YK	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/Pangnirtung -4:22:56 -	LMT	1884
            +# aka Panniqtuuq
            +Zone America/Pangnirtung 0	-	zzz	1921 # trading post est.
             			-4:00	NT_YK	A%sT	1995 Apr Sun>=1 2:00
             			-5:00	Canada	E%sT	1999 Oct 31 2:00
             			-6:00	Canada	C%sT	2000 Oct 29 2:00
             			-5:00	Canada	E%sT
            -Zone America/Iqaluit	-4:33:52 -	LMT	1884 # Frobisher Bay before 1987
            +# formerly Frobisher Bay
            +Zone America/Iqaluit	0	-	zzz	1942 Aug # Frobisher Bay est.
             			-5:00	NT_YK	E%sT	1999 Oct 31 2:00
             			-6:00	Canada	C%sT	2000 Oct 29 2:00
             			-5:00	Canada	E%sT
            -Zone America/Rankin_Inlet -6:08:40 -	LMT	1884
            +# aka Qausuittuq
            +Zone America/Resolute	0	-	zzz	1947 Aug 31 # Resolute founded
             			-6:00	NT_YK	C%sT	2000 Oct 29 2:00
             			-5:00	-	EST	2001 Apr  1 3:00
            +			-6:00	Canada	C%sT	2006 Oct 29 2:00
            +			-5:00	-	EST	2007 Mar 11 3:00
             			-6:00	Canada	C%sT
            -Zone America/Cambridge_Bay -7:00:20 -	LMT	1884
            +# aka Kangiqiniq
            +Zone America/Rankin_Inlet 0	-	zzz	1957 # Rankin Inlet founded
            +			-6:00	NT_YK	C%sT	2000 Oct 29 2:00
            +			-5:00	-	EST	2001 Apr  1 3:00
            +			-6:00	Canada	C%sT
            +# aka Iqaluktuuttiaq
            +Zone America/Cambridge_Bay 0	-	zzz	1920 # trading post est.?
             			-7:00	NT_YK	M%sT	1999 Oct 31 2:00
             			-6:00	Canada	C%sT	2000 Oct 29 2:00
             			-5:00	-	EST	2000 Nov  5 0:00
             			-6:00	-	CST	2001 Apr  1 3:00
             			-7:00	Canada	M%sT
            -Zone America/Yellowknife -7:37:24 -	LMT	1884
            -			-7:00	NT_YK	M%sT
            -Zone America/Inuvik	-8:54:00 -	LMT	1884
            +Zone America/Yellowknife 0	-	zzz	1935 # Yellowknife founded?
            +			-7:00	NT_YK	M%sT	1980
            +			-7:00	Canada	M%sT
            +Zone America/Inuvik	0	-	zzz	1953 # Inuvik founded
             			-8:00	NT_YK	P%sT	1979 Apr lastSun 2:00
            -			-7:00	NT_YK	M%sT
            +			-7:00	NT_YK	M%sT	1980
            +			-7:00	Canada	M%sT
             Zone America/Whitehorse	-9:00:12 -	LMT	1900 Aug 20
             			-9:00	NT_YK	Y%sT	1966 Jul 1 2:00
            -			-8:00	NT_YK	P%sT
            +			-8:00	NT_YK	P%sT	1980
            +			-8:00	Canada	P%sT
             Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
             			-9:00	NT_YK	Y%sT	1973 Oct 28 0:00
            -			-8:00	NT_YK	P%sT
            +			-8:00	NT_YK	P%sT	1980
            +			-8:00	Canada	P%sT
             
             
             ###############################################################################
            @@ -1399,28 +2083,20 @@
             # history of Mexican local time (in Spanish)
             # .
             #
            -# Here are the discrepancies between Shanks and the MLoC.
            +# Here are the discrepancies between Shanks & Pottenger (S&P) and the MLoC.
             # (In all cases we go with the MLoC.)
            -# Shanks reports that Baja was at -8:00 in 1922/1923.
            -# Shanks says the 1930 transition in Baja was 1930-11-16.
            -# Shanks reports no DST during summer 1931.
            -# Shanks reports a transition at 1032-03-30 23:00, not 1932-04-01.
            -# Shanks does not report transitions for Baja in 1945 or 1948.
            -# Shanks reports southern Mexico transitions on 1981-12-01, not 12-23.
            -# Shanks says Quintana Roo switched to -6:00 on 1982-12-02, and to -5:00
            -# on 1997-10-26 at 02:00.
            +# S&P report that Baja was at -8:00 in 1922/1923.
            +# S&P say the 1930 transition in Baja was 1930-11-16.
            +# S&P report no DST during summer 1931.
            +# S&P report a transition at 1932-03-30 23:00, not 1932-04-01.
             
             # From Gwillim Law (2001-02-20):
             # There are some other discrepancies between the Decrees page and the
             # tz database.  I think they can best be explained by supposing that
             # the researchers who prepared the Decrees page failed to find some of
             # the relevant documents.
             
            -# From Paul Eggert (2000-07-26):
            -# Shanks gives 1942-04-01 instead of 1942-04-24, and omits the 1981
            -# and 1988 DST experiments.  Go with spin.com.mx.
            -
            -# From Alan Perry  (1996-02-15):
            +# From Alan Perry (1996-02-15):
             # A guy from our Mexico subsidiary finally found the Presidential Decree
             # outlining the timezone changes in Mexico.
             #
            @@ -1536,6 +2212,58 @@
             # http://www.conae.gob.mx/ahorro/horaver2001_m1_2002.html (2002-02-20)
             # confirms this.  Sonora as usual is the only state where DST is not applied.
             
            +# From Steffen Thorsen (2009-12-28):
            +#
            +# Steffen Thorsen wrote:
            +# > Mexico's House of Representatives has approved a proposal for northern
            +# > Mexico's border cities to share the same daylight saving schedule as
            +# > the United States.
            +# Now this has passed both the Congress and the Senate, so starting from
            +# 2010, some border regions will be the same:
            +# 
            +# http://www.signonsandiego.com/news/2009/dec/28/clocks-will-match-both-sides-border/
            +# 
            +# 
            +# http://www.elmananarey.com/diario/noticia/nacional/noticias/empatan_horario_de_frontera_con_eu/621939
            +# 
            +# (Spanish)
            +#
            +# Could not find the new law text, but the proposed law text changes are here:
            +# 
            +# http://gaceta.diputados.gob.mx/Gaceta/61/2009/dic/20091210-V.pdf
            +# 
            +# (Gaceta Parlamentaria)
            +#
            +# There is also a list of the votes here:
            +# 
            +# http://gaceta.diputados.gob.mx/Gaceta/61/2009/dic/V2-101209.html
            +# 
            +#
            +# Our page:
            +# 
            +# http://www.timeanddate.com/news/time/north-mexico-dst-change.html
            +# 
            +
            +# From Arthur David Olson (2010-01-20):
            +# The page
            +# 
            +# http://dof.gob.mx/nota_detalle.php?codigo=5127480&fecha=06/01/2010
            +# 
            +# includes this text:
            +# En los municipios fronterizos de Tijuana y Mexicali en Baja California;
            +# Juárez y Ojinaga en Chihuahua; Acuña y Piedras Negras en Coahuila;
            +# Anáhuac en Nuevo León; y Nuevo Laredo, Reynosa y Matamoros en
            +# Tamaulipas, la aplicación de este horario estacional surtirá efecto
            +# desde las dos horas del segundo domingo de marzo y concluirá a las dos
            +# horas del primer domingo de noviembre.
            +# En los municipios fronterizos que se encuentren ubicados en la franja
            +# fronteriza norte en el territorio comprendido entre la línea
            +# internacional y la línea paralela ubicada a una distancia de veinte
            +# kilómetros, así como la Ciudad de Ensenada, Baja California, hacia el
            +# interior del país, la aplicación de este horario estacional surtirá
            +# efecto desde las dos horas del segundo domingo de marzo y concluirá a
            +# las dos horas del primer domingo de noviembre.
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Mexico	1939	only	-	Feb	5	0:00	1:00	D
             Rule	Mexico	1939	only	-	Jun	25	0:00	0	S
            @@ -1562,13 +2290,19 @@
             			-6:00	-	CST	1981 Dec 23
             			-5:00	-	EST	1982 Dec  2
             			-6:00	Mexico	C%sT
            -# Coahuila, Durango, Nuevo Leon, Tamaulipas
            +# Coahuila, Durango, Nuevo Leon, Tamaulipas (near US border)
            +Zone America/Matamoros	-6:40:00 -	LMT	1921 Dec 31 23:20:00
            +			-6:00	-	CST	1988
            +			-6:00	US	C%sT	1989
            +			-6:00	Mexico	C%sT	2010
            +			-6:00	US	C%sT
            +# Coahuila, Durango, Nuevo Leon, Tamaulipas (away from US border)
             Zone America/Monterrey	-6:41:16 -	LMT	1921 Dec 31 23:18:44
             			-6:00	-	CST	1988
             			-6:00	US	C%sT	1989
             			-6:00	Mexico	C%sT
             # Central Mexico
            -Zone America/Mexico_City -6:36:36 -	LMT	1922 Jan  1  0:23:24
            +Zone America/Mexico_City -6:36:36 -	LMT	1922 Jan  1 0:23:24
             			-7:00	-	MST	1927 Jun 10 23:00
             			-6:00	-	CST	1930 Nov 15
             			-7:00	-	MST	1931 May  1 23:00
            @@ -1577,7 +2311,19 @@
             			-6:00	Mexico	C%sT	2001 Sep 30 02:00
             			-6:00	-	CST	2002 Feb 20
             			-6:00	Mexico	C%sT
            -# Chihuahua
            +# Chihuahua (near US border)
            +Zone America/Ojinaga	-6:57:40 -	LMT	1922 Jan 1 0:02:20
            +			-7:00	-	MST	1927 Jun 10 23:00
            +			-6:00	-	CST	1930 Nov 15
            +			-7:00	-	MST	1931 May  1 23:00
            +			-6:00	-	CST	1931 Oct
            +			-7:00	-	MST	1932 Apr  1
            +			-6:00	-	CST	1996
            +			-6:00	Mexico	C%sT	1998
            +			-6:00	-	CST	1998 Apr Sun>=1 3:00
            +			-7:00	Mexico	M%sT	2010
            +			-7:00	US	M%sT
            +# Chihuahua (away from US border)
             Zone America/Chihuahua	-7:04:20 -	LMT	1921 Dec 31 23:55:40
             			-7:00	-	MST	1927 Jun 10 23:00
             			-6:00	-	CST	1930 Nov 15
            @@ -1600,7 +2346,44 @@
             			-8:00	-	PST	1970
             			-7:00	Mexico	M%sT	1999
             			-7:00	-	MST
            +
            +# From Alexander Krivenyshev (2010-04-21):
            +# According to news, Bahía de Banderas (Mexican state of Nayarit)
            +# changed time zone UTC-7 to new time zone UTC-6 on April 4, 2010 (to
            +# share the same time zone as nearby city Puerto Vallarta, Jalisco).
            +#
            +# (Spanish)
            +# Bahía de Banderas homologa su horario al del centro del
            +# país, a partir de este domingo
            +# 
            +# http://www.nayarit.gob.mx/notes.asp?id=20748
            +# 
            +#
            +# Bahía de Banderas homologa su horario con el del Centro del
            +# País
            +# 
            +# http://www.bahiadebanderas.gob.mx/principal/index.php?option=com_content&view=article&id=261:bahia-de-banderas-homologa-su-horario-con-el-del-centro-del-pais&catid=42:comunicacion-social&Itemid=50"
            +# 
            +#
            +# (English)
            +# Puerto Vallarta and Bahía de Banderas: One Time Zone
            +# 
            +# http://virtualvallarta.com/puertovallarta/puertovallarta/localnews/2009-12-03-Puerto-Vallarta-and-Bahia-de-Banderas-One-Time-Zone.shtml
            +# 
            +#
            +# or
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_mexico08.html
            +# 
            +#
            +# "Mexico's Senate approved the amendments to the Mexican Schedule System that
            +# will allow Bahía de Banderas and Puerto Vallarta to share the same time
            +# zone ..."
             # Baja California Sur, Nayarit, Sinaloa
            +
            +# From Arthur David Olson (2010-05-01):
            +# Use "Bahia_Banderas" to keep the name to fourteen characters.
            +
             Zone America/Mazatlan	-7:05:40 -	LMT	1921 Dec 31 23:54:20
             			-7:00	-	MST	1927 Jun 10 23:00
             			-6:00	-	CST	1930 Nov 15
            @@ -1611,15 +2394,29 @@
             			-7:00	-	MST	1949 Jan 14
             			-8:00	-	PST	1970
             			-7:00	Mexico	M%sT
            -# Baja California
            +
            +Zone America/Bahia_Banderas	-7:01:00 -	LMT	1921 Dec 31 23:59:00
            +			-7:00	-	MST	1927 Jun 10 23:00
            +			-6:00	-	CST	1930 Nov 15
            +			-7:00	-	MST	1931 May  1 23:00
            +			-6:00	-	CST	1931 Oct
            +			-7:00	-	MST	1932 Apr  1
            +			-6:00	-	CST	1942 Apr 24
            +			-7:00	-	MST	1949 Jan 14
            +			-8:00	-	PST	1970
            +			-7:00	Mexico	M%sT	2010 Apr 4 2:00
            +			-6:00	Mexico	C%sT
            +
            +# Baja California (near US border)
             Zone America/Tijuana	-7:48:04 -	LMT	1922 Jan  1  0:11:56
             			-7:00	-	MST	1924
             			-8:00	-	PST	1927 Jun 10 23:00
             			-7:00	-	MST	1930 Nov 15
             			-8:00	-	PST	1931 Apr  1
             			-8:00	1:00	PDT	1931 Sep 30
             			-8:00	-	PST	1942 Apr 24
            -			-8:00	1:00	PWT	1945 Nov 12
            +			-8:00	1:00	PWT	1945 Aug 14 23:00u
            +			-8:00	1:00	PPT	1945 Nov 12 # Peace
             			-8:00	-	PST	1948 Apr  5
             			-8:00	1:00	PDT	1949 Jan 14
             			-8:00	-	PST	1954
            @@ -1628,13 +2425,34 @@
             			-8:00	US	P%sT	1996
             			-8:00	Mexico	P%sT	2001
             			-8:00	US	P%sT	2002 Feb 20
            +			-8:00	Mexico	P%sT	2010
            +			-8:00	US	P%sT
            +# Baja California (away from US border)
            +Zone America/Santa_Isabel	-7:39:28 -	LMT	1922 Jan  1  0:20:32
            +			-7:00	-	MST	1924
            +			-8:00	-	PST	1927 Jun 10 23:00
            +			-7:00	-	MST	1930 Nov 15
            +			-8:00	-	PST	1931 Apr  1
            +			-8:00	1:00	PDT	1931 Sep 30
            +			-8:00	-	PST	1942 Apr 24
            +			-8:00	1:00	PWT	1945 Aug 14 23:00u
            +			-8:00	1:00	PPT	1945 Nov 12 # Peace
            +			-8:00	-	PST	1948 Apr  5
            +			-8:00	1:00	PDT	1949 Jan 14
            +			-8:00	-	PST	1954
            +			-8:00	CA	P%sT	1961
            +			-8:00	-	PST	1976
            +			-8:00	US	P%sT	1996
            +			-8:00	Mexico	P%sT	2001
            +			-8:00	US	P%sT	2002 Feb 20
             			-8:00	Mexico	P%sT
            -# From Paul Eggert (2001-03-05):
            +# From Paul Eggert (2006-03-22):
             # Formerly there was an America/Ensenada zone, which differed from
             # America/Tijuana only in that it did not observe DST from 1976
            -# through 1995.  This was as per Shanks.  However, Guy Harris reports
            +# through 1995.  This was as per Shanks (1999).  But Shanks & Pottenger say
            +# Ensenada did not observe DST from 1948 through 1975.  Guy Harris reports
             # that the 1987 OAG says "Only Ensenada, Mexicale, San Felipe and
            -# Tijuana observe DST," which contradicts Shanks but does imply that
            +# Tijuana observe DST," which agrees with Shanks & Pottenger but implies that
             # DST-observance was a town-by-town matter back then.  This concerns
             # data after 1970 so most likely there should be at least one Zone
             # other than America/Tijuana for Baja, but it's not clear yet what its
            @@ -1657,13 +2475,19 @@
             			-4:00	-	AST
             
             # Bahamas
            +#
            +# From Sue Williams (2006-12-07):
            +# The Bahamas announced about a month ago that they plan to change their DST
            +# rules to sync with the U.S. starting in 2007....
            +# http://www.jonesbahamas.com/?c=45&a=10412
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -Rule	Bahamas	1964	max	-	Oct	lastSun	2:00	0	S
            -Rule	Bahamas	1964	1986	-	Apr	lastSun	2:00	1:00	D
            -Rule	Bahamas	1987	max	-	Apr	Sun>=1	2:00	1:00	D
            +Rule	Bahamas	1964	1975	-	Oct	lastSun	2:00	0	S
            +Rule	Bahamas	1964	1975	-	Apr	lastSun	2:00	1:00	D
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	America/Nassau	-5:09:24 -	LMT	1912 Mar 2
            -			-5:00	Bahamas	E%sT
            +			-5:00	Bahamas	E%sT	1976
            +			-5:00	US	E%sT
             
             # Barbados
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            @@ -1678,7 +2502,7 @@
             			-4:00	Barb	A%sT
             
             # Belize
            -# Whitman entirely disagrees with Shanks; go with Shanks.
            +# Whitman entirely disagrees with Shanks; go with Shanks & Pottenger.
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Belize	1918	1942	-	Oct	Sun>=2	0:00	0:30	HD
             Rule	Belize	1919	1943	-	Feb	Sun>=9	0:00	0	S
            @@ -1691,10 +2515,20 @@
             			-6:00	Belize	C%sT
             
             # Bermuda
            +
            +# From Dan Jones, reporting in The Royal Gazette (2006-06-26):
            +
            +# Next year, however, clocks in the US will go forward on the second Sunday
            +# in March, until the first Sunday in November.  And, after the Time Zone
            +# (Seasonal Variation) Bill 2006 was passed in the House of Assembly on
            +# Friday, the same thing will happen in Bermuda.
            +# http://www.theroyalgazette.com/apps/pbcs.dll/article?AID=/20060529/NEWS/105290135
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Atlantic/Bermuda	-4:19:04 -	LMT	1930 Jan  1 2:00    # Hamilton
             			-4:00	-	AST	1974 Apr 28 2:00
            -			-4:00	Bahamas	A%sT
            +			-4:00	Bahamas	A%sT	1976
            +			-4:00	US	A%sT
             
             # Cayman Is
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            @@ -1707,7 +2541,8 @@
             Rule	CR	1979	1980	-	Feb	lastSun	0:00	1:00	D
             Rule	CR	1979	1980	-	Jun	Sun>=1	0:00	0	S
             Rule	CR	1991	1992	-	Jan	Sat>=15	0:00	1:00	D
            -# IATA SSIM (1991-09) says the following was at 1:00; go with Shanks.
            +# IATA SSIM (1991-09) says the following was at 1:00;
            +# go with Shanks & Pottenger.
             Rule	CR	1991	only	-	Jul	 1	0:00	0	S
             Rule	CR	1992	only	-	Mar	15	0:00	0	S
             # There are too many San Joses elsewhere, so we'll use `Costa Rica'.
            @@ -1733,13 +2568,143 @@
             
             # From Evert van der Veer via Steffen Thorsen (2004-10-28):
             # Cuba is not going back to standard time this year.
            -# From Paul Eggert (2004-10-28):
            +# From Paul Eggert (2006-03-22):
             # http://www.granma.cu/ingles/2004/septiembre/juev30/41medid-i.html
             # says that it's due to a problem at the Antonio Guiteras
             # thermoelectric plant, and says "This October there will be no return
             # to normal hours (after daylight saving time)".
            -# For now, let's assume that it's a one-year temporary measure.
            +# For now, let's assume that it's a temporary measure.
             
            +# From Carlos A. Carnero Delgado (2005-11-12):
            +# This year (just like in 2004-2005) there's no change in time zone
            +# adjustment in Cuba.  We will stay in daylight saving time:
            +# http://www.granma.cu/espanol/2005/noviembre/mier9/horario.html
            +
            +# From Jesper Norgaard Welen (2006-10-21):
            +# An article in GRANMA INTERNACIONAL claims that Cuba will end
            +# the 3 years of permanent DST next weekend, see
            +# http://www.granma.cu/ingles/2006/octubre/lun16/43horario.html
            +# "On Saturday night, October 28 going into Sunday, October 29, at 01:00,
            +# watches should be set back one hour -- going back to 00:00 hours -- returning
            +# to the normal schedule....
            +
            +# From Paul Eggert (2007-03-02):
            +# http://www.granma.cubaweb.cu/english/news/art89.html, dated yesterday,
            +# says Cuban clocks will advance at midnight on March 10.
            +# For lack of better information, assume Cuba will use US rules,
            +# except that it switches at midnight standard time as usual.
            +#
            +# From Steffen Thorsen (2007-10-25):
            +# Carlos Alberto Fonseca Arauz informed me that Cuba will end DST one week 
            +# earlier - on the last Sunday of October, just like in 2006.
            +# 
            +# He supplied these references:
            +# 
            +# http://www.prensalatina.com.mx/article.asp?ID=%7B4CC32C1B-A9F7-42FB-8A07-8631AFC923AF%7D&language=ES
            +# http://actualidad.terra.es/sociedad/articulo/cuba_llama_ahorrar_energia_cambio_1957044.htm
            +# 
            +# From Alex Kryvenishev (2007-10-25):
            +# Here is also article from Granma (Cuba):
            +# 
            +# [Regira] el Horario Normal desde el [proximo] domingo 28 de octubre
            +# http://www.granma.cubaweb.cu/2007/10/24/nacional/artic07.html
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_cuba03.html
            +
            +# From Arthur David Olson (2008-03-09):
            +# I'm in Maryland which is now observing United States Eastern Daylight
            +# Time. At 9:44 local time I used RealPlayer to listen to
            +# 
            +# http://media.enet.cu/radioreloj
            +# , a Cuban information station, and heard
            +# the time announced as "ocho cuarenta y cuatro" ("eight forty-four"),
            +# indicating that Cuba is still on standard time.
            +
            +# From Steffen Thorsen (2008-03-12):
            +# It seems that Cuba will start DST on Sunday, 2007-03-16...
            +# It was announced yesterday, according to this source (in Spanish):
            +# 
            +# http://www.nnc.cubaweb.cu/marzo-2008/cien-1-11-3-08.htm
            +# 
            +#
            +# Some more background information is posted here:
            +# 
            +# http://www.timeanddate.com/news/time/cuba-starts-dst-march-16.html
            +# 
            +#
            +# The article also says that Cuba has been observing DST since 1963,
            +# while Shanks (and tzdata) has 1965 as the first date (except in the
            +# 1940's). Many other web pages in Cuba also claim that it has been
            +# observed since 1963, but with the exception of 1970 - an exception
            +# which is not present in tzdata/Shanks. So there is a chance we need to
            +# change some historic records as well.
            +#
            +# One example:
            +# 
            +# http://www.radiohc.cu/espanol/noticias/mar07/11mar/hor.htm
            +# 
            +
            +# From Jesper Norgaard Welen (2008-03-13):
            +# The Cuban time change has just been confirmed on the most authoritative
            +# web site, the Granma.  Please check out
            +# 
            +# http://www.granma.cubaweb.cu/2008/03/13/nacional/artic10.html
            +# 
            +#
            +# Basically as expected after Steffen Thorsens information, the change
            +# will take place midnight between Saturday and Sunday.
            +
            +# From Arthur David Olson (2008-03-12):
            +# Assume Sun>=15 (third Sunday) going forward.
            +
            +# From Alexander Krivenyshev (2009-03-04)
            +# According to the Radio Reloj - Cuba will start Daylight Saving Time on
            +# midnight between Saturday, March 07, 2009 and Sunday, March 08, 2009-
            +# not on midnight March 14 / March 15 as previously thought.
            +#
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_cuba05.html
            +# (in Spanish)
            +# 
            +
            +# From Arthur David Olson (2009-03-09)
            +# I listened over the Internet to
            +# 
            +# http://media.enet.cu/readioreloj
            +# 
            +# this morning; when it was 10:05 a. m. here in Bethesda, Maryland the
            +# the time was announced as "diez cinco"--the same time as here, indicating
            +# that has indeed switched to DST. Assume second Sunday from 2009 forward.
            +
            +# From Steffen Thorsen (2011-03-08):
            +# Granma announced that Cuba is going to start DST on 2011-03-20 00:00:00
            +# this year. Nothing about the end date known so far (if that has
            +# changed at all).
            +#
            +# Source:
            +# 
            +# http://granma.co.cu/2011/03/08/nacional/artic01.html
            +# 
            +#
            +# Our info:
            +# 
            +# http://www.timeanddate.com/news/time/cuba-starts-dst-2011.html
            +# 
            +#
            +# From Steffen Thorsen (2011-10-30)
            +# Cuba will end DST two weeks later this year. Instead of going back 
            +# tonight, it has been delayed to 2011-11-13 at 01:00.
            +#
            +# One source (Spanish)
            +# 
            +# http://www.radioangulo.cu/noticias/cuba/17105-cuba-restablecera-el-horario-del-meridiano-de-greenwich.html
            +# 
            +#
            +# Our page:
            +# 
            +# http://www.timeanddate.com/news/time/cuba-time-changes-2011.html
            +# 
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Cuba	1928	only	-	Jun	10	0:00	1:00	D
             Rule	Cuba	1928	only	-	Oct	10	0:00	0	S
            @@ -1769,8 +2734,15 @@
             Rule	Cuba	1997	only	-	Oct	12	0:00s	0	S
             Rule	Cuba	1998	1999	-	Mar	lastSun	0:00s	1:00	D
             Rule	Cuba	1998	2003	-	Oct	lastSun	0:00s	0	S
            -Rule	Cuba	2000	max	-	Apr	Sun>=1	0:00s	1:00	D
            -Rule	Cuba	2005	max	-	Oct	lastSun	0:00s	0	S
            +Rule	Cuba	2000	2004	-	Apr	Sun>=1	0:00s	1:00	D
            +Rule	Cuba	2006	2010	-	Oct	lastSun	0:00s	0	S
            +Rule	Cuba	2007	only	-	Mar	Sun>=8	0:00s	1:00	D
            +Rule	Cuba	2008	only	-	Mar	Sun>=15	0:00s	1:00	D
            +Rule	Cuba	2009	2010	-	Mar	Sun>=8	0:00s	1:00	D
            +Rule	Cuba	2011	only	-	Mar	Sun>=15	0:00s	1:00	D
            +Rule	Cuba	2011	only	-	Nov	13	0:00s	0	S
            +Rule	Cuba	2012	max	-	Mar	Sun>=8	0:00s	1:00	D
            +Rule	Cuba	2012	max	-	Oct	lastSun	0:00s	0	S
             
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	America/Havana	-5:29:28 -	LMT	1890
            @@ -1818,6 +2790,7 @@
             			-4:00	-	AST
             
             # El Salvador
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Salv	1987	1988	-	May	Sun>=1	0:00	1:00	D
             Rule	Salv	1987	1988	-	Sep	lastSun	0:00	0	S
            @@ -1836,37 +2809,126 @@
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Guadeloupe	-4:06:08 -	LMT	1911 Jun 8	# Pointe a Pitre
             			-4:00	-	AST
            +# St Barthelemy
            +Link America/Guadeloupe	America/St_Barthelemy
            +# St Martin (French part)
            +Link America/Guadeloupe	America/Marigot
             
             # Guatemala
            +#
            +# From Gwillim Law (2006-04-22), after a heads-up from Oscar van Vlijmen:
            +# Diario Co Latino, at
            +# http://www.diariocolatino.com/internacionales/detalles.asp?NewsID=8079,
            +# says in an article dated 2006-04-19 that the Guatemalan government had
            +# decided on that date to advance official time by 60 minutes, to lessen the
            +# impact of the elevated cost of oil....  Daylight saving time will last from
            +# 2006-04-29 24:00 (Guatemalan standard time) to 2006-09-30 (time unspecified).
            +# From Paul Eggert (2006-06-22):
            +# The Ministry of Energy and Mines, press release CP-15/2006
            +# (2006-04-19), says DST ends at 24:00.  See
            +# .
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Guat	1973	only	-	Nov	25	0:00	1:00	D
             Rule	Guat	1974	only	-	Feb	24	0:00	0	S
             Rule	Guat	1983	only	-	May	21	0:00	1:00	D
             Rule	Guat	1983	only	-	Sep	22	0:00	0	S
             Rule	Guat	1991	only	-	Mar	23	0:00	1:00	D
             Rule	Guat	1991	only	-	Sep	 7	0:00	0	S
            +Rule	Guat	2006	only	-	Apr	30	0:00	1:00	D
            +Rule	Guat	2006	only	-	Oct	 1	0:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Guatemala	-6:02:04 -	LMT	1918 Oct 5
             			-6:00	Guat	C%sT
             
             # Haiti
            +# From Gwillim Law (2005-04-15):
            +# Risto O. Nykanen wrote me that Haiti is now on DST.
            +# I searched for confirmation, and I found a
            +#  press release
            +# on the Web page of the Haitian Consulate in Chicago (2005-03-31),
            +# .  Translated from French, it says:
            +#
            +#  "The Prime Minister's Communication Office notifies the public in general
            +#   and the press in particular that, following a decision of the Interior
            +#   Ministry and the Territorial Collectivities [I suppose that means the
            +#   provinces], Haiti will move to Eastern Daylight Time in the night from next
            +#   Saturday the 2nd to Sunday the 3rd.
            +#
            +#  "Consequently, the Prime Minister's Communication Office wishes to inform
            +#   the population that the country's clocks will be set forward one hour
            +#   starting at midnight.  This provision will hold until the last Saturday in
            +#   October 2005.
            +#
            +#  "Port-au-Prince, March 31, 2005"
            +#
            +# From Steffen Thorsen (2006-04-04):
            +# I have been informed by users that Haiti observes DST this year like
            +# last year, so the current "only" rule for 2005 might be changed to a
            +# "max" rule or to last until 2006. (Who knows if they will observe DST
            +# next year or if they will extend their DST like US/Canada next year).
            +#
            +# I have found this article about it (in French):
            +# http://www.haitipressnetwork.com/news.cfm?articleID=7612
            +#
            +# The reason seems to be an energy crisis.
            +
            +# From Stephen Colebourne (2007-02-22):
            +# Some IATA info: Haiti won't be having DST in 2007.
            +
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Haiti	1983	only	-	May	8	0:00	1:00	D
             Rule	Haiti	1984	1987	-	Apr	lastSun	0:00	1:00	D
             Rule	Haiti	1983	1987	-	Oct	lastSun	0:00	0	S
            -# Shanks says AT is 2:00, but IATA SSIM (1991/1997) says 1:00s.  Go with IATA.
            +# Shanks & Pottenger say AT is 2:00, but IATA SSIM (1991/1997) says 1:00s.
            +# Go with IATA.
             Rule	Haiti	1988	1997	-	Apr	Sun>=1	1:00s	1:00	D
             Rule	Haiti	1988	1997	-	Oct	lastSun	1:00s	0	S
            +Rule	Haiti	2005	2006	-	Apr	Sun>=1	0:00	1:00	D
            +Rule	Haiti	2005	2006	-	Oct	lastSun	0:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Port-au-Prince -4:49:20 -	LMT	1890
             			-4:49	-	PPMT	1917 Jan 24 12:00 # P-a-P MT
             			-5:00	Haiti	E%sT
             
             # Honduras
            -# Shanks says 1921 Jan 1; go with Whitman's more precise Apr 1.
            +# Shanks & Pottenger say 1921 Jan 1; go with Whitman's more precise Apr 1.
            +
            +# From Paul Eggert (2006-05-05):
            +# worldtimezone.com reports a 2006-05-02 Spanish-language AP article
            +# saying Honduras will start using DST midnight Saturday, effective 4
            +# months until September.  La Tribuna reported today
            +#  that Manuel Zelaya, the president
            +# of Honduras, refused to back down on this.
            +
            +# From Jesper Norgaard Welen (2006-08-08):
            +# It seems that Honduras has returned from DST to standard time this Monday at
            +# 00:00 hours (prolonging Sunday to 25 hours duration).
            +# http://www.worldtimezone.com/dst_news/dst_news_honduras04.html
            +
            +# From Paul Eggert (2006-08-08):
            +# Also see Diario El Heraldo, The country returns to standard time (2006-08-08)
            +# .
            +# It mentions executive decree 18-2006.
            +
            +# From Steffen Thorsen (2006-08-17):
            +# Honduras will observe DST from 2007 to 2009, exact dates are not
            +# published, I have located this authoritative source:
            +# http://www.presidencia.gob.hn/noticia.aspx?nId=47
            +
            +# From Steffen Thorsen (2007-03-30):
            +# http://www.laprensahn.com/pais_nota.php?id04962=7386
            +# So it seems that Honduras will not enter DST this year....
            +
            +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            +Rule	Hond	1987	1988	-	May	Sun>=1	0:00	1:00	D
            +Rule	Hond	1987	1988	-	Sep	lastSun	0:00	0	S
            +Rule	Hond	2006	only	-	May	Sun>=1	0:00	1:00	D
            +Rule	Hond	2006	only	-	Aug	Mon>=1	0:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Tegucigalpa -5:48:52 -	LMT	1921 Apr
            -			-6:00	Salv	C%sT
            +			-6:00	Hond	C%sT
             #
             # Great Swan I ceded by US to Honduras in 1972
             
            @@ -1878,7 +2940,7 @@
             # From U. S. Naval Observatory (1989-01-19):
             # JAMAICA             5 H  BEHIND UTC
             
            -# From Shanks:
            +# From Shanks & Pottenger:
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	America/Jamaica	-5:07:12 -	LMT	1890		# Kingston
             			-5:07:12 -	KMT	1912 Feb    # Kingston Mean Time
            @@ -1895,32 +2957,77 @@
             			-4:00	-	AST
             
             # Montserrat
            -# From Paul Eggert (1997-08-31):
            -# Recent volcanic eruptions have forced evacuation of Plymouth, the capital.
            -# Luckily, Olveston, the current de facto capital, has the same longitude.
            +# From Paul Eggert (2006-03-22):
            +# In 1995 volcanic eruptions forced evacuation of Plymouth, the capital.
            +# world.gazetteer.com says Cork Hill is the most populous location now.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/Montserrat	-4:08:52 -	LMT	1911 Jul 1 0:01   # Olveston
            +Zone America/Montserrat	-4:08:52 -	LMT	1911 Jul 1 0:01   # Cork Hill
             			-4:00	-	AST
             
             # Nicaragua
             #
            -# From Steffen Thorsen (1998-12-29):
            -# Nicaragua seems to be back at -6:00 but I have not been able to find when
            -# they changed from -5:00.
            +# This uses Shanks & Pottenger for times before 2005.
             #
            +# From Steffen Thorsen (2005-04-12):
            +# I've got reports from 8 different people that Nicaragua just started
            +# DST on Sunday 2005-04-10, in order to save energy because of
            +# expensive petroleum.  The exact end date for DST is not yet
            +# announced, only "September" but some sites also say "mid-September".
            +# Some background information is available on the President's official site:
            +# http://www.presidencia.gob.ni/Presidencia/Files_index/Secretaria/Notas%20de%20Prensa/Presidente/2005/ABRIL/Gobierno-de-nicaragua-adelanta-hora-oficial-06abril.htm
            +# The Decree, no 23-2005 is available here:
            +# http://www.presidencia.gob.ni/buscador_gaceta/BD/DECRETOS/2005/Decreto%2023-2005%20Se%20adelanta%20en%20una%20hora%20en%20todo%20el%20territorio%20nacional%20apartir%20de%20las%2024horas%20del%2009%20de%20Abril.pdf
            +#
            +# From Paul Eggert (2005-05-01):
            +# The decree doesn't say anything about daylight saving, but for now let's
            +# assume that it is daylight saving....
            +#
            +# From Gwillim Law (2005-04-21):
            +# The Associated Press story on the time change, which can be found at
            +# http://www.lapalmainteractivo.com/guias/content/gen/ap/America_Latina/AMC_GEN_NICARAGUA_HORA.html
            +# and elsewhere, says (fifth paragraph, translated from Spanish):  "The last
            +# time that a change of clocks was applied to save energy was in the year 2000
            +# during the Arnoldo Aleman administration."...
            +# The northamerica file says that Nicaragua has been on UTC-6 continuously
            +# since December 1998.  I wasn't able to find any details of Nicaraguan time
            +# changes in 2000.  Perhaps a note could be added to the northamerica file, to
            +# the effect that we have indirect evidence that DST was observed in 2000.
            +#
            +# From Jesper Norgaard Welen (2005-11-02):
            +# Nicaragua left DST the 2005-10-02 at 00:00 (local time).
            +# http://www.presidencia.gob.ni/presidencia/files_index/secretaria/comunicados/2005/septiembre/26septiembre-cambio-hora.htm
            +# (2005-09-26)
            +#
            +# From Jesper Norgaard Welen (2006-05-05):
            +# http://www.elnuevodiario.com.ni/2006/05/01/nacionales/18410
            +# (my informal translation)
            +# By order of the president of the republic, Enrique Bolanos, Nicaragua
            +# advanced by sixty minutes their official time, yesterday at 2 in the
            +# morning, and will stay that way until 30.th. of september.
            +#
            +# From Jesper Norgaard Welen (2006-09-30):
            +# http://www.presidencia.gob.ni/buscador_gaceta/BD/DECRETOS/2006/D-063-2006P-PRN-Cambio-Hora.pdf
            +# My informal translation runs:
            +# The natural sun time is restored in all the national territory, in that the
            +# time is returned one hour at 01:00 am of October 1 of 2006.
            +#
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Nic	1979	1980	-	Mar	Sun>=16	0:00	1:00	D
             Rule	Nic	1979	1980	-	Jun	Mon>=23	0:00	0	S
            -Rule	Nic	1992	only	-	Jan	1	4:00	1:00	D
            -Rule	Nic	1992	only	-	Sep	24	0:00	0	S
            +Rule	Nic	2005	only	-	Apr	10	0:00	1:00	D
            +Rule	Nic	2005	only	-	Oct	Sun>=1	0:00	0	S
            +Rule	Nic	2006	only	-	Apr	30	2:00	1:00	D
            +Rule	Nic	2006	only	-	Oct	Sun>=1	1:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	America/Managua	-5:45:08 -	LMT	1890
             			-5:45:12 -	MMT	1934 Jun 23 # Managua Mean Time?
             			-6:00	-	CST	1973 May
             			-5:00	-	EST	1975 Feb 16
            -			-6:00	Nic	C%sT	1993 Jan 1 4:00
            -			-5:00	-	EST	1998 Dec
            -			-6:00	-	CST
            +			-6:00	Nic	C%sT	1992 Jan  1 4:00
            +			-5:00	-	EST	1992 Sep 24
            +			-6:00	-	CST	1993
            +			-5:00	-	EST	1997
            +			-6:00	Nic	C%sT
             
             # Panama
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            @@ -1933,7 +3040,7 @@
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Puerto_Rico -4:24:25 -	LMT	1899 Mar 28 12:00    # San Juan
             			-4:00	-	AST	1942 May  3
            -			-4:00	1:00	AWT	1945 Sep 30  2:00
            +			-4:00	US	A%sT	1946
             			-4:00	-	AST
             
             # St Kitts-Nevis
            @@ -1962,13 +3069,31 @@
             			-4:00	-	AST
             
             # Turks and Caicos
            -# From Paul Eggert (1998-08-06):
            -# Shanks says they use US DST rules, but IATA SSIM (1991/1998)
            -# says they switch at midnight.  Go with IATA SSIM.
            +#
            +# From Chris Dunn in
            +# 
            +# (2007-03-15): In the Turks & Caicos Islands (America/Grand_Turk) the
            +# daylight saving dates for time changes have been adjusted to match
            +# the recent U.S. change of dates.
            +#
            +# From Brian Inglis (2007-04-28):
            +# http://www.turksandcaicos.tc/calendar/index.htm [2007-04-26]
            +# there is an entry for Nov 4 "Daylight Savings Time Ends 2007" and three
            +# rows before that there is an out of date entry for Oct:
            +# "Eastern Standard Times Begins 2007
            +# Clocks are set back one hour at 2:00 a.m. local Daylight Saving Time"
            +# indicating that the normal ET rules are followed.
            +#
            +# From Paul Eggert (2006-05-01):
            +# Shanks & Pottenger say they use US DST rules, but IATA SSIM (1991/1998)
            +# says they switch at midnight.  Go with Shanks & Pottenger.
            +#
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -Rule	TC	1979	1986	-	Apr	lastSun	0:00	1:00	D
            -Rule	TC	1979	max	-	Oct	lastSun	0:00	0	S
            -Rule	TC	1987	max	-	Apr	Sun>=1	0:00	1:00	D
            +Rule	TC	1979	1986	-	Apr	lastSun	2:00	1:00	D
            +Rule	TC	1979	2006	-	Oct	lastSun	2:00	0	S
            +Rule	TC	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
            +Rule	TC	2007	max	-	Mar	Sun>=8	2:00	1:00	D
            +Rule	TC	2007	max	-	Nov	Sun>=1	2:00	0	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Grand_Turk	-4:44:32 -	LMT	1890
             			-5:07:12 -	KMT	1912 Feb    # Kingston Mean Time
            Index: 3rdParty_sources/joda-time/org/joda/time/tz/src/pacificnew
            ===================================================================
            diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/joda-time/org/joda/time/tz/src/pacificnew	(.../pacificnew)	(revision 4e266757c429613d78b0fd2914d40d77a447daad)
            +++ 3rdParty_sources/joda-time/org/joda/time/tz/src/pacificnew	(.../pacificnew)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -1,4 +1,7 @@
            -# @(#)pacificnew	7.10
            +# 
            +# @(#)pacificnew	8.2
            +# This file is in the public domain, so clarified as of
            +# 2009-05-17 by Arthur David Olson.
             
             # From Arthur David Olson (1989-04-05):
             # On 1989-04-05, the U. S. House of Representatives passed (238-154) a bill
            Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/tz/src/solar87'.
            Fisheye: No comparison available.  Pass `N' to diff?
            Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/tz/src/solar88'.
            Fisheye: No comparison available.  Pass `N' to diff?
            Fisheye: Tag 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d refers to a dead (removed) revision in file `3rdParty_sources/joda-time/org/joda/time/tz/src/solar89'.
            Fisheye: No comparison available.  Pass `N' to diff?
            Index: 3rdParty_sources/joda-time/org/joda/time/tz/src/southamerica
            ===================================================================
            diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/joda-time/org/joda/time/tz/src/southamerica	(.../southamerica)	(revision 4e266757c429613d78b0fd2914d40d77a447daad)
            +++ 3rdParty_sources/joda-time/org/joda/time/tz/src/southamerica	(.../southamerica)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -1,22 +1,25 @@
            -# @(#)southamerica	7.55
            +# 
            +# @(#)southamerica	8.52
            +# This file is in the public domain, so clarified as of
            +# 2009-05-17 by Arthur David Olson.
             
             # This data is by no means authoritative; if you think you know better,
             # go ahead and edit the file (and please send any changes to
             # tz@elsie.nci.nih.gov for general use in the future).
             
            -# From Paul Eggert  (1999-07-07):
            +# From Paul Eggert (2006-03-22):
             # A good source for time zone historical data outside the U.S. is
            -# Thomas G. Shanks, The International Atlas (5th edition),
            -# San Diego: ACS Publications, Inc. (1999).
            +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
            +# San Diego: ACS Publications, Inc. (2003).
             #
             # Gwillim Law writes that a good source
             # for recent time zone data is the International Air Transport
             # Association's Standard Schedules Information Manual (IATA SSIM),
             # published semiannually.  Law sent in several helpful summaries
             # of the IATA's data after 1990.
             #
            -# Except where otherwise noted, Shanks is the source for entries through 1990,
            -# and IATA SSIM is the source for entries after 1990.
            +# Except where otherwise noted, Shanks & Pottenger is the source for
            +# entries through 1990, and IATA SSIM is the source for entries afterwards.
             #
             # Earlier editions of these tables used the North American style (e.g. ARST and
             # ARDT for Argentine Standard and Daylight Time), but the following quote
            @@ -58,7 +61,7 @@
             # From U. S. Naval Observatory (1988-01-199):
             # ARGENTINA           3 H BEHIND   UTC
             
            -# From Hernan G. Otero  (1995-06-26):
            +# From Hernan G. Otero (1995-06-26):
             # I am sending modifications to the Argentine time zone table...
             # AR was chosen because they are the ISO letters that represent Argentina.
             
            @@ -86,17 +89,15 @@
             Rule	Arg	1974	only	-	May	 1	0:00	0	-
             Rule	Arg	1988	only	-	Dec	 1	0:00	1:00	S
             #
            -# From Hernan G. Otero  (1995-06-26):
            +# From Hernan G. Otero (1995-06-26):
             # These corrections were contributed by InterSoft Argentina S.A.,
             # obtaining the data from the:
             # Talleres de Hidrografia Naval Argentina
             # (Argentine Naval Hydrography Institute)
            -#
            -# Shanks stops after 1992-03-01; go with Otero.
             Rule	Arg	1989	1993	-	Mar	Sun>=1	0:00	0	-
             Rule	Arg	1989	1992	-	Oct	Sun>=15	0:00	1:00	S
             #
            -# From Hernan G. Otero  (1995-06-26):
            +# From Hernan G. Otero (1995-06-26):
             # From this moment on, the law that mandated the daylight saving
             # time corrections was derogated and no more modifications
             # to the time zones (for daylight saving) are now made.
            @@ -106,14 +107,18 @@
             # which did not result in the switch of a time zone, as they stayed 9 hours
             # from the International Date Line.
             Rule	Arg	1999	only	-	Oct	Sun>=1	0:00	1:00	S
            -Rule	Arg	2000	only	-	Mar	Sun>=1	0:00	0	-
            +# From Paul Eggert (2007-12-28):
            +# DST was set to expire on March 5, not March 3, but since it was converted
            +# to standard time on March 3 it's more convenient for us to pretend that
            +# it ended on March 3.
            +Rule	Arg	2000	only	-	Mar	3	0:00	0	-
             #
             # From Peter Gradelski via Steffen Thorsen (2000-03-01):
             # We just checked with our Sao Paulo office and they say the government of
             # Argentina decided not to become one of the countries that go on or off DST.
             # So Buenos Aires should be -3 hours from GMT at all times.
             #
            -# From Fabian L. Arce Jofre  (2000-04-04):
            +# From Fabian L. Arce Jofre (2000-04-04):
             # The law that claimed DST for Argentina was derogated by President Fernando
             # de la Rua on March 2, 2000, because it would make people spend more energy
             # in the winter time, rather than less.  The change took effect on March 3.
            @@ -141,6 +146,93 @@
             # This kind of things had always been done this way in Argentina.
             # We are still -03:00 all year round in all of the country.
             #
            +# From Steffen Thorsen (2007-12-21):
            +# A user (Leonardo Chaim) reported that Argentina will adopt DST....
            +# all of the country (all Zone-entries) are affected.  News reports like
            +# http://www.lanacion.com.ar/opinion/nota.asp?nota_id=973037 indicate
            +# that Argentina will use DST next year as well, from October to
            +# March, although exact rules are not given.
            +#
            +# From Jesper Norgaard Welen (2007-12-26)
            +# The last hurdle of Argentina DST is over, the proposal was approved in
            +# the lower chamber too (Deputados) with a vote 192 for and 2 against.
            +# By the way thanks to Mariano Absatz and Daniel Mario Vega for the link to
            +# the original scanned proposal, where the dates and the zero hours are
            +# clear and unambiguous...This is the article about final approval:
            +# 
            +# http://www.lanacion.com.ar/politica/nota.asp?nota_id=973996
            +# 
            +#
            +# From Paul Eggert (2007-12-22):
            +# For dates after mid-2008, the following rules are my guesses and
            +# are quite possibly wrong, but are more likely than no DST at all.
            +
            +# From Alexander Krivenyshev (2008-09-05):
            +# As per message from Carlos Alberto Fonseca Arauz (Nicaragua),
            +# Argentina will start DST on Sunday October 19, 2008.
            +#
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_argentina03.html
            +# 
            +# OR
            +# 
            +# http://www.impulsobaires.com.ar/nota.php?id=57832 (in spanish)
            +# 
            +
            +# From Rodrigo Severo (2008-10-06):
            +# Here is some info available at a Gentoo bug related to TZ on Argentina's DST:
            +# ...
            +# ------- Comment #1 from [jmdocile]  2008-10-06 16:28 0000 -------
            +# Hi, there is a problem with timezone-data-2008e and maybe with
            +# timezone-data-2008f
            +# Argentinian law [Number] 25.155 is no longer valid.
            +# 
            +# http://www.infoleg.gov.ar/infolegInternet/anexos/60000-64999/60036/norma.htm
            +# 
            +# The new one is law [Number] 26.350
            +# 
            +# http://www.infoleg.gov.ar/infolegInternet/anexos/135000-139999/136191/norma.htm
            +# 
            +# So there is no summer time in Argentina for now.
            +
            +# From Mariano Absatz (2008-10-20):
            +# Decree 1693/2008 applies Law 26.350 for the summer 2008/2009 establishing DST in Argentina
            +# From 2008-10-19 until 2009-03-15
            +# 
            +# http://www.boletinoficial.gov.ar/Bora.Portal/CustomControls/PdfContent.aspx?fp=16102008&pi=3&pf=4&s=0&sec=01
            +# 
            +#
            +# Decree 1705/2008 excepting 12 Provinces from applying DST in the summer 2008/2009:
            +# Catamarca, La Rioja, Mendoza, Salta, San Juan, San Luis, La Pampa, Neuquen, Rio Negro, Chubut, Santa Cruz
            +# and Tierra del Fuego
            +# 
            +# http://www.boletinoficial.gov.ar/Bora.Portal/CustomControls/PdfContent.aspx?fp=17102008&pi=1&pf=1&s=0&sec=01
            +# 
            +#
            +# Press release 235 dated Saturday October 18th, from the Government of the Province of Jujuy saying
            +# it will not apply DST either (even when it was not included in Decree 1705/2008)
            +# 
            +# http://www.jujuy.gov.ar/index2/partes_prensa/18_10_08/235-181008.doc
            +# 
            +
            +# From fullinet (2009-10-18):
            +# As announced in
            +# 
            +# http://www.argentina.gob.ar/argentina/portal/paginas.dhtml?pagina=356
            +# 
            +# (an official .gob.ar) under title: "Sin Cambio de Hora" (english: "No hour change")
            +#
            +# "Por el momento, el Gobierno Nacional resolvio no modificar la hora
            +# oficial, decision que estaba en estudio para su implementacion el
            +# domingo 18 de octubre. Desde el Ministerio de Planificacion se anuncio
            +# que la Argentina hoy, en estas condiciones meteorologicas, no necesita
            +# la modificacion del huso horario, ya que 2009 nos encuentra con
            +# crecimiento en la produccion y distribucion energetica."
            +
            +Rule	Arg	2007	only	-	Dec	30	0:00	1:00	S
            +Rule	Arg	2008	2009	-	Mar	Sun>=15	0:00	0	-
            +Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
            + 
             # From Mariano Absatz (2004-05-21):
             # Today it was officially published that the Province of Mendoza is changing
             # its timezone this winter... starting tomorrow night....
            @@ -149,12 +241,12 @@
             # It's Law No. 7,210.  This change is due to a public power emergency, so for
             # now we'll assume it's for this year only.
             #
            -# From Paul Eggert (2002-01-22):
            +# From Paul Eggert (2006-03-22):
             # 
            -# Hora de verano para la Republica Argentina (2000-10-01)
            +# Hora de verano para la Republica Argentina (2003-06-08)
             #  says that standard time in Argentina from 1894-10-31
             # to 1920-05-01 was -4:16:48.25.  Go with this more-precise value
            -# over Shanks.
            +# over Shanks & Pottenger.
             #
             # From Mariano Absatz (2004-06-05):
             # These media articles from a major newspaper mostly cover the current state:
            @@ -201,11 +293,171 @@
             # http://www.sanjuan.gov.ar/prensa/archivo/000426.html
             # http://www.sanjuan.gov.ar/prensa/archivo/000441.html
             
            -# Unless otherwise specified, data are from Shanks through 1992, from
            -# the IATA otherwise.  As noted below, Shanks says that
            -# America/Cordoba split into 6 subregions during 1991/1992, but we
            -# haven't verified this yet so for now we'll keep it a single region.
            +# From Alex Krivenyshev (2008-01-17):
            +# Here are articles that Argentina Province San Luis is planning to end DST
            +# as earlier as upcoming Monday January 21, 2008 or February 2008:
             #
            +# Provincia argentina retrasa reloj y marca diferencia con resto del pais
            +# (Argentine Province delayed clock and mark difference with the rest of the
            +# country)
            +# 
            +# http://cl.invertia.com/noticias/noticia.aspx?idNoticia=200801171849_EFE_ET4373&idtel
            +# 
            +#
            +# Es inminente que en San Luis atrasen una hora los relojes
            +# (It is imminent in San Luis clocks one hour delay)
            +# 
            +# http://www.lagaceta.com.ar/vernotae.asp?id_nota=253414
            +# 
            +#
            +# 
            +# http://www.worldtimezone.net/dst_news/dst_news_argentina02.html
            +# 
            +
            +# From Jesper Norgaard Welen (2008-01-18):
            +# The page of the San Luis provincial government
            +# 
            +# http://www.sanluis.gov.ar/notas.asp?idCanal=0&id=22812
            +# 
            +# confirms what Alex Krivenyshev has earlier sent to the tz
            +# emailing list about that San Luis plans to return to standard
            +# time much earlier than the rest of the country. It also
            +# confirms that upon request the provinces San Juan and Mendoza 
            +# refused to follow San Luis in this change. 
            +# 
            +# The change is supposed to take place Monday the 21.st at 0:00
            +# hours. As far as I understand it if this goes ahead, we need
            +# a new timezone for San Luis (although there are also documented
            +# independent changes in the southamerica file of San Luis in
            +# 1990 and 1991 which has not been confirmed).
            +
            +# From Jesper Norgaard Welen (2008-01-25):
            +# Unfortunately the below page has become defunct, about the San Luis
            +# time change. Perhaps because it now is part of a group of pages "Most
            +# important pages of 2008."
            +#
            +# You can use
            +# 
            +# http://www.sanluis.gov.ar/notas.asp?idCanal=8141&id=22834
            +# 
            +# instead it seems. Or use "Buscador" from the main page of the San Luis
            +# government, and fill in "huso" and click OK, and you will get 3 pages
            +# from which the first one is identical to the above.
            +
            +# From Mariano Absatz (2008-01-28):
            +# I can confirm that the Province of San Luis (and so far only that
            +# province) decided to go back to UTC-3 effective midnight Jan 20th 2008
            +# (that is, Monday 21st at 0:00 is the time the clocks were delayed back
            +# 1 hour), and they intend to keep UTC-3 as their timezone all year round
            +# (that is, unless they change their mind any minute now).
            +#
            +# So we'll have to add yet another city to 'southamerica' (I think San
            +# Luis city is the mos populated city in the Province, so it'd be
            +# America/Argentina/San_Luis... of course I can't remember if San Luis's
            +# history of particular changes goes along with Mendoza or San Juan :-(
            +# (I only remember not being able to collect hard facts about San Luis
            +# back in 2004, when these provinces changed to UTC-4 for a few days, I
            +# mailed them personally and never got an answer).
            +
            +# From Paul Eggert (2008-06-30):
            +# Unless otherwise specified, data are from Shanks & Pottenger through 1992,
            +# from the IATA otherwise.  As noted below, Shanks & Pottenger say that
            +# America/Cordoba split into 6 subregions during 1991/1992, one of which
            +# was America/San_Luis, but we haven't verified this yet so for now we'll
            +# keep America/Cordoba a single region rather than splitting it into the
            +# other 5 subregions.
            +
            +# From Mariano Absatz (2009-03-13):
            +# Yesterday (with our usual 2-day notice) the Province of San Luis
            +# decided that next Sunday instead of "staying" @utc-03:00 they will go
            +# to utc-04:00 until the second Saturday in October...
            +#
            +# The press release is at
            +# 
            +# http://www.sanluis.gov.ar/SL/Paginas/NoticiaDetalle.asp?TemaId=1&InfoPrensaId=3102
            +# 
            +# (I couldn't find the decree, but
            +# 
            +# www.sanluis.gov.ar
            +# 
            +# is the official page for the Province Government).
            +#
            +# There's also a note in only one of the major national papers (La Naci�n) at
            +# 
            +# http://www.lanacion.com.ar/nota.asp?nota_id=1107912
            +# 
            +# 
            +# The press release says:
            +#  (...) anunci� que el pr�ximo domingo a las 00:00 los puntanos deber�n
            +# atrasar una hora sus relojes.
            +#
            +# A partir de entonces, San Luis establecer� el huso horario propio de
            +# la Provincia. De esta manera, durante el periodo del calendario anual
            +# 2009, el cambio horario quedar� comprendido entre las 00:00 del tercer
            +# domingo de marzo y las 24:00 del segundo s�bado de octubre.
            +# Quick&dirty translation
            +# (...) announced that next Sunday, at 00:00, Puntanos (the San Luis
            +# inhabitants) will have to turn back one hour their clocks
            +#
            +# Since then, San Luis will establish its own Province timezone. Thus,
            +# during 2009, this timezone change will run from 00:00 the third Sunday
            +# in March until 24:00 of the second Saturday in October.
            +
            +# From Mariano Absatz (2009-10-16):
            +# ...the Province of San Luis is a case in itself.
            +#
            +# The Law at
            +# 
            +# is ambiguous because establishes a calendar from the 2nd Sunday in
            +# October at 0:00 thru the 2nd Saturday in March at 24:00 and the
            +# complement of that starting on the 2nd Sunday of March at 0:00 and
            +# ending on the 2nd Saturday of March at 24:00.
            +#
            +# This clearly breaks every time the 1st of March or October is a Sunday.
            +#
            +# IMHO, the "spirit of the Law" is to make the changes at 0:00 on the 2nd
            +# Sunday of October and March.
            +#
            +# The problem is that the changes in the rest of the Provinces that did
            +# change in 2007/2008, were made according to the Federal Law and Decrees
            +# that did so on the 3rd Sunday of October and March.
            +#
            +# In fact, San Luis actually switched from UTC-4 to UTC-3 last Sunday
            +# (October 11th) at 0:00.
            +#
            +# So I guess a new set of rules, besides "Arg", must be made and the last
            +# America/Argentina/San_Luis entries should change to use these...
            +#
            +# I'm enclosing a patch that does what I say... regretfully, the San Luis
            +# timezone must be called "WART/WARST" even when most of the time (like,
            +# right now) WARST == ART... that is, since last Sunday, all the country
            +# is using UTC-3, but in my patch, San Luis calls it "WARST" and the rest
            +# of the country calls it "ART".
            +# ...
            +
            +# From Alexander Krivenyshev (2010-04-09):
            +# According to news reports from El Diario de la Republica Province San
            +# Luis, Argentina (standard time UTC-04) will keep Daylight Saving Time
            +# after April 11, 2010--will continue to have same time as rest of
            +# Argentina (UTC-3) (no DST).
            +#
            +# Confirmaron la prórroga del huso horario de verano (Spanish)
            +# 
            +# http://www.eldiariodelarepublica.com/index.php?option=com_content&task=view&id=29383&Itemid=9
            +# 
            +# or (some English translation):
            +# 
            +# http://www.worldtimezone.com/dst_news/dst_news_argentina08.html
            +# 
            +
            +# From Mariano Absatz (2010-04-12):
            +# yes...I can confirm this...and given that San Luis keeps calling
            +# UTC-03:00 "summer time", we should't just let San Luis go back to "Arg"
            +# rules...San Luis is still using "Western ARgentina Time" and it got
            +# stuck on Summer daylight savings time even though the summer is over.
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             #
             # Buenos Aires (BA), Capital Federal (CF),
            @@ -215,18 +467,15 @@
             			-4:00	Arg	AR%sT	1969 Oct  5
             			-3:00	Arg	AR%sT	1999 Oct  3
             			-4:00	Arg	AR%sT	2000 Mar  3
            -			-3:00	-	ART
            +			-3:00	Arg	AR%sT
             #
            -# Santa Fe (SF), Entre Rios (ER), Corrientes (CN), Misiones (MN), Chaco (CC),
            -# Formosa (FM), Salta (SA), Santiago del Estero (SE), Cordoba (CB),
            -# San Luis (SL), La Pampa (LP), Neuquen (NQ), Rio Negro (RN)
            +# Cordoba (CB), Santa Fe (SF), Entre Rios (ER), Corrientes (CN), Misiones (MN),
            +# Chaco (CC), Formosa (FM), Santiago del Estero (SE)
             #
            -# Shanks also makes the following claims, which we haven't verified:
            +# Shanks & Pottenger also make the following claims, which we haven't verified:
             # - Formosa switched to -3:00 on 1991-01-07.
             # - Misiones switched to -3:00 on 1990-12-29.
             # - Chaco switched to -3:00 on 1991-01-04.
            -# - San Luis switched to -4:00 on 1990-03-14, then to -3:00 on 1990-10-15,
            -#   then to -4:00 on 1991-03-01, then to -3:00 on 1991-06-01.
             # - Santiago del Estero switched to -4:00 on 1991-04-01,
             #   then to -3:00 on 1991-04-26.
             #
            @@ -238,6 +487,18 @@
             			-4:00	-	WART	1991 Oct 20
             			-3:00	Arg	AR%sT	1999 Oct  3
             			-4:00	Arg	AR%sT	2000 Mar  3
            +			-3:00	Arg	AR%sT
            +#
            +# Salta (SA), La Pampa (LP), Neuquen (NQ), Rio Negro (RN)
            +Zone America/Argentina/Salta -4:21:40 - LMT	1894 Oct 31
            +			-4:16:48 -	CMT	1920 May
            +			-4:00	-	ART	1930 Dec
            +			-4:00	Arg	AR%sT	1969 Oct  5
            +			-3:00	Arg	AR%sT	1991 Mar  3
            +			-4:00	-	WART	1991 Oct 20
            +			-3:00	Arg	AR%sT	1999 Oct  3
            +			-4:00	Arg	AR%sT	2000 Mar  3
            +			-3:00	Arg	AR%sT	2008 Oct 18
             			-3:00	-	ART
             #
             # Tucuman (TM)
            @@ -251,7 +512,7 @@
             			-4:00	Arg	AR%sT	2000 Mar  3
             			-3:00	-	ART	2004 Jun  1
             			-4:00	-	WART	2004 Jun 13
            -			-3:00	-	ART
            +			-3:00	Arg	AR%sT
             #
             # La Rioja (LR)
             Zone America/Argentina/La_Rioja -4:27:24 - LMT	1894 Oct 31
            @@ -264,6 +525,7 @@
             			-4:00	Arg	AR%sT	2000 Mar  3
             			-3:00	-	ART	2004 Jun  1
             			-4:00	-	WART	2004 Jun 20
            +			-3:00	Arg	AR%sT	2008 Oct 18
             			-3:00	-	ART
             #
             # San Juan (SJ)
            @@ -277,6 +539,7 @@
             			-4:00	Arg	AR%sT	2000 Mar  3
             			-3:00	-	ART	2004 May 31
             			-4:00	-	WART	2004 Jul 25
            +			-3:00	Arg	AR%sT	2008 Oct 18
             			-3:00	-	ART
             #
             # Jujuy (JY)
            @@ -291,9 +554,10 @@
             			-3:00	1:00	ARST	1992
             			-3:00	Arg	AR%sT	1999 Oct  3
             			-4:00	Arg	AR%sT	2000 Mar  3
            +			-3:00	Arg	AR%sT	2008 Oct 18
             			-3:00	-	ART
             #
            -# Catamarca (CT)
            +# Catamarca (CT), Chubut (CH)
             Zone America/Argentina/Catamarca -4:23:08 - LMT	1894 Oct 31
             			-4:16:48 -	CMT	1920 May
             			-4:00	-	ART	1930 Dec
            @@ -304,6 +568,7 @@
             			-4:00	Arg	AR%sT	2000 Mar  3
             			-3:00	-	ART	2004 Jun  1
             			-4:00	-	WART	2004 Jun 20
            +			-3:00	Arg	AR%sT	2008 Oct 18
             			-3:00	-	ART
             #
             # Mendoza (MZ)
            @@ -321,21 +586,29 @@
             			-4:00	Arg	AR%sT	2000 Mar  3
             			-3:00	-	ART	2004 May 23
             			-4:00	-	WART	2004 Sep 26
            +			-3:00	Arg	AR%sT	2008 Oct 18
             			-3:00	-	ART
             #
            -# Chubut (CH)
            -# The name "Comodoro Rivadavia" exceeds the 14-byte POSIX limit.
            -Zone America/Argentina/ComodRivadavia -4:30:00 - LMT	1894 Oct 31
            +# San Luis (SL)
            +
            +Rule	SanLuis	2008	2009	-	Mar	Sun>=8	0:00	0	-
            +Rule	SanLuis	2007	2009	-	Oct	Sun>=8	0:00	1:00	S
            +
            +Zone America/Argentina/San_Luis -4:25:24 - LMT	1894 Oct 31
             			-4:16:48 -	CMT	1920 May
             			-4:00	-	ART	1930 Dec
             			-4:00	Arg	AR%sT	1969 Oct  5
            -			-3:00	Arg	AR%sT	1991 Mar  3
            -			-4:00	-	WART	1991 Oct 20
            -			-3:00	Arg	AR%sT	1999 Oct  3
            -			-4:00	Arg	AR%sT	2000 Mar  3
            -			-3:00	-	ART	2004 Jun  1
            -			-4:00	-	WART	2004 Jun 20
            -			-3:00	-	ART
            +			-3:00	Arg	AR%sT	1990
            +			-3:00	1:00	ARST	1990 Mar 14
            +			-4:00	-	WART	1990 Oct 15
            +			-4:00	1:00	WARST	1991 Mar  1
            +			-4:00	-	WART	1991 Jun  1
            +			-3:00	-	ART	1999 Oct  3
            +			-4:00	1:00	WARST	2000 Mar  3
            +			-3:00	-	ART	2004 May 31
            +			-4:00	-	WART	2004 Jul 25
            +			-3:00	Arg	AR%sT	2008 Jan 21
            +			-4:00	SanLuis	WAR%sT
             #
             # Santa Cruz (SC)
             Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31
            @@ -346,6 +619,7 @@
             			-4:00	Arg	AR%sT	2000 Mar  3
             			-3:00	-	ART	2004 Jun  1
             			-4:00	-	WART	2004 Jun 20
            +			-3:00	Arg	AR%sT	2008 Oct 18
             			-3:00	-	ART
             #
             # Tierra del Fuego, Antartida e Islas del Atlantico Sur (TF)
            @@ -357,6 +631,7 @@
             			-4:00	Arg	AR%sT	2000 Mar  3
             			-3:00	-	ART	2004 May 30
             			-4:00	-	WART	2004 Jun 20
            +			-3:00	Arg	AR%sT	2008 Oct 18
             			-3:00	-	ART
             
             # Aruba
            @@ -374,7 +649,7 @@
             
             # Brazil
             
            -# From Paul Eggert  (1993-11-18):
            +# From Paul Eggert (1993-11-18):
             # The mayor of Rio recently attempted to change the time zone rules
             # just in his city, in order to leave more summer time for the tourist trade.
             # The rule change lasted only part of the day;
            @@ -439,16 +714,123 @@
             # modern Brazilian eletronic voting machines which, apparently, can't deal
             # with a time change between the first and the second rounds of the elections.
             
            +# From Steffen Thorsen (2007-09-20):
            +# Brazil will start DST on 2007-10-14 00:00 and end on 2008-02-17 00:00:
            +# http://www.mme.gov.br/site/news/detail.do;jsessionid=BBA06811AFCAAC28F0285210913513DA?newsId=13975
            +
            +# From Paul Schulze (2008-06-24):
            +# ...by law number 11.662 of April 24, 2008 (published in the "Diario
            +# Oficial da Uniao"...) in Brazil there are changes in the timezones,
            +# effective today (00:00am at June 24, 2008) as follows:
            +#
            +# a) The timezone UTC+5 is e[x]tinguished, with all the Acre state and the
            +# part of the Amazonas state that had this timezone now being put to the
            +# timezone UTC+4
            +# b) The whole Para state now is put at timezone UTC+3, instead of just
            +# part of it, as was before.
            +#
            +# This change follows a proposal of senator Tiao Viana of Acre state, that
            +# proposed it due to concerns about open television channels displaying
            +# programs inappropriate to youths in the states that had the timezone
            +# UTC+5 too early in the night. In the occasion, some more corrections
            +# were proposed, trying to unify the timezones of any given state. This
            +# change modifies timezone rules defined in decree 2.784 of 18 June,
            +# 1913.
            +
            +# From Rodrigo Severo (2008-06-24):
            +# Just correcting the URL:
            +# 
            +# https://www.in.gov.br/imprensa/visualiza/index.jsp?jornal=do&secao=1&pagina=1&data=25/04/2008
            +# 
            +#
            +# As a result of the above Decree I believe the America/Rio_Branco
            +# timezone shall be modified from UTC-5 to UTC-4 and a new timezone shall
            +# be created to represent the...west side of the Para State. I
            +# suggest this new timezone be called Santarem as the most
            +# important/populated city in the affected area.
            +#
            +# This new timezone would be the same as the Rio_Branco timezone up to
            +# the 2008/06/24 change which would be to UTC-3 instead of UTC-4.
            +
            +# From Alex Krivenyshev (2008-06-24):
            +# This is a quick reference page for New and Old Brazil Time Zones map.
            +# 
            +# http://www.worldtimezone.com/brazil-time-new-old.php
            +# 
            +#
            +# - 4 time zones replaced by 3 time zones-eliminating time zone UTC- 05
            +# (state Acre and the part of the Amazonas will be UTC/GMT- 04) - western
            +# part of Par state is moving to one timezone UTC- 03 (from UTC -04).
            +
             # From Paul Eggert (2002-10-10):
             # The official decrees referenced below are mostly taken from
             # 
             # Decretos sobre o Horario de Verao no Brasil
            -#  (2001-09-20, in Portuguese).
            -# The official site for all decrees, including those not related to time, is
            -# 
            -# Presidencia da Republica, Subchefia para Assuntos Juridicos, Decretos
            -#  (in Portuguese).
            +# .
             
            +# From Steffen Thorsen (2008-08-29):
            +# As announced by the government and many newspapers in Brazil late
            +# yesterday, Brazil will start DST on 2008-10-19 (need to change rule) and
            +# it will end on 2009-02-15 (current rule for Brazil is fine). Based on
            +# past years experience with the elections, there was a good chance that
            +# the start was postponed to November, but it did not happen this year.
            +#
            +# It has not yet been posted to http://pcdsh01.on.br/DecHV.html
            +#
            +# An official page about it:
            +# 
            +# http://www.mme.gov.br/site/news/detail.do?newsId=16722
            +# 
            +# Note that this link does not always work directly, but must be accessed
            +# by going to
            +# 
            +# http://www.mme.gov.br/first
            +# 
            +#
            +# One example link that works directly:
            +# 
            +# http://jornale.com.br/index.php?option=com_content&task=view&id=13530&Itemid=54
            +# (Portuguese)
            +# 
            +#
            +# We have a written a short article about it as well:
            +# 
            +# http://www.timeanddate.com/news/time/brazil-dst-2008-2009.html
            +# 
            +#
            +# From Alexander Krivenyshev (2011-10-04):
            +# State Bahia will return to Daylight savings time this year after 8 years off.
            +# The announcement was made by Governor Jaques Wagner in an interview to a 
            +# television station in Salvador. 
            +
            +# In Portuguese:
            +# 
            +# http://g1.globo.com/bahia/noticia/2011/10/governador-jaques-wagner-confirma-horario-de-verao-na-bahia.html
            +#  and
            +# 
            +# http://noticias.terra.com.br/brasil/noticias/0,,OI5390887-EI8139,00-Bahia+volta+a+ter+horario+de+verao+apos+oito+anos.html
            +# 
            +
            +# From Guilherme Bernardes Rodrigues (2011-10-07):
            +# There is news in the media, however there is still no decree about it.
            +# I just send a e-mail to Zulmira Brand�o at
            +# http://pcdsh01.on.br/ the
            +# oficial agency about time in Brazil, and she confirmed that the old rule is
            +# still in force.
            +
            +# From Guilherme Bernardes Rodrigues (2011-10-14)
            +# It's official, the President signed a decree that includes Bahia in summer
            +# time.
            +#	 [ and in a second message (same day): ]
            +# I found the decree.
            +#
            +# DECRETO No- 7.584, DE 13 DE OUTUBRO DE 2011
            +# Link :
            +# 
            +# http://www.in.gov.br/visualiza/index.jsp?data=13/10/2011&jornal=1000&pagina=6&totalArquivos=6
            +# 
            +
            +
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             # Decree 20,466 (1931-10-01)
             # Decree 21,896 (1932-01-10)
            @@ -532,19 +914,13 @@
             # adopted by same states, minus AL, SE.
             Rule	Brazil	1996	only	-	Oct	 6	 0:00	1:00	S
             Rule	Brazil	1997	only	-	Feb	16	 0:00	0	-
            -# From Daniel C. Sobral  (1998-02-12):
            +# From Daniel C. Sobral (1998-02-12):
             # In 1997, the DS began on October 6. The stated reason was that
             # because international television networks ignored Brazil's policy on DS,
             # they bought the wrong times on satellite for coverage of Pope's visit.
             # This year, the ending date of DS was postponed to March 1
             # to help dealing with the shortages of electric power.
             #
            -# From Paul Eggert (1998-02-25):
            -# 
            -# Brazil Prepares for Papal Visit
            -# ,
            -# Church Net UK (1997-10-02).
            -#
             # Decree 2,317 (1997-09-04), adopted by same states.
             Rule	Brazil	1997	only	-	Oct	 6	 0:00	1:00	S
             # Decree 2,495
            @@ -569,24 +945,54 @@
             # Decree 3,916
             # (2001-09-13) reestablishes DST in AL, CE, MA, PB, PE, PI, RN, SE.
             Rule	Brazil	2000	2001	-	Oct	Sun>=8	 0:00	1:00	S
            -Rule	Brazil	2001	max	-	Feb	Sun>=15	 0:00	0	-
            +Rule	Brazil	2001	2006	-	Feb	Sun>=15	 0:00	0	-
             # Decree 4,399 (2002-10-01) repeals DST in AL, CE, MA, PB, PE, PI, RN, SE.
            -# 
            +# 4,399
             Rule	Brazil	2002	only	-	Nov	 3	 0:00	1:00	S
             # Decree 4,844 (2003-09-24; corrected 2003-09-26) repeals DST in BA, MT, TO.
            -# 
            +# 4,844
             Rule	Brazil	2003	only	-	Oct	19	 0:00	1:00	S
             # Decree 5,223 (2004-10-01) reestablishes DST in MT.
            -# 
            +# 5,223
             Rule	Brazil	2004	only	-	Nov	 2	 0:00	1:00	S
            +# Decree 5,539 (2005-09-19),
            +# adopted by the same states as before.
            +Rule	Brazil	2005	only	-	Oct	16	 0:00	1:00	S
            +# Decree 5,920 (2006-10-03),
            +# adopted by the same states as before.
            +Rule	Brazil	2006	only	-	Nov	 5	 0:00	1:00	S
            +Rule	Brazil	2007	only	-	Feb	25	 0:00	0	-
            +# Decree 6,212 (2007-09-26),
            +# adopted by the same states as before.
            +Rule	Brazil	2007	only	-	Oct	Sun>=8	 0:00	1:00	S
            +# From Frederico A. C. Neves (2008-09-10):
            +# Acording to this decree
            +# 
            +# http://www.planalto.gov.br/ccivil_03/_Ato2007-2010/2008/Decreto/D6558.htm
            +# 
            +# [t]he DST period in Brazil now on will be from the 3rd Oct Sunday to the
            +# 3rd Feb Sunday. There is an exception on the return date when this is
            +# the Carnival Sunday then the return date will be the next Sunday...
            +Rule	Brazil	2008	max	-	Oct	Sun>=15	0:00	1:00	S
            +Rule	Brazil	2008	2011	-	Feb	Sun>=15	0:00	0	-
            +Rule	Brazil	2012	only	-	Feb	Sun>=22	0:00	0	-
            +Rule	Brazil	2013	2014	-	Feb	Sun>=15	0:00	0	-
            +Rule	Brazil	2015	only	-	Feb	Sun>=22	0:00	0	-
            +Rule	Brazil	2016	2022	-	Feb	Sun>=15	0:00	0	-
            +Rule	Brazil	2023	only	-	Feb	Sun>=22	0:00	0	-
            +Rule	Brazil	2024	2025	-	Feb	Sun>=15	0:00	0	-
            +Rule	Brazil	2026	only	-	Feb	Sun>=22	0:00	0	-
            +Rule	Brazil	2027	2033	-	Feb	Sun>=15	0:00	0	-
            +Rule	Brazil	2034	only	-	Feb	Sun>=22	0:00	0	-
            +Rule	Brazil	2035	2036	-	Feb	Sun>=15	0:00	0	-
            +Rule	Brazil	2037	only	-	Feb	Sun>=22	0:00	0	-
            +# From Arthur David Olson (2008-09-29):
            +# The next is wrong in some years but is better than nothing.
            +Rule	Brazil	2038	max	-	Feb	Sun>=15	0:00	0	-
            +
             # The latest ruleset listed above says that the following states observe DST:
             # DF, ES, GO, MG, MS, MT, PR, RJ, RS, SC, SP.
            -#
            -Rule	Brazil	2005	max	-	Oct	Sun>=15	 0:00	1:00	S
            -# For dates after mid-2005, the above rules with TO="max" are guesses
            -# and are quite possibly wrong, but are more likely than no DST at all.
             
            -
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             #
             # Fernando de Noronha (administratively part of PE)
            @@ -612,6 +1018,13 @@
             			-3:00	Brazil	BR%sT	1988 Sep 12
             			-3:00	-	BRT
             #
            +# west Para (PA)
            +# West Para includes Altamira, Oribidos, Prainha, Oriximina, and Santarem.
            +Zone America/Santarem	-3:38:48 -	LMT	1914
            +			-4:00	Brazil	AM%sT	1988 Sep 12
            +			-4:00	-	AMT	2008 Jun 24 00:00
            +			-3:00	-	BRT
            +#
             # Maranhao (MA), Piaui (PI), Ceara (CE), Rio Grande do Norte (RN),
             # Paraiba (PB)
             Zone America/Fortaleza	-2:34:00 -	LMT	1914
            @@ -654,7 +1067,8 @@
             # of America/Salvador.
             Zone America/Bahia	-2:34:04 -	LMT	1914
             			-3:00	Brazil	BR%sT	2003 Sep 24
            -			-3:00	-	BRT
            +			-3:00	-	BRT	2011 Oct 16
            +			-3:00	Brazil	BR%sT
             #
             # Goias (GO), Distrito Federal (DF), Minas Gerais (MG),
             # Espirito Santo (ES), Rio de Janeiro (RJ), Sao Paulo (SP), Parana (PR),
            @@ -674,8 +1088,7 @@
             			-4:00	-	AMT	2004 Oct  1
             			-4:00	Brazil	AM%sT
             #
            -# west Para (PA), Rondonia (RO)
            -# West Para includes Altamira, Oribidos, Prainha, Oriximina, and Santarem.
            +# Rondonia (RO)
             Zone America/Porto_Velho -4:15:36 -	LMT	1914
             			-4:00	Brazil	AM%sT	1988 Sep 12
             			-4:00	-	AMT
            @@ -702,14 +1115,15 @@
             			-5:00	Brazil	AC%sT	1988 Sep 12
             			-5:00	-	ACT	1993 Sep 28
             			-5:00	Brazil	AC%sT	1994 Sep 22
            -			-5:00	-	ACT
            +			-5:00	-	ACT	2008 Jun 24 00:00
            +			-4:00	-	AMT
             #
             # Acre (AC)
             Zone America/Rio_Branco	-4:31:12 -	LMT	1914
             			-5:00	Brazil	AC%sT	1988 Sep 12
            -			-5:00	-	ACT
            +			-5:00	-	ACT	2008 Jun 24 00:00
            +			-4:00	-	AMT
             
            -
             # Chile
             
             # From Eduardo Krell (1995-10-19):
            @@ -724,65 +1138,150 @@
             # Because of the same drought, the government decided to end DST later,
             # on April 3, (one-time change).
             
            -# From Gwillim Law (2001-05-04):
            -# I came across another article in "La Tercera" about Chilean DST.
            -# 
            -# It clearly confirms my earlier suggestion, that DST begins at 22:00
            -# on Easter Island....  But it also seems to be saying that the
            -# observance of DST in Chile began in 1966, rather than 1969 as
            -# ... [Shanks] has it....
            +# From Oscar van Vlijmen (2006-10-08):
            +# http://www.horaoficial.cl/cambio.htm
            +
            +# From Jesper Norgaard Welen (2006-10-08):
            +# I think that there are some obvious mistakes in the suggested link
            +# from Oscar van Vlijmen,... for instance entry 66 says that GMT-4
            +# ended 1990-09-12 while entry 67 only begins GMT-3 at 1990-09-15
            +# (they should have been 1990-09-15 and 1990-09-16 respectively), but
            +# anyhow it clears up some doubts too.
            +
            +# From Paul Eggert (2006-12-27):
            +# The following data for Chile and America/Santiago are from
            +#  (2006-09-20), transcribed by
            +# Jesper Norgaard Welen.  The data for Pacific/Easter are from Shanks
            +# & Pottenger, except with DST transitions after 1932 cloned from
            +# America/Santiago.  The pre-1980 Pacific/Easter data are dubious,
            +# but we have no other source.
            +
            +# From German Poo-Caaman~o (2008-03-03):
            +# Due to drought, Chile extends Daylight Time in three weeks.  This
            +# is one-time change (Saturday 3/29 at 24:00 for America/Santiago
            +# and Saturday 3/29 at 22:00 for Pacific/Easter)
            +# The Supreme Decree is located at 
            +# 
            +# http://www.shoa.cl/servicios/supremo316.pdf
            +# 
            +# and the instructions for 2008 are located in:
            +# 
            +# http://www.horaoficial.cl/cambio.htm
            +# .
            +
            +# From Jose Miguel Garrido (2008-03-05):
            +# ...
            +# You could see the announces of the change on 
            +# 
            +# http://www.shoa.cl/noticias/2008/04hora/hora.htm
            +# .
            +
            +# From Angel Chiang (2010-03-04):
            +# Subject: DST in Chile exceptionally extended to 3 April due to earthquake
            +# 
            +# http://www.gobiernodechile.cl/viewNoticia.aspx?idArticulo=30098
            +# 
            +# (in Spanish, last paragraph).
             #
            -# My translation:
            +# This is breaking news. There should be more information available later.
            +
            +# From Arthur Daivd Olson (2010-03-06):
            +# Angel Chiang's message confirmed by Julio Pacheco; Julio provided a patch.
            +
            +# From Glenn Eychaner (2011-03-02): [geychaner@mac.com]
            +# It appears that the Chilean government has decided to postpone the
            +# change from summer time to winter time again, by three weeks to April
            +# 2nd:
            +# 
            +# http://www.emol.com/noticias/nacional/detalle/detallenoticias.asp?idnoticia=467651
            +# 
             #
            -# "The Chilean Army has announced that summer time will begin tomorrow,
            -# Saturday, October 14 in continental Chile, insular Chile, and
            -# Antarctica, as provided by Supreme Decree 25 of January 11, 1966.
            -# By the preceding, official time in continental Chile and Chilean
            -# Antarctic, and official time in Western Insular Chile, which applies
            -# to Easter Island and Sala y Gomez Island, will be set forward at
            -# midnight and at 22:00, respectively, by 20 minutes."
            +# This is not yet reflected in the offical "cambio de hora" site, but
            +# probably will be soon:
            +# 
            +# http://www.horaoficial.cl/cambio.htm
            +# 
             
            -# From Paul Eggert (2001-05-04):
            -# Go with this article in preference to Shanks's 1969 date for modern DST.
            -# Assume this rule has been used since DST was introduced in the islands.
            +# From Arthur David Olson (2011-03-02):
            +# The emol.com article mentions a water shortage as the cause of the
            +# postponement, which may mean that it's not a permanent change.
             
            -# From Paul Eggert (2002-10-24):
            -#  gives many details that
            -# disagree with the following table, but we haven't had time to compare them.
            +# From Glenn Eychaner (2011-03-28):
            +# The article:
            +# 
            +# http://diario.elmercurio.com/2011/03/28/_portada/_portada/noticias/7565897A-CA86-49E6-9E03-660B21A4883E.htm?id=3D{7565897A-CA86-49E6-9E03-660B21A4883E}
            +# 
            +#
            +# In English:
            +# Chile's clocks will go back an hour this year on the 7th of May instead
            +# of this Saturday. They will go forward again the 3rd Saturday in
            +# August, not in October as they have since 1968. This is a pilot plan
            +# which will be reevaluated in 2012.
             
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -Rule	Chile	1918	only	-	Sep	 1	0:00	1:00	S
            -Rule	Chile	1919	only	-	Jul	 2	0:00	0	-
            -Rule	Chile	1927	1931	-	Sep	 1	0:00	1:00	S
            +Rule	Chile	1927	1932	-	Sep	 1	0:00	1:00	S
             Rule	Chile	1928	1932	-	Apr	 1	0:00	0	-
            -Rule	Chile	1966	1997	-	Oct	Sun>=9	4:00u	1:00	S
            -Rule	Chile	1967	1998	-	Mar	Sun>=9	3:00u	0	-
            +Rule	Chile	1942	only	-	Jun	 1	4:00u	0	-
            +Rule	Chile	1942	only	-	Aug	 1	5:00u	1:00	S
            +Rule	Chile	1946	only	-	Jul	15	4:00u	1:00	S
            +Rule	Chile	1946	only	-	Sep	 1	3:00u	0:00	-
            +Rule	Chile	1947	only	-	Apr	 1	4:00u	0	-
            +Rule	Chile	1968	only	-	Nov	 3	4:00u	1:00	S
            +Rule	Chile	1969	only	-	Mar	30	3:00u	0	-
            +Rule	Chile	1969	only	-	Nov	23	4:00u	1:00	S
            +Rule	Chile	1970	only	-	Mar	29	3:00u	0	-
            +Rule	Chile	1971	only	-	Mar	14	3:00u	0	-
            +Rule	Chile	1970	1972	-	Oct	Sun>=9	4:00u	1:00	S
            +Rule	Chile	1972	1986	-	Mar	Sun>=9	3:00u	0	-
            +Rule	Chile	1973	only	-	Sep	30	4:00u	1:00	S
            +Rule	Chile	1974	1987	-	Oct	Sun>=9	4:00u	1:00	S
            +Rule	Chile	1987	only	-	Apr	12	3:00u	0	-
            +Rule	Chile	1988	1989	-	Mar	Sun>=9	3:00u	0	-
            +Rule	Chile	1988	only	-	Oct	Sun>=1	4:00u	1:00	S
            +Rule	Chile	1989	only	-	Oct	Sun>=9	4:00u	1:00	S
            +Rule	Chile	1990	only	-	Mar	18	3:00u	0	-
            +Rule	Chile	1990	only	-	Sep	16	4:00u	1:00	S
            +Rule	Chile	1991	1996	-	Mar	Sun>=9	3:00u	0	-
            +Rule	Chile	1991	1997	-	Oct	Sun>=9	4:00u	1:00	S
            +Rule	Chile	1997	only	-	Mar	30	3:00u	0	-
            +Rule	Chile	1998	only	-	Mar	Sun>=9	3:00u	0	-
             Rule	Chile	1998	only	-	Sep	27	4:00u	1:00	S
             Rule	Chile	1999	only	-	Apr	 4	3:00u	0	-
            -Rule	Chile	1999	max	-	Oct	Sun>=9	4:00u	1:00	S
            -Rule	Chile	2000	max	-	Mar	Sun>=9	3:00u	0	-
            -# IATA SSIM anomalies: (1990-09) says 1990-09-16; (1992-02) says 1992-03-14;
            +Rule	Chile	1999	2010	-	Oct	Sun>=9	4:00u	1:00	S
            +Rule	Chile	2011	only	-	Aug	Sun>=16	4:00u	1:00	S
            +Rule	Chile	2012	max	-	Oct	Sun>=9	4:00u	1:00	S
            +Rule	Chile	2000	2007	-	Mar	Sun>=9	3:00u	0	-
            +# N.B.: the end of March 29 in Chile is March 30 in Universal time,
            +# which is used below in specifying the transition.
            +Rule	Chile	2008	only	-	Mar	30	3:00u	0	-
            +Rule	Chile	2009	only	-	Mar	Sun>=9	3:00u	0	-
            +Rule	Chile	2010	only	-	Apr	Sun>=1	3:00u	0	-
            +Rule	Chile	2011	only	-	May	Sun>=2	3:00u	0	-
            +Rule	Chile	2012	max	-	Mar	Sun>=9	3:00u	0	-
            +# IATA SSIM anomalies: (1992-02) says 1992-03-14;
             # (1996-09) says 1998-03-08.  Ignore these.
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            -Zone America/Santiago	-4:42:40 -	LMT	1890
            -			-4:42:40 -	SMT	1910	    # Santiago Mean Time
            -			-5:00	Chile	CL%sT	1932 Sep    # Chile Time
            +Zone America/Santiago	-4:42:46 -	LMT	1890
            +			-4:42:46 -	SMT	1910 	    # Santiago Mean Time
            +			-5:00	-	CLT	1916 Jul  1 # Chile Time
            +			-4:42:46 -	SMT	1918 Sep  1 # Santiago Mean Time
            +			-4:00	-	CLT	1919 Jul  1 # Chile Time
            +			-4:42:46 -	SMT	1927 Sep  1 # Santiago Mean Time
            +			-5:00	Chile	CL%sT	1947 May 22 # Chile Time
             			-4:00	Chile	CL%sT
            -Zone Pacific/Easter	-7:17:28 -	LMT	1890	    # Mataveri
            -			-7:17:28 -	MMT	1932 Sep    # Mataveri Mean Time
            -			-7:00	Chile	EAS%sT	1982 Mar 14 # Easter I Time
            +Zone Pacific/Easter	-7:17:44 -	LMT	1890
            +			-7:17:28 -	EMT	1932 Sep    # Easter Mean Time
            +			-7:00	Chile	EAS%sT	1982 Mar 13 21:00 # Easter I Time
             			-6:00	Chile	EAS%sT
             #
             # Sala y Gomez Island is like Pacific/Easter.
             # Other Chilean locations, including Juan Fernandez Is, San Ambrosio,
             # San Felix, and Antarctic bases, are like America/Santiago.
             
             # Colombia
            -# Shanks specifies 24:00 for 1992 transition times; go with IATA,
            -# as it seems implausible to change clocks at midnight New Year's Eve.
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -Rule	CO	1992	only	-	May	 2	0:00	1:00	S
            -Rule	CO	1992	only	-	Dec	31	0:00	0	-
            +Rule	CO	1992	only	-	May	 3	0:00	1:00	S
            +Rule	CO	1993	only	-	Apr	 4	0:00	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	America/Bogota	-4:56:20 -	LMT	1884 Mar 13
             			-4:56:20 -	BMT	1914 Nov 23 # Bogota Mean Time
            @@ -791,16 +1290,42 @@
             # no information; probably like America/Bogota
             
             # Curacao
            -# Shanks says that Bottom and Oranjestad have been at -4:00 since
            -# standard time was introduced on 1912-03-02; and that Kralendijk and Rincon
            -# used Kralendijk Mean Time (-4:33:08) from 1912-02-02 to 1965-01-01.
            +#
            +# From Paul Eggert (2006-03-22):
            +# Shanks & Pottenger say that The Bottom and Philipsburg have been at
            +# -4:00 since standard time was introduced on 1912-03-02; and that
            +# Kralendijk and Rincon used Kralendijk Mean Time (-4:33:08) from
            +# 1912-02-02 to 1965-01-01.  The former is dubious, since S&P also say
            +# Saba Island has been like Curacao.
             # This all predates our 1970 cutoff, though.
            +#
            +# By July 2007 Curacao and St Maarten are planned to become
            +# associated states within the Netherlands, much like Aruba;
            +# Bonaire, Saba and St Eustatius would become directly part of the
            +# Netherlands as Kingdom Islands.  This won't affect their time zones
            +# though, as far as we know.
            +#
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	America/Curacao	-4:35:44 -	LMT	1912 Feb 12	# Willemstad
             			-4:30	-	ANT	1965 # Netherlands Antilles Time
             			-4:00	-	AST
             
            +# From Arthur David Olson (2011-06-15):
            +# At least for now, use links for places with new iso3166 codes.
            +# The name "Lower Prince's Quarter" is both longer than fourteen charaters
            +# and contains an apostrophe; use "Lower_Princes" below.
            +
            +Link	America/Curacao	America/Lower_Princes # Sint Maarten
            +Link	America/Curacao	America/Kralendijk # Bonaire, Sint Estatius and Saba
            +
             # Ecuador
            +#
            +# From Paul Eggert (2007-03-04):
            +# Apparently Ecuador had a failed experiment with DST in 1992.
            +#  (2007-02-27) and
            +#  (2006-11-06) both
            +# talk about "hora Sixto".  Leave this alone for now, as we have no data.
            +#
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Guayaquil	-5:19:20 -	LMT	1890
             			-5:14:00 -	QMT	1931 # Quito Mean Time
            @@ -811,9 +1336,9 @@
             
             # Falklands
             
            -# From Paul Eggert (2001-03-05):
            -# Between 1990 and 2000 inclusive, Shanks and the IATA agree except
            -# the IATA gives 1996-09-08.  Go with Shanks.
            +# From Paul Eggert (2006-03-22):
            +# Between 1990 and 2000 inclusive, Shanks & Pottenger and the IATA agree except
            +# the IATA gives 1996-09-08.  Go with Shanks & Pottenger.
             
             # From Falkland Islands Government Office, London (2001-01-22)
             # via Jesper Norgaard:
            @@ -860,6 +1385,24 @@
             # For now, we'll just record the time in Stanley, since we have no
             # better info.
             
            +# From Steffen Thorsen (2011-04-01):
            +# The Falkland Islands will not turn back clocks this winter, but stay on
            +# daylight saving time.
            +#
            +# One source:
            +# 
            +# http://www.falklandnews.com/public/story.cfm?get=5914&source=3
            +# 
            +#
            +# We have gotten this confirmed by a clerk of the legislative assembly:
            +# Normally the clocks revert to Local Mean Time (UTC/GMT -4 hours) on the
            +# third Sunday of April at 0200hrs and advance to Summer Time (UTC/GMT -3
            +# hours) on the first Sunday of September at 0200hrs.
            +#
            +# IMPORTANT NOTE: During 2011, on a trial basis, the Falkland Islands
            +# will not revert to local mean time, but clocks will remain on Summer
            +# time (UTC/GMT - 3 hours) throughout the whole of 2011.  Any long term
            +# change to local time following the trial period will be notified.
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Falk	1937	1938	-	Sep	lastSun	0:00	1:00	S
             Rule	Falk	1938	1942	-	Mar	Sun>=19	0:00	0	-
            @@ -871,7 +1414,8 @@
             Rule	Falk	1984	only	-	Sep	16	0:00	1:00	S
             Rule	Falk	1985	2000	-	Sep	Sun>=9	0:00	1:00	S
             Rule	Falk	1986	2000	-	Apr	Sun>=16	0:00	0	-
            -Rule	Falk	2001	max	-	Apr	Sun>=15	2:00	0	-
            +Rule	Falk	2001	2010	-	Apr	Sun>=15	2:00	0	-
            +Rule	Falk	2012	max	-	Apr	Sun>=15	2:00	0	-
             Rule	Falk	2001	max	-	Sep	Sun>=1	2:00	1:00	S
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone Atlantic/Stanley	-3:51:24 -	LMT	1890
            @@ -896,9 +1440,9 @@
             			-4:00	-	GYT
             
             # Paraguay
            -# From Paul Eggert (1999-10-29):
            -# Shanks (1999) says that spring transitions are from 01:00 -> 02:00,
            -# and autumn transitions are from 00:00 -> 23:00.  Go with earlier
            +# From Paul Eggert (2006-03-22):
            +# Shanks & Pottenger say that spring transitions are from 01:00 -> 02:00,
            +# and autumn transitions are from 00:00 -> 23:00.  Go with pre-1999
             # editions of Shanks, and with the IATA, who say transitions occur at 00:00.
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Para	1975	1988	-	Oct	 1	0:00	1:00	S
            @@ -929,23 +1473,45 @@
             # year, the time will change on the first Sunday of October; likewise, the
             # clock will be set back on the first Sunday of March.
             #
            -# From Jesper Norgaard (2001-03-06) [an official URL saying similar things]:
            -# http://gateway.abc.com.py:8000/pub/pag04.mbr/artic?FHA=2001-03-03-02.24.52.900592
            -#
             Rule	Para	1996	2001	-	Oct	Sun>=1	0:00	1:00	S
            -# IATA SSIM (1997-09) says Mar 1; go with Shanks.
            +# IATA SSIM (1997-09) says Mar 1; go with Shanks & Pottenger.
             Rule	Para	1997	only	-	Feb	lastSun	0:00	0	-
            -# Shanks says 1999-02-28; IATA SSIM (1999-02) says 1999-02-27, but
            +# Shanks & Pottenger say 1999-02-28; IATA SSIM (1999-02) says 1999-02-27, but
             # (1999-09) reports no date; go with above sources and Gerd Knops (2001-02-27).
             Rule	Para	1998	2001	-	Mar	Sun>=1	0:00	0	-
             # From Rives McDow (2002-02-28):
             # A decree was issued in Paraguay (no. 16350) on 2002-02-26 that changed the
             # dst method to be from the first Sunday in September to the first Sunday in
             # April.
            -Rule	Para	2002	max	-	Apr	Sun>=1	0:00	0	-
            -Rule	Para	2002	max	-	Sep	Sun>=1	0:00	1:00	S
            +Rule	Para	2002	2004	-	Apr	Sun>=1	0:00	0	-
            +Rule	Para	2002	2003	-	Sep	Sun>=1	0:00	1:00	S
            +#
            +# From Jesper Norgaard Welen (2005-01-02):
            +# There are several sources that claim that Paraguay made
            +# a timezone rule change in autumn 2004.
            +# From Steffen Thorsen (2005-01-05):
            +# Decree 1,867 (2004-03-05)
            +# From Carlos Raul Perasso via Jesper Norgaard Welen (2006-10-13)
            +# 
            +Rule	Para	2004	2009	-	Oct	Sun>=15	0:00	1:00	S
            +Rule	Para	2005	2009	-	Mar	Sun>=8	0:00	0	-
            +# From Carlos Raul Perasso (2010-02-18):
            +# By decree number 3958 issued yesterday (
            +# 
            +# http://www.presidencia.gov.py/v1/wp-content/uploads/2010/02/decreto3958.pdf
            +# 
            +# )
            +# Paraguay changes its DST schedule, postponing the March rule to April and
            +# modifying the October date. The decree reads:
            +# ...
            +# Art. 1. It is hereby established that from the second Sunday of the month of
            +# April of this year (2010), the official time is to be set back 60 minutes,
            +# and that on the first Sunday of the month of October, it is to be set
            +# forward 60 minutes, in all the territory of the Paraguayan Republic.
            +# ...
            +Rule	Para	2010	max	-	Oct	Sun>=1	0:00	1:00	S
            +Rule	Para	2010	max	-	Apr	Sun>=8	0:00	0	-
             
            -
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Asuncion	-3:50:40 -	LMT	1890
             			-3:50:40 -	AMT	1931 Oct 10 # Asuncion Mean Time
            @@ -957,11 +1523,11 @@
             #
             # 
             # From Evelyn C. Leeper via Mark Brader (2003-10-26):
            -# When we were in Peru in 1985-1986, they apparently switched over 
            +# When we were in Peru in 1985-1986, they apparently switched over
             # sometime between December 29 and January 3 while we were on the Amazon.
             #
            -# From Paul Eggert (2003-11-02):
            -# Shanks doesn't have this transition.  Assume 1986 was like 1987.
            +# From Paul Eggert (2006-03-22):
            +# Shanks & Pottenger don't have this transition.  Assume 1986 was like 1987.
             
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
             Rule	Peru	1938	only	-	Jan	 1	0:00	1:00	S
            @@ -972,7 +1538,7 @@
             Rule	Peru	1986	1987	-	Apr	 1	0:00	0	-
             Rule	Peru	1990	only	-	Jan	 1	0:00	1:00	S
             Rule	Peru	1990	only	-	Apr	 1	0:00	0	-
            -# IATA is ambiguous for 1993/1995; go with Shanks.
            +# IATA is ambiguous for 1993/1995; go with Shanks & Pottenger.
             Rule	Peru	1994	only	-	Jan	 1	0:00	1:00	S
             Rule	Peru	1994	only	-	Apr	 1	0:00	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
            @@ -1003,25 +1569,25 @@
             			-4:00	-	AST
             
             # Uruguay
            -# From Paul Eggert  (1993-11-18):
            +# From Paul Eggert (1993-11-18):
             # Uruguay wins the prize for the strangest peacetime manipulation of the rules.
            -# From Shanks:
            +# From Shanks & Pottenger:
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -# Whitman gives 1923 Oct 1; go with Shanks.
            +# Whitman gives 1923 Oct 1; go with Shanks & Pottenger.
             Rule	Uruguay	1923	only	-	Oct	 2	 0:00	0:30	HS
             Rule	Uruguay	1924	1926	-	Apr	 1	 0:00	0	-
             Rule	Uruguay	1924	1925	-	Oct	 1	 0:00	0:30	HS
             Rule	Uruguay	1933	1935	-	Oct	lastSun	 0:00	0:30	HS
            -# Shanks gives 1935 Apr 1 0:00 and 1936 Mar 30 0:00; go with Whitman.
            +# Shanks & Pottenger give 1935 Apr 1 0:00 & 1936 Mar 30 0:00; go with Whitman.
             Rule	Uruguay	1934	1936	-	Mar	Sat>=25	23:30s	0	-
             Rule	Uruguay	1936	only	-	Nov	 1	 0:00	0:30	HS
             Rule	Uruguay	1937	1941	-	Mar	lastSun	 0:00	0	-
            -# Whitman gives 1937 Oct 3; go with Shanks.
            +# Whitman gives 1937 Oct 3; go with Shanks & Pottenger.
             Rule	Uruguay	1937	1940	-	Oct	lastSun	 0:00	0:30	HS
             # Whitman gives 1941 Oct 24 - 1942 Mar 27, 1942 Dec 14 - 1943 Apr 13,
            -# and 1943 Apr 13 ``to present time''; go with Shanks.
            -Rule	Uruguay	1941	only	-	Aug	 1	 0:00	0	-
            -Rule	Uruguay	1942	only	-	Jan	 1	 0:00	0:30	HS
            +# and 1943 Apr 13 ``to present time''; go with Shanks & Pottenger.
            +Rule	Uruguay	1941	only	-	Aug	 1	 0:00	0:30	HS
            +Rule	Uruguay	1942	only	-	Jan	 1	 0:00	0	-
             Rule	Uruguay	1942	only	-	Dec	14	 0:00	1:00	S
             Rule	Uruguay	1943	only	-	Mar	14	 0:00	0	-
             Rule	Uruguay	1959	only	-	May	24	 0:00	1:00	S
            @@ -1047,7 +1613,7 @@
             Rule	Uruguay	1988	only	-	Dec	11	 0:00	1:00	S
             Rule	Uruguay	1989	only	-	Mar	12	 0:00	0	-
             Rule	Uruguay	1989	only	-	Oct	29	 0:00	1:00	S
            -# Shanks says no DST was observed in 1990/1 and 1991/2,
            +# Shanks & Pottenger say no DST was observed in 1990/1 and 1991/2,
             # and that 1992/3's DST was from 10-25 to 03-01.  Go with IATA.
             Rule	Uruguay	1990	1992	-	Mar	Sun>=1	 0:00	0	-
             Rule	Uruguay	1990	1991	-	Oct	Sun>=21	 0:00	1:00	S
            @@ -1056,17 +1622,41 @@
             # From Eduardo Cota (2004-09-20):
             # The uruguayan government has decreed a change in the local time....
             # http://www.presidencia.gub.uy/decretos/2004091502.htm
            -Rule	Uruguay	2004	only	-	Sep	Sun>=15	 0:00	1:00	S
            -Rule	Uruguay	2005	only	-	Mar	Sun>=8	 0:00	0	-
            +Rule	Uruguay	2004	only	-	Sep	19	 0:00	1:00	S
            +# From Steffen Thorsen (2005-03-11):
            +# Uruguay's DST was scheduled to end on Sunday, 2005-03-13, but in order to
            +# save energy ... it was postponed two weeks....
            +# http://www.presidencia.gub.uy/_Web/noticias/2005/03/2005031005.htm
            +Rule	Uruguay	2005	only	-	Mar	27	 2:00	0	-
            +# From Eduardo Cota (2005-09-27):
            +# http://www.presidencia.gub.uy/_Web/decretos/2005/09/CM%20119_09%2009%202005_00001.PDF
            +# This means that from 2005-10-09 at 02:00 local time, until 2006-03-12 at
            +# 02:00 local time, official time in Uruguay will be at GMT -2.
            +Rule	Uruguay	2005	only	-	Oct	 9	 2:00	1:00	S
            +Rule	Uruguay	2006	only	-	Mar	12	 2:00	0	-
            +# From Jesper Norgaard Welen (2006-09-06):
            +# http://www.presidencia.gub.uy/_web/decretos/2006/09/CM%20210_08%2006%202006_00001.PDF
            +Rule	Uruguay	2006	max	-	Oct	Sun>=1	 2:00	1:00	S
            +Rule	Uruguay	2007	max	-	Mar	Sun>=8	 2:00	0	-
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone America/Montevideo	-3:44:44 -	LMT	1898 Jun 28
             			-3:44:44 -	MMT	1920 May  1	# Montevideo MT
             			-3:30	Uruguay	UY%sT	1942 Dec 14	# Uruguay Time
             			-3:00	Uruguay	UY%sT
             
             # Venezuela
            +#
            +# From John Stainforth (2007-11-28):
            +# ... the change for Venezuela originally expected for 2007-12-31 has
            +# been brought forward to 2007-12-09.  The official announcement was
            +# published today in the "Gaceta Oficial de la Republica Bolivariana
            +# de Venezuela, numero 38.819" (official document for all laws or
            +# resolution publication)
            +# http://www.globovision.com/news.php?nid=72208
            +
             # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
             Zone	America/Caracas	-4:27:44 -	LMT	1890
             			-4:27:40 -	CMT	1912 Feb 12 # Caracas Mean Time?
             			-4:30	-	VET	1965	     # Venezuela Time
            -			-4:00	-	VET
            +			-4:00	-	VET	2007 Dec  9 03:00
            +			-4:30	-	VET
            Index: 3rdParty_sources/joda-time/org/joda/time/tz/src/systemv
            ===================================================================
            diff -u -r4e266757c429613d78b0fd2914d40d77a447daad -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/joda-time/org/joda/time/tz/src/systemv	(.../systemv)	(revision 4e266757c429613d78b0fd2914d40d77a447daad)
            +++ 3rdParty_sources/joda-time/org/joda/time/tz/src/systemv	(.../systemv)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -1,24 +1,27 @@
            -# @(#)systemv	7.3
            +# 
            +# @(#)systemv	8.2
            +# This file is in the public domain, so clarified as of
            +# 2009-05-17 by Arthur David Olson.
             
             # Old rules, should the need arise.
             # No attempt is made to handle Newfoundland, since it cannot be expressed
             # using the System V "TZ" scheme (half-hour offset), or anything outside
             # North America (no support for non-standard DST start/end dates), nor
            -# the change in the DST rules in the US in 1987 (which occurred before
            +# the changes in the DST rules in the US after 1976 (which occurred after
             # the old rules were written).
             #
            -# If you need the old rules, uncomment ## lines and comment-out Link lines.
            +# If you need the old rules, uncomment ## lines.
             # Compile this *without* leap second correction for true conformance.
             
             # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
            -## Rule	SystemV	min	1973	-	Apr	lastSun	2:00	1:00	D
            -## Rule	SystemV	min	1973	-	Oct	lastSun	2:00	0	S
            -## Rule	SystemV	1974	only	-	Jan	6	2:00	1:00	D
            -## Rule	SystemV	1974	only	-	Nov	lastSun	2:00	0	S
            -## Rule	SystemV	1975	only	-	Feb	23	2:00	1:00	D
            -## Rule	SystemV	1975	only	-	Oct	lastSun	2:00	0	S
            -## Rule	SystemV	1976	max	-	Apr	lastSun	2:00	1:00	D
            -## Rule	SystemV	1976	max	-	Oct	lastSun	2:00	0	S
            +Rule	SystemV	min	1973	-	Apr	lastSun	2:00	1:00	D
            +Rule	SystemV	min	1973	-	Oct	lastSun	2:00	0	S
            +Rule	SystemV	1974	only	-	Jan	6	2:00	1:00	D
            +Rule	SystemV	1974	only	-	Nov	lastSun	2:00	0	S
            +Rule	SystemV	1975	only	-	Feb	23	2:00	1:00	D
            +Rule	SystemV	1975	only	-	Oct	lastSun	2:00	0	S
            +Rule	SystemV	1976	max	-	Apr	lastSun	2:00	1:00	D
            +Rule	SystemV	1976	max	-	Oct	lastSun	2:00	0	S
             
             # Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
             ## Zone	SystemV/AST4ADT	-4:00	SystemV		A%sT
            @@ -34,17 +37,3 @@
             ## Zone	SystemV/PST8	-8:00	-		PST
             ## Zone	SystemV/YST9	-9:00	-		YST
             ## Zone	SystemV/HST10	-10:00	-		HST
            -# For now...
            -Link	America/Halifax		SystemV/AST4ADT
            -Link	America/New_York	SystemV/EST5EDT
            -Link	America/Chicago		SystemV/CST6CDT
            -Link	America/Denver		SystemV/MST7MDT
            -Link	America/Los_Angeles	SystemV/PST8PDT
            -Link	America/Anchorage	SystemV/YST9YDT
            -Link	America/Puerto_Rico	SystemV/AST4
            -Link	America/Indianapolis	SystemV/EST5
            -Link	America/Regina		SystemV/CST6
            -Link	America/Phoenix		SystemV/MST7
            -Link	Pacific/Pitcairn	SystemV/PST8
            -Link	Pacific/Gambier		SystemV/YST9
            -Link	Pacific/Honolulu	SystemV/HST10
            Index: 3rdParty_sources/opensaml/org/opensaml/saml1/core/impl/SubjectConfirmationUnmarshaller.java
            ===================================================================
            diff -u -r2e3463e873227c6a3edcb3e02d55270219e553ff -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/opensaml/org/opensaml/saml1/core/impl/SubjectConfirmationUnmarshaller.java	(.../SubjectConfirmationUnmarshaller.java)	(revision 2e3463e873227c6a3edcb3e02d55270219e553ff)
            +++ 3rdParty_sources/opensaml/org/opensaml/saml1/core/impl/SubjectConfirmationUnmarshaller.java	(.../SubjectConfirmationUnmarshaller.java)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -22,6 +22,7 @@
             import org.opensaml.saml1.core.SubjectConfirmation;
             import org.opensaml.xml.XMLObject;
             import org.opensaml.xml.io.UnmarshallingException;
            +import org.opensaml.xml.signature.KeyInfo;
             
             /**
              * A thread-safe Unmarshaller for {@link org.opensaml.saml1.core.SubjectConfirmation} objects.
            @@ -36,6 +37,8 @@
             
                     if (childSAMLObject instanceof ConfirmationMethod) {
                         subjectConfirmation.getConfirmationMethods().add((ConfirmationMethod) childSAMLObject);
            +        } else if(childSAMLObject instanceof KeyInfo) {
            +            subjectConfirmation.setKeyInfo((KeyInfo)childSAMLObject);
                     } else {
                         subjectConfirmation.setSubjectConfirmationData(childSAMLObject);
                     }
            Index: 3rdParty_sources/opensaml/org/opensaml/saml2/metadata/provider/AbstractReloadingMetadataProvider.java
            ===================================================================
            diff -u -r2e3463e873227c6a3edcb3e02d55270219e553ff -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/opensaml/org/opensaml/saml2/metadata/provider/AbstractReloadingMetadataProvider.java	(.../AbstractReloadingMetadataProvider.java)	(revision 2e3463e873227c6a3edcb3e02d55270219e553ff)
            +++ 3rdParty_sources/opensaml/org/opensaml/saml2/metadata/provider/AbstractReloadingMetadataProvider.java	(.../AbstractReloadingMetadataProvider.java)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -62,16 +62,16 @@
                 /** Current task to refresh metadata. */
                 private RefreshMetadataTask refresMetadataTask;
             
            -    /** Factor used to compute when the next refresh interval will occur. Default value: {@value} */
            +    /** Factor used to compute when the next refresh interval will occur. Default value: 0.75 */
                 private float refreshDelayFactor = 0.75f;
             
                 /**
                  * Refresh interval used when metadata does not contain any validUntil or cacheDuration information. Default value:
            -     * * {@value} ms
            +     * 14400000ms
                  */
                 private long maxRefreshDelay = 14400000;
             
            -    /** Floor, in milliseconds, for the refresh interval. Default value: {@value} ms */
            +    /** Floor, in milliseconds, for the refresh interval. Default value: 300000ms */
                 private int minRefreshDelay = 300000;
             
                 /** Time when the currently cached metadata file expires. */
            Index: 3rdParty_sources/opensaml/org/opensaml/saml2/metadata/provider/HTTPMetadataProvider.java
            ===================================================================
            diff -u -r2e3463e873227c6a3edcb3e02d55270219e553ff -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/opensaml/org/opensaml/saml2/metadata/provider/HTTPMetadataProvider.java	(.../HTTPMetadataProvider.java)	(revision 2e3463e873227c6a3edcb3e02d55270219e553ff)
            +++ 3rdParty_sources/opensaml/org/opensaml/saml2/metadata/provider/HTTPMetadataProvider.java	(.../HTTPMetadataProvider.java)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -272,6 +272,8 @@
                         String errMsg = "Error retrieving metadata from " + metadataURI;
                         log.error(errMsg, e);
                         throw new MetadataProviderException(errMsg, e);
            +        }finally{
            +            getMethod.releaseConnection();
                     }
                 }
             
            @@ -284,6 +286,7 @@
                  */
                 protected GetMethod buildGetMethod() {
                     GetMethod getMethod = new GetMethod(getMetadataURI());
            +        getMethod.addRequestHeader("Connection", "close");
             
                     getMethod.setRequestHeader("Accept-Encoding", "gzip,deflate");
                     if (cachedMetadataETag != null) {
            Index: 3rdParty_sources/opensaml/org/opensaml/xacml/policy/impl/AttributeDesignatorTypeImplBuilder.java
            ===================================================================
            diff -u -r2e3463e873227c6a3edcb3e02d55270219e553ff -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/opensaml/org/opensaml/xacml/policy/impl/AttributeDesignatorTypeImplBuilder.java	(.../AttributeDesignatorTypeImplBuilder.java)	(revision 2e3463e873227c6a3edcb3e02d55270219e553ff)
            +++ 3rdParty_sources/opensaml/org/opensaml/xacml/policy/impl/AttributeDesignatorTypeImplBuilder.java	(.../AttributeDesignatorTypeImplBuilder.java)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -17,7 +17,6 @@
             
             package org.opensaml.xacml.policy.impl;
             
            -import org.opensaml.saml1.core.AttributeDesignator;
             import org.opensaml.xacml.impl.AbstractXACMLObjectBuilder;
             import org.opensaml.xacml.policy.AttributeDesignatorType;
             
            @@ -33,7 +32,7 @@
             
                 /** {@inheritDoc} */
                 public AttributeDesignatorType buildObject() {
            -        return buildObject(AttributeDesignator.DEFAULT_ELEMENT_NAME);
            +        return buildObject(AttributeDesignatorType.DEFAULT_ELEMENT_NAME_XACML20);
                 }
             
             }
            Index: 3rdParty_sources/openws/org/opensaml/util/resource/HttpResource.java
            ===================================================================
            diff -u -r2e3463e873227c6a3edcb3e02d55270219e553ff -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/openws/org/opensaml/util/resource/HttpResource.java	(.../HttpResource.java)	(revision 2e3463e873227c6a3edcb3e02d55270219e553ff)
            +++ 3rdParty_sources/openws/org/opensaml/util/resource/HttpResource.java	(.../HttpResource.java)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -22,6 +22,7 @@
             
             import org.apache.commons.httpclient.Header;
             import org.apache.commons.httpclient.HttpClient;
            +import org.apache.commons.httpclient.HttpMethod;
             import org.apache.commons.httpclient.HttpStatus;
             import org.apache.commons.httpclient.methods.GetMethod;
             import org.apache.commons.httpclient.methods.HeadMethod;
            @@ -49,15 +50,15 @@
                  */
                 public HttpResource(String resource) {
                     super();
            -        
            +
                     resourceUrl = DatatypeHelper.safeTrimOrNullString(resource);
                     if (resourceUrl == null) {
                         throw new IllegalArgumentException("Resource URL may not be null or empty");
                     }
             
                     httpClient = new HttpClient();
                 }
            -    
            +
                 /**
                  * Constructor.
                  * 
            @@ -68,7 +69,7 @@
                  */
                 public HttpResource(String resource, ResourceFilter resourceFilter) {
                     super(resourceFilter);
            -        
            +
                     resourceUrl = DatatypeHelper.safeTrimOrNullString(resource);
                     if (resourceUrl == null) {
                         throw new IllegalArgumentException("Resource URL may not be null or empty");
            @@ -80,6 +81,7 @@
                 /** {@inheritDoc} */
                 public boolean exists() throws ResourceException {
                     HeadMethod headMethod = new HeadMethod(resourceUrl);
            +        headMethod.addRequestHeader("Connection", "close");
             
                     try {
                         httpClient.executeMethod(headMethod);
            @@ -90,14 +92,16 @@
                         return true;
                     } catch (IOException e) {
                         throw new ResourceException("Unable to contact resource URL: " + resourceUrl, e);
            +        } finally {
            +            headMethod.releaseConnection();
                     }
                 }
             
                 /** {@inheritDoc} */
                 public InputStream getInputStream() throws ResourceException {
                     GetMethod getMethod = getResource();
                     try {
            -            return applyFilter(getMethod.getResponseBodyAsStream());
            +            return new ConnectionClosingInputStream(getMethod, applyFilter(getMethod.getResponseBodyAsStream()));
                     } catch (IOException e) {
                         throw new ResourceException("Unable to read response", e);
                     }
            @@ -106,6 +110,7 @@
                 /** {@inheritDoc} */
                 public DateTime getLastModifiedTime() throws ResourceException {
                     HeadMethod headMethod = new HeadMethod(resourceUrl);
            +        headMethod.addRequestHeader("Connection", "close");
             
                     try {
                         httpClient.executeMethod(headMethod);
            @@ -114,7 +119,7 @@
                                     + ", received HTTP status code " + headMethod.getStatusCode());
                         }
                         Header lastModifiedHeader = headMethod.getResponseHeader("Last-Modified");
            -            if (lastModifiedHeader != null  && ! DatatypeHelper.isEmpty(lastModifiedHeader.getValue())) {
            +            if (lastModifiedHeader != null && !DatatypeHelper.isEmpty(lastModifiedHeader.getValue())) {
                             long lastModifiedTime = DateUtil.parseDate(lastModifiedHeader.getValue()).getTime();
                             return new DateTime(lastModifiedTime, ISOChronology.getInstanceUTC());
                         }
            @@ -124,6 +129,8 @@
                         throw new ResourceException("Unable to contact resource URL: " + resourceUrl, e);
                     } catch (DateParseException e) {
                         throw new ResourceException("Unable to parse last modified date for resource:" + resourceUrl, e);
            +        } finally {
            +            headMethod.releaseConnection();
                     }
                 }
             
            @@ -164,6 +171,7 @@
                  */
                 protected GetMethod getResource() throws ResourceException {
                     GetMethod getMethod = new GetMethod(resourceUrl);
            +        getMethod.addRequestHeader("Connection", "close");
             
                     try {
                         httpClient.executeMethod(getMethod);
            @@ -176,4 +184,74 @@
                         throw new ResourceException("Unable to contact resource URL: " + resourceUrl, e);
                     }
                 }
            +
            +    /**
            +     * A wrapper around the {@link InputStream} returned by a {@link HttpMethod} that closes the stream and releases the
            +     * HTTP connection when {@link #close()} is invoked.
            +     */
            +    private static class ConnectionClosingInputStream extends InputStream {
            +
            +        /** HTTP method that was invoked. */
            +        private final HttpMethod method;
            +
            +        /** Stream owned by the given HTTP method. */
            +        private final InputStream stream;
            +
            +        /**
            +         * Constructor.
            +         *
            +         * @param httpMethod HTTP method that was invoked
            +         * @param returnedStream stream owned by the given HTTP method
            +         */
            +        public ConnectionClosingInputStream(HttpMethod httpMethod, InputStream returnedStream) {
            +            method = httpMethod;
            +            stream = returnedStream;
            +        }
            +
            +        /** {@inheritDoc} */
            +        public int available() throws IOException {
            +            return stream.available();
            +        }
            +
            +        /** {@inheritDoc} */
            +        public void close() throws IOException {
            +            stream.close();
            +            method.releaseConnection();
            +        }
            +
            +        /** {@inheritDoc} */
            +        public void mark(int readLimit) {
            +            stream.mark(readLimit);
            +        }
            +
            +        /** {@inheritDoc} */
            +        public boolean markSupported() {
            +            return stream.markSupported();
            +        }
            +
            +        /** {@inheritDoc} */
            +        public int read() throws IOException {
            +            return stream.read();
            +        }
            +
            +        /** {@inheritDoc} */
            +        public int read(byte[] b) throws IOException {
            +            return stream.read(b);
            +        }
            +
            +        /** {@inheritDoc} */
            +        public int read(byte[] b, int off, int len) throws IOException {
            +            return stream.read(b, off, len);
            +        }
            +
            +        /** {@inheritDoc} */
            +        public synchronized void reset() throws IOException {
            +            stream.reset();
            +        }
            +
            +        /** {@inheritDoc} */
            +        public long skip(long n) throws IOException {
            +            return stream.skip(n);
            +        }
            +    }
             }
            \ No newline at end of file
            Index: 3rdParty_sources/versions.txt
            ===================================================================
            diff -u -r3d0166b43ce990fd9f27c433a1c58cc61085ecf4 -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/versions.txt	(.../versions.txt)	(revision 3d0166b43ce990fd9f27c433a1c58cc61085ecf4)
            +++ 3rdParty_sources/versions.txt	(.../versions.txt)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -24,7 +24,7 @@
             
             jgroups 2.6.10
             
            -Joda Time 0.98
            +Joda Time 2.1
             
             Joid 1.1
             
            @@ -35,9 +35,9 @@
             
             opencsv 1.8
             
            -opensaml 2.5.2
            +opensaml 2.5.3
             
            -openws 1.4.3
            +openws 1.4.4
             
             Quartz 1.5.2
             
            @@ -47,4 +47,6 @@
             
             Strutstest 2.1.3
             
            -xmltooling 1.3.3
            \ No newline at end of file
            +xmltooling 1.3.4
            +
            +XStream 1.1.3
            \ No newline at end of file
            Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSBoolean.java
            ===================================================================
            diff -u -r2e3463e873227c6a3edcb3e02d55270219e553ff -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSBoolean.java	(.../XSBoolean.java)	(revision 2e3463e873227c6a3edcb3e02d55270219e553ff)
            +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSBoolean.java	(.../XSBoolean.java)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -17,13 +17,20 @@
             
             package org.opensaml.xml.schema;
             
            +import javax.xml.namespace.QName;
            +
            +import org.opensaml.xml.util.XMLConstants;
             import org.opensaml.xml.validation.ValidatingXMLObject;
             
            -/**
            - * XSBoolean is the xs:boolean schema type.
            - */
            +/** XSBoolean is the xs:boolean schema type. */
             public abstract interface XSBoolean extends ValidatingXMLObject {
             
            +    /** Local name of the XSI type. */
            +    public static final String TYPE_LOCAL_NAME = "boolean"; 
            +            
            +    /** QName of the XSI type. */
            +    public static final QName TYPE_NAME = new QName(XMLConstants.XSD_NS, TYPE_LOCAL_NAME, XMLConstants.XSD_PREFIX);
            +    
                 /**
                  * Returns the XSBooleanValue value.
                  * 
            Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBooleanBuilder.java
            ===================================================================
            diff -u
            --- 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBooleanBuilder.java	(revision 0)
            +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBooleanBuilder.java	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -0,0 +1,30 @@
            +/*
            + * Licensed to the University Corporation for Advanced Internet Development, 
            + * Inc. (UCAID) under one or more contributor license agreements.  See the 
            + * NOTICE file distributed with this work for additional information regarding
            + * copyright ownership. The UCAID licenses this file to You under the Apache 
            + * License, Version 2.0 (the "License"); you may not use this file except in 
            + * compliance with the License.  You may obtain a copy of the License at
            + *
            + *    http://www.apache.org/licenses/LICENSE-2.0
            + *
            + * Unless required by applicable law or agreed to in writing, software
            + * distributed under the License is distributed on an "AS IS" BASIS,
            + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
            + * See the License for the specific language governing permissions and
            + * limitations under the License.
            + */
            +
            +package org.opensaml.xml.schema.impl;
            +
            +import org.opensaml.xml.AbstractXMLObjectBuilder;
            +import org.opensaml.xml.schema.XSBoolean;
            +
            +/** Builder of {@link org.opensaml.xml.schema.impl.XSBooleanImpl} objects. */
            +public class XSBooleanBuilder extends AbstractXMLObjectBuilder {
            +
            +    /** {@inheritDoc} */
            +    public XSBoolean buildObject(String namespaceURI, String localName, String namespacePrefix) {
            +        return new XSBooleanImpl(namespaceURI, localName, namespacePrefix);
            +    }
            +}
            \ No newline at end of file
            Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBooleanImpl.java
            ===================================================================
            diff -u
            --- 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBooleanImpl.java	(revision 0)
            +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBooleanImpl.java	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -0,0 +1,65 @@
            +/*
            + * Licensed to the University Corporation for Advanced Internet Development, 
            + * Inc. (UCAID) under one or more contributor license agreements.  See the 
            + * NOTICE file distributed with this work for additional information regarding
            + * copyright ownership. The UCAID licenses this file to You under the Apache 
            + * License, Version 2.0 (the "License"); you may not use this file except in 
            + * compliance with the License.  You may obtain a copy of the License at
            + *
            + *    http://www.apache.org/licenses/LICENSE-2.0
            + *
            + * Unless required by applicable law or agreed to in writing, software
            + * distributed under the License is distributed on an "AS IS" BASIS,
            + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
            + * See the License for the specific language governing permissions and
            + * limitations under the License.
            + */
            +
            +package org.opensaml.xml.schema.impl;
            +
            +import java.util.List;
            +
            +import org.opensaml.xml.XMLObject;
            +import org.opensaml.xml.schema.XSBoolean;
            +import org.opensaml.xml.schema.XSBooleanValue;
            +import org.opensaml.xml.validation.AbstractValidatingXMLObject;
            +
            +/** Concrete implementation of {@link org.opensaml.xml.schema.XSBoolean}. */
            +public class XSBooleanImpl extends AbstractValidatingXMLObject implements XSBoolean {
            +
            +    /** Value of this string element. */
            +    private XSBooleanValue value;
            +
            +    /**
            +     * Constructor.
            +     * 
            +     * @param namespaceURI the namespace the element is in
            +     * @param elementLocalName the local name of the XML element this Object represents
            +     * @param namespacePrefix the prefix for the given namespace
            +     */
            +    protected XSBooleanImpl(String namespaceURI, String elementLocalName, String namespacePrefix) {
            +        super(namespaceURI, elementLocalName, namespacePrefix);
            +    }
            +
            +    /**
            +     * {@inheritDoc}
            +     */
            +    public XSBooleanValue getValue() {
            +        return value;
            +    }
            +
            +    /**
            +     * {@inheritDoc}
            +     */
            +    public void setValue(XSBooleanValue newValue) {
            +        value = prepareForAssignment(value, newValue);
            +    }
            +
            +    /**
            +     * {@inheritDoc}
            +     */
            +    public List getOrderedChildren() {
            +        // no children
            +        return null;
            +    }
            +}
            \ No newline at end of file
            Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBooleanMarshaller.java
            ===================================================================
            diff -u
            --- 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBooleanMarshaller.java	(revision 0)
            +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBooleanMarshaller.java	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -0,0 +1,41 @@
            +/*
            + * Licensed to the University Corporation for Advanced Internet Development, 
            + * Inc. (UCAID) under one or more contributor license agreements.  See the 
            + * NOTICE file distributed with this work for additional information regarding
            + * copyright ownership. The UCAID licenses this file to You under the Apache 
            + * License, Version 2.0 (the "License"); you may not use this file except in 
            + * compliance with the License.  You may obtain a copy of the License at
            + *
            + *    http://www.apache.org/licenses/LICENSE-2.0
            + *
            + * Unless required by applicable law or agreed to in writing, software
            + * distributed under the License is distributed on an "AS IS" BASIS,
            + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
            + * See the License for the specific language governing permissions and
            + * limitations under the License.
            + */
            +
            +package org.opensaml.xml.schema.impl;
            +
            +import org.opensaml.xml.XMLObject;
            +import org.opensaml.xml.io.AbstractXMLObjectMarshaller;
            +import org.opensaml.xml.io.MarshallingException;
            +import org.opensaml.xml.schema.XSBoolean;
            +import org.opensaml.xml.util.XMLHelper;
            +import org.w3c.dom.Element;
            +
            +/** Thread-safe marshaller of {@link org.opensaml.xml.schema.XSBoolean} objects. */
            +public class XSBooleanMarshaller extends AbstractXMLObjectMarshaller {
            +
            +    /** {@inheritDoc} */
            +    protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException {
            +        // no attributes
            +    }
            +
            +    /** {@inheritDoc} */
            +    protected void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException {
            +        XSBoolean xsiBoolean = (XSBoolean) xmlObject;
            +
            +        XMLHelper.appendTextContent(domElement, xsiBoolean.getValue().getValue().toString());
            +    }
            +}
            \ No newline at end of file
            Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBooleanUnmarshaller.java
            ===================================================================
            diff -u
            --- 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBooleanUnmarshaller.java	(revision 0)
            +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBooleanUnmarshaller.java	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -0,0 +1,46 @@
            +/*
            + * Licensed to the University Corporation for Advanced Internet Development, 
            + * Inc. (UCAID) under one or more contributor license agreements.  See the 
            + * NOTICE file distributed with this work for additional information regarding
            + * copyright ownership. The UCAID licenses this file to You under the Apache 
            + * License, Version 2.0 (the "License"); you may not use this file except in 
            + * compliance with the License.  You may obtain a copy of the License at
            + *
            + *    http://www.apache.org/licenses/LICENSE-2.0
            + *
            + * Unless required by applicable law or agreed to in writing, software
            + * distributed under the License is distributed on an "AS IS" BASIS,
            + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
            + * See the License for the specific language governing permissions and
            + * limitations under the License.
            + */
            +
            +package org.opensaml.xml.schema.impl;
            +
            +import org.opensaml.xml.XMLObject;
            +import org.opensaml.xml.io.AbstractXMLObjectUnmarshaller;
            +import org.opensaml.xml.io.UnmarshallingException;
            +import org.opensaml.xml.schema.XSBoolean;
            +import org.opensaml.xml.schema.XSBooleanValue;
            +import org.w3c.dom.Attr;
            +
            +/** Thread-safe unmarshaller for {@link org.opensaml.xml.schema.XSBoolean} objects. */
            +public class XSBooleanUnmarshaller extends AbstractXMLObjectUnmarshaller {
            +
            +    /** {@inheritDoc} */
            +    protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject)
            +            throws UnmarshallingException {
            +        // no children
            +    }
            +
            +    /** {@inheritDoc} */
            +    protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException {
            +        // no attributes
            +    }
            +
            +    /** {@inheritDoc} */
            +    protected void processElementContent(XMLObject xmlObject, String elementContent) {
            +        XSBoolean xsiBoolean = (XSBoolean) xmlObject;
            +        xsiBoolean.setValue(XSBooleanValue.valueOf(elementContent));
            +    }
            +}
            \ No newline at end of file
            Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/CertPathPKIXTrustEvaluator.java
            ===================================================================
            diff -u -r2e3463e873227c6a3edcb3e02d55270219e553ff -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d
            --- 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/CertPathPKIXTrustEvaluator.java	(.../CertPathPKIXTrustEvaluator.java)	(revision 2e3463e873227c6a3edcb3e02d55270219e553ff)
            +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/CertPathPKIXTrustEvaluator.java	(.../CertPathPKIXTrustEvaluator.java)	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -50,7 +50,10 @@
                 /** Class logger. */
                 private final Logger log = LoggerFactory.getLogger(CertPathPKIXTrustEvaluator.class);
                 
            -    /** Responsible for parsing and serializing X.500 names to/from {@link X500Principal} instances. */
            +    /** 
            +     * Responsible for parsing and serializing X.500 names to/from {@link javax.security.auth.x500.X500Principal} 
            +     * instances.
            +     */
                 private X500DNHandler x500DNHandler;
                 
                 /** Options influencing processing behavior. */
            Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/MarshallingStrategy.java
            ===================================================================
            diff -u
            --- 3rdParty_sources/xstream/com/thoughtworks/xstream/MarshallingStrategy.java	(revision 0)
            +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/MarshallingStrategy.java	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -0,0 +1,15 @@
            +package com.thoughtworks.xstream;
            +
            +import com.thoughtworks.xstream.io.HierarchicalStreamReader;
            +import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
            +import com.thoughtworks.xstream.core.DefaultConverterLookup;
            +import com.thoughtworks.xstream.alias.ClassMapper;
            +import com.thoughtworks.xstream.converters.DataHolder;
            +
            +public interface MarshallingStrategy {
            +
            +    Object unmarshal(Object root, HierarchicalStreamReader reader, DataHolder dataHolder, DefaultConverterLookup converterLookup, ClassMapper classMapper);
            +
            +    void marshal(HierarchicalStreamWriter writer, Object obj, DefaultConverterLookup converterLookup, ClassMapper classMapper, DataHolder dataHolder);
            +
            +}
            Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/XStream.java
            ===================================================================
            diff -u
            --- 3rdParty_sources/xstream/com/thoughtworks/xstream/XStream.java	(revision 0)
            +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/XStream.java	(revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d)
            @@ -0,0 +1,861 @@
            +package com.thoughtworks.xstream;
            +
            +import com.thoughtworks.xstream.alias.ClassMapper;
            +import com.thoughtworks.xstream.converters.Converter;
            +import com.thoughtworks.xstream.converters.ConverterLookup;
            +import com.thoughtworks.xstream.converters.DataHolder;
            +import com.thoughtworks.xstream.converters.basic.*;
            +import com.thoughtworks.xstream.converters.collections.*;
            +import com.thoughtworks.xstream.converters.extended.*;
            +import com.thoughtworks.xstream.converters.reflection.ExternalizableConverter;
            +import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
            +import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
            +import com.thoughtworks.xstream.converters.reflection.SerializableConverter;
            +import com.thoughtworks.xstream.core.*;
            +import com.thoughtworks.xstream.core.util.ClassLoaderReference;
            +import com.thoughtworks.xstream.core.util.CompositeClassLoader;
            +import com.thoughtworks.xstream.core.util.CustomObjectInputStream;
            +import com.thoughtworks.xstream.core.util.CustomObjectOutputStream;
            +import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
            +import com.thoughtworks.xstream.io.HierarchicalStreamReader;
            +import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
            +import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
            +import com.thoughtworks.xstream.io.xml.XppDriver;
            +import com.thoughtworks.xstream.mapper.*;
            +
            +import java.io.*;
            +import java.lang.reflect.Constructor;
            +import java.lang.reflect.Method;
            +import java.math.BigDecimal;
            +import java.math.BigInteger;
            +import java.net.URL;
            +import java.sql.Time;
            +import java.sql.Timestamp;
            +import java.util.*;
            +
            +/**
            + * Simple facade to XStream library, a Java-XML serialization tool.
            + * 

            + *


            Example
            + * XStream xstream = new XStream();
            + * String xml = xstream.toXML(myObject); // serialize to XML
            + * Object myObject2 = xstream.fromXML(xml); // deserialize from XML
            + * 

            + *

            + *

            Aliasing classes

            + *

            + *

            To create shorter XML, you can specify aliases for classes using + * the alias() method. + * For example, you can shorten all occurences of element + * <com.blah.MyThing> to + * <my-thing> by registering an alias for the class. + *


            + * xstream.alias("my-thing", MyThing.class);
            + * 

            + *

            + *

            Converters

            + *

            + *

            XStream contains a map of {@link com.thoughtworks.xstream.converters.Converter} + * instances, each of which acts as a strategy for converting a particular type + * of class to XML and back again. Out of the box, XStream contains converters + * for most basic types (String, Date, int, boolean, etc) and collections (Map, List, + * Set, Properties, etc). For other objects reflection is used to serialize + * each field recursively.

            + *

            + *

            Extra converters can be registered using the registerConverter() + * method. Some non-standard converters are supplied in the + * {@link com.thoughtworks.xstream.converters.extended} package and you can create + * your own by implementing the {@link com.thoughtworks.xstream.converters.Converter} + * interface.

            + *

            + *


            Example
            + * xstream.registerConverter(new SqlTimestampConverter());
            + * xstream.registerConverter(new DynamicProxyConverter());
            + * 

            + *

            The default converter, ie the converter which will be used if no other registered + * converter is suitable, can be configured by either one of the constructors + * or can be changed using the changeDefaultConverter() method. + * If not set, XStream uses {@link com.thoughtworks.xstream.converters.reflection.ReflectionConverter} + * as the initial default converter. + *

            + *

            + *


            Example
            + * xstream.changeDefaultConverter(new ACustomDefaultConverter());
            + * 

            + *

            + *

            Object graphs

            + *

            + *

            XStream has support for object graphs; a deserialized object graph + * will keep references intact, including circular references.

            + *

            + *

            XStream can signify references in XML using either XPath or IDs. The + * mode can be changed using setMode():

            + *

            + * + * + * + * + * + * + * + * + * + * + * + * + * + *
            xstream.setMode(XStream.XPATH_REFERENCES);(Default) Uses XPath references to signify duplicate + * references. This produces XML with the least clutter.
            xstream.setMode(XStream.ID_REFERENCES);Uses ID references to signify duplicate references. In some + * scenarios, such as when using hand-written XML, this is + * easier to work with.
            xstream.setMode(XStream.NO_REFERENCES);This disables object graph support and treats the object + * structure like a tree. Duplicate references are treated + * as two seperate objects and circular references cause an + * exception. This is slightly faster and uses less memory + * than the other two modes.
            + * + *

            Thread safety

            + * + *

            The XStream instance is thread-safe. That is, once the XStream instance + * has been created and configured, it may be shared across multiple threads + * allowing objects to be serialized/deserialized concurrently. + * + *

            Implicit collections

            + *

            + *

            To avoid the need for special tags for collections, you can define implicit collections using one of the + * addImplicitCollection methods.

            + * + * @author Joe Walnes + * @author Mauro Talevi + */ +public class XStream { + + private ClassAliasingMapper classAliasingMapper; + private FieldAliasingMapper fieldAliasingMapper; + private DefaultImplementationsMapper defaultImplementationsMapper; + private ImmutableTypesMapper immutableTypesMapper; + private ImplicitCollectionMapper implicitCollectionMapper; + + private ReflectionProvider reflectionProvider; + private HierarchicalStreamDriver hierarchicalStreamDriver; + private MarshallingStrategy marshallingStrategy; + private ClassLoaderReference classLoaderReference; // TODO: Should be changeable + + private ClassMapper classMapper; + private DefaultConverterLookup converterLookup; + private JVM jvm = new JVM(); + + public static final int NO_REFERENCES = 1001; + public static final int ID_REFERENCES = 1002; + public static final int XPATH_REFERENCES = 1003; + + private static final int PRIORITY_NORMAL = 0; + private static final int PRIORITY_LOW = -10; + private static final int PRIORITY_VERY_LOW = -20; + + public XStream() { + this(null, null, new XppDriver()); + } + + /** + * @deprecated As of XStream 1.1.1, a default Converter is unnecessary as you can register a Converter with an + * associated priority. Use an alternate constructor. + */ + public XStream(Converter defaultConverter) { + this(null, null, new XppDriver(), null); + registerConverter(defaultConverter, PRIORITY_VERY_LOW); + } + + public XStream(HierarchicalStreamDriver hierarchicalStreamDriver) { + this(null, null, hierarchicalStreamDriver); + } + + public XStream(ReflectionProvider reflectionProvider) { + this(reflectionProvider, null, new XppDriver()); + } + + public XStream(ReflectionProvider reflectionProvider, HierarchicalStreamDriver hierarchicalStreamDriver) { + this(reflectionProvider, null, hierarchicalStreamDriver); + } + + public XStream(ReflectionProvider reflectionProvider, ClassMapper classMapper, HierarchicalStreamDriver driver) { + this(reflectionProvider, classMapper, driver, null); + } + + public XStream(ReflectionProvider reflectionProvider, ClassMapper classMapper, HierarchicalStreamDriver driver, String classAttributeIdentifier) { + jvm = new JVM(); + if (reflectionProvider == null) { + reflectionProvider = jvm.bestReflectionProvider(); + } + this.reflectionProvider = reflectionProvider; + this.hierarchicalStreamDriver = driver; + this.classLoaderReference = new ClassLoaderReference(new CompositeClassLoader()); + this.classMapper = classMapper == null ? buildMapper(classAttributeIdentifier) : classMapper; + converterLookup = new DefaultConverterLookup(this.classMapper); + setupAliases(); + setupDefaultImplementations(); + setupConverters(); + setupImmutableTypes(); + setMode(XPATH_REFERENCES); + } + + /** + * @deprecated As of XStream 1.1.1, a default Converter is unnecessary as you can register a Converter with an + * associated priority. Use an alternate constructor. + */ + public XStream(ReflectionProvider reflectionProvider, ClassMapper classMapper, HierarchicalStreamDriver driver, String classAttributeIdentifier, Converter defaultConverter) { + this(reflectionProvider, classMapper, driver, classAttributeIdentifier); + registerConverter(defaultConverter, PRIORITY_VERY_LOW); + } + + private ClassMapper buildMapper(String classAttributeIdentifier) { + MapperWrapper mapper = new DefaultMapper(classLoaderReference, classAttributeIdentifier); + mapper = new XmlFriendlyMapper(mapper); + mapper = new ClassAliasingMapper(mapper); + classAliasingMapper = (ClassAliasingMapper) mapper; // need a reference to that one + mapper = new FieldAliasingMapper(mapper); + fieldAliasingMapper = (FieldAliasingMapper) mapper; // need a reference to that one + mapper = new ImplicitCollectionMapper(mapper); + implicitCollectionMapper = (ImplicitCollectionMapper)mapper; // need a reference to this one + mapper = new DynamicProxyMapper(mapper); + if (JVM.is15()) { + mapper = new EnumMapper(mapper); + } + mapper = new OuterClassMapper(mapper); + mapper = new ArrayMapper(mapper); + mapper = new DefaultImplementationsMapper(mapper); + defaultImplementationsMapper = (DefaultImplementationsMapper) mapper; // and that one + mapper = new ImmutableTypesMapper(mapper); + immutableTypesMapper = (ImmutableTypesMapper)mapper; // that one too + mapper = wrapMapper(mapper); + mapper = new CachingMapper(mapper); + return mapper; + } + + protected MapperWrapper wrapMapper(MapperWrapper next) { + return next; + } + + protected void setupAliases() { + alias("null", ClassMapper.Null.class); + alias("int", Integer.class); + alias("float", Float.class); + alias("double", Double.class); + alias("long", Long.class); + alias("short", Short.class); + alias("char", Character.class); + alias("byte", Byte.class); + alias("boolean", Boolean.class); + alias("number", Number.class); + alias("object", Object.class); + alias("big-int", BigInteger.class); + alias("big-decimal", BigDecimal.class); + + alias("string-buffer", StringBuffer.class); + alias("string", String.class); + alias("java-class", Class.class); + alias("method", Method.class); + alias("constructor", Constructor.class); + alias("date", Date.class); + alias("url", URL.class); + alias("bit-set", BitSet.class); + + alias("map", Map.class); + alias("entry", Map.Entry.class); + alias("properties", Properties.class); + alias("list", List.class); + alias("set", Set.class); + + alias("linked-list", LinkedList.class); + alias("vector", Vector.class); + alias("tree-map", TreeMap.class); + alias("tree-set", TreeSet.class); + alias("hashtable", Hashtable.class); + + // Instantiating these two classes starts the AWT system, which is undesirable. Calling loadClass ensures + // a reference to the class is found but they are not instantiated. + alias("awt-color", jvm.loadClass("java.awt.Color")); + alias("awt-font", jvm.loadClass("java.awt.Font")); + + alias("sql-timestamp", Timestamp.class); + alias("sql-time", Time.class); + alias("sql-date", java.sql.Date.class); + alias("file", File.class); + alias("locale", Locale.class); + alias("gregorian-calendar", Calendar.class); + + + if (JVM.is14()) { + alias("linked-hash-map", jvm.loadClass("java.util.LinkedHashMap")); + alias("linked-hash-set", jvm.loadClass("java.util.LinkedHashSet")); + alias("trace", jvm.loadClass("java.lang.StackTraceElement")); + alias("currency", jvm.loadClass("java.util.Currency")); + // since jdk 1.4 included, but previously available as separate package ... + alias("auth-subject", jvm.loadClass("javax.security.auth.Subject")); + } + + if (JVM.is15()) { + alias("enum-set", jvm.loadClass("java.util.EnumSet")); + alias("enum-map", jvm.loadClass("java.util.EnumMap")); + } + } + + protected void setupDefaultImplementations() { + addDefaultImplementation(HashMap.class, Map.class); + addDefaultImplementation(ArrayList.class, List.class); + addDefaultImplementation(HashSet.class, Set.class); + addDefaultImplementation(GregorianCalendar.class, Calendar.class); + } + + protected void setupConverters() { + ReflectionConverter reflectionConverter = new ReflectionConverter(classMapper, reflectionProvider); + registerConverter(reflectionConverter, PRIORITY_VERY_LOW); + + registerConverter(new SerializableConverter(classMapper, reflectionProvider), PRIORITY_LOW); + registerConverter(new ExternalizableConverter(classMapper), PRIORITY_LOW); + + registerConverter(new IntConverter(), PRIORITY_NORMAL); + registerConverter(new FloatConverter(), PRIORITY_NORMAL); + registerConverter(new DoubleConverter(), PRIORITY_NORMAL); + registerConverter(new LongConverter(), PRIORITY_NORMAL); + registerConverter(new ShortConverter(), PRIORITY_NORMAL); + registerConverter(new CharConverter(), PRIORITY_NORMAL); + registerConverter(new BooleanConverter(), PRIORITY_NORMAL); + registerConverter(new ByteConverter(), PRIORITY_NORMAL); + + registerConverter(new StringConverter(), PRIORITY_NORMAL); + registerConverter(new StringBufferConverter(), PRIORITY_NORMAL); + registerConverter(new DateConverter(), PRIORITY_NORMAL); + registerConverter(new BitSetConverter(), PRIORITY_NORMAL); + registerConverter(new URLConverter(), PRIORITY_NORMAL); + registerConverter(new BigIntegerConverter(), PRIORITY_NORMAL); + registerConverter(new BigDecimalConverter(), PRIORITY_NORMAL); + + registerConverter(new ArrayConverter(classMapper), PRIORITY_NORMAL); + registerConverter(new CharArrayConverter(), PRIORITY_NORMAL); + registerConverter(new CollectionConverter(classMapper), PRIORITY_NORMAL); + registerConverter(new MapConverter(classMapper), PRIORITY_NORMAL); + registerConverter(new TreeMapConverter(classMapper), PRIORITY_NORMAL); + registerConverter(new TreeSetConverter(classMapper), PRIORITY_NORMAL); + registerConverter(new PropertiesConverter(), PRIORITY_NORMAL); + registerConverter(new EncodedByteArrayConverter(), PRIORITY_NORMAL); + + registerConverter(new FileConverter(), PRIORITY_NORMAL); + registerConverter(new SqlTimestampConverter(), PRIORITY_NORMAL); + registerConverter(new SqlTimeConverter(), PRIORITY_NORMAL); + registerConverter(new SqlDateConverter(), PRIORITY_NORMAL); + registerConverter(new DynamicProxyConverter(classMapper, classLoaderReference), PRIORITY_NORMAL); + registerConverter(new JavaClassConverter(classLoaderReference), PRIORITY_NORMAL); + registerConverter(new JavaMethodConverter(), PRIORITY_NORMAL); + registerConverter(new FontConverter(), PRIORITY_NORMAL); + registerConverter(new ColorConverter(), PRIORITY_NORMAL); + registerConverter(new LocaleConverter(), PRIORITY_NORMAL); + registerConverter(new GregorianCalendarConverter(), PRIORITY_NORMAL); + + if (JVM.is14()) { + // late bound converters - allows XStream to be compiled on earlier JDKs + dynamicallyRegisterConverter( + "com.thoughtworks.xstream.converters.extended.ThrowableConverter", PRIORITY_NORMAL, + new Class[] {Converter.class} , new Object[] { reflectionConverter} ); + dynamicallyRegisterConverter( + "com.thoughtworks.xstream.converters.extended.StackTraceElementConverter", PRIORITY_NORMAL, + null, null); + dynamicallyRegisterConverter( + "com.thoughtworks.xstream.converters.extended.CurrencyConverter", PRIORITY_NORMAL, + null, null); + dynamicallyRegisterConverter( + "com.thoughtworks.xstream.converters.extended.RegexPatternConverter", PRIORITY_NORMAL, + new Class[] {Converter.class} , new Object[] { reflectionConverter} ); + dynamicallyRegisterConverter( + "com.thoughtworks.xstream.converters.extended.SubjectConverter", PRIORITY_NORMAL, + new Class[] {Mapper.class}, new Object[] {classMapper}); + } + + if (JVM.is15()) { + // late bound converters - allows XStream to be compiled on earlier JDKs + dynamicallyRegisterConverter( + "com.thoughtworks.xstream.converters.enums.EnumConverter", PRIORITY_NORMAL, + null, null); + dynamicallyRegisterConverter( + "com.thoughtworks.xstream.converters.enums.EnumSetConverter", PRIORITY_NORMAL, + new Class[] {Mapper.class}, new Object[] {classMapper}); + dynamicallyRegisterConverter( + "com.thoughtworks.xstream.converters.enums.EnumMapConverter", PRIORITY_NORMAL, + new Class[] {Mapper.class}, new Object[] {classMapper}); + } + } + + private void dynamicallyRegisterConverter(String className, int priority, + Class[] constructorParamTypes, Object[] constructorParamValues) { + try { + Class type = Class.forName(className, false, classLoaderReference.getReference()); + Constructor constructor = type.getConstructor(constructorParamTypes); + Converter converter = (Converter) constructor.newInstance(constructorParamValues); + registerConverter(converter, priority); + } catch (Exception e) { + throw new InitializationException("Could not instatiate converter : " + className, e); + } + } + + protected void setupImmutableTypes() { + // primitives are always immutable + addImmutableType(boolean.class); + addImmutableType(Boolean.class); + addImmutableType(byte.class); + addImmutableType(Byte.class); + addImmutableType(char.class); + addImmutableType(Character.class); + addImmutableType(double.class); + addImmutableType(Double.class); + addImmutableType(float.class); + addImmutableType(Float.class); + addImmutableType(int.class); + addImmutableType(Integer.class); + addImmutableType(long.class); + addImmutableType(Long.class); + addImmutableType(short.class); + addImmutableType(Short.class); + + // additional types + addImmutableType(ClassMapper.Null.class); + addImmutableType(BigDecimal.class); + addImmutableType(BigInteger.class); + addImmutableType(String.class); + addImmutableType(URL.class); + addImmutableType(File.class); + addImmutableType(Class.class); + } + + public void setMarshallingStrategy(MarshallingStrategy marshallingStrategy) { + this.marshallingStrategy = marshallingStrategy; + } + + /** + * Serialize an object to a pretty-printed XML String. + */ + public String toXML(Object obj) { + Writer stringWriter = new StringWriter(); + HierarchicalStreamWriter writer = hierarchicalStreamDriver.createWriter(stringWriter); + marshal(obj, writer); + writer.flush(); + writer.close(); + return stringWriter.toString(); + } + + /** + * Serialize an object to the given Writer as pretty-printed XML. + */ + public void toXML(Object obj, Writer out) { + HierarchicalStreamWriter writer = hierarchicalStreamDriver.createWriter(out); + marshal(obj, writer); + writer.flush(); + } + + /** + * Serialize an object to the given OutputStream as pretty-printed XML. + */ + public void toXML(Object obj, OutputStream out) { + HierarchicalStreamWriter writer = hierarchicalStreamDriver.createWriter(out); + marshal(obj, writer); + writer.flush(); + } + + /** + * Serialize and object to a hierarchical data structure (such as XML). + */ + public void marshal(Object obj, HierarchicalStreamWriter writer) { + marshal(obj, writer, null); + } + + /** + * Serialize and object to a hierarchical data structure (such as XML). + * + * @param dataHolder Extra data you can use to pass to your converters. Use this as you want. If not present, XStream + * shall create one lazily as needed. + */ + public void marshal(Object obj, HierarchicalStreamWriter writer, DataHolder dataHolder) { + marshallingStrategy.marshal(writer, obj, converterLookup, classMapper, dataHolder); + } + + /** + * Deserialize an object from an XML String. + */ + public Object fromXML(String xml) { + return fromXML(new StringReader(xml)); + } + + /** + * Deserialize an object from an XML Reader. + */ + public Object fromXML(Reader xml) { + return unmarshal(hierarchicalStreamDriver.createReader(xml), null); + } + + /** + * Deserialize an object from an XML InputStream. + */ + public Object fromXML(InputStream input) { + return unmarshal(hierarchicalStreamDriver.createReader(input), null); + } + + /** + * Deserialize an object from an XML String, + * populating the fields of the given root object instead of instantiating + * a new one. + */ + public Object fromXML(String xml, Object root) { + return fromXML(new StringReader(xml), root); + } + + /** + * Deserialize an object from an XML Reader, + * populating the fields of the given root object instead of instantiating + * a new one. + */ + public Object fromXML(Reader xml, Object root) { + return unmarshal(hierarchicalStreamDriver.createReader(xml), root); + } + + /** + * Deserialize an object from an XML InputStream, + * populating the fields of the given root object instead of instantiating + * a new one. + */ + public Object fromXML(InputStream xml, Object root) { + return unmarshal(hierarchicalStreamDriver.createReader(xml), root); + } + + /** + * Deserialize an object from a hierarchical data structure (such as XML). + */ + public Object unmarshal(HierarchicalStreamReader reader) { + return unmarshal(reader, null, null); + } + + /** + * Deserialize an object from a hierarchical data structure (such as XML), + * populating the fields of the given root object instead of instantiating + * a new one. + */ + public Object unmarshal(HierarchicalStreamReader reader, Object root) { + return unmarshal(reader, root, null); + } + + /** + * Deserialize an object from a hierarchical data structure (such as XML). + * + * @param root If present, the passed in object will have its fields populated, as opposed to XStream creating a + * new instance. + * @param dataHolder Extra data you can use to pass to your converters. Use this as you want. If not present, XStream + * shall create one lazily as needed. + */ + public Object unmarshal(HierarchicalStreamReader reader, Object root, DataHolder dataHolder) { + return marshallingStrategy.unmarshal(root, reader, dataHolder, converterLookup, classMapper); + } + + /** + * Alias a Class to a shorter name to be used in XML elements. + * + * @param name Short name + * @param type Type to be aliased + */ + public void alias(String name, Class type) { + classAliasingMapper.addClassAlias(name, type); + } + + /** + * Alias a Class to a shorter name to be used in XML elements. + * + * @param name Short name + * @param type Type to be aliased + * @param defaultImplementation Default implementation of type to use if no other specified. + */ + public void alias(String name, Class type, Class defaultImplementation) { + alias(name, type); + addDefaultImplementation(defaultImplementation, type); + } + + public void aliasField(String alias, Class type, String fieldName) { + fieldAliasingMapper.addFieldAlias(alias, type, fieldName); + } + + /** + * Associate a default implementation of a class with an object. Whenever XStream encounters an instance of this + * type, it will use the default implementation instead. + * + * For example, java.util.ArrayList is the default implementation of java.util.List. + * @param defaultImplementation + * @param ofType + */ + public void addDefaultImplementation(Class defaultImplementation, Class ofType) { + defaultImplementationsMapper.addDefaultImplementation(defaultImplementation, ofType); + } + + public void addImmutableType(Class type) { + immutableTypesMapper.addImmutableType(type); + } + + /** + * @deprecated As of 1.1.1 you should register a converter with the appropriate priority. + */ + public void changeDefaultConverter(Converter defaultConverter) { + registerConverter(defaultConverter, PRIORITY_VERY_LOW); + } + + public void registerConverter(Converter converter) { + registerConverter(converter, PRIORITY_NORMAL); + } + + public void registerConverter(Converter converter, int priority) { + converterLookup.registerConverter(converter, priority); + } + + public ClassMapper getClassMapper() { + return classMapper; + } + + public ConverterLookup getConverterLookup() { + return converterLookup; + } + + /** + * Change mode for dealing with duplicate references. + * Valid valuse are XStream.XPATH_REFERENCES, + * XStream.ID_REFERENCES and XStream.NO_REFERENCES. + * + * @see #XPATH_REFERENCES + * @see #ID_REFERENCES + * @see #NO_REFERENCES + */ + public void setMode(int mode) { + switch (mode) { + case NO_REFERENCES: + setMarshallingStrategy(new TreeMarshallingStrategy()); + break; + case ID_REFERENCES: + setMarshallingStrategy(new ReferenceByIdMarshallingStrategy()); + break; + case XPATH_REFERENCES: + setMarshallingStrategy(new ReferenceByXPathMarshallingStrategy()); + break; + default: + throw new IllegalArgumentException("Unknown mode : " + mode); + } + } + + /** + * @deprecated Use addImplicitCollection() instead. + */ + public void addDefaultCollection(Class ownerType, String fieldName) { + addImplicitCollection(ownerType, fieldName); + } + + /** + * Adds a default implicit collection which is used for any unmapped xml tag. + * + * @param ownerType class owning the implicit collection + * @param fieldName name of the field in the ownerType. This field must be an java.util.ArrayList. + */ + public void addImplicitCollection(Class ownerType, String fieldName) { + implicitCollectionMapper.add(ownerType, fieldName, null, Object.class); + } + + /** + * Adds implicit collection which is used for all items of the given itemType. + * + * @param ownerType class owning the implicit collection + * @param fieldName name of the field in the ownerType. This field must be an java.util.ArrayList. + * @param itemType type of the items to be part of this collection. + */ + public void addImplicitCollection(Class ownerType, String fieldName, Class itemType) { + implicitCollectionMapper.add(ownerType, fieldName, null, itemType); + } + + /** + * Adds implicit collection which is used for all items of the given element name defined by itemFieldName. + * + * @param ownerType class owning the implicit collection + * @param fieldName name of the field in the ownerType. This field must be an java.util.ArrayList. + * @param itemFieldName element name of the implicit collection + * @param itemType item type to be aliases be the itemFieldName + */ + public void addImplicitCollection(Class ownerType, String fieldName, String itemFieldName, Class itemType) { + implicitCollectionMapper.add(ownerType, fieldName, itemFieldName, itemType); + } + + public DataHolder newDataHolder() { + return new MapBackedDataHolder(); + } + + /** + * Creates an ObjectOutputStream that serializes a stream of objects to the writer using XStream. + * + *

            To change the name of the root element (from <object-stream>), use + * {@link #createObjectOutputStream(java.io.Writer, String)}.

            + * + * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) + * @since 1.0.3 + */ + public ObjectOutputStream createObjectOutputStream(Writer writer) throws IOException { + return createObjectOutputStream(new PrettyPrintWriter(writer), "object-stream"); + } + + /** + * Creates an ObjectOutputStream that serializes a stream of objects to the writer using XStream. + * + *

            To change the name of the root element (from <object-stream>), use + * {@link #createObjectOutputStream(java.io.Writer, String)}.

            + * + * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) + * @since 1.0.3 + */ + public ObjectOutputStream createObjectOutputStream(HierarchicalStreamWriter writer) throws IOException { + return createObjectOutputStream(writer, "object-stream"); + } + + /** + * Creates an ObjectOutputStream that serializes a stream of objects to the writer using XStream. + * + * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) + * @since 1.0.3 + */ + public ObjectOutputStream createObjectOutputStream(Writer writer, String rootNodeName) throws IOException { + return createObjectOutputStream(new PrettyPrintWriter(writer), rootNodeName); + } + + /** + * Creates an ObjectOutputStream that serializes a stream of objects to the writer using XStream. + * + *

            Because an ObjectOutputStream can contain multiple items and XML only allows a single root node, the stream + * must be written inside an enclosing node.

            + * + *

            It is necessary to call ObjectOutputStream.close() when done, otherwise the stream will be incomplete.

            + * + *

            Example

            + *
            ObjectOutputStream out = xstream.createObjectOutputStream(aWriter, "things");
            +     * out.writeInt(123);
            +     * out.writeObject("Hello");
            +     * out.writeObject(someObject)
            +     * out.close();
            + * + * @param writer The writer to serialize the objects to. + * @param rootNodeName The name of the root node enclosing the stream of objects. + * + * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) + * @since 1.0.3 + */ + public ObjectOutputStream createObjectOutputStream(final HierarchicalStreamWriter writer, String rootNodeName) throws IOException { + writer.startNode(rootNodeName); + return new CustomObjectOutputStream(new CustomObjectOutputStream.StreamCallback() { + public void writeToStream(Object object) { + marshal(object, writer); + } + + public void writeFieldsToStream(Map fields) throws NotActiveException { + throw new NotActiveException("not in call to writeObject"); + } + + public void defaultWriteObject() throws NotActiveException { + throw new NotActiveException("not in call to writeObject"); + } + + public void flush() { + writer.flush(); + } + + public void close() { + writer.endNode(); + writer.close(); + } + }); + } + + /** + * Creates an ObjectInputStream that deserializes a stream of objects from a reader using XStream. + * + * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) + * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @since 1.0.3 + */ + public ObjectInputStream createObjectInputStream(Reader xmlReader) throws IOException { + return createObjectInputStream(hierarchicalStreamDriver.createReader(xmlReader)); + } + + /** + * Creates an ObjectInputStream that deserializes a stream of objects from a reader using XStream. + * + *

            Example

            + *
            ObjectInputStream in = xstream.createObjectOutputStream(aReader);
            +     * int a = out.readInt();
            +     * Object b = out.readObject();
            +     * Object c = out.readObject();
            + * + * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @since 1.0.3 + */ + public ObjectInputStream createObjectInputStream(final HierarchicalStreamReader reader) throws IOException { + return new CustomObjectInputStream(new CustomObjectInputStream.StreamCallback() { + public Object readFromStream() throws EOFException { + if (!reader.hasMoreChildren()) { + throw new EOFException(); + } + reader.moveDown(); + Object result = unmarshal(reader); + reader.moveUp(); + return result; + } + + public Map readFieldsFromStream() throws IOException { + throw new NotActiveException("not in call to readObject"); + } + + public void defaultReadObject() throws NotActiveException { + throw new NotActiveException("not in call to readObject"); + } + + public void registerValidation(ObjectInputValidation validation, int priority) throws NotActiveException { + throw new NotActiveException("stream inactive"); + } + + public void close() { + reader.close(); + } + }); + } + + /** + * Change the ClassLoader XStream uses to load classes. + * + * @since 1.1.1 + */ + public void setClassLoader(ClassLoader classLoader) { + classLoaderReference.setReference(classLoader); + } + + /** + * Change the ClassLoader XStream uses to load classes. + * + * @since 1.1.1 + */ + public ClassLoader getClassLoader() { + return classLoaderReference.getReference(); + } + + /** + * Prevents a field from being serialized. + * + * @since 1.2 + */ + public void omitField(Class type, String fieldName) { + fieldAliasingMapper.omitField(type, fieldName); + } + + public static class InitializationException extends BaseException { + public InitializationException(String message, Throwable cause) { + super(message, cause); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/alias/CannotResolveClassException.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/alias/CannotResolveClassException.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/alias/CannotResolveClassException.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,7 @@ +package com.thoughtworks.xstream.alias; + +public class CannotResolveClassException extends RuntimeException { + public CannotResolveClassException(String className) { + super(className); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/alias/ClassMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/alias/ClassMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/alias/ClassMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,44 @@ +package com.thoughtworks.xstream.alias; + +import com.thoughtworks.xstream.mapper.Mapper; + +public interface ClassMapper extends Mapper { + + /** + * Place holder type used for null values. + */ + class Null {} + + /** + * @deprecated As of 1.1.1, use {@link #serializedClass(Class)} + */ + String lookupName(Class type); + + /** + * @deprecated As of 1.1.1, use {@link #realClass(String)} + */ + Class lookupType(String elementName); + + /** + * @deprecated As of 1.1.1, use {@link #serializedMember(Class, String)} + */ + String mapNameFromXML( String xmlName ); + + /** + * @deprecated As of 1.1.1, use {@link #realMember(Class, String)} + */ + String mapNameToXML( String javaName ); + + /** + * @deprecated As of 1.1.1, use {@link #defaultImplementationOf(Class)} + */ + Class lookupDefaultType(Class baseType); + + /** + * @deprecated As of 1.1.1, use {@link com.thoughtworks.xstream.mapper.ClassAliasingMapper#addClassAlias(String, Class)} for creating an alias and + * {@link com.thoughtworks.xstream.mapper.DefaultImplementationsMapper#addDefaultImplementation(Class, Class)} for specifiny a + * default implementation. + */ + void alias(String elementName, Class type, Class defaultImplementation); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/alias/NameMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/alias/NameMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/alias/NameMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,7 @@ +package com.thoughtworks.xstream.alias; + +public interface NameMapper { + String fromXML(String elementName); + + String toXML(String fieldName); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/Annotations.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/Annotations.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/Annotations.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,210 @@ +package com.thoughtworks.xstream.annotations; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter; +import com.thoughtworks.xstream.mapper.Mapper; + +/** + * Contains utility methods that enable to configure an XStream instance + * with class and field aliases, based on a class decorated + * with annotations defined in this package. + * + * @author Emil Kirschner + * @author Chung-Onn Cheong + */ +public class Annotations { + private static final Set> configuredTypes = new HashSet>(); + private static boolean debug = false; + + /** + * This class is not instantiable + */ + private Annotations() { + } + + /** + * Configures aliases on the specified XStream object based on annotations that decorate the specified class. + * + * @param topLevelClass the class for which the XStream object is configured. + * This class is expected to be decorated with annotations defined in this package. + * @param xstream the XStream object that will be configured + */ + public static synchronized void configureAliases(XStream xstream, Class... topLevelClasses) { + assert debug = true; + configuredTypes.clear(); + for(Class topLevelClass : topLevelClasses){ + configureClass(xstream, topLevelClass); + } + } + + private static synchronized void configureClass(XStream xstream, Class configurableClass) { + if (configurableClass == null + || configuredTypes.contains(configurableClass) + || (!configurableClass.isAnnotationPresent(XStreamAlias.class) + && !Converter.class.isAssignableFrom(configurableClass))) + return; + + if(Converter.class.isAssignableFrom(configurableClass)){ + Class converterType = (Class)configurableClass; + registerConverter(xstream, converterType); + return; + } + + if(debug){ + System.out.println("Aliasing class:"+ configurableClass); + } + + //Do Class Level Converters + AnnotatedElement element = configurableClass; + if(configurableClass.isAnnotationPresent(XStreamConverters.class)){ + XStreamConverters convertersAnnotation = element.getAnnotation(XStreamConverters.class); + for(XStreamConverter converterAnnotation : convertersAnnotation.value()){ + registerConverter(xstream, converterAnnotation.value()); + } + } + + //Do Class Leve - Converter + if(configurableClass.isAnnotationPresent(XStreamConverter.class)){ + XStreamConverter converterAnnotation = element.getAnnotation(XStreamConverter.class); + registerConverter(xstream, converterAnnotation.value()); + } + + //Do Class Level Alias + if(configurableClass.isAnnotationPresent(XStreamAlias.class)){ + XStreamAlias aliasAnnotation = element.getAnnotation(XStreamAlias.class); + if(aliasAnnotation.impl() != Void.class){ + //Alias for Interface/Class with an impl + xstream.alias(aliasAnnotation.value(), configurableClass, aliasAnnotation.impl()); + configuredTypes.add(configurableClass); + if(configurableClass.isInterface()){ + configureClass(xstream,aliasAnnotation.impl()); //alias Interface's impl + return; + } + }else{ + xstream.alias(aliasAnnotation.value(), configurableClass); + configuredTypes.add(configurableClass); + } + } + + //Do Class Level ImplicitCollection + if(configurableClass.isAnnotationPresent(XStreamImplicitCollection.class)){ + XStreamImplicitCollection implicitColAnnotation = element.getAnnotation(XStreamImplicitCollection.class); + String fieldName = implicitColAnnotation.value(); + String itemFieldName = implicitColAnnotation.item(); + Field field; + try { + field = configurableClass.getDeclaredField(fieldName); + Class itemType = getFieldParameterizedType(field, xstream); + if (itemType == null) { + xstream.addImplicitCollection(configurableClass, fieldName); + } else { + if (itemFieldName.equals("")) { + xstream.addImplicitCollection(configurableClass, fieldName, + itemType); + } else { + xstream.addImplicitCollection(configurableClass, fieldName, + itemFieldName, itemType); + } + } + configuredTypes.add(configurableClass); + } catch (Exception e) { + System.err.println("Fail to derive ImplicitCollection member type"); + } + } + + //Do Member Level Alias and XStreamContainedType + Field[] fields = configurableClass.getDeclaredFields(); + for (Field field : fields) { + if(field.isSynthetic()) continue; + + //Alias the member's Type + Class fieldType = field.getType(); + if (Collection.class.isAssignableFrom(fieldType)) { + if(field.isAnnotationPresent(XStreamContainedType.class)){ + Class containedClass = getFieldParameterizedType(field, xstream); + configureClass(xstream, containedClass); + } + } else if (!field.getType().isPrimitive()) { + if(field.isAnnotationPresent(XStreamAlias.class)){ + XStreamAlias fieldXStreamAliasAnnotation = field.getAnnotation(XStreamAlias.class); + xstream.aliasField(fieldXStreamAliasAnnotation.value(), configurableClass, field.getName()); + configureClass(xstream, field.getType()); + } + } + } + + //Do Member Classes Alias + for(ClassmemberClass : configurableClass.getDeclaredClasses()){ + configureClass(xstream, memberClass); + } + + //Do Superclass and Superinterface Alias + Class superClass = configurableClass.getSuperclass(); + if (superClass != null && !Object.class.equals(superClass)) + configureClass(xstream, superClass); + Class[] interfaces = configurableClass.getInterfaces(); + for(Class intf : interfaces){ + configureClass(xstream, intf); + } + } + + + private static void registerConverter(XStream xstream, Class converterType) { + Converter converter; + if(configuredTypes.contains(converterType)) + return; + if (AbstractCollectionConverter.class.isAssignableFrom(converterType)) { + try { + Constructor converterConstructor = converterType.getConstructor(Mapper.class); + converter = converterConstructor.newInstance(xstream.getClassMapper()); + } catch (Exception e) { + e.printStackTrace(); + return; + } + + } else { + try { + converter = converterType.newInstance(); + } catch (Exception e) { + e.printStackTrace(); + return; + } + } + xstream.registerConverter(converter); + configuredTypes.add(converterType); + if(debug){ + System.out.println("Registered converter:"+ converterType); + } + + } + + /* + * Return a concrete class + */ + private static Class getFieldParameterizedType(Field field, XStream xstream){ + if(field.getGenericType() instanceof ParameterizedType) { + ParameterizedType pType = (ParameterizedType) field.getGenericType(); + Class type = (Class) pType.getActualTypeArguments()[0]; + //Get the interface Impl + if(type.isInterface()){ + AnnotatedElement element = type; + XStreamAlias alias = element.getAnnotation(XStreamAlias.class); + configureClass(xstream, type); + type = alias.impl(); + assert !type.isInterface() : type; + } + return type; + } + assert false : "Field is raw type :" + field; + return null; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamAlias.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamAlias.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamAlias.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,19 @@ +package com.thoughtworks.xstream.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Annotation used to define an XStream class or field value. This annotation should only be used with classes and fields + * + * @author Emil Kirschner + * @author Chung-Onn Cheong + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface XStreamAlias { + /** + * The value of the class or field value + */ + public String value(); + public Class impl() default Void.class; //Use Void to denote as Null +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamContainedType.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamContainedType.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamContainedType.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,20 @@ +package com.thoughtworks.xstream.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation used to specify the value of objects contained by a collection. + * This annotation can only be applied to class attributes, + * but is only effective on collections and collection specializations. + * + * @author Emil Kirschner + * @author Chung-Onn Cheong + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface XStreamContainedType { + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,18 @@ +package com.thoughtworks.xstream.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.thoughtworks.xstream.converters.Converter; + +/** + * + * @author Chung-Onn Cheong + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface XStreamConverter { + Class value(); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamConverters.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamConverters.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamConverters.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,16 @@ +package com.thoughtworks.xstream.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author Chung-Onn Cheong + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface XStreamConverters { + XStreamConverter[] value(); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamImplicitCollection.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamImplicitCollection.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamImplicitCollection.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,17 @@ +package com.thoughtworks.xstream.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author Chung-Onn Cheong + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface XStreamImplicitCollection { + String value(); //fieldName + String item() default ""; //itemfieldName +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConversionException.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConversionException.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConversionException.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,88 @@ +package com.thoughtworks.xstream.converters; + +import com.thoughtworks.xstream.core.BaseException; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Thrown by {@link Converter} implementations when they cannot convert an object + * to/from textual data. + * + * When this exception is thrown it can be passed around to things that accept an + * {@link ErrorWriter}, allowing them to add diagnostics to the stack trace. + * + * @author Joe Walnes + * + * @see ErrorWriter + */ +public class ConversionException extends BaseException implements ErrorWriter { + + private Map stuff = new HashMap(); + + /** + * Plays nice with JDK1.3 and JDK1.4 + */ + protected Exception cause; + + public ConversionException(String msg, Exception cause) { + super(msg); + if (msg != null) { + add("message", msg); + } + if (cause != null) { + add("cause-exception", cause.getClass().getName()); + add("cause-message", cause.getMessage()); + this.cause = cause; + } + } + + public ConversionException(String msg) { + super(msg); + } + + public ConversionException(Exception cause) { + this(cause.getMessage(), cause); + } + + public String get(String errorKey) { + return (String) stuff.get(errorKey); + } + + public void add(String name, String information) { + stuff.put(name, information); + } + + public Iterator keys() { + return stuff.keySet().iterator(); + } + + public String getMessage() { + StringBuffer result = new StringBuffer(); + if (super.getMessage() != null) { + result.append(super.getMessage()); + } + result.append("\n---- Debugging information ----"); + for (Iterator iterator = keys(); iterator.hasNext();) { + String k = (String) iterator.next(); + String v = get(k); + result.append('\n').append(k); + int padding = 20 - k.length(); + for (int i = 0; i < padding; i++) { + result.append(' '); + } + result.append(": ").append(v).append(' '); + } + result.append("\n-------------------------------"); + return result.toString(); + } + + public Throwable getCause() { + return cause; + } + + public String getShortMessage() { + return super.getMessage(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/Converter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/Converter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/Converter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,60 @@ +package com.thoughtworks.xstream.converters; + +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * Converter implementations are responsible marshalling Java objects + * to/from textual data. + *

            + *

            If an exception occurs during processing, a {@link ConversionException} + * should be thrown.

            + *

            + *

            If working with the high level {@link com.thoughtworks.xstream.XStream} facade, + * you can register new converters using the XStream.registerConverter() method.

            + *

            + *

            If working with the lower level API, the + * {@link com.thoughtworks.xstream.converters.ConverterLookup} implementation is + * responsible for looking up the appropriate converter.

            + *

            + *

            {@link com.thoughtworks.xstream.converters.basic.AbstractBasicConverter} + * provides a starting point for objects that can store all information + * in a single String.

            + *

            + *

            {@link com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter} + * provides a starting point for objects that hold a collection of other objects + * (such as Lists and Maps).

            + * + * @author Joe Walnes + * @see com.thoughtworks.xstream.XStream + * @see com.thoughtworks.xstream.converters.ConverterLookup + * @see com.thoughtworks.xstream.converters.basic.AbstractBasicConverter + * @see com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter + */ +public interface Converter { + + /** + * Called by XStream to determine whether to use this converter + * instance to marshall a particular type. + */ + boolean canConvert(Class type); + + /** + * Convert an object to textual data. + * + * @param source The object to be marshalled. + * @param writer A stream to write to. + * @param context A context that allows nested objects to be processed by XStream. + */ + void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context); + + /** + * Convert textual data back into an object. + * + * @param reader The stream to read the text from. + * @param context + * @return The resulting object. + */ + Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConverterLookup.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConverterLookup.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConverterLookup.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,24 @@ +package com.thoughtworks.xstream.converters; + +/** + * Responsible for looking up the correct Converter implementation for a specific type. + * + * @author Joe Walnes + * @see Converter + */ +public interface ConverterLookup { + + /** + * Lookup a converter for a specific type. + *

            + * This type may be any Class, including primitive and array types. It may also be null, signifying + * the value to be converted is a null type. + */ + Converter lookupConverterForType(Class type); + + /** + * @deprecated As of 1.1.1 you can register Converters with priorities, making the need for a default converter redundant. + */ + Converter defaultConverter(); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/DataHolder.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/DataHolder.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/DataHolder.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,16 @@ +package com.thoughtworks.xstream.converters; + +import java.util.Iterator; + +/** + * Holds generic data, to be used as seen fit by the user. + * + * @author Joe Walnes + */ +public interface DataHolder { + + Object get(Object key); + void put(Object key, Object value); + Iterator keys(); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ErrorWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ErrorWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ErrorWriter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,20 @@ +package com.thoughtworks.xstream.converters; + +/** + * To aid debugging, some components are passed an ErrorWriter + * when things go wrong, allowing them to add information + * to the error message that may be helpful to diagnose problems. + * + * @author Joe Walnes + */ +public interface ErrorWriter { + + /** + * Add some information to the error message. + * + * @param name Something to identify the type of information (e.g. 'XPath'). + * @param information Detail of the message (e.g. '/blah/moo[3]' + */ + void add(String name, String information); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/MarshallingContext.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/MarshallingContext.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/MarshallingContext.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,8 @@ +package com.thoughtworks.xstream.converters; + + +public interface MarshallingContext extends DataHolder { + + void convertAnother(Object nextItem); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/UnmarshallingContext.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/UnmarshallingContext.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/UnmarshallingContext.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,13 @@ +package com.thoughtworks.xstream.converters; + +public interface UnmarshallingContext extends DataHolder { + + Object convertAnother(Object current, Class type); + + Object currentObject(); + + Class getRequiredType(); + + void addCompletionCallback(Runnable work, int priority); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/AbstractBasicConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/AbstractBasicConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/AbstractBasicConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,36 @@ +package com.thoughtworks.xstream.converters.basic; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * Base helper class for converters that can store the + * state of an object as a single String. + *

            + *

            Subclasses should implement the toString(Object) and + * fromString(String) methods for the conversion.

            + * + * @author Joe Walnes + */ +public abstract class AbstractBasicConverter implements Converter { + + protected abstract Object fromString(String str); + + public abstract boolean canConvert(Class type); + + protected String toString(Object obj) { + return obj.toString(); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + writer.setValue(toString(source)); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + return fromString(reader.getValue()); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BigDecimalConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BigDecimalConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BigDecimalConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,21 @@ +package com.thoughtworks.xstream.converters.basic; + +import java.math.BigDecimal; + +/** + * Converts a java.math.BigDecimal to a String, retaining + * its precision. + * + * @author Joe Walnes + */ +public class BigDecimalConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(BigDecimal.class); + } + + protected Object fromString(String str) { + return new BigDecimal(str); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BigIntegerConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BigIntegerConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BigIntegerConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,20 @@ +package com.thoughtworks.xstream.converters.basic; + +import java.math.BigInteger; + +/** + * Converts a java.math.BigInteger to a String. + * + * @author Joe Walnes + */ +public class BigIntegerConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(BigInteger.class); + } + + protected Object fromString(String str) { + return new BigInteger(str); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BooleanConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BooleanConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BooleanConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,19 @@ +package com.thoughtworks.xstream.converters.basic; + +/** + * Converts a boolean primitive or java.lang.Boolean wrapper to + * a String. + * + * @author Joe Walnes + */ +public class BooleanConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(boolean.class) || type.equals(Boolean.class); + } + + protected Object fromString(String str) { + return str.equals("true") ? Boolean.TRUE : Boolean.FALSE; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ByteConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ByteConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ByteConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,19 @@ +package com.thoughtworks.xstream.converters.basic; + +/** + * Converts a byte primitive or java.lang.Byte wrapper to + * a String. + * + * @author Joe Walnes + */ +public class ByteConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(byte.class) || type.equals(Byte.class); + } + + protected Object fromString(String str) { + return new Byte((byte) Integer.parseInt(str)); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/CharConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/CharConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/CharConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,39 @@ +package com.thoughtworks.xstream.converters.basic; + +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.Converter; + +/** + * Converts a char primitive or java.lang.Character wrapper to + * a String. If char is \0, this will be marked as an attribute as + * XML does not allow this. + * + * @author Joe Walnes + */ +public class CharConverter implements Converter { + + public boolean canConvert(Class type) { + return type.equals(char.class) || type.equals(Character.class); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + if (source.toString().equals("\0")) { + writer.addAttribute("null", "true"); + } else { + writer.setValue(source.toString()); + } + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + String nullAttribute = reader.getAttribute("null"); + if (nullAttribute != null && nullAttribute.equals("true")) { + return new Character('\0'); + } else { + return new Character(reader.getValue().charAt(0)); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/DateConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/DateConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/DateConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,59 @@ +package com.thoughtworks.xstream.converters.basic; + +import com.thoughtworks.xstream.converters.ConversionException; + +import java.text.ParseException; +import java.util.Date; + +/** + * Converts a java.util.Date to a String as a date format, + * retaining precision down to milliseconds. + * + * @author Joe Walnes + */ +public class DateConverter extends AbstractBasicConverter { + + private final ThreadSafeSimpleDateFormat defaultFormat; + private final ThreadSafeSimpleDateFormat[] acceptableFormats; + + public DateConverter() { + this("yyyy-MM-dd HH:mm:ss.S z", + new String[] { + "yyyy-MM-dd HH:mm:ss.S a", + "yyyy-MM-dd HH:mm:ssz", "yyyy-MM-dd HH:mm:ss z", // JDK 1.3 needs both versions + "yyyy-MM-dd HH:mm:ssa" }); // backwards compatability + } + + public DateConverter(String defaultFormat, String[] acceptableFormats) { + this.defaultFormat = new ThreadSafeSimpleDateFormat(defaultFormat, 4, 20); + this.acceptableFormats = new ThreadSafeSimpleDateFormat[acceptableFormats.length]; + for (int i = 0; i < acceptableFormats.length; i++) { + this.acceptableFormats[i] = new ThreadSafeSimpleDateFormat(acceptableFormats[i], 1, 20); + } + } + + public boolean canConvert(Class type) { + return type.equals(Date.class); + } + + protected Object fromString(String str) { + try { + return defaultFormat.parse(str); + } catch (ParseException e) { + for (int i = 0; i < acceptableFormats.length; i++) { + try { + return acceptableFormats[i].parse(str); + } catch (ParseException e2) { + // no worries, let's try the next format. + } + } + // no dateFormats left to try + throw new ConversionException("Cannot parse date " + str); + } + } + + protected String toString(Object obj) { + return defaultFormat.format((Date) obj); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/DoubleConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/DoubleConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/DoubleConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,19 @@ +package com.thoughtworks.xstream.converters.basic; + +/** + * Converts a double primitive or java.lang.Double wrapper to + * a String. + * + * @author Joe Walnes + */ +public class DoubleConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(double.class) || type.equals(Double.class); + } + + protected Object fromString(String str) { + return Double.valueOf(str); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/FloatConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/FloatConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/FloatConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,19 @@ +package com.thoughtworks.xstream.converters.basic; + +/** + * Converts a float primitive or java.lang.Float wrapper to + * a String. + * + * @author Joe Walnes + */ +public class FloatConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(float.class) || type.equals(Float.class); + } + + protected Object fromString(String str) { + return Float.valueOf(str); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/IntConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/IntConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/IntConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,19 @@ +package com.thoughtworks.xstream.converters.basic; + +/** + * Converts an int primitive or java.lang.Integer wrapper to + * a String. + * + * @author Joe Walnes + */ +public class IntConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(int.class) || type.equals(Integer.class); + } + + protected Object fromString(String str) { + return Integer.decode(str); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/LongConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/LongConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/LongConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,19 @@ +package com.thoughtworks.xstream.converters.basic; + +/** + * Converts a long primitive or java.lang.Long wrapper to + * a String. + * + * @author Joe Walnes + */ +public class LongConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(long.class) || type.equals(Long.class); + } + + protected Object fromString(String str) { + return Long.valueOf(str); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/NullConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/NullConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/NullConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,28 @@ +package com.thoughtworks.xstream.converters.basic; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * Special converter to signify nulls at the root level. + * + * @author Joe Walnes + */ +public class NullConverter implements Converter { + + public boolean canConvert(Class type) { + return type == null; + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + writer.startNode("null"); + writer.endNode(); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + return null; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ShortConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ShortConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ShortConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,19 @@ +package com.thoughtworks.xstream.converters.basic; + +/** + * Converts a short primitive or java.lang.Short wrapper to + * a String. + * + * @author Joe Walnes + */ +public class ShortConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(short.class) || type.equals(Short.class); + } + + protected Object fromString(String str) { + return Short.valueOf(str); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringBufferConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringBufferConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringBufferConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,17 @@ +package com.thoughtworks.xstream.converters.basic; + +/** + * Converts the contents of a StringBuffer to XML. + * + * @author Joe Walnes + */ +public class StringBufferConverter extends AbstractBasicConverter { + + protected Object fromString(String str) { + return new StringBuffer(str); + } + + public boolean canConvert(Class type) { + return type.equals(StringBuffer.class); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,22 @@ +package com.thoughtworks.xstream.converters.basic; + +/** + * Converts a String to a String ;). Well ok, it doesn't + * actually do any conversion. + *

            The converter always calls intern() on the returned + * String to encourage the JVM to reuse instances.

            + * + * @author Joe Walnes + * @see String#intern() + */ +public class StringConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(String.class); + } + + protected Object fromString(String str) { + return str.intern(); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ThreadSafeSimpleDateFormat.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ThreadSafeSimpleDateFormat.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ThreadSafeSimpleDateFormat.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,98 @@ +package com.thoughtworks.xstream.converters.basic; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * Wrapper around java.text.SimpleDateFormat that can + * be called by multiple threads concurrently. + *

            + *

            SimpleDateFormat has a high overhead in creating + * and is not thread safe. To make best use of resources, + * the ThreadSafeSimpleDateFormat provides a dynamically + * sizing pool of instances, each of which will only + * be called by a single thread at a time.

            + *

            + *

            The pool has a maximum capacity, to limit overhead. + * If all instances in the pool are in use and another is + * required, it shall block until one becomes available.

            + * + * @author Joe Walnes + */ +public class ThreadSafeSimpleDateFormat { + + private String formatString; + private final int initialPoolSize; + private final int maxPoolSize; + private transient DateFormat[] pool; + private int nextAvailable = 0; + private final Object mutex = new Object(); + + public ThreadSafeSimpleDateFormat(String format, int initialPoolSize, int maxPoolSize) { + this.formatString = format; + this.initialPoolSize = initialPoolSize; + this.maxPoolSize = maxPoolSize; + } + + public String format(Date date) { + DateFormat format = fetchFromPool(); + try { + return format.format(date); + } finally { + putInPool(format); + } + } + + public Date parse(String date) throws ParseException { + DateFormat format = fetchFromPool(); + try { + return format.parse(date); + } finally { + putInPool(format); + } + } + + private DateFormat fetchFromPool() { + DateFormat result; + synchronized (mutex) { + if (pool == null) { + nextAvailable = -1; + pool = new DateFormat[maxPoolSize]; + for (int i = 0; i < initialPoolSize; i++) { + putInPool(createNew()); + } + } + while (nextAvailable < 0) { + try { + mutex.wait(); + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted whilst waiting " + + "for a free item in the pool : " + e.getMessage()); + } + } + result = pool[nextAvailable]; + nextAvailable--; + } + if (result == null) { + result = createNew(); + putInPool(result); + } + return result; + } + + private void putInPool(DateFormat format) { + synchronized (mutex) { + nextAvailable++; + pool[nextAvailable] = format; + mutex.notify(); + } + } + + private DateFormat createNew() { + return new SimpleDateFormat(formatString, Locale.ENGLISH); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/URLConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/URLConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/URLConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,27 @@ +package com.thoughtworks.xstream.converters.basic; + +import com.thoughtworks.xstream.converters.ConversionException; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Converts a java.net.URL to a string. + * + * @author J. Matthew Pryor + */ +public class URLConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(URL.class); + } + + protected Object fromString(String str) { + try { + return new URL(str); + } catch (MalformedURLException e) { + throw new ConversionException(e); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/package.html =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/package.html (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/package.html (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,9 @@ +

            Converters for common basic types in Java. These include +primitives (int, boolean, etc), wrapper objects (Integer, Boolean, etc), +String, StringBuffer, java.util.Date, null, java.net.URL, +java.math.BigInteger and java.math.BigDecimal.

            + +

            These converters are enabled by default.

            + +

            All of the basic converters will convert the item +into a single String, with no nested elements.

            Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/AbstractCollectionConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/AbstractCollectionConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/AbstractCollectionConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,95 @@ +package com.thoughtworks.xstream.converters.collections; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + +/** + * Base helper class for converters that need to handle + * collections of items (arrays, Lists, Maps, etc). + *

            + *

            Typically, subclasses of this will converter the outer + * structure of the collection, loop through the contents and + * call readItem() or writeItem() for each item.

            + * + * @author Joe Walnes + */ +public abstract class AbstractCollectionConverter implements Converter { + + private final Mapper mapper; + + /** + * @deprecated As of 1.1.1, use {@link #mapper()} + */ + protected ClassMapper classMapper; + + /** + * @deprecated As of 1.1.1, use {@link #mapper()} + */ + protected String classAttributeIdentifier; + + public abstract boolean canConvert(Class type); + + /** + * @deprecated As of 1.1.1, use other constructor. + */ + public AbstractCollectionConverter(ClassMapper classMapper, String classAttributeIdentifier) { + // TODO: this classAttributeIdentifer should be optional - most uses of XStream don't need it. + this.classMapper = classMapper; + this.classAttributeIdentifier = classAttributeIdentifier; + this.mapper = classMapper; + } + + public AbstractCollectionConverter(Mapper mapper) { + this.mapper = mapper; + } + + protected Mapper mapper() { + return mapper; + } + + public abstract void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context); + + public abstract Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context); + + protected void writeItem(Object item, MarshallingContext context, HierarchicalStreamWriter writer) { + // PUBLISHED API METHOD! If changing signature, ensure backwards compatability. + if (item == null) { + // todo: this is duplicated in TreeMarshaller.start() + writer.startNode(mapper().serializedClass(ClassMapper.Null.class)); + writer.endNode(); + } else { + writer.startNode(mapper().serializedClass(item.getClass())); + context.convertAnother(item); + writer.endNode(); + } + } + + protected Object readItem(HierarchicalStreamReader reader, UnmarshallingContext context, Object current) { + // PUBLISHED API METHOD! If changing signature, ensure backwards compatability. + String classAttribute = reader.getAttribute(mapper().attributeForImplementationClass()); + Class type; + if (classAttribute == null) { + type = mapper().realClass(reader.getNodeName()); + } else { + type = mapper().realClass(classAttribute); + } + return context.convertAnother(current, type); + } + + protected Object createCollection(Class type) { + Class defaultType = mapper().defaultImplementationOf(type); + try { + return defaultType.newInstance(); + } catch (InstantiationException e) { + throw new ConversionException("Cannot instantiate " + defaultType.getName(), e); + } catch (IllegalAccessException e) { + throw new ConversionException("Cannot instantiate " + defaultType.getName(), e); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/ArrayConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/ArrayConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/ArrayConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,65 @@ +package com.thoughtworks.xstream.converters.collections; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Converts an array of objects or primitives to XML, using + * a nested child element for each item. + * + * @author Joe Walnes + */ +public class ArrayConverter extends AbstractCollectionConverter { + + /** + * @deprecated As of 1.1.1, use other constructor. + */ + public ArrayConverter(ClassMapper classMapper, String classAttributeIdentifier) { + super(classMapper, classAttributeIdentifier); + } + + public ArrayConverter(Mapper mapper) { + super(mapper); + } + + public boolean canConvert(Class type) { + return type.isArray(); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + int length = Array.getLength(source); + for (int i = 0; i < length; i++) { + Object item = Array.get(source, i); + writeItem(item, context, writer); + } + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + // read the items from xml into a list + List items = new ArrayList(); + while (reader.hasMoreChildren()) { + reader.moveDown(); + Object item = readItem(reader, context, null); // TODO: arg, what should replace null? + items.add(item); + reader.moveUp(); + } + // now convertAnother the list into an array + // (this has to be done as a separate list as the array size is not + // known until all items have been read) + Object array = Array.newInstance(context.getRequiredType().getComponentType(), items.size()); + int i = 0; + for (Iterator iterator = items.iterator(); iterator.hasNext();) { + Array.set(array, i++, iterator.next()); + } + return array; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/BitSetConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/BitSetConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/BitSetConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,50 @@ +package com.thoughtworks.xstream.converters.collections; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +import java.util.BitSet; +import java.util.StringTokenizer; + +/** + * Converts a java.util.BitSet to XML, as a compact + * comma delimited list of ones and zeros. + * + * @author Joe Walnes + */ +public class BitSetConverter implements Converter { + + public boolean canConvert(Class type) { + return type.equals(BitSet.class); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + BitSet bitSet = (BitSet) source; + StringBuffer buffer = new StringBuffer(); + boolean seenFirst = false; + for (int i = 0; i < bitSet.length(); i++) { + if (bitSet.get(i)) { + if (seenFirst) { + buffer.append(','); + } else { + seenFirst = true; + } + buffer.append(i); + } + } + writer.setValue(buffer.toString()); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + BitSet result = new BitSet(); + StringTokenizer tokenizer = new StringTokenizer(reader.getValue(), ",", false); + while (tokenizer.hasMoreTokens()) { + int index = Integer.parseInt(tokenizer.nextToken()); + result.set(index); + } + return result; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/CharArrayConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/CharArrayConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/CharArrayConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,29 @@ +package com.thoughtworks.xstream.converters.collections; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * Converts a char[] to XML, storing the contents as a single + * String. + * + * @author Joe Walnes + */ +public class CharArrayConverter implements Converter { + + public boolean canConvert(Class type) { + return type.isArray() && type.getComponentType().equals(char.class); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + char[] chars = (char[]) source; + writer.setValue(new String(chars)); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + return reader.getValue().toCharArray(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/CollectionConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/CollectionConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/CollectionConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,66 @@ +package com.thoughtworks.xstream.converters.collections; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + +import java.util.*; + +/** + * Converts most common Collections (Lists and Sets) to XML, specifying a nested + * element for each item. + *

            + *

            Supports java.util.ArrayList, java.util.HashSet, + * java.util.LinkedList, java.util.Vector and java.util.LinkedHashSet.

            + * + * @author Joe Walnes + */ +public class CollectionConverter extends AbstractCollectionConverter { + + /** + * @deprecated As of 1.1.1, use other constructor. + */ + public CollectionConverter(ClassMapper classMapper, String classAttributeIdentifier) { + super(classMapper, classAttributeIdentifier); + } + + public CollectionConverter(Mapper mapper) { + super(mapper); + } + + public boolean canConvert(Class type) { + return type.equals(ArrayList.class) + || type.equals(HashSet.class) + || type.equals(LinkedList.class) + || type.equals(Vector.class) + || (JVM.is14() && type.getName().equals("java.util.LinkedHashSet")); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + Collection collection = (Collection) source; + for (Iterator iterator = collection.iterator(); iterator.hasNext();) { + Object item = iterator.next(); + writeItem(item, context, writer); + } + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + Collection collection = (Collection) createCollection(context.getRequiredType()); + populateCollection(reader, context, collection); + return collection; + } + + protected void populateCollection(HierarchicalStreamReader reader, UnmarshallingContext context, Collection collection) { + while (reader.hasMoreChildren()) { + reader.moveDown(); + Object item = readItem(reader, context, collection); + collection.add(item); + reader.moveUp(); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/MapConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/MapConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/MapConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,81 @@ +package com.thoughtworks.xstream.converters.collections; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; + +/** + * Converts a java.util.Map to XML, specifying an 'entry' + * element with 'key' and 'value' children. + *

            + *

            Supports java.util.HashMap, java.util.Hashtable and + * java.util.LinkedHashMap.

            + * + * @author Joe Walnes + */ +public class MapConverter extends AbstractCollectionConverter { + + /** + * @deprecated As of 1.1.1, use other constructor. + */ + public MapConverter(ClassMapper classMapper, String classAttributeIdentifier) { + super(classMapper, classAttributeIdentifier); + } + + public MapConverter(Mapper mapper) { + super(mapper); + } + + public boolean canConvert(Class type) { + return type.equals(HashMap.class) + || type.equals(Hashtable.class) + || (JVM.is14() && type.getName().equals("java.util.LinkedHashMap")); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + Map map = (Map) source; + for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) { + Map.Entry entry = (Map.Entry) iterator.next(); + writer.startNode(mapper().serializedClass(Map.Entry.class)); + + writeItem(entry.getKey(), context, writer); + writeItem(entry.getValue(), context, writer); + + writer.endNode(); + } + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + Map map = (Map) createCollection(context.getRequiredType()); + populateMap(reader, context, map); + return map; + } + + protected void populateMap(HierarchicalStreamReader reader, UnmarshallingContext context, Map map) { + while (reader.hasMoreChildren()) { + reader.moveDown(); + + reader.moveDown(); + Object key = readItem(reader, context, map); + reader.moveUp(); + + reader.moveDown(); + Object value = readItem(reader, context, map); + reader.moveUp(); + + map.put(key, value); + + reader.moveUp(); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/PropertiesConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/PropertiesConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/PropertiesConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,70 @@ +package com.thoughtworks.xstream.converters.collections; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.core.util.Fields; + +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.lang.reflect.Field; + +/** + * Special converter for java.util.Properties that stores + * properties in a more compact form than java.util.Map. + *

            + *

            Because all entries of a Properties instance + * are Strings, a single element is used for each property + * with two attributes; one for key and one for value.

            + *

            Additionally, default properties are also serialized, if they are present.

            + * + * @author Joe Walnes + * @author Kevin Ring + */ +public class PropertiesConverter implements Converter { + + private final Field defaultsField = Fields.find(Properties.class, "defaults"); + + public boolean canConvert(Class type) { + return Properties.class == type; + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + Properties properties = (Properties) source; + for (Iterator iterator = properties.entrySet().iterator(); iterator.hasNext();) { + Map.Entry entry = (Map.Entry) iterator.next(); + writer.startNode("property"); + writer.addAttribute("name", entry.getKey().toString()); + writer.addAttribute("value", entry.getValue().toString()); + writer.endNode(); + } + Properties defaults = (Properties) Fields.read(defaultsField, properties); + if (defaults != null) { + writer.startNode("defaults"); + marshal(defaults, writer, context); + writer.endNode(); + } + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + Properties properties = new Properties(); + while (reader.hasMoreChildren()) { + reader.moveDown(); + if (reader.getNodeName().equals("defaults")) { + Properties defaults = (Properties) unmarshal(reader, context); + Fields.write(defaultsField, properties, defaults); + } else { + String name = reader.getAttribute("name"); + String value = reader.getAttribute("value"); + properties.setProperty(name, value); + } + reader.moveUp(); + } + return properties; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/TreeMapConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/TreeMapConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/TreeMapConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,69 @@ +package com.thoughtworks.xstream.converters.collections; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + +import java.util.Comparator; +import java.util.TreeMap; + +/** + * Converts a java.util.TreeMap to XML, and serializes + * the associated java.util.Comparator. + * + * @author Joe Walnes + */ +public class TreeMapConverter extends MapConverter { + + /** + * @deprecated As of 1.1.1, use other constructor. + */ + public TreeMapConverter(ClassMapper classMapper, String classAttributeIdentifier) { + super(classMapper, classAttributeIdentifier); + } + + public TreeMapConverter(Mapper mapper) { + super(mapper); + } + + public boolean canConvert(Class type) { + return type.equals(TreeMap.class); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + TreeMap treeMap = (TreeMap) source; + Comparator comparator = treeMap.comparator(); + if (comparator == null) { + writer.startNode("no-comparator"); + writer.endNode(); + } else { + writer.startNode("comparator"); + writer.addAttribute("class", mapper().serializedClass(comparator.getClass())); + context.convertAnother(comparator); + writer.endNode(); + } + super.marshal(source, writer, context); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + reader.moveDown(); + TreeMap result; + if (reader.getNodeName().equals("comparator")) { + String comparatorClass = reader.getAttribute("class"); + Comparator comparator = (Comparator) context.convertAnother(null, mapper().realClass(comparatorClass)); + result = new TreeMap(comparator); + } else if (reader.getNodeName().equals("no-comparator")) { + result = new TreeMap(); + } else { + throw new ConversionException("TreeMap does not contain element"); + } + reader.moveUp(); + super.populateMap(reader, context, result); + return result; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/TreeSetConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/TreeSetConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/TreeSetConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,69 @@ +package com.thoughtworks.xstream.converters.collections; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + +import java.util.Comparator; +import java.util.TreeSet; + +/** + * Converts a java.util.TreeSet to XML, and serializes + * the associated java.util.Comparator. + * + * @author Joe Walnes + */ +public class TreeSetConverter extends CollectionConverter { + + /** + * @deprecated As of 1.1.1, use other constructor. + */ + public TreeSetConverter(ClassMapper classMapper, String classAttributeIdentifier) { + super(classMapper, classAttributeIdentifier); + } + + public TreeSetConverter(Mapper mapper) { + super(mapper); + } + + public boolean canConvert(Class type) { + return type.equals(TreeSet.class); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + TreeSet treeSet = (TreeSet) source; + Comparator comparator = treeSet.comparator(); + if (comparator == null) { + writer.startNode("no-comparator"); + writer.endNode(); + } else { + writer.startNode("comparator"); + writer.addAttribute("class", mapper().serializedClass(comparator.getClass())); + context.convertAnother(comparator); + writer.endNode(); + } + super.marshal(source, writer, context); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + reader.moveDown(); + TreeSet result; + if (reader.getNodeName().equals("comparator")) { + String comparatorClass = reader.getAttribute("class"); + Comparator comparator = (Comparator) context.convertAnother(null, mapper().realClass(comparatorClass)); + result = new TreeSet(comparator); + } else if (reader.getNodeName().equals("no-comparator")) { + result = new TreeSet(); + } else { + throw new ConversionException("TreeSet does not contain element"); + } + reader.moveUp(); + super.populateCollection(reader, context, result); + return result; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/package.html =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/package.html (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/package.html (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,4 @@ +

            Converters for collection objects that write their items +as nested elements, such as arrays, Lists, Sets and Maps.

            + +

            All the converters in this package are enabled by default.

            \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,37 @@ +// ***** READ THIS ***** +// This class will only compile with JDK 1.5.0 or above as it test Java enums. +// If you are using an earlier version of Java, just don't try to build this class. XStream should work fine without it. + +package com.thoughtworks.xstream.converters.enums; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + +/** + * Converter for JDK 1.5 enums. Combined with EnumMapper this also deals with polymorphic enums. + * + * @author Eric Snell + * @author Bryan Coleman + */ +public class EnumConverter implements Converter { + + public boolean canConvert(Class type) { + return type.isEnum() || Enum.class.isAssignableFrom(type); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + writer.setValue(((Enum) source).name()); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + Class type = context.getRequiredType(); + if (type.getSuperclass() != Enum.class) { + type = type.getSuperclass(); // polymorphic enums + } + return Enum.valueOf(type, reader.getValue()); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumMapConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumMapConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumMapConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,48 @@ +// ***** READ THIS ***** +// This class will only compile with JDK 1.5.0 or above as it test Java enums. +// If you are using an earlier version of Java, just don't try to build this class. XStream should work fine without it. + +package com.thoughtworks.xstream.converters.enums; + +import com.thoughtworks.xstream.converters.collections.MapConverter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.mapper.Mapper; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.core.util.Fields; + +import java.util.EnumMap; +import java.lang.reflect.Field; + +/** + * Serializes an Java 5 EnumMap, including the type of Enum it's for. + * + * @author Joe Walnes + */ +public class EnumMapConverter extends MapConverter { + + private final Field typeField; + + public EnumMapConverter(Mapper mapper) { + super(mapper); + typeField = Fields.find(EnumMap.class, "keyType"); + } + + public boolean canConvert(Class type) { + return type == EnumMap.class; + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + Class type = (Class) Fields.read(typeField, source); + writer.addAttribute(mapper().attributeForEnumType(), mapper().serializedClass(type)); + super.marshal(source, writer, context); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + Class type = mapper().realClass(reader.getAttribute(mapper().attributeForEnumType())); + EnumMap map = new EnumMap(type); + populateMap(reader, context, map); + return map; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumSetConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumSetConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumSetConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,73 @@ +// ***** READ THIS ***** +// This class will only compile with JDK 1.5.0 or above as it test Java enums. +// If you are using an earlier version of Java, just don't try to build this class. XStream should work fine without it. + +package com.thoughtworks.xstream.converters.enums; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; +import com.thoughtworks.xstream.core.util.Fields; + +import java.lang.reflect.Field; +import java.util.EnumSet; +import java.util.Iterator; + +/** + * Serializes a Java 5 EnumSet. + * + * @author Joe Walnes + */ +public class EnumSetConverter implements Converter { + + private final Field typeField; + private final Mapper mapper; + + public EnumSetConverter(Mapper mapper) { + this.mapper = mapper; + typeField = Fields.find(EnumSet.class, "elementType"); + } + + public boolean canConvert(Class type) { + return EnumSet.class.isAssignableFrom(type); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + EnumSet set = (EnumSet) source; + Class enumTypeForSet = (Class) Fields.read(typeField, set); + writer.addAttribute(mapper.attributeForEnumType(), mapper.serializedClass(enumTypeForSet)); + writer.setValue(joinEnumValues(set)); + } + + private String joinEnumValues(EnumSet set) { + boolean seenFirst = false; + StringBuffer result = new StringBuffer(); + for (Iterator iterator = set.iterator(); iterator.hasNext();) { + Enum value = (Enum) iterator.next(); + if (seenFirst) { + result.append(','); + } else { + seenFirst = true; + } + result.append(value.name()); + } + return result.toString(); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + Class enumTypeForSet = mapper.realClass(reader.getAttribute(mapper.attributeForEnumType())); + EnumSet set = EnumSet.noneOf(enumTypeForSet); + String[] enumValues = reader.getValue().split(","); + for (int i = 0; i < enumValues.length; i++) { + String enumValue = enumValues[i]; + if(enumValue.length() > 0) { + set.add(Enum.valueOf(enumTypeForSet, enumValue)); + } + } + return set; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ColorConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ColorConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ColorConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,54 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +import java.awt.*; +import java.util.HashMap; +import java.util.Map; + +/** + * Converts a java.awt.Color to XML, using four nested elements: + * red, green, blue, alpha. + * + * @author Joe Walnes + */ +public class ColorConverter implements Converter { + + public boolean canConvert(Class type) { + // String comparison is used here because Color.class loads the class which in turns instantiates AWT, + // which is nasty if you don't want it. + return type.getName().equals("java.awt.Color"); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + Color color = (Color) source; + write("red", color.getRed(), writer); + write("green", color.getGreen(), writer); + write("blue", color.getBlue(), writer); + write("alpha", color.getAlpha(), writer); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + Map elements = new HashMap(); + while (reader.hasMoreChildren()) { + reader.moveDown(); + elements.put(reader.getNodeName(), Integer.valueOf(reader.getValue())); + reader.moveUp(); + } + return new Color(((Integer) elements.get("red")).intValue(), + ((Integer) elements.get("green")).intValue(), + ((Integer) elements.get("blue")).intValue(), + ((Integer) elements.get("alpha")).intValue()); + } + + private void write(String fieldName, int value, HierarchicalStreamWriter writer) { + writer.startNode(fieldName); + writer.setValue(String.valueOf(value)); + writer.endNode(); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/CurrencyConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/CurrencyConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/CurrencyConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,25 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; + +import java.sql.Date; +import java.util.Currency; + +/** + * Converts a java.util.Currency to String. Despite the name of this class, it has nothing to do with converting + * currencies between exchange rates! It makes sense in the context of XStream. + * + * @author Jose A. Illescas + * @author Joe Walnes + */ +public class CurrencyConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(Currency.class); + } + + protected Object fromString(String str) { + return Currency.getInstance(str); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,81 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.DynamicProxyMapper; +import com.thoughtworks.xstream.mapper.Mapper; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.List; + +/** + * Converts a dynamic proxy to XML, storing the implemented + * interfaces and handler. + * + * @author Joe Walnes + */ +public class DynamicProxyConverter implements Converter { + + private ClassLoader classLoader; + private Mapper mapper; + + public DynamicProxyConverter(Mapper mapper) { + this(mapper, DynamicProxyConverter.class.getClassLoader()); + } + + public DynamicProxyConverter(Mapper mapper, ClassLoader classLoader) { + this.classLoader = classLoader; + this.mapper = mapper; + } + + public boolean canConvert(Class type) { + return type.equals(DynamicProxyMapper.DynamicProxy.class) || Proxy.isProxyClass(type); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + InvocationHandler invocationHandler = Proxy.getInvocationHandler(source); + addInterfacesToXml(source, writer); + writer.startNode("handler"); + writer.addAttribute("class", mapper.serializedClass(invocationHandler.getClass())); + context.convertAnother(invocationHandler); + writer.endNode(); + } + + private void addInterfacesToXml(Object source, HierarchicalStreamWriter writer) { + Class[] interfaces = source.getClass().getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + Class currentInterface = interfaces[i]; + writer.startNode("interface"); + writer.setValue(mapper.serializedClass(currentInterface)); + writer.endNode(); + } + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + List interfaces = new ArrayList(); + InvocationHandler handler = null; + while (reader.hasMoreChildren()) { + reader.moveDown(); + String elementName = reader.getNodeName(); + if (elementName.equals("interface")) { + interfaces.add(mapper.realClass(reader.getValue())); + } else if (elementName.equals("handler")) { + Class handlerType = mapper.realClass(reader.getAttribute("class")); + handler = (InvocationHandler) context.convertAnother(null, handlerType); + } + reader.moveUp(); + } + if (handler == null) { + throw new ConversionException("No InvocationHandler specified for dynamic proxy"); + } + Class[] interfacesAsArray = new Class[interfaces.size()]; + interfaces.toArray(interfacesAsArray); + return Proxy.newProxyInstance(classLoader, interfacesAsArray, handler); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,63 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.basic.ByteConverter; +import com.thoughtworks.xstream.core.util.Base64Encoder; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Converts a byte array to a single Base64 encoding string. + * + * @author Joe Walnes + */ +public class EncodedByteArrayConverter implements Converter { + + private final Base64Encoder base64 = new Base64Encoder(); + private final ByteConverter byteConverter = new ByteConverter(); + + public boolean canConvert(Class type) { + return type.isArray() && type.getComponentType().equals(byte.class); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + writer.setValue(base64.encode((byte[]) source)); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + String data = reader.getValue(); // needs to be called before hasMoreChildren. + if (!reader.hasMoreChildren()) { + return base64.decode(data); + } else { + // backwards compatability ... try to unmarshal byte arrays that haven't been encoded + return unmarshalIndividualByteElements(reader, context); + } + } + + private Object unmarshalIndividualByteElements(HierarchicalStreamReader reader, UnmarshallingContext context) { + List bytes = new ArrayList(); // have to create a temporary list because don't know the size of the array + boolean firstIteration = true; + while (firstIteration || reader.hasMoreChildren()) { // hangover from previous hasMoreChildren + reader.moveDown(); + bytes.add(byteConverter.unmarshal(reader, context)); + reader.moveUp(); + firstIteration = false; + } + // copy into real array + byte[] result = new byte[bytes.size()]; + int i = 0; + for (Iterator iterator = bytes.iterator(); iterator.hasNext();) { + Byte b = (Byte) iterator.next(); + result[i] = b.byteValue(); + i++; + } + return result; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/FileConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/FileConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/FileConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,27 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; + +import java.io.File; + +/** + * This converter will take care of storing and retrieving File with either + * an absolute path OR a relative path depending on how they were created. + * + * @author Joe Walnes + */ +public class FileConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(File.class); + } + + protected Object fromString(String str) { + return new File(str); + } + + protected String toString(Object obj) { + return ((File) obj).getPath(); + } + +} \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/FontConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/FontConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/FontConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,40 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +import javax.swing.plaf.FontUIResource; +import java.awt.*; +import java.util.Map; + +public class FontConverter implements Converter { + + public boolean canConvert(Class type) { + // String comparison is used here because Font.class loads the class which in turns instantiates AWT, + // which is nasty if you don't want it. + return type.getName().equals("java.awt.Font") || type.getName().equals("javax.swing.plaf.FontUIResource"); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + Font font = (Font) source; + Map attributes = font.getAttributes(); + writer.startNode("attributes"); // + context.convertAnother(attributes); + writer.endNode(); // + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + reader.moveDown(); // into + Map attributes = (Map) context.convertAnother(null, Map.class); + reader.moveUp(); // out of + Font font = Font.getFont(attributes); + if (context.getRequiredType() == FontUIResource.class) { + return new FontUIResource(font); + } else { + return font; + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,57 @@ +package com.thoughtworks.xstream.converters.extended; + +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * Converts a java.util.GregorianCalendar to XML. Note that although it currently only contains one field, it nests + * it inside a child element, to allow for other fields to be stored in the future. + * + * @author Joe Walnes + * @author Jörg Schaible + */ +public class GregorianCalendarConverter implements Converter { + + public boolean canConvert(Class type) { + return type.equals(GregorianCalendar.class); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + GregorianCalendar calendar = (GregorianCalendar) source; + writer.startNode("time"); + long timeInMillis = calendar.getTime().getTime(); // calendar.getTimeInMillis() not available under JDK 1.3 + writer.setValue(String.valueOf(timeInMillis)); + writer.endNode(); + writer.startNode("timezone"); + writer.setValue(calendar.getTimeZone().getID()); + writer.endNode(); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + reader.moveDown(); + long timeInMillis = Long.parseLong(reader.getValue()); + reader.moveUp(); + final String timeZone; + if (reader.hasMoreChildren()) { + reader.moveDown(); + timeZone = reader.getValue(); + reader.moveUp(); + } else { // backward compatibility to XStream 1.1.2 and below + timeZone = TimeZone.getDefault().getID(); + } + + GregorianCalendar result = new GregorianCalendar(); + result.setTimeZone(TimeZone.getTimeZone(timeZone)); + result.setTime(new Date(timeInMillis)); // calendar.setTimeInMillis() not available under JDK 1.3 + + return result; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601DateConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601DateConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601DateConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,29 @@ +package com.thoughtworks.xstream.converters.extended; + +import java.util.Calendar; +import java.util.Date; + + +/** + * A DateConverter conforming to the ISO8601 standard. + * http://www.iso.ch/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=26780 + * + * @author Mauro Talevi + * @author Jörg Schaible + */ +public class ISO8601DateConverter extends ISO8601GregorianCalendarConverter { + + public boolean canConvert(Class type) { + return type.equals(Date.class); + } + + protected Object fromString(String str) { + return ((Calendar)super.fromString(str)).getTime(); + } + + protected String toString(Object obj) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime((Date)obj); + return super.toString(calendar); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,104 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; + +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; + +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.TimeZone; + + +/** + * A GregorianCalendarConverter conforming to the ISO8601 standard. + * http://www.iso.ch/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=26780 + * + * @author Mauro Talevi + * @author Jörg Schaible + */ +public class ISO8601GregorianCalendarConverter extends AbstractBasicConverter { + private static final DateTimeFormatter[] formattersUTC = new DateTimeFormatter[]{ + ISODateTimeFormat.dateTime(), + ISODateTimeFormat.dateTimeNoMillis(), + ISODateTimeFormat.basicDateTime(), + ISODateTimeFormat.basicOrdinalDateTime(), + ISODateTimeFormat.basicOrdinalDateTimeNoMillis(), + ISODateTimeFormat.basicTime(), + ISODateTimeFormat.basicTimeNoMillis(), + ISODateTimeFormat.basicTTime(), + ISODateTimeFormat.basicTTimeNoMillis(), + ISODateTimeFormat.basicWeekDateTime(), + ISODateTimeFormat.basicWeekDateTimeNoMillis(), + ISODateTimeFormat.ordinalDateTime(), + ISODateTimeFormat.ordinalDateTimeNoMillis(), + ISODateTimeFormat.time(), + ISODateTimeFormat.timeNoMillis(), + ISODateTimeFormat.tTime(), + ISODateTimeFormat.tTimeNoMillis(), + ISODateTimeFormat.weekDateTime(), + ISODateTimeFormat.weekDateTimeNoMillis(),}; + private static final DateTimeFormatter[] formattersNoUTC = new DateTimeFormatter[]{ + ISODateTimeFormat.basicDate(), + ISODateTimeFormat.basicOrdinalDate(), + ISODateTimeFormat.basicWeekDate(), + ISODateTimeFormat.date(), + ISODateTimeFormat.dateHour(), + ISODateTimeFormat.dateHourMinute(), + ISODateTimeFormat.dateHourMinuteSecond(), + ISODateTimeFormat.dateHourMinuteSecondFraction(), + ISODateTimeFormat.dateHourMinuteSecondMillis(), + ISODateTimeFormat.hour(), + ISODateTimeFormat.hourMinute(), + ISODateTimeFormat.hourMinuteSecond(), + ISODateTimeFormat.hourMinuteSecondFraction(), + ISODateTimeFormat.hourMinuteSecondMillis(), + ISODateTimeFormat.ordinalDate(), + ISODateTimeFormat.weekDate(), + ISODateTimeFormat.year(), + ISODateTimeFormat.yearMonth(), + ISODateTimeFormat.yearMonthDay(), + ISODateTimeFormat.weekyear(), + ISODateTimeFormat.weekyearWeek(), + ISODateTimeFormat.weekyearWeekDay(),}; + + public boolean canConvert(Class type) { + return type.equals(GregorianCalendar.class); + } + + protected Object fromString(String str) { + for (int i = 0; i < formattersUTC.length; i++) { + DateTimeFormatter formatter = formattersUTC[i]; + try { + DateTime dt = formatter.parseDateTime(str); + Calendar calendar = dt.toCalendar(Locale.getDefault()); + calendar.setTimeZone(TimeZone.getDefault()); + return calendar; + } catch (IllegalArgumentException e) { + // try with next formatter + } + } + String timeZoneID = TimeZone.getDefault().getID(); + for (int i = 0; i < formattersNoUTC.length; i++) { + try { + DateTimeFormatter formatter = formattersNoUTC[i].withZone(DateTimeZone.forID(timeZoneID)); + DateTime dt = formatter.parseDateTime(str); + Calendar calendar = dt.toCalendar(Locale.getDefault()); + calendar.setTimeZone(TimeZone.getDefault()); + return calendar; + } catch (IllegalArgumentException e) { + // try with next formatter + } + } + throw new ConversionException("Cannot parse date " + str); + } + + protected String toString(Object obj) { + DateTime dt = new DateTime(obj); + return dt.toString(formattersUTC[0]); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,50 @@ +package com.thoughtworks.xstream.converters.extended; + +import java.sql.Timestamp; +import java.util.Date; + + +/** + * A SqlTimestampConverter conforming to the ISO8601 standard. + * http://www.iso.ch/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=26780 + * + * @author Jörg Schaible + * @since 1.2 + */ +public class ISO8601SqlTimestampConverter extends ISO8601DateConverter { + + final static String PADDING = "000000000"; + + public boolean canConvert(Class type) { + return type.equals(Timestamp.class); + } + + protected Object fromString(String str) { + final int idxFraction = str.lastIndexOf('.'); + int nanos = 0; + if (idxFraction > 0) { + int idx; + for (idx = idxFraction + 1; Character.isDigit(str.charAt(idx)); ++idx) + ; + nanos = Integer.parseInt(str.substring(idxFraction + 1, idx)); + str = str.substring(0, idxFraction) + str.substring(idx); + } + final Date date = (Date)super.fromString(str); + final Timestamp timestamp = new Timestamp(date.getTime()); + timestamp.setNanos(nanos); + return timestamp; + } + + protected String toString(Object obj) { + final Timestamp timestamp = (Timestamp)obj; + String str = super.toString(new Date((timestamp.getTime() / 1000) * 1000)); + final String nanos = String.valueOf(timestamp.getNanos()); + final int idxFraction = str.lastIndexOf('.'); + str = str.substring(0, idxFraction + 1) + + PADDING.substring(nanos.length()) + + nanos + + str.substring(idxFraction + 4); + return str; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaClassConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaClassConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaClassConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,54 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; + +/** + * Converts a java.lang.Class to XML. + * + * @author Aslak Hellesøy + * @author Joe Walnes + * @author Matthew Sandoz + */ +public class JavaClassConverter extends AbstractBasicConverter { + + private ClassLoader classLoader; + + /** + * @deprecated As of 1.1.1 - use other constructor and explicitly supply a ClassLoader. + */ + public JavaClassConverter() { + this(Thread.currentThread().getContextClassLoader()); + } + + public JavaClassConverter(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + public boolean canConvert(Class clazz) { + return Class.class.equals(clazz); // :) + } + + protected String toString(Object obj) { + return ((Class) obj).getName(); + } + + protected Object fromString(String str) { + try { + return + str.equals("void") ? void.class : + str.equals("byte") ? byte.class : + str.equals("int") ? int.class : + str.equals("long") ? long.class : + str.equals("float") ? float.class : + str.equals("boolean") ? boolean.class : + str.equals("double") ? double.class : + str.equals("char") ? char.class : + str.equals("short") ? short.class : + Class.forName(str, false, classLoader); + } catch (ClassNotFoundException e) { + throw new ConversionException("Cannot load java class " + str, e); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaMethodConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaMethodConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaMethodConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,133 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +/** + * Converts a java.lang.reflect.Method to XML. + * + * @author Aslak Hellesøy + */ +public class JavaMethodConverter implements Converter { + + private final ClassLoader classLoader; + + public JavaMethodConverter() { + this(JavaMethodConverter.class.getClassLoader()); + } + + public JavaMethodConverter(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + public boolean canConvert(Class type) { + return type.equals(Method.class) || type.equals(Constructor.class); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + if (source instanceof Method) { + Method method = (Method) source; + String declaringClassName = method.getDeclaringClass().getName(); + marshalMethod(writer, declaringClassName, method.getName(), method.getParameterTypes()); + } else { + Constructor method = (Constructor) source; + String declaringClassName = method.getDeclaringClass().getName(); + marshalMethod(writer, declaringClassName, null, method.getParameterTypes()); + } + } + + private void marshalMethod(HierarchicalStreamWriter writer, String declaringClassName, String methodName, Class[] parameterTypes) { + + writer.startNode("class"); + writer.setValue(declaringClassName); + writer.endNode(); + + if (methodName != null) { + // it's a method and not a ctor + writer.startNode("name"); + writer.setValue(methodName); + writer.endNode(); + } + + writer.startNode("parameter-types"); + for (int i = 0; i < parameterTypes.length; i++) { + Class parameterType = parameterTypes[i]; + writer.startNode("class"); + writer.setValue(parameterType.getName()); + writer.endNode(); + } + writer.endNode(); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + try { + boolean isMethodNotConstructor = context.getRequiredType().equals(Method.class); + + reader.moveDown(); + String declaringClassName = reader.getValue(); + Class declaringClass = loadClass(declaringClassName); + reader.moveUp(); + + String methodName = null; + if (isMethodNotConstructor) { + reader.moveDown(); + methodName = reader.getValue(); + reader.moveUp(); + } + + reader.moveDown(); + List parameterTypeList = new ArrayList(); + while (reader.hasMoreChildren()) { + reader.moveDown(); + String parameterTypeName = reader.getValue(); + parameterTypeList.add(loadClass(parameterTypeName)); + reader.moveUp(); + } + Class[] parameterTypes = (Class[]) parameterTypeList.toArray(new Class[parameterTypeList.size()]); + reader.moveUp(); + + if (isMethodNotConstructor) { + return declaringClass.getDeclaredMethod(methodName, parameterTypes); + } else { + return declaringClass.getDeclaredConstructor(parameterTypes); + } + } catch (ClassNotFoundException e) { + throw new ConversionException(e); + } catch (NoSuchMethodException e) { + throw new ConversionException(e); + } + } + + private Class loadClass(String className) throws ClassNotFoundException { + Class primitiveClass = primitiveClassForName(className); + if( primitiveClass != null ){ + return primitiveClass; + } + return classLoader.loadClass(className); + } + + /** + * Lookup table for primitive types. + */ + private Class primitiveClassForName(String name) { + return name.equals("void") ? Void.TYPE : + name.equals("boolean") ? Boolean.TYPE : + name.equals("byte") ? Byte.TYPE : + name.equals("char") ? Character.TYPE : + name.equals("short") ? Short.TYPE : + name.equals("int") ? Integer.TYPE : + name.equals("long") ? Long.TYPE : + name.equals("float") ? Float.TYPE : + name.equals("double") ? Double.TYPE : + null; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/LocaleConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/LocaleConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/LocaleConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,47 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; + +import java.util.Locale; + +/** + * Converts a java.util.Locale to a string. + * + * @author Jose A. Illescas + * @author Joe Walnes + */ +public class LocaleConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(Locale.class); + } + + protected Object fromString(String str) { + int[] underscorePositions = underscorePositions(str); + String language, country, variant; + if (underscorePositions[0] == -1) { // "language" + language = str; + country = ""; + variant = ""; + } else if (underscorePositions[1] == -1) { // "language_country" + language = str.substring(0, underscorePositions[0]); + country = str.substring(underscorePositions[0] + 1); + variant = ""; + } else { // "language_country_variant" + language = str.substring(0, underscorePositions[0]); + country = str.substring(underscorePositions[0] + 1, underscorePositions[1]); + variant = str.substring(underscorePositions[1] + 1); + } + return new Locale(language, country, variant); + } + + private int[] underscorePositions(String in) { + int[] result = new int[2]; + for (int i = 0; i < result.length; i++) { + int last = i == 0 ? 0 : result[i - 1]; + result[i] = in.indexOf('_', last + 1); + } + return result; + } + +} \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/RegexPatternConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/RegexPatternConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/RegexPatternConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,35 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + +import java.util.regex.Pattern; + +/** + * Ensures java.util.regex.Pattern is compiled upon deserialization. + */ +public class RegexPatternConverter implements Converter { + + private Converter defaultConverter; + + public RegexPatternConverter(Converter defaultConverter) { + this.defaultConverter = defaultConverter; + } + + public boolean canConvert(final Class type) { + return type.equals(Pattern.class); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + defaultConverter.marshal(source, writer, context); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + Pattern notCompiled = (Pattern) defaultConverter.unmarshal(reader, context); + return Pattern.compile(notCompiled.pattern(), notCompiled.flags()); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlDateConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlDateConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlDateConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,23 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; + +import java.sql.Date; +import java.sql.Time; + +/** + * Converts a java.sql.Date to text. + * + * @author Jose A. Illescas + */ +public class SqlDateConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(Date.class); + } + + protected Object fromString(String str) { + return Date.valueOf(str); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlTimeConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlTimeConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlTimeConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,22 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; + +import java.sql.Time; + +/** + * Converts a java.sql.Time to text. Warning: Any granularity smaller than seconds is lost. + * + * @author Jose A. Illescas + */ +public class SqlTimeConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(Time.class); + } + + protected Object fromString(String str) { + return Time.valueOf(str); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlTimestampConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlTimestampConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlTimestampConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,22 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; + +import java.sql.Timestamp; + +/** + * Converts a java.sql.Timestamp to text. + * + * @author Joe Walnes + */ +public class SqlTimestampConverter extends AbstractBasicConverter { + + public boolean canConvert(Class type) { + return type.equals(Timestamp.class); + } + + protected Object fromString(String str) { + return Timestamp.valueOf(str); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/StackTraceElementConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/StackTraceElementConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/StackTraceElementConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,57 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +import java.lang.reflect.Field; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Converter for StackTraceElement (the lines of a stack trace) - JDK 1.4+ only. + * + * @author B. K. Oxley (binkley) + * @author Joe Walnes + */ +public class StackTraceElementConverter extends AbstractBasicConverter { + + // Regular expression to parse a line of a stack trace. Returns 4 groups. + // + // Example: com.blah.MyClass.doStuff(MyClass.java:123) + // |-------1------| |--2--| |----3-----| |4| + // (Note group 4 is optional is optional and only present if a colon char exists.) + + private static final Pattern PATTERN = Pattern.compile("^(.+)\\.([^\\(]+)\\(([^:]*)(:(\\d+))?\\)$"); + + private final StackTraceElementFactory factory = new StackTraceElementFactory(); + + public boolean canConvert(Class type) { + return StackTraceElement.class.equals(type); + } + + protected Object fromString(String str) { + Matcher matcher = PATTERN.matcher(str); + if (matcher.matches()) { + String declaringClass = matcher.group(1); + String methodName = matcher.group(2); + String fileName = matcher.group(3); + if (fileName.equals("Unknown Source")) { + return factory.unknownSourceElement(declaringClass, methodName); + } else if (fileName.equals("Native Method")) { + return factory.nativeMethodElement(declaringClass, methodName); + } else { + if (matcher.group(4) != null) { + int lineNumber = Integer.parseInt(matcher.group(5)); + return factory.element(declaringClass, methodName, fileName, lineNumber); + } else { + return factory.element(declaringClass, methodName, fileName); + } + } + } else { + throw new ConversionException("Could not parse StackTraceElement : " + str); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/StackTraceElementFactory.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/StackTraceElementFactory.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/StackTraceElementFactory.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,51 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.ConversionException; + +import java.lang.reflect.Field; + +/** + * Factory for creating StackTraceElements. + * Factory for creating StackTraceElements. + * + * @author B. K. Oxley (binkley) + * @author Joe Walnes + */ +public class StackTraceElementFactory { + + public StackTraceElement nativeMethodElement(String declaringClass, String methodName) { + return create(declaringClass, methodName, "Native Method", -2); + } + + public StackTraceElement unknownSourceElement(String declaringClass, String methodName) { + return create(declaringClass, methodName, "Unknown Source", -1); + } + + public StackTraceElement element(String declaringClass, String methodName, String fileName) { + return create(declaringClass, methodName, fileName, -1); + } + + public StackTraceElement element(String declaringClass, String methodName, String fileName, int lineNumber) { + return create(declaringClass, methodName, fileName, lineNumber); + } + + private StackTraceElement create(String declaringClass, String methodName, String fileName, int lineNumber) { + StackTraceElement result = new Throwable().getStackTrace()[0]; + setField(result, "declaringClass", declaringClass); + setField(result, "methodName", methodName); + setField(result, "fileName", fileName); + setField(result, "lineNumber", new Integer(lineNumber)); + return result; + } + + private void setField(StackTraceElement element, String fieldName, Object value) { + try { + final Field field = StackTraceElement.class.getDeclaredField(fieldName); + field.setAccessible(true); + field.set(element, value); + } catch (Exception e) { + throw new ConversionException(e); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SubjectConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SubjectConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SubjectConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,102 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + +import javax.security.auth.Subject; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * Converts a {@link Subject} instance. Note, that this Converter does only convert the contained Principals as + * it is done by JDK serialization, but not any credentials. For other behaviour you can derive your own converter, + * overload the appropriate methods and register it in the {@link com.thoughtworks.xstream.XStream}. + * + * @author Jörg Schaible + */ +public class SubjectConverter extends AbstractCollectionConverter { + + public SubjectConverter(Mapper mapper) { + super(mapper); + } + + public boolean canConvert(Class type) { + return type.equals(Subject.class); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + Subject subject = (Subject) source; + marshalPrincipals(subject.getPrincipals(), writer, context); + marshalPublicCredentials(subject.getPublicCredentials(), writer, context); + marshalPrivateCredentials(subject.getPrivateCredentials(), writer, context); + marshalReadOnly(subject.isReadOnly(), writer); + } + + protected void marshalPrincipals(Set principals, HierarchicalStreamWriter writer, MarshallingContext context) { + writer.startNode("principals"); + for (final Iterator iter = principals.iterator(); iter.hasNext();) { + final Object principal = iter.next(); // pre jdk 1.4 a Principal was also in javax.security + writeItem(principal, context, writer); + } + writer.endNode(); + }; + + protected void marshalPublicCredentials(Set pubCredentials, HierarchicalStreamWriter writer, MarshallingContext context) { + }; + + protected void marshalPrivateCredentials(Set privCredentials, HierarchicalStreamWriter writer, MarshallingContext context) { + }; + + protected void marshalReadOnly(boolean readOnly, HierarchicalStreamWriter writer) { + writer.startNode("readOnly"); + writer.setValue(String.valueOf(readOnly)); + writer.endNode(); + }; + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + Set principals = unmarshalPrincipals(reader, context); + Set publicCredentials = unmarshalPublicCredentials(reader, context); + Set privateCredentials = unmarshalPrivateCredentials(reader, context); + boolean readOnly = unmarshalReadOnly(reader); + return new Subject(readOnly, principals, publicCredentials, privateCredentials); + } + + protected Set unmarshalPrincipals(HierarchicalStreamReader reader, UnmarshallingContext context) { + return populateSet(reader, context); + }; + + protected Set unmarshalPublicCredentials(HierarchicalStreamReader reader, UnmarshallingContext context) { + return Collections.EMPTY_SET; + }; + + protected Set unmarshalPrivateCredentials(HierarchicalStreamReader reader, UnmarshallingContext context) { + return Collections.EMPTY_SET; + }; + + protected boolean unmarshalReadOnly(HierarchicalStreamReader reader) { + reader.moveDown(); + boolean readOnly = Boolean.getBoolean(reader.getValue()); + reader.moveUp(); + return readOnly; + }; + + protected Set populateSet(HierarchicalStreamReader reader, UnmarshallingContext context) { + Set set = new HashSet(); + reader.moveDown(); + while (reader.hasMoreChildren()) { + reader.moveDown(); + Object elementl = readItem(reader, context, set); + reader.moveUp(); + set.add(elementl); + } + reader.moveUp(); + return set; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ThrowableConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ThrowableConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ThrowableConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,40 @@ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +/** + * Converter for Throwable (and Exception) that retains stack trace, for JDK1.4 only. + * + * @author B. K. Oxley (binkley) + * @author Joe Walnes + */ +public class ThrowableConverter implements Converter { + + private Converter defaultConverter; + + public ThrowableConverter(Converter defaultConverter) { + this.defaultConverter = defaultConverter; + } + + public boolean canConvert(final Class type) { + return Throwable.class.isAssignableFrom(type); + } + + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + Throwable throwable = (Throwable) source; + throwable.getStackTrace(); // Force stackTrace field to be lazy loaded by special JVM native witchcraft (outside our control). + defaultConverter.marshal(throwable, writer, context); + } + + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + return defaultConverter.unmarshal(reader, context); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/package.html =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/package.html (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/package.html (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,2 @@ +

            Extra converters that are not enabled in XStream +by default.

            \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/BeanProperty.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/BeanProperty.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/BeanProperty.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,126 @@ +package com.thoughtworks.xstream.converters.javabean; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.UndeclaredThrowableException; + +/** + * Provide access to a bean property. + * + * @author Andrea Aime + */ +public class BeanProperty { + + /** the target class */ + private Class memberClass; + + /** the property name */ + private String propertyName; + + /** the property type */ + private Class type; + + /** the getter */ + protected Method getter; + + /** the setter */ + private Method setter; + + private static final Object[] EMPTY_ARGS = new Object[0]; + + /** + * Creates a new {@link BeanProperty}that gets the specified property from + * the specified class. + */ + public BeanProperty(Class memberClass, String propertyName, Class propertyType) { + this.memberClass = memberClass; + this.propertyName = propertyName; + this.type = propertyType; + } + + /** + * Gets the base class that this getter accesses. + */ + public Class getBeanClass() { + return memberClass; + } + + /** + * Returns the property type + * + * @return + */ + public Class getType() { + return type; + } + + /** + * Gets the name of the property that this getter extracts. + */ + public String getName() { + return propertyName; + } + + /** + * Gets whether this property can get get. + */ + public boolean isReadable() { + return (getter != null); + } + + /** + * Gets whether this property can be set. + */ + public boolean isWritable() { + return (setter != null); + } + + /** + * Gets the value of this property for the specified Object. + * @throws IllegalAccessException + * @throws IllegalArgumentException + */ + public Object get(Object member) throws IllegalArgumentException, IllegalAccessException { + if (!isReadable()) + throw new IllegalStateException("Property " + propertyName + " of " + memberClass + + " not readable"); + + try { + return getter.invoke(member, EMPTY_ARGS); + } catch (InvocationTargetException e) { + throw new UndeclaredThrowableException(e.getTargetException()); + } + } + + /** + * Sets the value of this property for the specified Object. + * @throws IllegalAccessException + * @throws IllegalArgumentException + */ + public Object set(Object member, Object newValue) throws IllegalArgumentException, IllegalAccessException { + if (!isWritable()) + throw new IllegalStateException("Property " + propertyName + " of " + memberClass + + " not writable"); + + try { + return setter.invoke(member, new Object[] { newValue }); + } catch (InvocationTargetException e) { + throw new UndeclaredThrowableException(e.getTargetException()); + } + } + + /** + * @param method + */ + public void setGetterMethod(Method method) { + this.getter = method; + + } + + /** + * @param method + */ + public void setSetterMethod(Method method) { + this.setter = method; + } +} \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/BeanProvider.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/BeanProvider.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/BeanProvider.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,143 @@ +package com.thoughtworks.xstream.converters.javabean; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.Iterator; + +import com.thoughtworks.xstream.converters.reflection.ObjectAccessException; + +/** + * Pure Java ObjectFactory that instantiates objects using standard Java + * reflection, however the types of objects that can be constructed are limited. + *

            Can newInstance: classes with public visibility, outer classes, static + * inner classes, classes with default constructors and any class that + * implements java.io.Serializable. Cannot newInstance: classes without public + * visibility, non-static inner classes, classes without default constructors. + * Note that any code in the constructor of a class will be executed when the + * ObjectFactory instantiates the object. + *

            + */ +public class BeanProvider { + +// private final Map serializedDataCache = Collections.synchronizedMap(new HashMap()); +// + protected PropertyDictionary propertyDictionary = new PropertyDictionary(); + + protected static final Object[] NO_PARAMS = new Object[0]; + + public Object newInstance(Class type) { + try { + return getDefaultConstrutor(type).newInstance(NO_PARAMS); + } catch (InstantiationException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (IllegalAccessException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (InvocationTargetException e) { + if (e.getTargetException() instanceof RuntimeException) { + throw (RuntimeException) e.getTargetException(); + } else if (e.getTargetException() instanceof Error) { + throw (Error) e.getTargetException(); + } else { + throw new ObjectAccessException("Constructor for " + type.getName() + + " threw an exception", e); + } + } + } + +// private Object instantiateUsingSerialization(Class type) { +// try { +// byte[] data; +// if (serializedDataCache.containsKey(type)) { +// data = (byte[]) serializedDataCache.get(type); +// } else { +// ByteArrayOutputStream bytes = new ByteArrayOutputStream(); +// DataOutputStream stream = new DataOutputStream(bytes); +// stream.writeShort(ObjectStreamConstants.STREAM_MAGIC); +// stream.writeShort(ObjectStreamConstants.STREAM_VERSION); +// stream.writeByte(ObjectStreamConstants.TC_OBJECT); +// stream.writeByte(ObjectStreamConstants.TC_CLASSDESC); +// stream.writeUTF(type.getName()); +// stream.writeLong(ObjectStreamClass.lookup(type).getSerialVersionUID()); +// stream.writeByte(2); // classDescFlags (2 = Serializable) +// stream.writeShort(0); // field count +// stream.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); +// stream.writeByte(ObjectStreamConstants.TC_NULL); +// data = bytes.toByteArray(); +// serializedDataCache.put(type, data); +// } +// +// ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data)); +// return in.readObject(); +// } catch (IOException e) { +// throw new ObjectAccessException("", e); +// } catch (ClassNotFoundException e) { +// throw new ObjectAccessException("", e); +// } +// } + + public void visitSerializableProperties(Object object, Visitor visitor) { + for (Iterator iterator = propertyDictionary.serializablePropertiesFor(object.getClass()); iterator + .hasNext();) { + BeanProperty property = (BeanProperty) iterator.next(); + try { + Object value = property.get(object); + visitor.visit(property.getName(), property.getType(), value); + } catch (IllegalArgumentException e) { + throw new ObjectAccessException("Could not get property " + property.getClass() + + "." + property.getName(), e); + } catch (IllegalAccessException e) { + throw new ObjectAccessException("Could not get property " + property.getClass() + + "." + property.getName(), e); + } + } + } + + public void writeProperty(Object object, String propertyName, Object value) { + BeanProperty property = propertyDictionary.property(object.getClass(), propertyName); + try { + property.set(object, value); + } catch (IllegalArgumentException e) { + throw new ObjectAccessException("Could not set property " + object.getClass() + "." + + property.getName(), e); + } catch (IllegalAccessException e) { + throw new ObjectAccessException("Could not set property " + object.getClass() + "." + + property.getName(), e); + } + } + + public Class getPropertyType(Object object, String name) { + return propertyDictionary.property(object.getClass(), name).getType(); + } + + public boolean propertyDefinedInClass(String name, Class type) { + return propertyDictionary.property(type, name) != null; + } + + /** + * Returns true if the Bean provider can instantiate the specified class + */ + public boolean canInstantiate(Class type) { + return getDefaultConstrutor(type) != null; + } + + /** + * Returns the default constructor, or null if none is found + * @param type + * @return + */ + protected Constructor getDefaultConstrutor(Class type) { + Constructor[] constructors = type.getConstructors(); + for (int i = 0; i < constructors.length; i++) { + Constructor c = constructors[i]; + if (c.getParameterTypes().length == 0 && Modifier.isPublic(c.getModifiers())) + return c; + } + return null; + } + + interface Visitor { + void visit(String name, Class type, Object value); + } + +} \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/JavaBeanConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/JavaBeanConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/JavaBeanConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,116 @@ +package com.thoughtworks.xstream.converters.javabean; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * Can convert any bean with a public default constructor. BeanInfo are not + * taken into consideration, this class looks for bean patterns for simple + * properties + */ +public class JavaBeanConverter implements Converter { + + /** + * TODO: + * - use bean introspection instead of reflection. + * - support indexed properties + * - ignore default values + * - use BeanInfo + */ + private ClassMapper classMapper; + + private String classAttributeIdentifier; + + private BeanProvider beanProvider; + + public JavaBeanConverter(ClassMapper classMapper, String classAttributeIdentifier) { + this.classMapper = classMapper; + this.classAttributeIdentifier = classAttributeIdentifier; + this.beanProvider = new BeanProvider(); + } + + /** + * Only checks for the availability of a public default constructor. + * If you need stricter checks, subclass JavaBeanConverter + */ + public boolean canConvert(Class type) { + return beanProvider.canInstantiate(type); + } + + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + + beanProvider.visitSerializableProperties(source, new BeanProvider.Visitor() { + public void visit(String propertyName, Class fieldType, Object newObj) { + if (newObj != null) { + writeField(propertyName, fieldType, newObj); + } + } + + private void writeField(String propertyName, Class fieldType, Object newObj) { + writer.startNode(classMapper.serializedMember(source.getClass(), propertyName)); + + Class actualType = newObj.getClass(); + + Class defaultType = classMapper.defaultImplementationOf(fieldType); + if (!actualType.equals(defaultType)) { + writer.addAttribute(classAttributeIdentifier, classMapper.serializedClass(actualType)); + } + context.convertAnother(newObj); + + writer.endNode(); + } + + }); + } + + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final Object result = instantiateNewInstance(context); + + while (reader.hasMoreChildren()) { + reader.moveDown(); + + String propertyName = classMapper.realMember(result.getClass(), reader.getNodeName()); + + boolean propertyExistsInClass = beanProvider.propertyDefinedInClass(propertyName, result.getClass()); + + Class type = determineType(reader, result, propertyName); + Object value = context.convertAnother(result, type); + + if (propertyExistsInClass) { + beanProvider.writeProperty(result, propertyName, value); + } + + reader.moveUp(); + } + + return result; + } + + private Object instantiateNewInstance(UnmarshallingContext context) { + Object result = context.currentObject(); + if (result == null) { + result = beanProvider.newInstance(context.getRequiredType()); + } + return result; + } + + private Class determineType(HierarchicalStreamReader reader, Object result, String fieldName) { + String classAttribute = reader.getAttribute(classAttributeIdentifier); + if (classAttribute != null) { + return classMapper.realClass(classAttribute); + } else { + return classMapper.defaultImplementationOf(beanProvider.getPropertyType(result, fieldName)); + } + } + + public static class DuplicateFieldException extends ConversionException { + public DuplicateFieldException(String msg) { + super(msg); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/PropertyDictionary.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/PropertyDictionary.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/PropertyDictionary.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,199 @@ +package com.thoughtworks.xstream.converters.javabean; + +import java.beans.Introspector; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.thoughtworks.xstream.converters.reflection.ObjectAccessException; + +/** + * Builds the serializable properties maps for each bean and caches them. + */ +public class PropertyDictionary { + + private final Map keyedByPropertyNameCache = Collections.synchronizedMap(new HashMap()); + + public Iterator serializablePropertiesFor(Class cls) { + return buildMap(cls).values().iterator(); + } + + /** + * Locates a serializable property + * + * @param cls + * @param name + * @param definedIn + * @return + */ + public BeanProperty property(Class cls, String name) { + Map properties = buildMap(cls); + BeanProperty property = (BeanProperty) properties.get(name); + if (property == null) { + throw new ObjectAccessException("No such property " + cls.getName() + "." + name); + } else { + return property; + } + } + + /** + * Builds the map of all serializable properties for the the provided bean + * + * @param cls + * @param tupleKeyed + * @return + */ + private Map buildMap(Class cls) { + final String clsName = cls.getName(); + if (!keyedByPropertyNameCache.containsKey(clsName)) { + synchronized (keyedByPropertyNameCache) { + if (!keyedByPropertyNameCache.containsKey(clsName)) { // double check + // Gather all the properties, using only the keyed map. It + // is possible that a class have two writable only + // properties that have the same name + // but different types + final Map propertyMap = new HashMap(); + Method[] methods = cls.getMethods(); + + for (int i = 0; i < methods.length; i++) { + if (!Modifier.isPublic(methods[i].getModifiers()) + || Modifier.isStatic(methods[i].getModifiers())) + continue; + + String methodName = methods[i].getName(); + Class[] parameters = methods[i].getParameterTypes(); + Class returnType = methods[i].getReturnType(); + String propertyName; + if ((methodName.startsWith("get") || methodName.startsWith("is")) + && parameters.length == 0 && returnType != void.class) { + if (methodName.startsWith("get")) { + propertyName = Introspector.decapitalize(methodName.substring(3)); + } else { + propertyName = Introspector.decapitalize(methodName.substring(2)); + } + BeanProperty property = getBeanProperty(propertyMap, cls, propertyName, + returnType); + property.setGetterMethod(methods[i]); + } else if (methodName.startsWith("set") && parameters.length == 1 + && returnType == void.class) { + propertyName = Introspector.decapitalize(methodName.substring(3)); + BeanProperty property = getBeanProperty(propertyMap, cls, propertyName, + parameters[0]); + property.setSetterMethod(methods[i]); + } + } + + // retain only those that can be both read and written and + // sort them by name + List serializableProperties = new ArrayList(); + for (Iterator it = propertyMap.values().iterator(); it.hasNext();) { + BeanProperty property = (BeanProperty) it.next(); + if (property.isReadable() && property.isWritable()) { + serializableProperties.add(property); + } + } + Collections.sort(serializableProperties, new BeanPropertyComparator()); + + // build the maps and return + final Map keyedByFieldName = new OrderRetainingMap(); + for (Iterator it = serializableProperties.iterator(); it.hasNext();) { + BeanProperty property = (BeanProperty) it.next(); + keyedByFieldName.put(property.getName(), property); + } + + keyedByPropertyNameCache.put(clsName, keyedByFieldName); + } + } + } + return (Map) keyedByPropertyNameCache.get(clsName); + } + + private BeanProperty getBeanProperty(Map propertyMap, Class cls, String propertyName, Class type) { + PropertyKey key = new PropertyKey(propertyName, type); + BeanProperty property = (BeanProperty) propertyMap.get(key); + if (property == null) { + property = new BeanProperty(cls, propertyName, type); + propertyMap.put(key, property); + } + return property; + } + + /** + * Needed to avoid problems with multiple setters with the same name, but + * referred to different types + */ + private static class PropertyKey { + private String propertyName; + + private Class propertyType; + + public PropertyKey(String propertyName, Class propertyType) { + this.propertyName = propertyName; + this.propertyType = propertyType; + } + + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof PropertyKey)) + return false; + + final PropertyKey propertyKey = (PropertyKey) o; + + if (propertyName != null ? !propertyName.equals(propertyKey.propertyName) + : propertyKey.propertyName != null) + return false; + if (propertyType != null ? !propertyType.equals(propertyKey.propertyType) + : propertyKey.propertyType != null) + return false; + + return true; + } + + public int hashCode() { + int result; + result = (propertyName != null ? propertyName.hashCode() : 0); + result = 29 * result + (propertyType != null ? propertyType.hashCode() : 0); + return result; + } + + public String toString() { + return "PropertyKey{propertyName='" + propertyName + "'" + ", propertyType=" + + propertyType + "}"; + } + + } + + /** + * Compares properties by name + */ + private static class BeanPropertyComparator implements Comparator { + + public int compare(Object o1, Object o2) { + return ((BeanProperty) o1).getName().compareTo(((BeanProperty) o2).getName()); + } + + } + + private static class OrderRetainingMap extends HashMap { + + private List valueOrder = new ArrayList(); + + public Object put(Object key, Object value) { + valueOrder.add(value); + return super.put(key, value); + } + + public Collection values() { + return Collections.unmodifiableList(valueOrder); + } + } + +} \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,118 @@ +package com.thoughtworks.xstream.converters.reflection; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.util.CustomObjectInputStream; +import com.thoughtworks.xstream.core.util.CustomObjectOutputStream; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.NotActiveException; +import java.io.ObjectInput; +import java.io.ObjectInputValidation; +import java.io.ObjectOutput; +import java.util.Map; + +/** + * Converts any object that implements the java.io.Externalizable interface, allowing compatability with native Java + * serialization. + * + * @author Joe Walnes + */ +public class ExternalizableConverter implements Converter { + + private Mapper mapper; + + public ExternalizableConverter(Mapper mapper) { + this.mapper = mapper; + } + + public boolean canConvert(Class type) { + return Externalizable.class.isAssignableFrom(type); + } + + public void marshal(Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + try { + Externalizable externalizable = (Externalizable) source; + CustomObjectOutputStream.StreamCallback callback = new CustomObjectOutputStream.StreamCallback() { + public void writeToStream(Object object) { + if (object == null) { + writer.startNode("null"); + writer.endNode(); + } else { + writer.startNode(mapper.serializedClass(object.getClass())); + context.convertAnother(object); + writer.endNode(); + } + } + + public void writeFieldsToStream(Map fields) { + throw new UnsupportedOperationException(); + } + + public void defaultWriteObject() { + throw new UnsupportedOperationException(); + } + + public void flush() { + writer.flush(); + } + + public void close() { + throw new UnsupportedOperationException("Objects are not allowed to call ObjecOutput.close() from writeExternal()"); + } + }; + ObjectOutput objectOutput = CustomObjectOutputStream.getInstance(context, callback); + externalizable.writeExternal(objectOutput); + } catch (IOException e) { + throw new ConversionException("Cannot serialize " + source.getClass().getName() + " using Externalization", e); + } + } + + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final Class type = context.getRequiredType(); + try { + final Externalizable externalizable = (Externalizable) type.newInstance(); + CustomObjectInputStream.StreamCallback callback = new CustomObjectInputStream.StreamCallback() { + public Object readFromStream() { + reader.moveDown(); + Object streamItem = context.convertAnother(externalizable, mapper.realClass(reader.getNodeName())); + reader.moveUp(); + return streamItem; + } + + public Map readFieldsFromStream() { + throw new UnsupportedOperationException(); + } + + public void defaultReadObject() { + throw new UnsupportedOperationException(); + } + + public void registerValidation(ObjectInputValidation validation, int priority) throws NotActiveException { + throw new NotActiveException("stream inactive"); + } + + public void close() { + throw new UnsupportedOperationException("Objects are not allowed to call ObjectInput.close() from readExternal()"); + } + }; + ObjectInput objectInput = CustomObjectInputStream.getInstance(context, callback); + externalizable.readExternal(objectInput); + return externalizable; + } catch (InstantiationException e) { + throw new ConversionException("Cannot construct " + type.getClass(), e); + } catch (IllegalAccessException e) { + throw new ConversionException("Cannot construct " + type.getClass(), e); + } catch (IOException e) { + throw new ConversionException("Cannot externalize " + type.getClass(), e); + } catch (ClassNotFoundException e) { + throw new ConversionException("Cannot externalize " + type.getClass(), e); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/FieldDictionary.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/FieldDictionary.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/FieldDictionary.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,110 @@ +package com.thoughtworks.xstream.converters.reflection; + +import com.thoughtworks.xstream.core.util.OrderRetainingMap; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class FieldDictionary { + + private final Map keyedByFieldNameCache = Collections.synchronizedMap(new HashMap()); + private final Map keyedByFieldKeyCache = Collections.synchronizedMap(new HashMap()); + + public Iterator serializableFieldsFor(Class cls) { + return buildMap(cls, true).values().iterator(); + } + + public Field field(Class cls, String name, Class definedIn) { + Map fields = buildMap(cls, definedIn != null); + Field field = (Field) fields.get(definedIn != null ? (Object) new FieldKey(name, definedIn, 0) : (Object) name); + if (field == null) { + throw new ObjectAccessException("No such field " + cls.getName() + "." + name); + } else { + return field; + } + } + + private Map buildMap(Class cls, boolean tupleKeyed) { + final String clsName = cls.getName(); + if (!keyedByFieldNameCache.containsKey(clsName)) { + synchronized (keyedByFieldKeyCache) { + if (!keyedByFieldNameCache.containsKey(clsName)) { // double check + final Map keyedByFieldName = new HashMap(); + final Map keyedByFieldKey = new OrderRetainingMap(); + while (!Object.class.equals(cls)) { + Field[] fields = cls.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + field.setAccessible(true); + if (!keyedByFieldName.containsKey(field.getName())) { + keyedByFieldName.put(field.getName(), field); + } + keyedByFieldKey.put(new FieldKey(field.getName(), field.getDeclaringClass(), i), field); + } + cls = cls.getSuperclass(); + } + keyedByFieldNameCache.put(clsName, keyedByFieldName); + keyedByFieldKeyCache.put(clsName, keyedByFieldKey); + } + } + } + return (Map) (tupleKeyed ? keyedByFieldKeyCache.get(clsName) : keyedByFieldNameCache.get(clsName)); + } + + private static class FieldKey { + private String fieldName; + private Class declaringClass; + private Integer depth; + private int order; + + public FieldKey(String fieldName, Class declaringClass, int order) { + this.fieldName = fieldName; + this.declaringClass = declaringClass; + this.order = order; + Class c = declaringClass; + int i = 0; + while (c.getSuperclass() != null) { + i++; + c = c.getSuperclass(); + } + depth = new Integer(i); + } + + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof FieldKey)) return false; + + final FieldKey fieldKey = (FieldKey) o; + + if (declaringClass != null ? !declaringClass.equals(fieldKey.declaringClass) : fieldKey.declaringClass != null) return false; + if (fieldName != null ? !fieldName.equals(fieldKey.fieldName) : fieldKey.fieldName != null) return false; + + return true; + } + + public int hashCode() { + int result; + result = (fieldName != null ? fieldName.hashCode() : 0); + result = 29 * result + (declaringClass != null ? declaringClass.hashCode() : 0); + return result; + } + + public String toString() { + return "FieldKey{" + + "order=" + order + + ", writer=" + depth + + ", declaringClass=" + declaringClass + + ", fieldName='" + fieldName + "'" + + "}"; + } + + + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ObjectAccessException.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ObjectAccessException.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ObjectAccessException.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,13 @@ +package com.thoughtworks.xstream.converters.reflection; + +import com.thoughtworks.xstream.core.BaseException; + +public class ObjectAccessException extends BaseException { + public ObjectAccessException(String message) { + super(message); + } + + public ObjectAccessException(String message, Throwable cause) { + super(message, cause); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,154 @@ +package com.thoughtworks.xstream.converters.reflection; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Iterator; +import java.util.Map; +import java.util.HashMap; +import java.util.Collections; +import java.io.Serializable; +import java.io.ObjectStreamConstants; +import java.io.DataOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ByteArrayInputStream; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; + +/** + * Pure Java ObjectFactory that instantiates objects using standard Java reflection, however the types of objects + * that can be constructed are limited. + *

            + * Can newInstance: classes with public visibility, outer classes, static inner classes, classes with default constructors + * and any class that implements java.io.Serializable. + * Cannot newInstance: classes without public visibility, non-static inner classes, classes without default constructors. + * Note that any code in the constructor of a class will be executed when the ObjectFactory instantiates the object. + *

            + */ +public class PureJavaReflectionProvider implements ReflectionProvider { + + private final Map serializedDataCache = Collections.synchronizedMap(new HashMap()); + + protected FieldDictionary fieldDictionary = new FieldDictionary(); + + public Object newInstance(Class type) { + try { + Constructor[] constructors = type.getDeclaredConstructors(); + for (int i = 0; i < constructors.length; i++) { + if (constructors[i].getParameterTypes().length == 0) { + if (!Modifier.isPublic(constructors[i].getModifiers())) { + constructors[i].setAccessible(true); + } + return constructors[i].newInstance(new Object[0]); + } + } + if (Serializable.class.isAssignableFrom(type)) { + return instantiateUsingSerialization(type); + } else { + throw new ObjectAccessException("Cannot construct " + type.getName() + + " as it does not have a no-args constructor"); + } + } catch (InstantiationException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (IllegalAccessException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (InvocationTargetException e) { + if (e.getTargetException() instanceof RuntimeException) { + throw (RuntimeException)e.getTargetException(); + } else if (e.getTargetException() instanceof Error) { + throw (Error)e.getTargetException(); + } else { + throw new ObjectAccessException("Constructor for " + type.getName() + " threw an exception", e); + } + } + } + + private Object instantiateUsingSerialization(Class type) { + try { + byte[] data; + if (serializedDataCache.containsKey(type)) { + data = (byte[]) serializedDataCache.get(type); + } else { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream stream = new DataOutputStream(bytes); + stream.writeShort(ObjectStreamConstants.STREAM_MAGIC); + stream.writeShort(ObjectStreamConstants.STREAM_VERSION); + stream.writeByte(ObjectStreamConstants.TC_OBJECT); + stream.writeByte(ObjectStreamConstants.TC_CLASSDESC); + stream.writeUTF(type.getName()); + stream.writeLong(ObjectStreamClass.lookup(type).getSerialVersionUID()); + stream.writeByte(2); // classDescFlags (2 = Serializable) + stream.writeShort(0); // field count + stream.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); + stream.writeByte(ObjectStreamConstants.TC_NULL); + data = bytes.toByteArray(); + serializedDataCache.put(type, data); + } + + ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data)); + return in.readObject(); + } catch (IOException e) { + throw new ObjectAccessException("", e); + } catch (ClassNotFoundException e) { + throw new ObjectAccessException("", e); + } + } + + public void visitSerializableFields(Object object, ReflectionProvider.Visitor visitor) { + for (Iterator iterator = fieldDictionary.serializableFieldsFor(object.getClass()); iterator.hasNext();) { + Field field = (Field) iterator.next(); + if (!fieldModifiersSupported(field)) { + continue; + } + validateFieldAccess(field); + try { + Object value = field.get(object); + visitor.visit(field.getName(), field.getType(), field.getDeclaringClass(), value); + } catch (IllegalArgumentException e) { + throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e); + } catch (IllegalAccessException e) { + throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e); + } + } + } + + public void writeField(Object object, String fieldName, Object value, Class definedIn) { + Field field = fieldDictionary.field(object.getClass(), fieldName, definedIn); + validateFieldAccess(field); + try { + field.set(object, value); + } catch (IllegalArgumentException e) { + throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e); + } catch (IllegalAccessException e) { + throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e); + } + } + + public Class getFieldType(Object object, String fieldName, Class definedIn) { + return fieldDictionary.field(object.getClass(), fieldName, definedIn).getType(); + } + + public boolean fieldDefinedInClass(String fieldName, Class type) { + try { + fieldDictionary.field(type, fieldName, null); + return true; + } catch (ObjectAccessException e) { + return false; + } + } + + protected boolean fieldModifiersSupported(Field field) { + return !(Modifier.isStatic(field.getModifiers()) + || Modifier.isTransient(field.getModifiers())); + } + + protected void validateFieldAccess(Field field) { + if (Modifier.isFinal(field.getModifiers())) { + throw new ObjectAccessException("Invalid final field " + + field.getDeclaringClass().getName() + "." + field.getName()); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,191 @@ +package com.thoughtworks.xstream.converters.reflection; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +public class ReflectionConverter implements Converter { + + private final Mapper mapper; + private final ReflectionProvider reflectionProvider; + private final SerializationMethodInvoker serializationMethodInvoker; + + public ReflectionConverter(Mapper mapper, ReflectionProvider reflectionProvider) { + this.mapper = mapper; + this.reflectionProvider = reflectionProvider; + serializationMethodInvoker = new SerializationMethodInvoker(); + } + + public boolean canConvert(Class type) { + return true; + } + + public void marshal(Object original, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Object source = serializationMethodInvoker.callWriteReplace(original); + + if (source.getClass() != original.getClass()) { + writer.addAttribute(mapper.attributeForReadResolveField(), mapper.serializedClass(source.getClass())); + } + + final Set seenFields = new HashSet(); + + reflectionProvider.visitSerializableFields(source, new ReflectionProvider.Visitor() { + public void visit(String fieldName, Class fieldType, Class definedIn, Object newObj) { + if (newObj != null) { + Mapper.ImplicitCollectionMapping mapping = mapper.getImplicitCollectionDefForFieldName(source.getClass(), fieldName); + if (mapping != null) { + if (mapping.getItemFieldName() != null) { + ArrayList list = (ArrayList) newObj; + for (Iterator iter = list.iterator(); iter.hasNext();) { + Object obj = iter.next(); + writeField(mapping.getItemFieldName(), mapping.getItemType(), definedIn, obj); + } + } else { + context.convertAnother(newObj); + } + } else { + writeField(fieldName, fieldType, definedIn, newObj); + seenFields.add(fieldName); + } + } + } + + private void writeField(String fieldName, Class fieldType, Class definedIn, Object newObj) { + if (!mapper.shouldSerializeMember(definedIn, fieldName)) { + return; + } + writer.startNode(mapper.serializedMember(definedIn, fieldName)); + + Class actualType = newObj.getClass(); + + Class defaultType = mapper.defaultImplementationOf(fieldType); + if (!actualType.equals(defaultType)) { + writer.addAttribute(mapper.attributeForImplementationClass(), mapper.serializedClass(actualType)); + } + + if (seenFields.contains(fieldName)) { + writer.addAttribute(mapper.attributeForClassDefiningField(), mapper.serializedClass(definedIn)); + } + context.convertAnother(newObj); + + writer.endNode(); + } + + }); + } + + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final Object result = instantiateNewInstance(context, reader.getAttribute(mapper.attributeForReadResolveField())); + final SeenFields seenFields = new SeenFields(); + + Map implicitCollectionsForCurrentObject = null; + while (reader.hasMoreChildren()) { + reader.moveDown(); + + String fieldName = mapper.realMember(result.getClass(), reader.getNodeName()); + + Class classDefiningField = determineWhichClassDefinesField(reader); + boolean fieldExistsInClass = reflectionProvider.fieldDefinedInClass(fieldName, result.getClass()); + + Class type = determineType(reader, fieldExistsInClass, result, fieldName, classDefiningField); + Object value = context.convertAnother(result, type); + + if (fieldExistsInClass) { + reflectionProvider.writeField(result, fieldName, value, classDefiningField); + seenFields.add(classDefiningField, fieldName); + } else { + implicitCollectionsForCurrentObject = writeValueToImplicitCollection(context, value, implicitCollectionsForCurrentObject, result, fieldName); + } + + reader.moveUp(); + } + + return serializationMethodInvoker.callReadResolve(result); + } + + + private Map writeValueToImplicitCollection(UnmarshallingContext context, Object value, Map implicitCollections, Object result, String itemFieldName) { + String fieldName = mapper.getFieldNameForItemTypeAndName(context.getRequiredType(), value.getClass(), itemFieldName); + if (fieldName != null) { + if (implicitCollections == null) { + implicitCollections = new HashMap(); // lazy instantiation + } + Collection collection = (Collection) implicitCollections.get(fieldName); + if (collection == null) { + collection = new ArrayList(); + reflectionProvider.writeField(result, fieldName, collection, null); + implicitCollections.put(fieldName, collection); + } + collection.add(value); + } + return implicitCollections; + } + + private Class determineWhichClassDefinesField(HierarchicalStreamReader reader) { + String definedIn = reader.getAttribute(mapper.attributeForClassDefiningField()); + return definedIn == null ? null : mapper.realClass(definedIn); + } + + private Object instantiateNewInstance(UnmarshallingContext context, String readResolveValue) { + Object currentObject = context.currentObject(); + if (currentObject != null) { + return currentObject; + } else if (readResolveValue != null) { + return reflectionProvider.newInstance(mapper.realClass(readResolveValue)); + } else { + return reflectionProvider.newInstance(context.getRequiredType()); + } + } + + private static class SeenFields { + + private Set seen = new HashSet(); + + public void add(Class definedInCls, String fieldName) { + String uniqueKey = fieldName; + if (definedInCls != null) { + uniqueKey += " [" + definedInCls.getName() + "]"; + } + if (seen.contains(uniqueKey)) { + throw new DuplicateFieldException(uniqueKey); + } else { + seen.add(uniqueKey); + } + } + + } + + private Class determineType(HierarchicalStreamReader reader, boolean validField, Object result, String fieldName, Class definedInCls) { + String classAttribute = reader.getAttribute(mapper.attributeForImplementationClass()); + if (classAttribute != null) { + return mapper.realClass(classAttribute); + } else if (!validField) { + Class itemType = mapper.getItemTypeForItemFieldName(result.getClass(), fieldName); + if (itemType != null) { + return itemType; + } else { + return mapper.realClass(reader.getNodeName()); + } + } else { + return mapper.defaultImplementationOf(reflectionProvider.getFieldType(result, fieldName, definedInCls)); + } + } + + public static class DuplicateFieldException extends ConversionException { + public DuplicateFieldException(String msg) { + super(msg); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionProvider.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionProvider.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionProvider.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,21 @@ +package com.thoughtworks.xstream.converters.reflection; + +/** + * Provides core reflection services. + */ +public interface ReflectionProvider { + + Object newInstance(Class type); + + void visitSerializableFields(Object object, Visitor visitor); + + void writeField(Object object, String fieldName, Object value, Class definedIn); + + Class getFieldType(Object object, String fieldName, Class definedIn); + + boolean fieldDefinedInClass(String fieldName, Class type); + + interface Visitor { + void visit(String name, Class type, Class definedIn, Object value); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,374 @@ +package com.thoughtworks.xstream.converters.reflection; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.util.CustomObjectInputStream; +import com.thoughtworks.xstream.core.util.CustomObjectOutputStream; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectInputValidation; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; +import java.io.ObjectStreamField; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Emulates the mechanism used by standard Java Serialization for classes that implement java.io.Serializable AND + * implement a custom readObject()/writeObject() method. + * + *

            Supported features of serialization

            + *
              + *
            • readObject(), writeObject()
            • + *
            • class inheritance
            • + *
            • readResolve(), writeReplace()
            • + *
            + * + *

            Currently unsupported features

            + *
              + *
            • putFields(), writeFields(), readFields()
            • + *
            • ObjectStreamField[] serialPersistentFields
            • + *
            • ObjectInputValidation
            • + *
            + * + * @author Joe Walnes + */ +public class SerializableConverter implements Converter { + + private final SerializationMethodInvoker serializationMethodInvoker = new SerializationMethodInvoker(); + private final Mapper mapper; + private final ReflectionProvider reflectionProvider; + + private static final String ELEMENT_NULL = "null"; + private static final String ELEMENT_DEFAULT = "default"; + private static final String ATTRIBUTE_CLASS = "class"; + private static final String ATTRIBUTE_SERIALIZATION = "serialization"; + private static final String ATTRIBUTE_VALUE_CUSTOM = "custom"; + private static final String ELEMENT_FIELDS = "fields"; + private static final String ELEMENT_FIELD = "field"; + private static final String ATTRIBUTE_NAME = "name"; + + public SerializableConverter(Mapper mapper, ReflectionProvider reflectionProvider) { + this.mapper = mapper; + this.reflectionProvider = reflectionProvider; + } + + public boolean canConvert(Class type) { + return Serializable.class.isAssignableFrom(type) + && ( serializationMethodInvoker.supportsReadObject(type, true) + || serializationMethodInvoker.supportsWriteObject(type, true) ); + } + + public void marshal(Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Object replacedSource = serializationMethodInvoker.callWriteReplace(source); + + if (replacedSource.getClass() != source.getClass()) { + writer.addAttribute(mapper.attributeForReadResolveField(), mapper.serializedClass(replacedSource.getClass())); + } + + writer.addAttribute(ATTRIBUTE_SERIALIZATION, ATTRIBUTE_VALUE_CUSTOM); + + // this is an array as it's a non final value that's accessed from an anonymous inner class. + final Class[] currentType = new Class[1]; + final boolean[] writtenClassWrapper = {false}; + + CustomObjectOutputStream.StreamCallback callback = new CustomObjectOutputStream.StreamCallback() { + + public void writeToStream(Object object) { + if (object == null) { + writer.startNode(ELEMENT_NULL); + writer.endNode(); + } else { + writer.startNode(mapper.serializedClass(object.getClass())); + context.convertAnother(object); + writer.endNode(); + } + } + + public void writeFieldsToStream(Map fields) { + ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(currentType[0]); + + writer.startNode(ELEMENT_DEFAULT); + for (Iterator iterator = fields.keySet().iterator(); iterator.hasNext();) { + String name = (String) iterator.next(); + ObjectStreamField field = objectStreamClass.getField(name); + Object value = fields.get(name); + if (field == null) { + throw new ObjectAccessException("Class " + value.getClass().getName() + + " may not write a field named '" + name + "'"); + } + if (value != null) { + writer.startNode(mapper.serializedMember(currentType[0], name)); + if (field.getType() != value.getClass() && !field.getType().isPrimitive()) { + writer.addAttribute(ATTRIBUTE_CLASS, mapper.serializedClass(value.getClass())); + } + context.convertAnother(value); + writer.endNode(); + } + } + writer.endNode(); + } + + public void defaultWriteObject() { + boolean writtenDefaultFields = false; + + ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(currentType[0]); + + if (objectStreamClass == null) { + return; + } + + ObjectStreamField[] fields = objectStreamClass.getFields(); + for (int i = 0; i < fields.length; i++) { + ObjectStreamField field = fields[i]; + Object value = readField(field, currentType[0], replacedSource); + if (value != null) { + if (!writtenClassWrapper[0]) { + writer.startNode(mapper.serializedClass(currentType[0])); + writtenClassWrapper[0] = true; + } + if (!writtenDefaultFields) { + writer.startNode(ELEMENT_DEFAULT); + writtenDefaultFields = true; + } + + writer.startNode(mapper.serializedMember(currentType[0], field.getName())); + + Class actualType = value.getClass(); + Class defaultType = mapper.defaultImplementationOf(field.getType()); + if (!actualType.equals(defaultType)) { + writer.addAttribute(ATTRIBUTE_CLASS, mapper.serializedClass(actualType)); + } + + context.convertAnother(value); + + writer.endNode(); + } + } + if (writtenClassWrapper[0] && !writtenDefaultFields) { + writer.startNode(ELEMENT_DEFAULT); + writer.endNode(); + } else if (writtenDefaultFields) { + writer.endNode(); + } + } + + public void flush() { + writer.flush(); + } + + public void close() { + throw new UnsupportedOperationException("Objects are not allowed to call ObjectOutputStream.close() from writeObject()"); + } + }; + + try { + Iterator classHieararchy = hierarchyFor(replacedSource.getClass()); + while (classHieararchy.hasNext()) { + currentType[0] = (Class) classHieararchy.next(); + if (serializationMethodInvoker.supportsWriteObject(currentType[0], false)) { + writtenClassWrapper[0] = true; + writer.startNode(mapper.serializedClass(currentType[0])); + ObjectOutputStream objectOutputStream = CustomObjectOutputStream.getInstance(context, callback); + serializationMethodInvoker.callWriteObject(currentType[0], replacedSource, objectOutputStream); + writer.endNode(); + } else if (serializationMethodInvoker.supportsReadObject(currentType[0], false)) { + // Special case for objects that have readObject(), but not writeObject(). + // The class wrapper is always written, whether or not this class in the hierarchy has + // serializable fields. This guarantees that readObject() will be called upon deserialization. + writtenClassWrapper[0] = true; + writer.startNode(mapper.serializedClass(currentType[0])); + callback.defaultWriteObject(); + writer.endNode(); + } else { + writtenClassWrapper[0] = false; + callback.defaultWriteObject(); + if (writtenClassWrapper[0]) { + writer.endNode(); + } + } + } + } catch (IOException e) { + throw new ObjectAccessException("Could not call defaultWriteObject()", e); + } + } + + private Object readField(ObjectStreamField field, Class type, Object instance) { + try { + Field javaField = type.getDeclaredField(field.getName()); + javaField.setAccessible(true); + return javaField.get(instance); + } catch (IllegalArgumentException e) { + throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e); + } catch (IllegalAccessException e) { + throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e); + } catch (NoSuchFieldException e) { + throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e); + } catch (SecurityException e) { + throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e); + } + } + + private Iterator hierarchyFor(Class type) { + List result = new ArrayList(); + while(type != null) { + result.add(type); + type = type.getSuperclass(); + } + + // In Java Object Serialization, the classes are deserialized starting from parent class and moving down. + Collections.reverse(result); + + return result.iterator(); + } + + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + String resolvesAttribute = reader.getAttribute(mapper.attributeForReadResolveField()); + Class requiredType; + if (resolvesAttribute != null) { + requiredType = mapper.realClass(resolvesAttribute); + } else { + requiredType = context.getRequiredType(); + } + final Object result = reflectionProvider.newInstance(requiredType); + + // this is an array as it's a non final value that's accessed from an anonymous inner class. + final Class[] currentType = new Class[1]; + + if (!ATTRIBUTE_VALUE_CUSTOM.equals(reader.getAttribute(ATTRIBUTE_SERIALIZATION))) { + throw new ConversionException("Cannot deserialize object with new readObject()/writeObject() methods"); + } + + CustomObjectInputStream.StreamCallback callback = new CustomObjectInputStream.StreamCallback() { + public Object readFromStream() { + reader.moveDown(); + Class type = mapper.realClass(reader.getNodeName()); + Object value = context.convertAnother(result, type); + reader.moveUp(); + return value; + } + + public Map readFieldsFromStream() { + Map result = new HashMap(); + reader.moveDown(); + if (reader.getNodeName().equals(ELEMENT_FIELDS)) { + // Maintain compatability with XStream 1.1.0 + while (reader.hasMoreChildren()) { + reader.moveDown(); + if (!reader.getNodeName().equals(ELEMENT_FIELD)) { + throw new ConversionException("Expected <" + ELEMENT_FIELD + "/> element inside <" + ELEMENT_FIELD + "/>"); + } + String name = reader.getAttribute(ATTRIBUTE_NAME); + Class type = mapper.realClass(reader.getAttribute(ATTRIBUTE_CLASS)); + Object value = context.convertAnother(result, type); + result.put(name, value); + reader.moveUp(); + } + } else if (reader.getNodeName().equals(ELEMENT_DEFAULT)) { + // New format introduced in XStream 1.1.1 + ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(currentType[0]); + while (reader.hasMoreChildren()) { + reader.moveDown(); + String name = reader.getNodeName(); + String typeName = reader.getAttribute(ATTRIBUTE_CLASS); + Class type; + if (typeName != null) { + type = mapper.realClass(typeName); + } else { + ObjectStreamField field = objectStreamClass.getField(name); + if (field == null) { + throw new ObjectAccessException("Class " + currentType[0] + + " does not contain a field named '" + name + "'"); + } + type = field.getType(); + } + Object value = context.convertAnother(result, type); + result.put(name, value); + reader.moveUp(); + } + } else { + throw new ConversionException("Expected <" + ELEMENT_FIELDS + "/> or <" + + ELEMENT_DEFAULT + "/> element when calling ObjectInputStream.readFields()"); + } + reader.moveUp(); + return result; + } + + public void defaultReadObject() { + if (!reader.hasMoreChildren()) { + return; + } + reader.moveDown(); + if (!reader.getNodeName().equals(ELEMENT_DEFAULT)) { + throw new ConversionException("Expected <" + ELEMENT_DEFAULT + "/> element in readObject() stream"); + } + while (reader.hasMoreChildren()) { + reader.moveDown(); + + Class type; + String fieldName = mapper.realMember(currentType[0], reader.getNodeName()); + String classAttribute = reader.getAttribute(ATTRIBUTE_CLASS); + if (classAttribute != null) { + type = mapper.realClass(classAttribute); + } else { + type = mapper.defaultImplementationOf(reflectionProvider.getFieldType(result, fieldName, currentType[0])); + } + + Object value = context.convertAnother(result, type); + reflectionProvider.writeField(result, fieldName, value, currentType[0]); + + reader.moveUp(); + } + reader.moveUp(); + } + + public void registerValidation(final ObjectInputValidation validation, int priority) { + context.addCompletionCallback(new Runnable() { + public void run() { + try { + validation.validateObject(); + } catch (InvalidObjectException e) { + throw new ObjectAccessException("Cannot validate object : " + e.getMessage(), e); + } + } + }, priority); + } + + public void close() { + throw new UnsupportedOperationException("Objects are not allowed to call ObjectInputStream.close() from readObject()"); + } + }; + + while (reader.hasMoreChildren()) { + reader.moveDown(); + currentType[0] = mapper.defaultImplementationOf(mapper.realClass(reader.getNodeName())); + if (serializationMethodInvoker.supportsReadObject(currentType[0], false)) { + ObjectInputStream objectInputStream = CustomObjectInputStream.getInstance(context, callback); + serializationMethodInvoker.callReadObject(currentType[0], result, objectInputStream); + } else { + try { + callback.defaultReadObject(); + } catch (IOException e) { + throw new ObjectAccessException("Could not call defaultWriteObject()", e); + } + } + reader.moveUp(); + } + + return serializationMethodInvoker.callReadResolve(result); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,128 @@ +package com.thoughtworks.xstream.converters.reflection; + +import com.thoughtworks.xstream.converters.ConversionException; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.HashMap; +import java.util.Collections; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +/** + * Convenience wrapper to invoke special serialization methods on objects (and perform reflection caching). + * + * @author Joe Walnes + */ +public class SerializationMethodInvoker { + + private Map cache = Collections.synchronizedMap(new HashMap()); + private static final Object NO_METHOD = new Object(); + private static final Object[] EMPTY_ARGS = new Object[0]; + + /** + * Resolves an object as native serialization does by calling readResolve(), if available. + */ + public Object callReadResolve(Object result) { + if (result == null) { + return null; + } else { + Method readResolveMethod = getMethod(result.getClass(), "readResolve", null, true); + if (readResolveMethod != null) { + try { + return readResolveMethod.invoke(result, EMPTY_ARGS); + } catch (IllegalAccessException e) { + throw new ObjectAccessException("Could not call " + result.getClass().getName() + ".readResolve()", e); + } catch (InvocationTargetException e) { + throw new ObjectAccessException("Could not call " + result.getClass().getName() + ".readResolve()", e); + } + } else { + return result; + } + } + } + + public Object callWriteReplace(Object object) { + if (object == null) { + return null; + } else { + Method writeReplaceMethod = getMethod(object.getClass(), "writeReplace", null, true); + if (writeReplaceMethod != null) { + try { + Object[] EMPTY_ARGS = new Object[0]; + return writeReplaceMethod.invoke(object, EMPTY_ARGS); + } catch (IllegalAccessException e) { + throw new ObjectAccessException("Could not call " + object.getClass().getName() + ".writeReplace()", e); + } catch (InvocationTargetException e) { + throw new ObjectAccessException("Could not call " + object.getClass().getName() + ".writeReplace()", e); + } + } else { + return object; + } + } + } + + public boolean supportsReadObject(Class type, boolean includeBaseClasses) { + return getMethod(type, "readObject", new Class[]{ObjectInputStream.class}, includeBaseClasses) != null; + } + + public void callReadObject(Class type, Object object, ObjectInputStream stream) { + try { + Method readObjectMethod = getMethod(type, "readObject", new Class[]{ObjectInputStream.class}, false); + readObjectMethod.invoke(object, new Object[]{stream}); + } catch (IllegalAccessException e) { + throw new ConversionException("Could not call " + object.getClass().getName() + ".readObject()", e); + } catch (InvocationTargetException e) { + throw new ConversionException("Could not call " + object.getClass().getName() + ".readObject()", e); + } + } + + public boolean supportsWriteObject(Class type, boolean includeBaseClasses) { + return getMethod(type, "writeObject", new Class[]{ObjectOutputStream.class}, includeBaseClasses) != null; + } + + public void callWriteObject(Class type, Object instance, ObjectOutputStream stream) { + try { + Method readObjectMethod = getMethod(type, "writeObject", new Class[]{ObjectOutputStream.class}, false); + readObjectMethod.invoke(instance, new Object[]{stream}); + } catch (IllegalAccessException e) { + throw new ConversionException("Could not call " + instance.getClass().getName() + ".writeObject()", e); + } catch (InvocationTargetException e) { + throw new ConversionException("Could not call " + instance.getClass().getName() + ".writeObject()", e); + } + } + + private Method getMethod(Class type, String name, Class[] parameterTypes, boolean includeBaseclasses) { + Object key = type.getName() + "." + name + "." + includeBaseclasses; + if (cache.containsKey(key)) { + Object result = cache.get(key); + return (Method) (result == NO_METHOD ? null : result); + } + if (includeBaseclasses) { + while (type != null) { + try { + Method result = type.getDeclaredMethod(name, parameterTypes); + result.setAccessible(true); + cache.put(key, result); + return result; + } catch (NoSuchMethodException e) { + type = type.getSuperclass(); + } + } + cache.put(key, NO_METHOD); + return null; + } else { + try { + Method result = type.getDeclaredMethod(name, parameterTypes); + result.setAccessible(true); + cache.put(key, result); + return result; + } catch (NoSuchMethodException e) { + cache.put(key, NO_METHOD); + return null; + } + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/Sun14ReflectionProvider.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/Sun14ReflectionProvider.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/Sun14ReflectionProvider.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,115 @@ +package com.thoughtworks.xstream.converters.reflection; + +import sun.misc.Unsafe; +import sun.reflect.ReflectionFactory; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; +import java.util.Collections; + +/** + * Instantiates a new object on the Sun JVM by bypassing the constructor (meaning code in the constructor + * will never be executed and parameters do not have to be known). This is the same method used by the internals of + * standard Java serialization, but relies on internal Sun code that may not be present on all JVMs. + * + * @author Joe Walnes + * @author Brian Slesinsky + */ +public class Sun14ReflectionProvider extends PureJavaReflectionProvider { + + private final ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory(); + private Unsafe cachedUnsafe; + private final Map constructorCache = Collections.synchronizedMap(new HashMap()); + + private Unsafe getUnsafe() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { + if (cachedUnsafe != null) { + return cachedUnsafe; + } + Class objectStreamClass = Class.forName("java.io.ObjectStreamClass$FieldReflector"); + Field unsafeField = objectStreamClass.getDeclaredField("unsafe"); + unsafeField.setAccessible(true); + cachedUnsafe = (Unsafe) unsafeField.get(null); + return cachedUnsafe; + } + + public Object newInstance(Class type) { + try { + Constructor customConstructor = getMungedConstructor(type); + return customConstructor.newInstance(new Object[0]); + } catch (NoSuchMethodException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (SecurityException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (InstantiationException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (IllegalAccessException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (IllegalArgumentException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (InvocationTargetException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } + } + + private Constructor getMungedConstructor(Class type) throws NoSuchMethodException { + if (!constructorCache.containsKey(type)) { + Constructor javaLangObjectConstructor = Object.class.getDeclaredConstructor(new Class[0]); + Constructor customConstructor = reflectionFactory.newConstructorForSerialization(type, javaLangObjectConstructor); + constructorCache.put(type, customConstructor); + } + return (Constructor) constructorCache.get(type); + } + + public void writeField(Object object, String fieldName, Object value, Class definedIn) { + write(fieldDictionary.field(object.getClass(), fieldName, definedIn), object, value); + } + + private void write(Field field, Object object, Object value) { + try { + Unsafe unsafe = getUnsafe(); + long offset = unsafe.objectFieldOffset(field); + Class type = field.getType(); + if (type.isPrimitive()) { + if (type.equals(Integer.TYPE)) { + unsafe.putInt(object, offset, ((Integer) value).intValue()); + } else if (type.equals(Long.TYPE)) { + unsafe.putLong(object, offset, ((Long) value).longValue()); + } else if (type.equals(Short.TYPE)) { + unsafe.putShort(object, offset, ((Short) value).shortValue()); + } else if (type.equals(Character.TYPE)) { + unsafe.putChar(object, offset, ((Character) value).charValue()); + } else if (type.equals(Byte.TYPE)) { + unsafe.putByte(object, offset, ((Byte) value).byteValue()); + } else if (type.equals(Float.TYPE)) { + unsafe.putFloat(object, offset, ((Float) value).floatValue()); + } else if (type.equals(Double.TYPE)) { + unsafe.putDouble(object, offset, ((Double) value).doubleValue()); + } else if (type.equals(Boolean.TYPE)) { + unsafe.putBoolean(object, offset, ((Boolean) value).booleanValue()); + } else { + throw new ObjectAccessException("Could not set field " + + object.getClass() + "." + field.getName() + + ": Unknown type " + type); + } + } else { + unsafe.putObject(object, offset, value); + } + + } catch (IllegalArgumentException e) { + throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e); + } catch (IllegalAccessException e) { + throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e); + } catch (NoSuchFieldException e) { + throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e); + } catch (ClassNotFoundException e) { + throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e); + } + } + + protected void validateFieldAccess(Field field) { + // (overriden) don't mind final fields. + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/BaseException.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/BaseException.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/BaseException.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,31 @@ +package com.thoughtworks.xstream.core; + +/** + * JDK1.3 friendly exception that retains cause. + */ +public abstract class BaseException extends RuntimeException { + + private Throwable cause; + + protected BaseException(String message, Throwable cause) { + super(message + (cause == null ? "" : " : " + cause.getMessage())); + this.cause = cause; + } + + protected BaseException(Throwable cause) { + this("", cause); + } + + protected BaseException(String message) { + this(message, null); + } + + protected BaseException() { + this("", null); + } + + public Throwable getCause() { + return cause; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/DefaultClassMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/DefaultClassMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/DefaultClassMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,23 @@ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.core.util.CompositeClassLoader; +import com.thoughtworks.xstream.mapper.ClassAliasingMapper; +import com.thoughtworks.xstream.mapper.ArrayMapper; +import com.thoughtworks.xstream.mapper.CachingMapper; +import com.thoughtworks.xstream.mapper.DefaultImplementationsMapper; +import com.thoughtworks.xstream.mapper.DefaultMapper; +import com.thoughtworks.xstream.mapper.DynamicProxyMapper; +import com.thoughtworks.xstream.mapper.ImmutableTypesMapper; +import com.thoughtworks.xstream.mapper.MapperWrapper; +import com.thoughtworks.xstream.mapper.XmlFriendlyMapper; + +/** + * @deprecated As of 1.1.1. + */ +public class DefaultClassMapper extends MapperWrapper { + + public DefaultClassMapper() { + super(new CachingMapper(new ImmutableTypesMapper(new DefaultImplementationsMapper(new ArrayMapper(new DynamicProxyMapper(new ClassAliasingMapper(new XmlFriendlyMapper(new DefaultMapper(new CompositeClassLoader()))))))))); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/DefaultConverterLookup.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/DefaultConverterLookup.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/DefaultConverterLookup.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,55 @@ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.basic.NullConverter; +import com.thoughtworks.xstream.core.util.PrioritizedList; +import com.thoughtworks.xstream.XStream; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class DefaultConverterLookup implements ConverterLookup { + + private final PrioritizedList converters = new PrioritizedList(); + private final Converter nullConverter = new NullConverter(); + private final Map typeToConverterMap = Collections.synchronizedMap(new HashMap()); + private final ClassMapper classMapper; + + public DefaultConverterLookup(ClassMapper classMapper) { + this.classMapper = classMapper; + } + + /** + * @deprecated As of 1.1.1 you can register Converters with priorities, making the need for a default converter redundant. + */ + public Converter defaultConverter() { + return (Converter) converters.firstOfLowestPriority(); + } + + public Converter lookupConverterForType(Class type) { + if (type == null) { + return nullConverter; + } + Converter cachedConverter = (Converter) typeToConverterMap.get(type); + if (cachedConverter != null) return cachedConverter; + Class mapType = classMapper.defaultImplementationOf(type); + Iterator iterator = converters.iterator(); + while (iterator.hasNext()) { + Converter converter = (Converter) iterator.next(); + if (converter.canConvert(mapType)) { + typeToConverterMap.put(type, converter); + return converter; + } + } + throw new ConversionException("No converter specified for " + type); + } + public void registerConverter(Converter converter, int priority) { + converters.add(converter, priority); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/JVM.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/JVM.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/JVM.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,97 @@ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; +import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; + +import java.security.AccessControlException; + +public class JVM { + + private ReflectionProvider reflectionProvider; + + private static final float majorJavaVersion = getMajorJavaVersion(System.getProperty("java.version")); + + static final float DEFAULT_JAVA_VERSION = 1.3f; + + /** + * Parses the java version system property to determine the major java version, + * ie 1.x + * + * @param javaVersion the system property 'java.version' + * @return A float of the form 1.x + */ + static final float getMajorJavaVersion(String javaVersion) { + try { + return Float.parseFloat(javaVersion.substring(0, 3)); + } catch ( NumberFormatException e ){ + // Some JVMs may not conform to the x.y.z java.version format + return DEFAULT_JAVA_VERSION; + } + } + + public static boolean is14() { + return majorJavaVersion >= 1.4f; + } + + public static boolean is15() { + return majorJavaVersion >= 1.5f; + } + + private static boolean isSun() { + return System.getProperty("java.vm.vendor").indexOf("Sun") != -1; + } + + private static boolean isApple() { + return System.getProperty("java.vm.vendor").indexOf("Apple") != -1; + } + + private static boolean isHPUX() { + return System.getProperty("java.vm.vendor").indexOf("Hewlett-Packard Company") != -1; + } + + private static boolean isIBM() { + return System.getProperty("java.vm.vendor").indexOf("IBM") != -1; + } + + private static boolean isBlackdown() { + return System.getProperty("java.vm.vendor").indexOf("Blackdown") != -1; + } + + private static boolean isBEA() { + return System.getProperty("java.vm.vendor").indexOf("BEA") != -1; + } + + public Class loadClass(String name) { + try { + return Class.forName(name, false, getClass().getClassLoader()); + } catch (ClassNotFoundException e) { + return null; + } + } + + public synchronized ReflectionProvider bestReflectionProvider() { + if (reflectionProvider == null) { + try { + if ( canUseSun14ReflectionProvider() ) { + String cls = "com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider"; + reflectionProvider = (ReflectionProvider) loadClass(cls).newInstance(); + } else { + reflectionProvider = new PureJavaReflectionProvider(); + } + } catch (InstantiationException e) { + reflectionProvider = new PureJavaReflectionProvider(); + } catch (IllegalAccessException e) { + reflectionProvider = new PureJavaReflectionProvider(); + } catch (AccessControlException e) { + // thrown when trying to access sun.misc package in Applet context. + reflectionProvider = new PureJavaReflectionProvider(); + } + } + return reflectionProvider; + } + + private boolean canUseSun14ReflectionProvider() { + return (isSun() || isApple() || isHPUX() || isIBM() || isBlackdown()) && is14() && loadClass("sun.misc.Unsafe") != null; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/MapBackedDataHolder.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/MapBackedDataHolder.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/MapBackedDataHolder.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,32 @@ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.converters.DataHolder; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class MapBackedDataHolder implements DataHolder { + private final Map map; + + public MapBackedDataHolder() { + this(new HashMap()); + } + + public MapBackedDataHolder(Map map) { + this.map = map; + } + + public Object get(Object key) { + return map.get(key); + } + + public void put(Object key, Object value) { + map.put(key, value); + } + + public Iterator keys() { + return Collections.unmodifiableCollection(map.keySet()).iterator(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdMarshaller.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdMarshaller.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdMarshaller.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,51 @@ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.core.util.ObjectIdDictionary; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class ReferenceByIdMarshaller extends TreeMarshaller { + + private ObjectIdDictionary references = new ObjectIdDictionary(); + private IDGenerator idGenerator; + + public static interface IDGenerator { + String next(); + } + + public ReferenceByIdMarshaller(HierarchicalStreamWriter writer, + ConverterLookup converterLookup, + ClassMapper classMapper, + IDGenerator idGenerator) { + super(writer, converterLookup, classMapper); + this.idGenerator = idGenerator; + } + + public ReferenceByIdMarshaller(HierarchicalStreamWriter writer, + ConverterLookup converterLookup, + ClassMapper classMapper) { + this(writer, converterLookup, classMapper, new SequenceGenerator(1)); + } + + public void convertAnother(Object item) { + Converter converter = converterLookup.lookupConverterForType(item.getClass()); + + if (classMapper.isImmutableValueType(item.getClass())) { + // strings, ints, dates, etc... don't bother using references. + converter.marshal(item, writer, this); + } else { + Object idOfExistingReference = references.lookupId(item); + if (idOfExistingReference != null) { + writer.addAttribute("reference", idOfExistingReference.toString()); + } else { + String newId = idGenerator.next(); + writer.addAttribute("id", newId); + references.associateId(item, newId); + converter.marshal(item, writer, this); + } + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdMarshallingStrategy.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdMarshallingStrategy.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdMarshallingStrategy.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,22 @@ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.MarshallingStrategy; +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.DataHolder; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class ReferenceByIdMarshallingStrategy implements MarshallingStrategy { + + public Object unmarshal(Object root, HierarchicalStreamReader reader, DataHolder dataHolder, DefaultConverterLookup converterLookup, ClassMapper classMapper) { + return new ReferenceByIdUnmarshaller( + root, reader, converterLookup, + classMapper).start(dataHolder); + } + + public void marshal(HierarchicalStreamWriter writer, Object obj, DefaultConverterLookup converterLookup, ClassMapper classMapper, DataHolder dataHolder) { + new ReferenceByIdMarshaller( + writer, converterLookup, classMapper).start(obj, dataHolder); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdUnmarshaller.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdUnmarshaller.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdUnmarshaller.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,41 @@ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.core.util.FastStack; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + +import java.util.HashMap; +import java.util.Map; + +public class ReferenceByIdUnmarshaller extends TreeUnmarshaller { + + private Map values = new HashMap(); + private FastStack parentIdStack = new FastStack(16); + + public ReferenceByIdUnmarshaller(Object root, HierarchicalStreamReader reader, + ConverterLookup converterLookup, ClassMapper classMapper) { + super(root, reader, converterLookup, classMapper); + } + + public Object convertAnother(Object parent, Class type) { + if (parentIdStack.size() > 0) { // handles circular references + Object parentId = parentIdStack.peek(); + if (!values.containsKey(parentId)) { // see AbstractCircularReferenceTest.testWeirdCircularReference() + values.put(parentId, parent); + } + } + String reference = reader.getAttribute("reference"); + if (reference != null) { + return values.get(reference); + } else { + String currentId = reader.getAttribute("id"); + parentIdStack.push(currentId); + Object result = super.convertAnother(parent, type); + values.put(currentId, result); + parentIdStack.popSilently(); + return result; + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathMarshaller.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathMarshaller.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathMarshaller.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,41 @@ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.core.util.ObjectIdDictionary; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.path.Path; +import com.thoughtworks.xstream.io.path.PathTracker; +import com.thoughtworks.xstream.io.path.PathTrackingWriter; + +public class ReferenceByXPathMarshaller extends TreeMarshaller { + + private PathTracker pathTracker = new PathTracker(); + private ObjectIdDictionary references = new ObjectIdDictionary(); + + public ReferenceByXPathMarshaller(HierarchicalStreamWriter writer, ConverterLookup converterLookup, ClassMapper classMapper) { + super(writer, converterLookup, classMapper); + this.writer = new PathTrackingWriter(writer, pathTracker); + } + + public void convertAnother(Object item) { + Converter converter = converterLookup.lookupConverterForType(item.getClass()); + + if (classMapper.isImmutableValueType(item.getClass())) { + // strings, ints, dates, etc... don't bother using references. + converter.marshal(item, writer, this); + } else { + Path currentPath = pathTracker.getPath(); + Path pathOfExistingReference = (Path) references.lookupId(item); + if (pathOfExistingReference != null) { + Path absolutePath = currentPath.relativeTo(pathOfExistingReference); + writer.addAttribute("reference", absolutePath.toString()); + } else { + references.associateId(item, currentPath); + converter.marshal(item, writer, this); + } + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathMarshallingStrategy.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathMarshallingStrategy.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathMarshallingStrategy.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,19 @@ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.MarshallingStrategy; +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.DataHolder; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class ReferenceByXPathMarshallingStrategy implements MarshallingStrategy { + + public Object unmarshal(Object root, HierarchicalStreamReader reader, DataHolder dataHolder, DefaultConverterLookup converterLookup, ClassMapper classMapper) { + return new ReferenceByXPathUnmarshaller(root, reader, converterLookup, + classMapper).start(dataHolder); + } + + public void marshal(HierarchicalStreamWriter writer, Object obj, DefaultConverterLookup converterLookup, ClassMapper classMapper, DataHolder dataHolder) { + new ReferenceByXPathMarshaller(writer, converterLookup, classMapper).start(obj, dataHolder); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathUnmarshaller.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathUnmarshaller.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathUnmarshaller.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,46 @@ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.core.util.FastStack; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.path.Path; +import com.thoughtworks.xstream.io.path.PathTracker; +import com.thoughtworks.xstream.io.path.PathTrackingReader; + +import java.util.HashMap; +import java.util.Map; + +public class ReferenceByXPathUnmarshaller extends TreeUnmarshaller { + + private Map values = new HashMap(); + private FastStack parentPathStack = new FastStack(16); + private PathTracker pathTracker = new PathTracker(); + + public ReferenceByXPathUnmarshaller(Object root, HierarchicalStreamReader reader, + ConverterLookup converterLookup, ClassMapper classMapper) { + super(root, reader, converterLookup, classMapper); + this.reader = new PathTrackingReader(reader, pathTracker); + } + + public Object convertAnother(Object parent, Class type) { + if (parentPathStack.size() > 0) { // handles circular references + Object parentPath = parentPathStack.peek(); + if (!values.containsKey(parentPath)) { // see AbstractCircularReferenceTest.testWeirdCircularReference() + values.put(parentPath, parent); + } + } + String relativePathOfReference = reader.getAttribute("reference"); + Path currentPath = pathTracker.getPath(); + if (relativePathOfReference != null) { + return values.get(currentPath.apply(new Path(relativePathOfReference))); + } else { + parentPathStack.push(currentPath); + Object result = super.convertAnother(parent, type); + values.put(currentPath, result); + parentPathStack.popSilently(); + return result; + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/SequenceGenerator.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/SequenceGenerator.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/SequenceGenerator.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,15 @@ +package com.thoughtworks.xstream.core; + +public class SequenceGenerator implements ReferenceByIdMarshaller.IDGenerator { + + private int counter; + + public SequenceGenerator(int startsAt) { + this.counter = startsAt; + } + + public String next() { + return String.valueOf(counter++); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeMarshaller.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeMarshaller.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeMarshaller.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,75 @@ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.DataHolder; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.core.util.ObjectIdDictionary; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +import java.util.Iterator; + +public class TreeMarshaller implements MarshallingContext { + + protected HierarchicalStreamWriter writer; + protected ConverterLookup converterLookup; + protected ClassMapper classMapper; + private ObjectIdDictionary parentObjects = new ObjectIdDictionary(); + private DataHolder dataHolder; + + public TreeMarshaller(HierarchicalStreamWriter writer, + ConverterLookup converterLookup, + ClassMapper classMapper) { + this.writer = writer; + this.converterLookup = converterLookup; + this.classMapper = classMapper; + } + + public void convertAnother(Object item) { + if (parentObjects.containsId(item)) { + throw new CircularReferenceException(); + } + parentObjects.associateId(item, ""); + Converter converter = converterLookup.lookupConverterForType(item.getClass()); + converter.marshal(item, writer, this); + parentObjects.removeId(item); + } + + public void start(Object item, DataHolder dataHolder) { + this.dataHolder = dataHolder; + if (item == null) { + writer.startNode(classMapper.serializedClass(ClassMapper.Null.class)); + writer.endNode(); + } else { + writer.startNode(classMapper.serializedClass(item.getClass())); + convertAnother(item); + writer.endNode(); + } + } + + public Object get(Object key) { + lazilyCreateDataHolder(); + return dataHolder.get(key); + } + + public void put(Object key, Object value) { + lazilyCreateDataHolder(); + dataHolder.put(key, value); + } + + public Iterator keys() { + lazilyCreateDataHolder(); + return dataHolder.keys(); + } + + private void lazilyCreateDataHolder() { + if (dataHolder == null) { + dataHolder = new MapBackedDataHolder(); + } + } + + public static class CircularReferenceException extends RuntimeException { + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeMarshallingStrategy.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeMarshallingStrategy.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeMarshallingStrategy.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,21 @@ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.MarshallingStrategy; +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.DataHolder; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class TreeMarshallingStrategy implements MarshallingStrategy { + + public Object unmarshal(Object root, HierarchicalStreamReader reader, DataHolder dataHolder, DefaultConverterLookup converterLookup, ClassMapper classMapper) { + return new TreeUnmarshaller( + root, reader, converterLookup, + classMapper).start(dataHolder); + } + + public void marshal(HierarchicalStreamWriter writer, Object obj, DefaultConverterLookup converterLookup, ClassMapper classMapper, DataHolder dataHolder) { + new TreeMarshaller(writer, converterLookup, classMapper).start(obj, dataHolder); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeUnmarshaller.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeUnmarshaller.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeUnmarshaller.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,108 @@ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.DataHolder; +import com.thoughtworks.xstream.converters.ErrorWriter; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.util.ClassStack; +import com.thoughtworks.xstream.core.util.PrioritizedList; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + +import java.util.Iterator; + +public class TreeUnmarshaller implements UnmarshallingContext { + + private Object root; + protected HierarchicalStreamReader reader; + private ConverterLookup converterLookup; + private ClassMapper classMapper; + private ClassStack types = new ClassStack(16); + private DataHolder dataHolder; + private final PrioritizedList validationList = new PrioritizedList(); + + public TreeUnmarshaller(Object root, HierarchicalStreamReader reader, + ConverterLookup converterLookup, ClassMapper classMapper) { + this.root = root; + this.reader = reader; + this.converterLookup = converterLookup; + this.classMapper = classMapper; + } + + public Object convertAnother(Object parent, Class type) { + try { + Converter converter = converterLookup.lookupConverterForType(type); + types.push(classMapper.defaultImplementationOf(type)); + Object result = converter.unmarshal(reader, this); + types.popSilently(); + return result; + } catch (ConversionException conversionException) { + addInformationTo(conversionException, type); + throw conversionException; + } catch (RuntimeException e) { + ConversionException conversionException = new ConversionException(e); + addInformationTo(conversionException, type); + throw conversionException; + } + } + + private void addInformationTo(ErrorWriter errorWriter, Class type) { + errorWriter.add("class", type.getName()); + errorWriter.add("required-type", getRequiredType().getName()); + reader.appendErrors(errorWriter); + } + + public void addCompletionCallback(Runnable work, int priority) { + validationList.add(work, priority); + } + + public Object currentObject() { + return types.size() == 1 ? root : null; + } + + public Class getRequiredType() { + return types.peek(); + } + + public Object get(Object key) { + lazilyCreateDataHolder(); + return dataHolder.get(key); + } + + public void put(Object key, Object value) { + lazilyCreateDataHolder(); + dataHolder.put(key, value); + } + + public Iterator keys() { + lazilyCreateDataHolder(); + return dataHolder.keys(); + } + + private void lazilyCreateDataHolder() { + if (dataHolder == null) { + dataHolder = new MapBackedDataHolder(); + } + } + + public Object start(DataHolder dataHolder) { + this.dataHolder = dataHolder; + String classAttribute = reader.getAttribute(classMapper.attributeForImplementationClass()); + Class type; + if (classAttribute == null) { + type = classMapper.realClass(reader.getNodeName()); + } else { + type = classMapper.realClass(classAttribute); + } + Object result = convertAnother(root, type); + Iterator validations = validationList.iterator(); + while (validations.hasNext()) { + Runnable runnable = (Runnable) validations.next(); + runnable.run(); + } + return result; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Base64Encoder.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Base64Encoder.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Base64Encoder.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,83 @@ +package com.thoughtworks.xstream.core.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; + +/** + * Encodes binary data to plain text as Base64. + * + *

            Despite there being a gazillion other Base64 implementations out there, this has been written as part of XStream as + * it forms a core part but is too trivial to warrant an extra dependency.

            + * + *

            This meets the standard as described in RFC 1521, section 5.2 , allowing + * other Base64 tools to manipulate the data.

            + * + * @author Joe Walnes + */ +public class Base64Encoder { + + // Here's how encoding works: + // + // 1) Incoming bytes are broken up into groups of 3 (each byte having 8 bits). + // + // 2) The combined 24 bits (3 * 8) are split into 4 groups of 6 bits. + // + // input |------||------||------| (3 values each with 8 bits) + // 101010101010101010101010 + // output |----||----||----||----| (4 values each with 6 bits) + // + // 3) Each of these 4 groups of 6 bits are converted back to a number, which will fall in the range of 0 - 63. + // + // 4) Each of these 4 numbers are converted to an alphanumeric char in a specified mapping table, to create + // a 4 character string. + // + // 5) This is repeated for all groups of three bytes. + // + // 6) Special padding is done at the end of the stream using the '=' char. + + private static final char[] SIXTY_FOUR_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray(); + private static final int[] REVERSE_MAPPING = new int[123]; + + static { + for (int i = 0; i < SIXTY_FOUR_CHARS.length; i++) REVERSE_MAPPING[SIXTY_FOUR_CHARS[i]] = i + 1; + } + + public String encode(byte[] input) { + StringBuffer result = new StringBuffer(); + int outputCharCount = 0; + for (int i = 0; i < input.length; i += 3) { + int remaining = Math.min(3, input.length - i); + int oneBigNumber = (input[i] & 0xff) << 16 | (remaining <= 1 ? 0 : input[i + 1] & 0xff) << 8 | (remaining <= 2 ? 0 : input[i + 2] & 0xff); + for (int j = 0; j < 4; j++) result.append(remaining + 1 > j ? SIXTY_FOUR_CHARS[0x3f & oneBigNumber >> 6 * (3 - j)] : '='); + if ((outputCharCount += 4) % 76 == 0) result.append('\n'); + } + return result.toString(); + } + + public byte[] decode(String input) { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StringReader in = new StringReader(input); + for (int i = 0; i < input.length(); i += 4) { + int a[] = {mapCharToInt(in), mapCharToInt(in), mapCharToInt(in), mapCharToInt(in)}; + int oneBigNumber = (a[0] & 0x3f) << 18 | (a[1] & 0x3f) << 12 | (a[2] & 0x3f) << 6 | (a[3] & 0x3f); + for (int j = 0; j < 3; j++) if (a[j + 1] >= 0) out.write(0xff & oneBigNumber >> 8 * (2 - j)); + } + return out.toByteArray(); + } catch (IOException e) { + throw new Error(e + ": " + e.getMessage()); + } + } + + private int mapCharToInt(Reader input) throws IOException { + int c; + while ((c = input.read()) != -1) { + int result = REVERSE_MAPPING[c]; + if (result != 0) return result -1; + if (c == '=') return -1; + } + return -1; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ClassLoaderReference.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ClassLoaderReference.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ClassLoaderReference.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,29 @@ +package com.thoughtworks.xstream.core.util; + +/** + * ClassLoader that refers to another ClassLoader, allowing a single instance to be passed around the codebase that + * can later have its destination changed. + * + * @author Joe Walnes + * @since 1.1.1 + */ +public class ClassLoaderReference extends ClassLoader { + + private ClassLoader reference; + + public ClassLoaderReference(ClassLoader reference) { + this.reference = reference; + } + + public Class loadClass(String name) throws ClassNotFoundException { + return reference.loadClass(name); + } + + public ClassLoader getReference() { + return reference; + } + + public void setReference(ClassLoader reference) { + this.reference = reference; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ClassStack.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ClassStack.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ClassStack.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,44 @@ +package com.thoughtworks.xstream.core.util; + +public final class ClassStack { + + private Class[] stack; + private int pointer; + + public ClassStack(int initialCapacity) { + stack = new Class[initialCapacity]; + } + + public void push(Class value) { + if (pointer + 1 >= stack.length) { + resizeStack(stack.length * 2); + } + stack[pointer++] = value; + } + + public void popSilently() { + pointer--; + } + + public Class pop() { + return stack[--pointer]; + } + + public Class peek() { + return pointer == 0 ? null : stack[pointer - 1]; + } + + public int size() { + return pointer; + } + + public Class get(int i) { + return stack[i]; + } + + private void resizeStack(int newCapacity) { + Class[] newStack = new Class[newCapacity]; + System.arraycopy(stack, 0, newStack, 0, Math.min(stack.length, newCapacity)); + stack = newStack; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CompositeClassLoader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CompositeClassLoader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CompositeClassLoader.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,74 @@ +package com.thoughtworks.xstream.core.util; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * ClassLoader that is composed of other classloaders. Each loader will be used to try to load the particular class, until + * one of them succeeds. Note: The loaders will always be called in the REVERSE order they were added in. + * + *

            The Composite class loader also has registered the classloader that loaded xstream.jar + * and (if available) the thread's context classloader.

            + * + *

            Example

            + *
            CompositeClassLoader loader = new CompositeClassLoader();
            + * loader.add(MyClass.class.getClassLoader());
            + * loader.add(new AnotherClassLoader());
            + *  
            + * loader.loadClass("com.blah.ChickenPlucker");
            + * 
            + * + *

            The above code will attempt to load a class from the following classloaders (in order):

            + * + *
              + *
            • AnotherClassLoader (and all its parents)
            • + *
            • The classloader for MyClas (and all its parents)
            • + *
            • The thread's context classloader (and all its parents)
            • + *
            • The classloader for XStream (and all its parents)
            • + *
            + * + * @author Joe Walnes + * @since 1.0.3 + */ +public class CompositeClassLoader extends ClassLoader { + + private final List classLoaders = Collections.synchronizedList(new ArrayList()); + + public CompositeClassLoader() { + add(Object.class.getClassLoader()); // bootstrap loader. + add(getClass().getClassLoader()); // whichever classloader loaded this jar. + } + + /** + * Add a loader to the n + * @param classLoader + */ + public void add(ClassLoader classLoader) { + if (classLoader != null) { + classLoaders.add(0, classLoader); + } + } + + public Class loadClass(String name) throws ClassNotFoundException { + for (Iterator iterator = classLoaders.iterator(); iterator.hasNext();) { + ClassLoader classLoader = (ClassLoader) iterator.next(); + try { + return classLoader.loadClass(name); + } catch (ClassNotFoundException notFound) { + // ok.. try another one + } + } + // One last try - the context class loader associated with the current thread. Often used in j2ee servers. + // Note: The contextClassLoader cannot be added to the classLoaders list up front as the thread that constructs + // XStream is potentially different to thread that uses it. + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + if (contextClassLoader != null) { + return contextClassLoader.loadClass(name); + } else { + throw new ClassNotFoundException(name); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CustomObjectInputStream.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CustomObjectInputStream.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CustomObjectInputStream.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,238 @@ +package com.thoughtworks.xstream.core.util; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.DataHolder; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.NotActiveException; +import java.io.ObjectInputStream; +import java.io.ObjectInputValidation; +import java.io.ObjectStreamClass; +import java.util.Map; + +public class CustomObjectInputStream extends ObjectInputStream { + + private StreamCallback callback; + + private static final String DATA_HOLDER_KEY = CustomObjectInputStream.class.getName(); + + public static interface StreamCallback { + Object readFromStream() throws IOException; + Map readFieldsFromStream() throws IOException; + void defaultReadObject() throws IOException; + void registerValidation(ObjectInputValidation validation, int priority) throws NotActiveException, InvalidObjectException; + void close() throws IOException; + } + + public static synchronized CustomObjectInputStream getInstance(DataHolder whereFrom, CustomObjectInputStream.StreamCallback callback) { + try { + CustomObjectInputStream result = (CustomObjectInputStream) whereFrom.get(DATA_HOLDER_KEY); + if (result == null) { + result = new CustomObjectInputStream(callback); + whereFrom.put(DATA_HOLDER_KEY, result); + } else { + result.setCallback(callback); + } + return result; + } catch (IOException e) { + throw new ConversionException("Cannot create CustomObjectStream", e); + } + } + + /** + * Warning, this object is expensive to create (due to functionality inherited from superclass). + * Use the static fetch() method instead, wherever possible. + * + * @see #getInstance(com.thoughtworks.xstream.converters.DataHolder, com.thoughtworks.xstream.core.util.CustomObjectInputStream.StreamCallback) + */ + public CustomObjectInputStream(StreamCallback callback) throws IOException, SecurityException { + super(); + this.callback = callback; + } + + /** + * Allows the CustomObjectInputStream (which is expensive to create) to be reused. + */ + public void setCallback(StreamCallback callback) { + this.callback = callback; + } + + public void defaultReadObject() throws IOException, ClassNotFoundException { + callback.defaultReadObject(); + } + + protected Object readObjectOverride() throws IOException, ClassNotFoundException { + return callback.readFromStream(); + } + + public boolean readBoolean() throws IOException { + return ((Boolean)callback.readFromStream()).booleanValue(); + } + + public byte readByte() throws IOException { + return ((Byte)callback.readFromStream()).byteValue(); + } + + public int readInt() throws IOException { + return ((Integer)callback.readFromStream()).intValue(); + } + + public char readChar() throws IOException { + return ((Character)callback.readFromStream()).charValue(); + } + + public float readFloat() throws IOException { + return ((Float)callback.readFromStream()).floatValue(); + } + + public double readDouble() throws IOException { + return ((Double)callback.readFromStream()).doubleValue(); + } + + public long readLong() throws IOException { + return ((Long)callback.readFromStream()).longValue(); + } + + public short readShort() throws IOException { + return ((Short)callback.readFromStream()).shortValue(); + } + + public String readUTF() throws IOException { + return (String) callback.readFromStream(); + } + + public void readFully(byte[] buf) throws IOException { + readFully(buf, 0, buf.length); + } + + public void readFully(byte[] buf, int off, int len) throws IOException { + byte[] b = (byte[])callback.readFromStream(); + System.arraycopy(b, 0, buf, off, len); + } + + public GetField readFields() throws IOException, ClassNotFoundException { + return new CustomGetField(callback.readFieldsFromStream()); + } + + private class CustomGetField extends GetField { + + private Map fields; + + public CustomGetField(Map fields) { + this.fields = fields; + } + + public ObjectStreamClass getObjectStreamClass() { + throw new UnsupportedOperationException(); + } + + private Object get(String name) { + return fields.get(name); + } + + public boolean defaulted(String name) throws IOException { + return !fields.containsKey(name); + } + + public byte get(String name, byte val) throws IOException { + return defaulted(name) ? val : ((Byte)get(name)).byteValue(); + } + + public char get(String name, char val) throws IOException { + return defaulted(name) ? val : ((Character)get(name)).charValue(); + } + + public double get(String name, double val) throws IOException { + return defaulted(name) ? val : ((Double)get(name)).doubleValue(); + } + + public float get(String name, float val) throws IOException { + return defaulted(name) ? val : ((Float)get(name)).floatValue(); + } + + public int get(String name, int val) throws IOException { + return defaulted(name) ? val : ((Integer)get(name)).intValue(); + } + + public long get(String name, long val) throws IOException { + return defaulted(name) ? val : ((Long)get(name)).longValue(); + } + + public short get(String name, short val) throws IOException { + return defaulted(name) ? val : ((Short)get(name)).shortValue(); + } + + public boolean get(String name, boolean val) throws IOException { + return defaulted(name) ? val : ((Boolean)get(name)).booleanValue(); + } + + public Object get(String name, Object val) throws IOException { + return defaulted(name) ? val : get(name); + } + + } + + public void registerValidation(ObjectInputValidation validation, int priority) throws NotActiveException, InvalidObjectException { + callback.registerValidation(validation, priority); + } + + /****** Unsupported methods ******/ + + public int available() throws IOException { + throw new UnsupportedOperationException(); + } + + public void close() throws IOException { + callback.close(); + } + + public int readUnsignedByte() throws IOException { + throw new UnsupportedOperationException(); + } + + public String readLine() throws IOException { + throw new UnsupportedOperationException(); + } + + public Object readUnshared() throws IOException, ClassNotFoundException { + throw new UnsupportedOperationException(); + } + + public int readUnsignedShort() throws IOException { + throw new UnsupportedOperationException(); + } + + public int read() throws IOException { + throw new UnsupportedOperationException(); + } + + public int read(byte[] buf, int off, int len) throws IOException { + throw new UnsupportedOperationException(); + } + + public int skipBytes(int len) throws IOException { + throw new UnsupportedOperationException(); + } + + public int read(byte b[]) throws IOException { + throw new UnsupportedOperationException(); + } + + public long skip(long n) throws IOException { + throw new UnsupportedOperationException(); + } + + public void mark(int readlimit) { + throw new UnsupportedOperationException(); + } + + public void reset() throws IOException { + throw new UnsupportedOperationException(); + } + + public boolean markSupported() { + return false; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CustomObjectOutputStream.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CustomObjectOutputStream.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CustomObjectOutputStream.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,210 @@ +package com.thoughtworks.xstream.core.util; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.DataHolder; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.ObjectOutput; +import java.util.Map; +import java.util.HashMap; + +public class CustomObjectOutputStream extends ObjectOutputStream { + + private StreamCallback callback; + private FastStack customFields = new FastStack(1); + + private static final String DATA_HOLDER_KEY = CustomObjectOutputStream.class.getName(); + + public static synchronized CustomObjectOutputStream getInstance(DataHolder whereFrom, StreamCallback callback) { + try { + CustomObjectOutputStream result = (CustomObjectOutputStream) whereFrom.get(DATA_HOLDER_KEY); + if (result == null) { + result = new CustomObjectOutputStream(callback); + whereFrom.put(DATA_HOLDER_KEY, result); + } else { + result.setCallback(callback); + } + return result; + } catch (IOException e) { + throw new ConversionException("Cannot create CustomObjectStream", e); + } + } + + public static interface StreamCallback { + void writeToStream(Object object) throws IOException; + void writeFieldsToStream(Map fields) throws IOException; + void defaultWriteObject() throws IOException; + void flush() throws IOException; + void close() throws IOException; + } + + /** + * Warning, this object is expensive to create (due to functionality inherited from superclass). + * Use the static fetch() method instead, wherever possible. + * + * @see #getInstance(com.thoughtworks.xstream.converters.DataHolder, com.thoughtworks.xstream.core.util.CustomObjectOutputStream.StreamCallback) + */ + public CustomObjectOutputStream(StreamCallback callback) throws IOException, SecurityException { + this.callback = callback; + } + + /** + * Allows the CustomObjectOutputStream (which is expensive to create) to be reused. + */ + public void setCallback(StreamCallback callback) { + this.callback = callback; + } + + /*** Methods to delegate to callback ***/ + + public void defaultWriteObject() throws IOException { + callback.defaultWriteObject(); + } + + protected void writeObjectOverride(Object obj) throws IOException { + callback.writeToStream(obj); + } + + public void writeBoolean(boolean val) throws IOException { + callback.writeToStream(val ? Boolean.TRUE : Boolean.FALSE); // JDK 1.3 friendly + } + + public void writeByte(int val) throws IOException { + callback.writeToStream(new Byte((byte) val)); + } + + public void writeInt(int val) throws IOException { + callback.writeToStream(new Integer(val)); + } + + public void writeChar(int val) throws IOException { + callback.writeToStream(new Character((char)val)); + } + + public void writeDouble(double val) throws IOException { + callback.writeToStream(new Double(val)); + } + + public void writeFloat(float val) throws IOException { + callback.writeToStream(new Float(val)); + } + + public void writeLong(long val) throws IOException { + callback.writeToStream(new Long(val)); + } + + public void writeShort(int val) throws IOException { + callback.writeToStream(new Short((short) val)); + } + + public void write(byte[] buf) throws IOException { + callback.writeToStream(buf); + } + + public void writeChars(String str) throws IOException { + callback.writeToStream(str.toCharArray()); + } + + public void writeUTF(String str) throws IOException { + callback.writeToStream(str); + } + + public void write(int val) throws IOException { + callback.writeToStream(new Byte((byte) val)); + } + + public void write(byte[] buf, int off, int len) throws IOException { + byte[] b = new byte[len]; + System.arraycopy(buf, off, b, 0, len); + callback.writeToStream(b); + } + + public void flush() throws IOException { + callback.flush(); + } + + public void close() throws IOException { + callback.close(); + } + + public PutField putFields() throws IOException { + CustomPutField result = new CustomPutField(); + customFields.push(result); + return result; + } + + public void writeFields() throws IOException { + CustomPutField customPutField = (CustomPutField) customFields.pop(); + callback.writeFieldsToStream(customPutField.asMap()); + } + + private class CustomPutField extends PutField { + + private final Map fields = new OrderRetainingMap(); + + public Map asMap() { + return fields; + } + + public void write(ObjectOutput out) throws IOException { + callback.writeToStream(asMap()); + } + + public void put(String name, Object val) { + fields.put(name, val); + } + + public void put(String name, byte val) { + put(name, new Byte(val)); + } + + public void put(String name, char val) { + put(name, new Character(val)); + } + + public void put(String name, double val) { + put(name, new Double(val)); + } + + public void put(String name, float val) { + put(name, new Float(val)); + } + + public void put(String name, int val) { + put(name, new Integer(val)); + } + + public void put(String name, long val) { + put(name, new Long(val)); + } + + public void put(String name, short val) { + put(name, new Short(val)); + } + + public void put(String name, boolean val) { + put(name, val ? Boolean.TRUE : Boolean.FALSE); // JDK 1.3 friendly + } + + } + + /****** Unsupported methods ******/ + + public void reset() throws IOException { + throw new UnsupportedOperationException(); + } + + public void useProtocolVersion(int version) throws IOException { + throw new UnsupportedOperationException(); + } + + public void writeBytes(String str) throws IOException { + throw new UnsupportedOperationException(); + } + + public void writeUnshared(Object obj) throws IOException { + throw new UnsupportedOperationException(); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/FastStack.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/FastStack.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/FastStack.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,63 @@ +package com.thoughtworks.xstream.core.util; + +public final class FastStack { + + private Object[] stack; + private int pointer; + + public FastStack(int initialCapacity) { + stack = new Object[initialCapacity]; + } + + public Object push(Object value) { + if (pointer + 1 >= stack.length) { + resizeStack(stack.length * 2); + } + stack[pointer++] = value; + return value; + } + + public void popSilently() { + stack[--pointer] = null; + } + + public Object pop() { + final Object result = stack[--pointer]; + stack[pointer] = null; + return result; + } + + public Object peek() { + return pointer == 0 ? null : stack[pointer - 1]; + } + + public int size() { + return pointer; + } + + public boolean hasStuff() { + return pointer > 0; + } + + public Object get(int i) { + return stack[i]; + } + + private void resizeStack(int newCapacity) { + Object[] newStack = new Object[newCapacity]; + System.arraycopy(stack, 0, newStack, 0, Math.min(stack.length, newCapacity)); + stack = newStack; + } + + public String toString() { + StringBuffer result = new StringBuffer("["); + for (int i = 0; i < pointer; i++) { + if (i > 0) { + result.append(", "); + } + result.append(stack[i]); + } + result.append(']'); + return result.toString(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Fields.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Fields.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Fields.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,37 @@ +package com.thoughtworks.xstream.core.util; + +import java.lang.reflect.Field; + +/** + * Slightly nicer way to find, get and set fields in classes. Wraps standard java.lang.reflect.Field calls but wraps + * wraps exception in RuntimeExceptions. + * + * @author Joe Walnes + */ +public class Fields { + public static Field find(Class type, String name) { + try { + Field result = type.getDeclaredField(name); + result.setAccessible(true); + return result; + } catch (NoSuchFieldException e) { + throw new RuntimeException("Could not access " + type.getName() + "." + name + " field"); + } + } + + public static void write(Field field, Object instance, Object value) { + try { + field.set(instance, value); + } catch (IllegalAccessException e) { + throw new RuntimeException("Could not write " + field.getType().getName() + "." + field.getName() + " field"); + } + } + + public static Object read(Field field, Object instance) { + try { + return field.get(instance); + } catch (IllegalAccessException e) { + throw new RuntimeException("Could not read " + field.getType().getName() + "." + field.getName() + " field"); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/IntQueue.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/IntQueue.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/IntQueue.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,49 @@ +package com.thoughtworks.xstream.core.util; + +public final class IntQueue { + + private final int[] data; + private int writePointer = 0; + private int readPointer = 0; + private boolean empty = true; + + public IntQueue(int size) { + data = new int[size]; + } + + public void write(int value) { + if (!empty && writePointer == readPointer) { + throw new OverflowException(); + } + data[writePointer++] = value; + if (writePointer == data.length) { + writePointer = 0; + } + empty = false; + } + + public int read() { + if (empty) { + throw new NothingToReadException(); + } + int result = data[readPointer++]; + if (readPointer == data.length) { + readPointer = 0; + } + if (readPointer == writePointer) { + empty = true; + } + return result; + } + + public boolean isEmpty() { + return empty; + } + + public static class OverflowException extends RuntimeException { + } + + public static class NothingToReadException extends RuntimeException { + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ObjectIdDictionary.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ObjectIdDictionary.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ObjectIdDictionary.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,52 @@ +package com.thoughtworks.xstream.core.util; + +import java.util.HashMap; +import java.util.Map; + +/** + * Store IDs against given object references. + *

            + * Behaves the same way as java.util.IdentityHashMap, but in JDK1.3 as well. + */ +public class ObjectIdDictionary { + + private Map map = new HashMap(); + + private static class IdWrapper { + + private final Object obj; + + public IdWrapper(Object obj) { + this.obj = obj; + } + + public int hashCode() { + return System.identityHashCode(obj); + } + + public boolean equals(Object other) { + return obj == ((IdWrapper)other).obj; + } + + public String toString() { + return obj.toString(); + } + } + + public void associateId(Object obj, Object id) { + map.put(new IdWrapper(obj), id); + } + + public Object lookupId(Object obj) { + return map.get(new IdWrapper(obj)); + } + + public boolean containsId(Object item) { + return map.containsKey(new IdWrapper(item)); + } + + public void removeId(Object item) { + map.remove(new IdWrapper(item)); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/OrderRetainingMap.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/OrderRetainingMap.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/OrderRetainingMap.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,37 @@ +package com.thoughtworks.xstream.core.util; + +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; +import java.util.TreeSet; + +public class OrderRetainingMap extends HashMap { + + private Set keyOrder = new ArraySet(); + private List valueOrder = new ArrayList(); + + public Object put(Object key, Object value) { + keyOrder.add(key); + valueOrder.add(value); + return super.put(key, value); + } + + public Collection values() { + return Collections.unmodifiableList(valueOrder); + } + + public Set keySet() { + return Collections.unmodifiableSet(keyOrder); + } + + public Set entrySet() { + throw new UnsupportedOperationException(); + } + + private static class ArraySet extends ArrayList implements Set { + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/PrioritizedList.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/PrioritizedList.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/PrioritizedList.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,99 @@ +package com.thoughtworks.xstream.core.util; + +import com.thoughtworks.xstream.converters.Converter; + +import java.util.Iterator; + +/** + * List that allows items to be added with a priority that will affect the order in which they are later iterated over. + * + * Objects with a high priority will appear before objects with a low priority in the list. If two objects of the same + * priority are added to the list, the most recently added one will be iterated over first. + * + * @author Joe Walnes + */ +public class PrioritizedList { + + /** + * Start of forward only linked list. Each item contains a value, priority and pointer to next item. + * The first item does not contain a value, rather just a pointer to the next real item. This makes + * the add() algorithm easier as there is no special case for adding to the beginning of the list. + */ + private final LinkedItem pointerToFirst = new LinkedItem(null, 0, null); + + private int lowestPriority = Integer.MAX_VALUE; + + /** + * Add an item with a default priority of zero. + */ + public void add(Object item) { + add(item, 0); + } + + public void add(Object item, int priority) { + // Note: this is quite efficient if the client tends to add low priority items before high priority items + // as it will not have to iterate over much of the list. However for the other way round, maybe some + // optimizations can be made? -joe + LinkedItem current = pointerToFirst; + while(current.next != null && priority < current.next.priority) { + current = current.next; + } + current.next = new LinkedItem(item, priority, current.next); + if (priority < lowestPriority) { + lowestPriority = priority; + } + } + + public Iterator iterator() { + return new LinkedItemIterator(pointerToFirst.next); + } + + public Object firstOfLowestPriority() { + for(LinkedItem current = pointerToFirst.next; current != null; current = current.next) { + if (current.priority == lowestPriority) { + return current.value; + } + } + return null; + } + + private static class LinkedItem { + + final Object value; + final int priority; + + LinkedItem next; + + public LinkedItem(Object value, int priority, LinkedItem next) { + this.value = value; + this.priority = priority; + this.next = next; + } + + } + + private static class LinkedItemIterator implements Iterator { + + private LinkedItem current; + + public LinkedItemIterator(LinkedItem current) { + this.current = current; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + public boolean hasNext() { + return current != null; + } + + public Object next() { + Object result = current.value; + current = current.next; + return result; + } + + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/QuickWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/QuickWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/QuickWriter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,85 @@ +package com.thoughtworks.xstream.core.util; + +import com.thoughtworks.xstream.io.StreamException; + +import java.io.IOException; +import java.io.Writer; + +public class QuickWriter { + + private final Writer writer; + private char[] buffer; + private int pointer; + + public QuickWriter(Writer writer) { + this.writer = writer; + buffer = new char[1024]; + } + + public QuickWriter(Writer writer, int bufferSize) { + this.writer = writer; + buffer = new char[bufferSize]; + } + + public void write(String str) { + int len = str.length(); + if (pointer + len >= buffer.length) { + flush(); + if (len > buffer.length) { + raw(str.toCharArray()); + return; + } + } + str.getChars(0, len, buffer, pointer); + pointer += len; + } + + public void write(char c) { + if (pointer + 1 >= buffer.length) { + flush(); + } + buffer[pointer++] = c; + } + + public void write(char[] c) { + int len = c.length; + if (pointer + len >= buffer.length) { + flush(); + if (len > buffer.length) { + raw(c); + return; + } + } + System.arraycopy(c, 0, buffer, pointer, len); + pointer += len; + } + + public void flush() { + try { + writer.write(buffer, 0, pointer); + pointer = 0; + writer.flush(); + } catch (IOException e) { + throw new StreamException(e); + } + } + + public void close() { + try { + writer.write(buffer, 0, pointer); + pointer = 0; + writer.close(); + } catch (IOException e) { + throw new StreamException(e); + } + } + + private void raw(char[] c) { + try { + writer.write(c); + writer.flush(); + } catch (IOException e) { + throw new StreamException(e); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AttributeNameIterator.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AttributeNameIterator.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AttributeNameIterator.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,35 @@ +package com.thoughtworks.xstream.io; + +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + +import java.util.Iterator; + +/** + * Provide an iterator over the attribute names of the current node of a reader. + * + * @author Joe Walnes + */ +public class AttributeNameIterator implements Iterator { + + private int current; + private final int count; + private final HierarchicalStreamReader reader; + + public AttributeNameIterator(HierarchicalStreamReader reader) { + this.reader = reader; + count = reader.getAttributeCount(); + } + + public boolean hasNext() { + return current < count; + } + + public Object next() { + return reader.getAttributeName(current++); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamDriver.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,24 @@ +package com.thoughtworks.xstream.io; + +import java.io.Reader; +import java.io.Writer; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Provides implementation of XML parsers and writers to XStream. + * + * @author Joe Walnes + * @author James Strachan + */ +public interface HierarchicalStreamDriver { + + HierarchicalStreamReader createReader(Reader in); + /** @since 1.2 */ + HierarchicalStreamReader createReader(InputStream in); + + HierarchicalStreamWriter createWriter(Writer out); + /** @since 1.2 */ + HierarchicalStreamWriter createWriter(OutputStream out); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamReader.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,94 @@ +package com.thoughtworks.xstream.io; + +import com.thoughtworks.xstream.converters.ErrorWriter; + +import java.util.Iterator; + +/** + * @author Joe Walnes + */ +public interface HierarchicalStreamReader { + + /** + * Does the node have any more children remaining that have not yet been read? + */ + boolean hasMoreChildren(); + + void moveDown(); + + void moveUp(); + + /** + * Get the name of the current node. + */ + String getNodeName(); + + /** + * Get the value (text content) of the current node. + */ + String getValue(); + + /** + * Get the value of an attribute of the current node. + */ + String getAttribute(String name); + + /** + * Get the value of an attribute of the current node, by index. + */ + String getAttribute(int index); + + /** + * Number of attributes in current node. + */ + int getAttributeCount(); + + /** + * Name of attribute in current node. + */ + String getAttributeName(int index); + + /** + * Names of attributes (as Strings). + */ + Iterator getAttributeNames(); + + /** + * If any errors are detected, allow the reader to add any additional information that can aid debugging + * (such as line numbers, XPath expressions, etc). + */ + void appendErrors(ErrorWriter errorWriter); + + /** + * Close the reader, if necessary. + */ + void close(); + + /** + * Return the underlying HierarchicalStreamReader implementation. + * + *

            If a Converter needs to access methods of a specific HierarchicalStreamReader implementation that are not + * defined in the HierarchicalStreamReader interface, it should call this method before casting. This is because + * the reader passed to the Converter is often wrapped/decorated by another implementation to provide additional + * functionality (such as XPath tracking).

            + * + *

            For example:

            + *
            MySpecificReader mySpecificReader = (MySpecificReader)reader; // INCORRECT!
            +     * mySpecificReader.doSomethingSpecific();
            + + *
            MySpecificReader mySpecificReader = (MySpecificReader)reader.underlyingReader();  // CORRECT!
            +     * mySpecificReader.doSomethingSpecific();
            + * + *

            Implementations of HierarchicalStreamReader should return 'this', unless they are a decorator, in which case + * they should delegate to whatever they are wrapping.

            + */ + HierarchicalStreamReader underlyingReader(); + + /** + * @deprecated This method should not be used and is only provided for backwards compatability. + * As of XStream 1.1.1, you can use the {@link #underlyingReader()} method to get the underlying + * reader implementation and call implementation specific methods on that. + */ + Object peekUnderlyingNode(); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamWriter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,49 @@ +package com.thoughtworks.xstream.io; + +/** + * @author Joe Walnes + */ +public interface HierarchicalStreamWriter { + + void startNode(String name); + + void addAttribute(String name, String value); + + /** + * Write the value (text content) of the current node. + */ + void setValue(String text); + + void endNode(); + + /** + * Flush the writer, if necessary. + */ + void flush(); + + /** + * Close the writer, if necessary. + */ + void close(); + + /** + * Return the underlying HierarchicalStreamWriter implementation. + * + *

            If a Converter needs to access methods of a specific HierarchicalStreamWriter implementation that are not + * defined in the HierarchicalStreamWriter interface, it should call this method before casting. This is because + * the writer passed to the Converter is often wrapped/decorated by another implementation to provide additional + * functionality (such as XPath tracking).

            + * + *

            For example:

            + *
            MySpecificWriter mySpecificWriter = (MySpecificWriter)writer; // INCORRECT!
            +     * mySpecificWriter.doSomethingSpecific();
            + + *
            MySpecificWriter mySpecificWriter = (MySpecificWriter)writer.underlyingWriter();  // CORRECT!
            +     * mySpecificWriter.doSomethingSpecific();
            + * + *

            Implementations of HierarchicalStreamWriter should return 'this', unless they are a decorator, in which case + * they should delegate to whatever they are wrapping.

            + */ + HierarchicalStreamWriter underlyingWriter(); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ReaderWrapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ReaderWrapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ReaderWrapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,75 @@ +package com.thoughtworks.xstream.io; + +import com.thoughtworks.xstream.converters.ErrorWriter; + +import java.util.Iterator; + +/** + * Base class to make it easy to create wrappers (decorators) for HierarchicalStreamReader. + * + * @author Joe Walnes + */ +public abstract class ReaderWrapper implements HierarchicalStreamReader { + + protected HierarchicalStreamReader wrapped; + + protected ReaderWrapper(HierarchicalStreamReader reader) { + this.wrapped = reader; + } + + public boolean hasMoreChildren() { + return wrapped.hasMoreChildren(); + } + + public void moveDown() { + wrapped.moveDown(); + } + + public void moveUp() { + wrapped.moveUp(); + } + + public String getNodeName() { + return wrapped.getNodeName(); + } + + public String getValue() { + return wrapped.getValue(); + } + + public String getAttribute(String name) { + return wrapped.getAttribute(name); + } + + public String getAttribute(int index) { + return wrapped.getAttribute(index); + } + + public int getAttributeCount() { + return wrapped.getAttributeCount(); + } + + public String getAttributeName(int index) { + return wrapped.getAttributeName(index); + } + + public Iterator getAttributeNames() { + return wrapped.getAttributeNames(); + } + + public Object peekUnderlyingNode() { + return wrapped.peekUnderlyingNode(); + } + + public void appendErrors(ErrorWriter errorWriter) { + wrapped.appendErrors(errorWriter); + } + + public void close() { + wrapped.close(); + } + + public HierarchicalStreamReader underlyingReader() { + return wrapped.underlyingReader(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/StreamException.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/StreamException.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/StreamException.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,9 @@ +package com.thoughtworks.xstream.io; + +import com.thoughtworks.xstream.core.BaseException; + +public class StreamException extends BaseException { + public StreamException(Throwable e) { + super(e); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/WriterWrapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/WriterWrapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/WriterWrapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,44 @@ +package com.thoughtworks.xstream.io; + +/** + * Base class to make it easy to create wrappers (decorators) for HierarchicalStreamWriter. + * + * @author Joe Walnes + */ +public abstract class WriterWrapper implements HierarchicalStreamWriter { + + protected HierarchicalStreamWriter wrapped; + + protected WriterWrapper(HierarchicalStreamWriter wrapped) { + this.wrapped = wrapped; + } + + public void startNode(String name) { + wrapped.startNode(name); + } + + public void endNode() { + wrapped.endNode(); + } + + public void addAttribute(String key, String value) { + wrapped.addAttribute(key, value); + } + + public void setValue(String text) { + wrapped.setValue(text); + } + + public void flush() { + wrapped.flush(); + } + + public void close() { + wrapped.close(); + } + + public HierarchicalStreamWriter underlyingWriter() { + return wrapped.underlyingWriter(); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/Path.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/Path.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/Path.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,149 @@ +package com.thoughtworks.xstream.io.path; + +import com.thoughtworks.xstream.core.util.FastStack; + +import java.util.List; +import java.util.ArrayList; + +/** + * Represents a path (subset of XPath) to a single node in the tree. + * + *

            Two absolute paths can also be compared to calculate the relative path between them. + * A relative path can be applied to an absolute path to calculate another absolute path.

            + * + *

            Note that the paths produced are XPath compliant, so can be read by other XPath engines. + * The following are examples of path expressions that the Path object supports:

            + *
              + *
            • /
            • + *
            • /some/node
            • + *
            • /a/b/c/b/a
            • + *
            • /some[3]/node[2]/a
            • + *
            • ../../../another[3]/node
            • + *
            + * + *

            Example

            + * + *
            + * Path a = new Path("/html/body/div/table[2]/tr[3]/td/div");
            + * Path b = new Path("/html/body/div/table[2]/tr[6]/td/form");
            + *
            + * Path relativePath = a.relativeTo(b); // produces: "../../../tr[6]/td/form"
            + * Path c = a.apply(relativePath); // same as Path b.
            + * 
            + * + * @see PathTracker + * + * @author Joe Walnes + */ +public class Path { + + private final String[] chunks; + private transient String pathAsString; + private static final Path DOT = new Path(new String[] {"."}); + + public Path(String pathAsString) { + // String.split() too slow. StringTokenizer too crappy. + List result = new ArrayList(); + int currentIndex = 0; + int nextSeperator; + while ((nextSeperator = pathAsString.indexOf('/', currentIndex)) != -1) { + result.add(pathAsString.substring(currentIndex, nextSeperator)); + currentIndex = nextSeperator + 1; + } + result.add(pathAsString.substring(currentIndex)); + String[] arr = new String[result.size()]; + result.toArray(arr); + chunks = arr; + this.pathAsString = pathAsString; + } + + public Path(String[] chunks) { + this.chunks = chunks; + } + + public String toString() { + if (pathAsString == null) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < chunks.length; i++) { + if (i > 0) buffer.append('/'); + buffer.append(chunks[i]); + } + pathAsString = buffer.toString(); + } + return pathAsString; + } + + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Path)) return false; + + final Path other = (Path) o; + if (chunks.length != other.chunks.length) return false; + for (int i = 0; i < chunks.length; i++) { + if (!chunks[i].equals(other.chunks[i])) return false; + } + + return true; + } + + public int hashCode() { + int result = 543645643; + for (int i = 0; i < chunks.length; i++) { + result = 29 * result + chunks[i].hashCode(); + } + return result; + } + + public Path relativeTo(Path that) { + int depthOfPathDivergence = depthOfPathDivergence(chunks, that.chunks); + String[] result = new String[chunks.length + that.chunks.length - 2 * depthOfPathDivergence]; + int count = 0; + + for (int i = depthOfPathDivergence; i < chunks.length; i++) { + result[count++] = ".."; + } + for (int j = depthOfPathDivergence; j < that.chunks.length; j++) { + result[count++] = that.chunks[j]; + } + + if (count == 0) { + return DOT; + } else { + return new Path(result); + } + } + + private int depthOfPathDivergence(String[] path1, String[] path2) { + int minLength = Math.min(path1.length, path2.length); + for (int i = 0; i < minLength; i++) { + if (!path1[i].equals(path2[i])) { + return i; + } + } + return minLength; + } + + public Path apply(Path relativePath) { + FastStack absoluteStack = new FastStack(16); + + for (int i = 0; i < chunks.length; i++) { + absoluteStack.push(chunks[i]); + } + + for (int i = 0; i < relativePath.chunks.length; i++) { + String relativeChunk = relativePath.chunks[i]; + if (relativeChunk.equals("..")) { + absoluteStack.pop(); + } else if (!relativeChunk.equals(".")) { + absoluteStack.push(relativeChunk); + } + } + + String[] result = new String[absoluteStack.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = (String) absoluteStack.get(i); + } + + return new Path(result); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTracker.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTracker.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTracker.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,131 @@ +package com.thoughtworks.xstream.io.path; + +import java.util.HashMap; +import java.util.Map; + +/** + * Maintains the current {@link Path} as a stream is moved through. + * + *

            Can be linked to a HierarchicalStreamWriter or + * HierarchicalStreamReader by wrapping them with a + * PathTrackingWriter or + * PathTrackingReader.

            + * + *

            Example

            + * + *
            + * PathTracker tracker = new PathTracker();
            + * tracker.pushElement("table");
            + * tracker.pushElement("tr");
            + * tracker.pushElement("td");
            + * tracker.pushElement("form");
            + * tracker.popElement("form");
            + * tracker.popElement("td");
            + * tracker.pushElement("td");
            + * tracker.pushElement("div");
            + *
            + * Path path = tracker.getPath(); // returns "/table/tr/td[2]/div"
            + * 
            + * + * @see Path + * @see PathTrackingReader + * @see PathTrackingWriter + * + * @author Joe Walnes + */ +public class PathTracker { + + private int pointer; + private int capacity; + private String[] pathStack; + private Map[] indexMapStack; + + private Path currentPath; + + public PathTracker() { + this(16); + } + + /** + * @param initialCapacity Size of the initial stack of nodes (one level per depth in the tree). Note that this is + * only for optimizations - the stack will resize itself if it exceeds its capacity. If in doubt, + * use the other constructor. + */ + public PathTracker(int initialCapacity) { + this.capacity = initialCapacity; + pathStack = new String[capacity]; + indexMapStack = new Map[capacity]; + } + + /** + * Notify the tracker that the stream has moved into a new element. + * + * @param name Name of the element + */ + public void pushElement(String name) { + if (pointer + 1 >= capacity) { + resizeStacks(capacity * 2); + } + pathStack[pointer] = name; + Map indexMap = indexMapStack[pointer]; + if (indexMap == null) { + indexMap = new HashMap(); + indexMapStack[pointer] = indexMap; + } + if (indexMap.containsKey(name)) { + indexMap.put(name, new Integer(((Integer) indexMap.get(name)).intValue() + 1)); + } else { + indexMap.put(name, new Integer(1)); + } + pointer++; + currentPath = null; + } + + /** + * Notify the tracker that the stream has moved out of an element. + */ + public void popElement() { + indexMapStack[pointer] = null; + currentPath = null; + pointer--; + } + + /** + * @deprecated Use {@link #getPath()} instead. + */ + public String getCurrentPath() { + return getPath().toString(); + } + + private void resizeStacks(int newCapacity) { + String[] newPathStack = new String[newCapacity]; + Map[] newIndexMapStack = new Map[newCapacity]; + int min = Math.min(capacity, newCapacity); + System.arraycopy(pathStack, 0, newPathStack, 0, min); + System.arraycopy(indexMapStack, 0, newIndexMapStack, 0, min); + pathStack = newPathStack; + indexMapStack = newIndexMapStack; + capacity = newCapacity; + } + + /** + * Current Path in stream. + */ + public Path getPath() { + if (currentPath == null) { + String[] chunks = new String[pointer + 1]; + chunks[0] = ""; + for (int i = 0; i < pointer; i++) { + Integer integer = ((Integer) indexMapStack[i].get(pathStack[i])); + int index = integer.intValue(); + if (index > 1) { + chunks[i + 1] = pathStack[i] + '[' + index + ']'; + } else { + chunks[i + 1] = pathStack[i]; + } + } + currentPath = new Path(chunks); + } + return currentPath; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTrackingReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTrackingReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTrackingReader.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,40 @@ +package com.thoughtworks.xstream.io.path; + +import com.thoughtworks.xstream.converters.ErrorWriter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.ReaderWrapper; + +/** + * Wrapper for HierarchicalStreamReader that tracks the path (a subset of XPath) of the current node that is being read. + * + * @see PathTracker + * @see Path + * + * @author Joe Walnes + */ +public class PathTrackingReader extends ReaderWrapper { + + private final PathTracker pathTracker; + + public PathTrackingReader(HierarchicalStreamReader reader, PathTracker pathTracker) { + super(reader); + this.pathTracker = pathTracker; + pathTracker.pushElement(getNodeName()); + } + + public void moveDown() { + super.moveDown(); + pathTracker.pushElement(getNodeName()); + } + + public void moveUp() { + super.moveUp(); + pathTracker.popElement(); + } + + public void appendErrors(ErrorWriter errorWriter) { + errorWriter.add("path", pathTracker.getPath().toString()); + super.appendErrors(errorWriter); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTrackingWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTrackingWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTrackingWriter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,33 @@ +package com.thoughtworks.xstream.io.path; + +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.WriterWrapper; + +/** + * Wrapper for HierarchicalStreamWriter that tracks the path (a subset of XPath) of the current node that is being written. + * + * @see PathTracker + * @see Path + * + * @author Joe Walnes + */ +public class PathTrackingWriter extends WriterWrapper { + + private final PathTracker pathTracker; + + public PathTrackingWriter(HierarchicalStreamWriter writer, PathTracker pathTracker) { + super(writer); + this.pathTracker = pathTracker; + } + + public void startNode(String name) { + pathTracker.pushElement(name); + super.startNode(name); + } + + public void endNode() { + super.endNode(); + pathTracker.popElement(); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/package.html =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/package.html (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/package.html (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,32 @@ + + + + +

            Library for tracking paths of nodes in documents using a subset of XPath. This subset of XPath is just enough + for XStream to be able to use XPath expressions to represent references across the object graph, while still remaining + very quick.

            + +

            The Path class represents a path to a single node in the tree. + Two absolute paths can also be compared to calculate the relative path between them. + A relative path can be applied to an absolute path to calculate another absolute path.

            + +

            A PathTracker can be linked to a + HierarchicalStreamWriter or + HierarchicalStreamReader and expose the path of wherever the node + is currently positioned. This is done by wrapping the HierarchicalStreamWriter/HierarchicalStreamReader instances + with a PathTrackingWriter or PathTrackingReader.

            + +

            Note that the paths produced are XPath compliant, so can be read by other XPath engines. The following are examples of path + expressions that the Path object supports:

            + +
              +
            • /
            • +
            • /some/node
            • +
            • /a/b/c/b/a
            • +
            • /some[3]/node[2]/a
            • +
            • ../../../another[3]/node
            • +
            + + + + Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractDocumentReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractDocumentReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractDocumentReader.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,74 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.converters.ErrorWriter; +import com.thoughtworks.xstream.core.util.FastStack; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.AttributeNameIterator; + +import java.util.Iterator; + +public abstract class AbstractDocumentReader implements HierarchicalStreamReader { + + private FastStack pointers = new FastStack(16); + private Object current; + + protected AbstractDocumentReader(Object rootElement) { + this.current = rootElement; + pointers.push(new Pointer()); + reassignCurrentElement(current); + } + + protected abstract void reassignCurrentElement(Object current); + protected abstract Object getParent(); + protected abstract Object getChild(int index); + protected abstract int getChildCount(); + + private static class Pointer { + public int v; + } + + public boolean hasMoreChildren() { + Pointer pointer = (Pointer) pointers.peek(); + + if (pointer.v < getChildCount()) { + return true; + } else { + return false; + } + } + + public void moveUp() { + current = getParent(); + pointers.popSilently(); + reassignCurrentElement(current); + } + + public void moveDown() { + Pointer pointer = (Pointer) pointers.peek(); + pointers.push(new Pointer()); + + current = getChild(pointer.v); + + pointer.v++; + reassignCurrentElement(current); + } + + public Iterator getAttributeNames() { + return new AttributeNameIterator(this); + } + + public void appendErrors(ErrorWriter errorWriter) { + } + + public Object peekUnderlyingNode() { + return current; + } + + public void close() { + // don't need to do anything + } + + public HierarchicalStreamReader underlyingReader() { + return this; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractPullReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractPullReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractPullReader.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,191 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.core.util.FastStack; +import com.thoughtworks.xstream.io.AttributeNameIterator; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + +import java.util.Iterator; + +/** + * Base class that contains common functionality across HierarchicalStreamReader implementations + * that need to read from a pull parser. + * + * @author Joe Walnes + * @author James Strachan + */ +public abstract class AbstractPullReader implements HierarchicalStreamReader { + + protected static final int START_NODE = 1; + protected static final int END_NODE = 2; + protected static final int TEXT = 3; + protected static final int COMMENT = 4; + protected static final int OTHER = 0; + + private final FastStack elementStack = new FastStack(16); + + private final FastStack lookahead = new FastStack(4); + private final FastStack lookback = new FastStack(4); + private boolean marked; + + private static class Event { + int type; + String value; + } + + /** + * Pull the next event from the stream. + * + *

            This MUST return {@link #START_NODE}, {@link #END_NODE}, {@link #TEXT}, {@link #COMMENT}, + * {@link #OTHER} or throw {@link com.thoughtworks.xstream.io.StreamException}.

            + * + *

            The underlying pull parser will most likely return its own event types. These must be + * mapped to the appropriate events.

            + */ + protected abstract int pullNextEvent(); + + /** + * Pull the name of the current element from the stream. + */ + protected abstract String pullElementName(); + + /** + * Pull the contents of the current text node from the stream. + */ + protected abstract String pullText(); + + public boolean hasMoreChildren() { + mark(); + while (true) { + switch (readEvent().type) { + case START_NODE: + reset(); + return true; + case END_NODE: + reset(); + return false; + default: + continue; + } + } + } + + public void moveDown() { + int currentDepth = elementStack.size(); + while (elementStack.size() <= currentDepth) { + move(); + if (elementStack.size() < currentDepth) { + throw new RuntimeException(); // sanity check + } + } + } + + public void moveUp() { + int currentDepth = elementStack.size(); + while (elementStack.size() >= currentDepth) { + move(); + } + } + + private void move() { + switch (readEvent().type) { + case START_NODE: + elementStack.push(pullElementName()); + break; + case END_NODE: + elementStack.pop(); + break; + } + } + + private Event readEvent() { + if (marked) { + if (lookback.hasStuff()) { + return (Event) lookahead.push(lookback.pop()); + } else { + return (Event) lookahead.push(readRealEvent()); + } + } else { + if (lookback.hasStuff()) { + return (Event) lookback.pop(); + } else { + return readRealEvent(); + } + } + } + + private Event readRealEvent() { + Event event = new Event(); + event.type = pullNextEvent(); + if (event.type == TEXT) { + event.value = pullText(); + } else if (event.type == START_NODE) { + event.value = pullElementName(); + } + return event; + } + + public void mark() { + marked = true; + } + + public void reset() { + while(lookahead.hasStuff()) { + lookback.push(lookahead.pop()); + } + marked = false; + } + + public String getValue() { + // we should collapse together any text which + // contains comments + + // lets only use a string buffer when we get 2 strings + // to avoid copying strings + String last = null; + StringBuffer buffer = null; + + mark(); + Event event = readEvent(); + while (true) { + if (event.type == TEXT) { + String text = event.value; + if (text != null && text.length() > 0) { + if (last == null) { + last = text; + } else { + if (buffer == null) { + buffer = new StringBuffer(last); + } + buffer.append(text); + } + } + } else if (event.type != COMMENT) { + break; + } + event = readEvent(); + } + reset(); + if (buffer != null) { + return buffer.toString(); + } else { + return (last == null) ? "" : last; + } + } + + public Iterator getAttributeNames() { + return new AttributeNameIterator(this); + } + + public String getNodeName() { + return (String) elementStack.peek(); + } + + public Object peekUnderlyingNode() { + throw new UnsupportedOperationException(); + } + + public HierarchicalStreamReader underlyingReader() { + return this; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/CompactWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/CompactWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/CompactWriter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,14 @@ +package com.thoughtworks.xstream.io.xml; + +import java.io.Writer; + +public class CompactWriter extends PrettyPrintWriter { + + public CompactWriter(Writer writer) { + super(writer); + } + + protected void endOfLine() { + // override parent: don't write anything at end of line + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JDriver.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,105 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.*; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.DocumentFactory; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.SAXReader; +import org.dom4j.io.XMLWriter; + +import java.io.*; + +public class Dom4JDriver implements HierarchicalStreamDriver { + + private DocumentFactory documentFactory; + private OutputFormat outputFormat; + + public Dom4JDriver(DocumentFactory documentFactory, OutputFormat outputFormat) { + this.documentFactory = documentFactory; + this.outputFormat = outputFormat; + } + + public Dom4JDriver() { + this(new DocumentFactory(), OutputFormat.createPrettyPrint()); + } + + public DocumentFactory getDocumentFactory() { + return documentFactory; + } + + public void setDocumentFactory(DocumentFactory documentFactory) { + this.documentFactory = documentFactory; + } + + public OutputFormat getOutputFormat() { + return outputFormat; + } + + public void setOutputFormat(OutputFormat outputFormat) { + this.outputFormat = outputFormat; + } + + public HierarchicalStreamReader createReader(Reader text) { + try { + SAXReader reader = new SAXReader(); + Document document = reader.read(text); + return new Dom4JReader(document); + } catch (DocumentException e) { + throw new StreamException(e); + } + } + + public HierarchicalStreamReader createReader(InputStream in) { + try { + SAXReader reader = new SAXReader(); + Document document = reader.read(in); + return new Dom4JReader(document); + } catch (DocumentException e) { + throw new StreamException(e); + } + } + + public HierarchicalStreamWriter createWriter(final Writer out) { + final Document document = documentFactory.createDocument(); + HierarchicalStreamWriter writer = new Dom4JWriter(document); + + // Ensure that on writer.close(), the Document is written back to the text output. + writer = new WriterWrapper(writer) { + public void close() { + super.close(); + try { + XMLWriter writer = new XMLWriter(out, outputFormat); + writer.write(document); + writer.flush(); + } catch (IOException e) { + throw new StreamException(e); + } + } + }; + + return writer; + } + + public HierarchicalStreamWriter createWriter(final OutputStream out) { + final Document document = documentFactory.createDocument(); + HierarchicalStreamWriter writer = new Dom4JWriter(document); + + // Ensure that on writer.close(), the Document is written back to the text output. + writer = new WriterWrapper(writer) { + public void close() { + super.close(); + try { + XMLWriter writer = new XMLWriter(out, outputFormat); + writer.write(document); + writer.flush(); + } catch (IOException e) { + throw new StreamException(e); + } + } + }; + + return writer; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JReader.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,65 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.converters.ErrorWriter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import org.dom4j.Document; +import org.dom4j.Element; +import org.dom4j.Attribute; + +public class Dom4JReader extends AbstractDocumentReader { + + private Element currentElement; + + public Dom4JReader(Element rootElement) { + super(rootElement); + } + + public Dom4JReader(Document document) { + this(document.getRootElement()); + } + + public String getNodeName() { + return currentElement.getName(); + } + + public String getValue() { + return currentElement.getText(); + } + + public String getAttribute(String name) { + return currentElement.attributeValue(name); + } + + public String getAttribute(int index) { + return currentElement.attribute(index).getValue(); + } + + public int getAttributeCount() { + return currentElement.attributeCount(); + } + + public String getAttributeName(int index) { + return currentElement.attribute(index).getQualifiedName(); + } + + protected Object getParent() { + return currentElement.getParent(); + } + + protected Object getChild(int index) { + return currentElement.elements().get(index); + } + + protected int getChildCount() { + return currentElement.elements().size(); + } + + protected void reassignCurrentElement(Object current) { + currentElement = (Element) current; + } + + public void appendErrors(ErrorWriter errorWriter) { + errorWriter.add("xpath", currentElement.getPath()); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JWriter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,52 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import org.dom4j.Branch; +import org.dom4j.DocumentFactory; +import org.dom4j.Element; + +import java.util.LinkedList; + +public class Dom4JWriter implements HierarchicalStreamWriter { + + private DocumentFactory documentFactory = new DocumentFactory(); + private LinkedList elementStack = new LinkedList(); + + public Dom4JWriter(Branch container) { + elementStack.addLast(container); + } + + public void startNode(String name) { + Element element = documentFactory.createElement(name); + top().add(element); + elementStack.addLast(element); + } + + public void setValue(String text) { + top().setText(text); + } + + public void addAttribute(String key, String value) { + ((Element) top()).addAttribute(key, value); + } + + public void endNode() { + elementStack.removeLast(); + } + + private Branch top() { + return (Branch) elementStack.getLast(); + } + + public void flush() { + // don't need to do anything + } + + public void close() { + // don't need to do anything + } + + public HierarchicalStreamWriter underlyingWriter() { + return this; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomDriver.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,60 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.*; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.ParserConfigurationException; +import java.io.*; + +public class DomDriver implements HierarchicalStreamDriver { + + private final String encoding; + private final DocumentBuilderFactory documentBuilderFactory; + + public DomDriver(String encoding) { + documentBuilderFactory = DocumentBuilderFactory.newInstance(); + this.encoding = encoding; + } + + public DomDriver() { + this("UTF-8"); + } + + public HierarchicalStreamReader createReader(Reader xml) { + return createReader(new InputSource(xml)); + } + + public HierarchicalStreamReader createReader(InputStream xml) { + return createReader(new InputSource(xml)); + } + + private HierarchicalStreamReader createReader(InputSource source) { + try { + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + source.setEncoding(encoding); + Document document = documentBuilder.parse(source); + return new DomReader(document); + } catch (FactoryConfigurationError e) { + throw new StreamException(e); + } catch (ParserConfigurationException e) { + throw new StreamException(e); + } catch (SAXException e) { + throw new StreamException(e); + } catch (IOException e) { + throw new StreamException(e); + } + } + + public HierarchicalStreamWriter createWriter(Writer out) { + return new PrettyPrintWriter(out); + } + + public HierarchicalStreamWriter createWriter(OutputStream out) { + return createWriter(new OutputStreamWriter(out)); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomReader.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,89 @@ +package com.thoughtworks.xstream.io.xml; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +import java.util.ArrayList; +import java.util.List; + +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + +public class DomReader extends AbstractDocumentReader { + + private Element currentElement; + private StringBuffer textBuffer; + private List childElements; + + public DomReader(Element rootElement) { + super(rootElement); + textBuffer = new StringBuffer(); + } + + public DomReader(Document document) { + this(document.getDocumentElement()); + } + + public String getNodeName() { + return currentElement.getTagName(); + } + + public String getValue() { + NodeList childNodes = currentElement.getChildNodes(); + textBuffer.setLength(0); + int length = childNodes.getLength(); + for (int i = 0; i < length; i++) { + Node childNode = childNodes.item(i); + if (childNode instanceof Text) { + Text text = (Text) childNode; + textBuffer.append(text.getData()); + } + } + return textBuffer.toString(); + } + + public String getAttribute(String name) { + Attr attribute = currentElement.getAttributeNode(name); + return attribute == null ? null : attribute.getValue(); + } + + public String getAttribute(int index) { + return ((Attr) currentElement.getAttributes().item(index)).getValue(); + } + + public int getAttributeCount() { + return currentElement.getAttributes().getLength(); + } + + public String getAttributeName(int index) { + return ((Attr) currentElement.getAttributes().item(index)).getName(); + } + + protected Object getParent() { + return currentElement.getParentNode(); + } + + protected Object getChild(int index) { + return childElements.get(index); + } + + protected int getChildCount() { + return childElements.size(); + } + + protected void reassignCurrentElement(Object current) { + currentElement = (Element) current; + NodeList childNodes = currentElement.getChildNodes(); + childElements = new ArrayList(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node node = childNodes.item(i); + if (node instanceof Element) { + childElements.add(node); + } + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomWriter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,59 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * @author Michael Kopp + */ +public class DomWriter implements HierarchicalStreamWriter { + private final Document document; + private Element current; + + public DomWriter(Document document) { + this.document = document; + this.current = document.getDocumentElement(); + } + + public DomWriter(Element rootElement) { + document = rootElement.getOwnerDocument(); + current = rootElement; + } + + public void startNode(String name) { + final Element child = document.createElement(name); + if (current == null) { + document.appendChild(child); + } else { + current.appendChild(child); + } + current = child; + } + + public void addAttribute(String name, String value) { + current.setAttribute(name, value); + } + + public void setValue(String text) { + current.appendChild(document.createTextNode(text)); + } + + public void endNode() { + Node parent = current.getParentNode(); + current = parent instanceof Element ? (Element)parent : null; + } + + public void flush() { + // don't need to do anything + } + + public void close() { + // don't need to do anything + } + + public HierarchicalStreamWriter underlyingWriter() { + return this; + } +} \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomDriver.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,52 @@ +package com.thoughtworks.xstream.io.xml; + +import java.io.*; + +import org.jdom.Document; +import org.jdom.JDOMException; +import org.jdom.input.SAXBuilder; + +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author Laurent Bihanic + */ +public class JDomDriver implements HierarchicalStreamDriver { + + public HierarchicalStreamReader createReader(Reader reader) { + try { + SAXBuilder builder = new SAXBuilder(); + Document document = builder.build(reader); + return new JDomReader(document); + } catch (IOException e) { + throw new StreamException(e); + } catch (JDOMException e) { + throw new StreamException(e); + } + } + + public HierarchicalStreamReader createReader(InputStream in) { + try { + SAXBuilder builder = new SAXBuilder(); + Document document = builder.build(in); + return new JDomReader(document); + } catch (IOException e) { + throw new StreamException(e); + } catch (JDOMException e) { + throw new StreamException(e); + } + } + + public HierarchicalStreamWriter createWriter(Writer out) { + return new PrettyPrintWriter(out); + } + + public HierarchicalStreamWriter createWriter(OutputStream out) { + return new PrettyPrintWriter(new OutputStreamWriter(out)); + } + +} + Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomReader.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,71 @@ +package com.thoughtworks.xstream.io.xml; + +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.Parent; +import org.jdom.Attribute; + +/** + * @author Laurent Bihanic + */ +public class JDomReader extends AbstractDocumentReader { + + private Element currentElement; + + public JDomReader(Element root) { + super(root); + } + + public JDomReader(Document document) { + super(document.getRootElement()); + } + + protected void reassignCurrentElement(Object current) { + currentElement = (Element) current; + } + + protected Object getParent() { + // JDOM 1.0: + return currentElement.getParentElement(); + + // JDOM b10: + // Parent parent = currentElement.getParent(); + // return (parent instanceof Element) ? (Element)parent : null; + + // JDOM b9 and earlier: + // return currentElement.getParent(); + } + + protected Object getChild(int index) { + return currentElement.getChildren().get(index); + } + + protected int getChildCount() { + return currentElement.getChildren().size(); + } + + public String getNodeName() { + return currentElement.getName(); + } + + public String getValue() { + return currentElement.getText(); + } + + public String getAttribute(String name) { + return currentElement.getAttributeValue(name); + } + + public String getAttribute(int index) { + return ((Attribute) currentElement.getAttributes().get(index)).getValue(); + } + + public int getAttributeCount() { + return currentElement.getAttributes().size(); + } + + public String getAttributeName(int index) { + return ((Attribute) currentElement.getAttributes().get(index)).getQualifiedName(); + } +} + Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomWriter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,89 @@ +package com.thoughtworks.xstream.io.xml; + +import java.util.List; +import java.util.LinkedList; + +import org.jdom.Element; +import org.jdom.JDOMFactory; +import org.jdom.DefaultJDOMFactory; + +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * @author Laurent Bihanic + */ +public class JDomWriter implements HierarchicalStreamWriter { + + private List result = new LinkedList(); + private List elementStack = new LinkedList(); + private final JDOMFactory documentFactory; + + public JDomWriter(Element container, JDOMFactory factory) { + elementStack.add(0, container); + result.add(container); + this.documentFactory = factory; + } + + public JDomWriter(JDOMFactory documentFactory) { + this.documentFactory = documentFactory; + } + + public JDomWriter(Element container) { + this(container, new DefaultJDOMFactory()); + } + + public JDomWriter() { + this(new DefaultJDOMFactory()); + } + + public void startNode(String name) { + Element element = this.documentFactory.element(name); + + Element parent = this.top(); + if (parent != null) { + parent.addContent(element); + } + else { + result.add(element); + } + elementStack.add(0, element); + } + + public void setValue(String text) { + top().addContent(this.documentFactory.text(text)); + } + + public void addAttribute(String key, String value) { + top().setAttribute( + this.documentFactory.attribute(key, value)); + } + + public void endNode() { + this.elementStack.remove(0); + } + + private Element top() { + Element top = null; + + if (this.elementStack.isEmpty() == false) { + top = (Element) this.elementStack.get(0); + } + return top; + } + + public List getResult() { + return this.result; + } + + public void flush() { + // don't need to do anything + } + + public void close() { + // don't need to do anything + } + + public HierarchicalStreamWriter underlyingWriter() { + return this; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,169 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.core.util.FastStack; +import com.thoughtworks.xstream.core.util.QuickWriter; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +import java.io.Writer; + +/** + * A simple writer that outputs XML in a pretty-printed indented stream. + * + *

            By default, the chars

            & < > " ' \r are escaped and replaced with a suitable XML entity. + * To alter this behavior, override the the {@link #writeText(com.thoughtworks.xstream.core.util.QuickWriter, String)} + * and {@link #writeAttributeValue(com.thoughtworks.xstream.core.util.QuickWriter, String)} methods.

            + * + * @author Joe Walnes + */ +public class PrettyPrintWriter implements HierarchicalStreamWriter { + + private final QuickWriter writer; + private final FastStack elementStack = new FastStack(16); + private final char[] lineIndenter; + + private boolean tagInProgress; + private int depth; + private boolean readyForNewLine; + private boolean tagIsEmpty; + + private static final char[] NULL = "�".toCharArray(); + private static final char[] AMP = "&".toCharArray(); + private static final char[] LT = "<".toCharArray(); + private static final char[] GT = ">".toCharArray(); + private static final char[] SLASH_R = " ".toCharArray(); + private static final char[] QUOT = """.toCharArray(); + private static final char[] APOS = "'".toCharArray(); + private static final char[] CLOSE = "': + this.writer.write(GT); + break; + case '"': + this.writer.write(QUOT); + break; + case '\'': + this.writer.write(APOS); + break; + case '\r': + this.writer.write(SLASH_R); + break; + default: + this.writer.write(c); + } + } + } + + public void endNode() { + depth--; + if (tagIsEmpty) { + writer.write('/'); + readyForNewLine = false; + finishTag(); + elementStack.popSilently(); + } else { + finishTag(); + writer.write(CLOSE); + writer.write((String)elementStack.pop()); + writer.write('>'); + } + readyForNewLine = true; + if (depth == 0 ) { + writer.flush(); + } + } + + private void finishTag() { + if (tagInProgress) { + writer.write('>'); + } + tagInProgress = false; + if (readyForNewLine) { + endOfLine(); + } + readyForNewLine = false; + tagIsEmpty = false; + } + + protected void endOfLine() { + writer.write('\n'); + for (int i = 0; i < depth; i++) { + writer.write(lineIndenter); + } + } + + public void flush() { + writer.flush(); + } + + public void close() { + writer.close(); + } + + public HierarchicalStreamWriter underlyingWriter() { + return this; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/QNameMap.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/QNameMap.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/QNameMap.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,89 @@ +package com.thoughtworks.xstream.io.xml; + +import javax.xml.namespace.QName; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Represents a mapping of {@link QName} intsnaces to Java class names + * allowing class aliases and namespace aware mappings of QNames to class names. + * + * @author James Strachan + * @version $Revision$ + */ +public class QNameMap { + + // lets make the mapping a no-op unless we specify some mapping + private Map qnameToJava; + private Map javaToQName; + private String defaultPrefix = ""; + private String defaultNamespace = ""; + + /** + * Returns the Java class name that should be used for the given QName. + * If no explicit mapping has been made then the localPart of the QName is used + * which is the normal default in XStream. + */ + public String getJavaClassName(QName qname) { + if (qnameToJava != null) { + String answer = (String) qnameToJava.get(qname); + if (answer != null) { + return answer; + } + } + return qname.getLocalPart(); + } + + /** + * Returns the Java class name that should be used for the given QName. + * If no explicit mapping has been made then the localPart of the QName is used + * which is the normal default in XStream. + */ + public QName getQName(String javaClassName) { + if (javaToQName != null) { + QName answer = (QName) javaToQName.get(javaClassName); + if (answer != null) { + return answer; + } + } + return new QName(defaultNamespace, javaClassName, defaultPrefix); + } + + /** + * Registers the mapping of the Java class name to the QName + */ + public synchronized void registerMapping(QName qname, String javaClassName) { + if (javaToQName == null) { + javaToQName = Collections.synchronizedMap(new HashMap()); + } + if (qnameToJava == null) { + qnameToJava = Collections.synchronizedMap(new HashMap()); + } + javaToQName.put(javaClassName, qname); + qnameToJava.put(qname, javaClassName); + } + + /** + * Registers the mapping of the type to the QName + */ + public synchronized void registerMapping(QName qname, Class type) { + registerMapping(qname, type.getName()); + } + + public String getDefaultNamespace() { + return defaultNamespace; + } + + public void setDefaultNamespace(String defaultNamespace) { + this.defaultNamespace = defaultNamespace; + } + + public String getDefaultPrefix() { + return defaultPrefix; + } + + public void setDefaultPrefix(String defaultPrefix) { + this.defaultPrefix = defaultPrefix; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/SaxWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/SaxWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/SaxWriter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,686 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.AttributesImpl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * A SAX {@link org.xml.sax.XMLReader parser} that acts as an XStream + * {@link HierarchicalStreamWriter} to enable direct generation of + * a SAX event flow from the XStream serialization of a list of + * list of Java objects. + *

            + * As a custom SAX parser, this class ignores the arguments of the + * two standard parse methods ({@link #parse(java.lang.String)} and + * {@link #parse(org.xml.sax.InputSource)}) but relies on a + * proprietary SAX property {@link #SOURCE_OBJECT_LIST_PROPERTY} to + * define the list of objects to serialize.

            + *

            + * Configuration of this SAX parser is achieved through the standard + * {@link #setProperty SAX property mecanism}. While specific setter + * methods require direct access to the parser instance, SAX + * properties support configuration settings to be propagated through + * a chain of {@link org.xml.sax.XMLFilter filters} down to the + * underlying parser object.

            + *

            + * This mecanism shall be used to configure the + * {@link #SOURCE_OBJECT_LIST_PROPERTY objects to be serialized} as + * well as the {@link #CONFIGURED_XSTREAM_PROPERTY XStream facade}.

            + * + * @author Laurent Bihanic + */ +public final class SaxWriter implements HierarchicalStreamWriter, XMLReader { + /** + * The {@link #setProperty SAX property} to configure the XStream + * facade to be used for object serialization. If the property + * is not set, a new XStream facade will be allocated for each + * parse. + */ + public final static String CONFIGURED_XSTREAM_PROPERTY = + "http://com.thoughtworks.xstream/sax/property/configured-xstream"; + + /** + * The {@link #setProperty SAX property} to configure the list of + * Java objects to serialize. Setting this property prior + * invoking one of the parse() methods is mandatory. + * + * @see #parse(java.lang.String) + * @see #parse(org.xml.sax.InputSource) + */ + public final static String SOURCE_OBJECT_LIST_PROPERTY = + "http://com.thoughtworks.xstream/sax/property/source-object-list"; + + //========================================================================= + // SAX XMLReader interface support + //========================================================================= + + /** + * The SAX EntityResolver associated to this XMLReader. + */ + private EntityResolver entityResolver = null; + + /** + * The SAX DTDHandler associated to this XMLReader. + */ + private DTDHandler dtdHandler = null; + + /** + * The SAX ContentHandler associated to this XMLReader. + */ + private ContentHandler contentHandler = null; + + /** + * The SAX ErrorHandler associated to this XMLReader. + */ + private ErrorHandler errorHandler = null; + + /** + * The SAX features defined for this XMLReader. + *

            + * This class does not define any feature (yet) and ignores + * the SAX mandatory feature. Thus, this member is present + * only to support the mandatory feature setting and retrieval + * logic defined by SAX.

            + */ + private Map features = new HashMap(); + + /** + * The SAX properties defined for this XMLReader. + */ + private final Map properties = new HashMap(); + + private final boolean includeEnclosingDocument; + + public SaxWriter(boolean includeEnclosingDocument) { + this.includeEnclosingDocument = includeEnclosingDocument; + } + + public SaxWriter() { + this(true); + } + + //------------------------------------------------------------------------- + // Configuration + //------------------------------------------------------------------------- + + /** + * Sets the state of a feature. + *

            + * The feature name is any fully-qualified URI.

            + *

            + * All XMLReaders are required to support setting + * http://xml.org/sax/features/namespaces to + * true and + * http://xml.org/sax/features/namespace-prefixes to + * false.

            + *

            + * Some feature values may be immutable or mutable only + * in specific contexts, such as before, during, or after + * a parse.

            + *

            + * Note: This implemention only supports the two + * mandatory SAX features.

            + * + * @param name the feature name, which is a fully-qualified URI. + * @param value the requested state of the feature (true or false). + * @throws SAXNotRecognizedException when the XMLReader does not + * recognize the feature name. + * @see #getFeature + */ + public void setFeature(String name, boolean value) + throws SAXNotRecognizedException { + if ((name.equals("http://xml.org/sax/features/namespaces")) || + (name.equals("http://xml.org/sax/features/namespace-prefixes"))) { + this.features.put(name, value ? Boolean.TRUE : Boolean.FALSE); // JDK 1.3 friendly + } else { + throw new SAXNotRecognizedException(name); + } + } + + /** + * Looks up the value of a feature. + *

            + * The feature name is any fully-qualified URI. It is + * possible for an XMLReader to recognize a feature name but + * to be unable to return its value; this is especially true + * in the case of an adapter for a SAX1 Parser, which has + * no way of knowing whether the underlying parser is + * performing validation or expanding external entities.

            + *

            + * All XMLReaders are required to recognize the + * http://xml.org/sax/features/namespaces and the + * http://xml.org/sax/features/namespace-prefixes feature + * names.

            + *

            + * Some feature values may be available only in specific + * contexts, such as before, during, or after a parse.

            + *

            + * Implementors are free (and encouraged) to invent their own + * features, using names built on their own URIs.

            + * + * @param name the feature name, which is a fully-qualified URI. + * @return the current state of the feature (true or false). + * @throws SAXNotRecognizedException when the XMLReader does not + * recognize the feature name. + * @see #setFeature + */ + public boolean getFeature(String name) + throws SAXNotRecognizedException { + if ((name.equals("http://xml.org/sax/features/namespaces")) || + (name.equals("http://xml.org/sax/features/namespace-prefixes"))) { + Boolean value = (Boolean) (this.features.get(name)); + + if (value == null) { + value = Boolean.FALSE; + } + return value.booleanValue(); + } else { + throw new SAXNotRecognizedException(name); + } + } + + /** + * Sets the value of a property. + *

            + * The property name is any fully-qualified URI. It is + * possible for an XMLReader to recognize a property name but + * to be unable to set its value.

            + *

            + * XMLReaders are not required to recognize setting any + * specific property names, though a core set is provided with + * SAX2.

            + *

            + * Some property values may be immutable or mutable only + * in specific contexts, such as before, during, or after + * a parse.

            + *

            + * This method is also the standard mechanism for setting + * extended handlers.

            + *

            + * Note: This implemention only supports two + * (proprietary) properties: {@link #CONFIGURED_XSTREAM_PROPERTY} + * and {@link #SOURCE_OBJECT_LIST_PROPERTY}.

            + * + * @param name the property name, which is a fully-qualified URI. + * @param value the requested value for the property. + * @throws SAXNotRecognizedException when the XMLReader does not + * recognize the property name. + * @throws SAXNotSupportedException when the XMLReader recognizes + * the property name but cannot set + * the requested value. + * @see #getProperty + */ + public void setProperty(String name, Object value) + throws SAXNotRecognizedException, + SAXNotSupportedException { + if (name.equals(CONFIGURED_XSTREAM_PROPERTY)) { + if (!(value instanceof XStream)) { + throw new SAXNotSupportedException("Value for property \"" + + CONFIGURED_XSTREAM_PROPERTY + + "\" must be a non-null XStream object"); + } + } else if (name.equals(SOURCE_OBJECT_LIST_PROPERTY)) { + if (value instanceof List) { + List list = (List) value; + + if (list.isEmpty()) { + throw new SAXNotSupportedException("Value for property \"" + + SOURCE_OBJECT_LIST_PROPERTY + + "\" shall not be an empty list"); + } else { + // Perform a copy of the list to prevent the application to + // modify its content while the parse is being performed. + value = Collections.unmodifiableList(new ArrayList(list)); + } + } else { + throw new SAXNotSupportedException("Value for property \"" + + SOURCE_OBJECT_LIST_PROPERTY + + "\" must be a non-null List object"); + } + } else { + throw new SAXNotRecognizedException(name); + } + this.properties.put(name, value); + } + + /** + * Looks up the value of a property. + *

            + * The property name is any fully-qualified URI. It is + * possible for an XMLReader to recognize a property name but + * to be unable to return its state.

            + *

            + * XMLReaders are not required to recognize any specific + * property names, though an initial core set is documented for + * SAX2.

            + *

            + * Some property values may be available only in specific + * contexts, such as before, during, or after a parse.

            + *

            + * Implementors are free (and encouraged) to invent their own properties, + * using names built on their own URIs.

            + * + * @param name the property name, which is a fully-qualified URI. + * @return the current value of the property. + * @throws SAXNotRecognizedException when the XMLReader does not + * recognize the property name. + * @see #getProperty + */ + public Object getProperty(String name) + throws SAXNotRecognizedException { + if ((name.equals(CONFIGURED_XSTREAM_PROPERTY)) || + (name.equals(SOURCE_OBJECT_LIST_PROPERTY))) { + return this.properties.get(name); + } else { + throw new SAXNotRecognizedException(name); + } + } + + //--------------------------------------------------------------------- + // Event handlers + //--------------------------------------------------------------------- + + /** + * Allows an application to register an entity resolver. + *

            + * If the application does not register an entity resolver, + * the XMLReader will perform its own default resolution.

            + *

            + * Applications may register a new or different resolver in the + * middle of a parse, and the SAX parser must begin using the new + * resolver immediately.

            + * + * @param resolver the entity resolver. + * @throws NullPointerException if the resolver argument is + * null. + * @see #getEntityResolver + */ + public void setEntityResolver(EntityResolver resolver) { + if (resolver == null) { + throw new NullPointerException("resolver"); + } + this.entityResolver = resolver; + return; + } + + /** + * Returns the current entity resolver. + * + * @return the current entity resolver, or null if none + * has been registered. + * @see #setEntityResolver + */ + public EntityResolver getEntityResolver() { + return this.entityResolver; + } + + /** + * Allows an application to register a DTD event handler. + *

            + * If the application does not register a DTD handler, all DTD + * events reported by the SAX parser will be silently ignored.

            + *

            + * Applications may register a new or different handler in the + * middle of a parse, and the SAX parser must begin using the new + * handler immediately.

            + * + * @param handler the DTD handler. + * @throws NullPointerException if the handler argument is + * null. + * @see #getDTDHandler + */ + public void setDTDHandler(DTDHandler handler) { + if (handler == null) { + throw new NullPointerException("handler"); + } + this.dtdHandler = handler; + return; + } + + /** + * Returns the current DTD handler. + * + * @return the current DTD handler, or null if none + * has been registered. + * @see #setDTDHandler + */ + public DTDHandler getDTDHandler() { + return this.dtdHandler; + } + + /** + * Allows an application to register a content event handler. + *

            + * If the application does not register a content handler, all + * content events reported by the SAX parser will be silently + * ignored.

            + *

            + * Applications may register a new or different handler in the + * middle of a parse, and the SAX parser must begin using the new + * handler immediately.

            + * + * @param handler the content handler. + * @throws NullPointerException if the handler argument is + * null. + * @see #getContentHandler + */ + public void setContentHandler(ContentHandler handler) { + if (handler == null) { + throw new NullPointerException("handler"); + } + this.contentHandler = handler; + return; + } + + /** + * Returns the current content handler. + * + * @return the current content handler, or null if none + * has been registered. + * @see #setContentHandler + */ + public ContentHandler getContentHandler() { + return this.contentHandler; + } + + /** + * Allows an application to register an error event handler. + *

            + * If the application does not register an error handler, all + * error events reported by the SAX parser will be silently + * ignored; however, normal processing may not continue. It is + * highly recommended that all SAX applications implement an + * error handler to avoid unexpected bugs.

            + *

            + * Applications may register a new or different handler in the + * middle of a parse, and the SAX parser must begin using the new + * handler immediately.

            + * + * @param handler the error handler. + * @throws NullPointerException if the handler argument is + * null. + * @see #getErrorHandler + */ + public void setErrorHandler(ErrorHandler handler) { + if (handler == null) { + throw new NullPointerException("handler"); + } + this.errorHandler = handler; + return; + } + + /** + * Returns the current error handler. + * + * @return the current error handler, or null if none + * has been registered. + * @see #setErrorHandler + */ + public ErrorHandler getErrorHandler() { + return this.errorHandler; + } + + //--------------------------------------------------------------------- + // Parsing + //--------------------------------------------------------------------- + + /** + * Parses an XML document from a system identifier (URI). + *

            + * This method is a shortcut for the common case of reading a + * document from a system identifier. It is the exact + * equivalent of the following:

            + *
            + *
            +     *    parse(new InputSource(systemId));
            +     *  
            + *
            + *

            + * If the system identifier is a URL, it must be fully resolved + * by the application before it is passed to the parser.

            + *

            + * Note: As a custom SAX parser, this class + * ignores the systemId argument of this method + * and relies on the proprietary SAX property + * {@link #SOURCE_OBJECT_LIST_PROPERTY}) to define the list of + * objects to serialize.

            + * + * @param systemId the system identifier (URI). + * @throws SAXException Any SAX exception, possibly wrapping + * another exception. + * @see #parse(org.xml.sax.InputSource) + */ + public void parse(String systemId) throws SAXException { + this.parse(); + } + + /** + * Parse an XML document. + *

            + * The application can use this method to instruct the XML + * reader to begin parsing an XML document from any valid input + * source (a character stream, a byte stream, or a URI).

            + *

            + * Applications may not invoke this method while a parse is in + * progress (they should create a new XMLReader instead for each + * nested XML document). Once a parse is complete, an + * application may reuse the same XMLReader object, possibly + * with a different input source.

            + *

            + * During the parse, the XMLReader will provide information + * about the XML document through the registered event + * handlers.

            + *

            + * This method is synchronous: it will not return until parsing + * has ended. If a client application wants to terminate + * parsing early, it should throw an exception.

            + *

            + * Note: As a custom SAX parser, this class + * ignores the source argument of this method + * and relies on the proprietary SAX property + * {@link #SOURCE_OBJECT_LIST_PROPERTY}) to define the list of + * objects to serialize.

            + * + * @param input The input source for the top-level of the + * XML document. + * @throws SAXException Any SAX exception, possibly wrapping + * another exception. + * @see org.xml.sax.InputSource + * @see #parse(java.lang.String) + * @see #setEntityResolver + * @see #setDTDHandler + * @see #setContentHandler + * @see #setErrorHandler + */ + public void parse(InputSource input) throws SAXException { + this.parse(); + } + + /** + * Serializes the Java objects of the configured list into a flow + * of SAX events. + * + * @throws SAXException if the configured object list is invalid + * or object serialization failed. + */ + private void parse() throws SAXException { + XStream xstream = (XStream) (this.properties.get(CONFIGURED_XSTREAM_PROPERTY)); + if (xstream == null) { + xstream = new XStream(); + } + + List source = (List) (this.properties.get(SOURCE_OBJECT_LIST_PROPERTY)); + if ((source == null) || (source.isEmpty())) { + throw new SAXException("Missing or empty source object list. Setting property \"" + + SOURCE_OBJECT_LIST_PROPERTY + "\" is mandatory"); + } + + try { + this.startDocument(true); + for (Iterator i = source.iterator(); i.hasNext();) { + xstream.marshal(i.next(), this); + } + this.endDocument(true); + } catch (StreamException e) { + if (e.getCause() instanceof SAXException) { + throw (SAXException) (e.getCause()); + } else { + throw new SAXException(e); + } + } + } + + + //========================================================================= + // XStream HierarchicalStreamWriter interface support + //========================================================================= + + private int depth = 0; + private List elementStack = new LinkedList(); + private char[] buffer = new char[128]; + private boolean startTagInProgress = false; + private final AttributesImpl attributeList = new AttributesImpl(); + + public void startNode(String name) { + try { + if (this.depth != 0) { + this.flushStartTag(); + } else if (includeEnclosingDocument) { + this.startDocument(false); + } + this.elementStack.add(0, name); + + this.startTagInProgress = true; + this.depth++; + } catch (SAXException e) { + throw new StreamException(e); + } + } + + public void addAttribute(String name, String value) { + if (this.startTagInProgress) { + this.attributeList.addAttribute("", name, name, "CDATA", value); + } else { + throw new StreamException(new IllegalStateException("No startElement being processed")); + } + } + + public void setValue(String text) { + try { + this.flushStartTag(); + + int lg = text.length(); + if (lg > buffer.length) { + buffer = new char[lg]; + } + text.getChars(0, lg, buffer, 0); + + this.contentHandler.characters(buffer, 0, lg); + } catch (SAXException e) { + throw new StreamException(e); + } + } + + public void endNode() { + try { + this.flushStartTag(); + + String tagName = (String) (this.elementStack.remove(0)); + + this.contentHandler.endElement("", tagName, tagName); + + this.depth--; + if (this.depth == 0 && includeEnclosingDocument) { + this.endDocument(false); + } + } catch (SAXException e) { + throw new StreamException(e); + } + } + + /** + * Fires the SAX startDocument event towards the configured + * ContentHandler. + * + * @param multiObjectMode whether serialization of several + * object will be merge into a single + * SAX document. + * @throws SAXException if thrown by the ContentHandler. + */ + private void startDocument(boolean multiObjectMode) throws SAXException { + if (this.depth == 0) { + // Notify contentHandler of document start. + this.contentHandler.startDocument(); + + if (multiObjectMode) { + // Prevent marshalling of each object to fire its own + // start/endDocument events. + this.depth++; + } + } + } + + /** + * Fires the SAX endDocument event towards the configured + * ContentHandler. + * + * @param multiObjectMode whether serialization of several + * object will be merge into a single + * SAX document. + * @throws SAXException if thrown by the ContentHandler. + */ + private void endDocument(boolean multiObjectMode) throws SAXException { + if ((this.depth == 0) || ((this.depth == 1) && (multiObjectMode))) { + this.contentHandler.endDocument(); + this.depth = 0; + } + } + + /** + * Fires any pending SAX startElement event towards the + * configured ContentHandler. + * + * @throws SAXException if thrown by the ContentHandler. + */ + private void flushStartTag() throws SAXException { + if (this.startTagInProgress) { + String tagName = (String) (this.elementStack.get(0)); + + this.contentHandler.startElement("", tagName, + tagName, this.attributeList); + this.attributeList.clear(); + this.startTagInProgress = false; + } + } + + public void flush() { + // don't need to do anything + } + + public void close() { + // don't need to do anything + } + + public HierarchicalStreamWriter underlyingWriter() { + return this; + } +} + Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxDriver.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,145 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; + +import javax.xml.stream.*; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; + +/** + * A driver using the StAX API + * + * @author James Strachan + * @version $Revision$ + */ +public class StaxDriver implements HierarchicalStreamDriver { + + private static boolean libraryPresent; + + private QNameMap qnameMap; + private XMLInputFactory inputFactory; + private XMLOutputFactory outputFactory; + private boolean repairingNamespace = false; + + public StaxDriver() { + this.qnameMap = new QNameMap(); + } + + public StaxDriver(QNameMap qnameMap) { + this.qnameMap = qnameMap; + } + + public StaxDriver(QNameMap qnameMap, boolean repairingNamespace) { + this.qnameMap = qnameMap; + this.repairingNamespace = repairingNamespace; + } + + public HierarchicalStreamReader createReader(Reader xml) { + loadLibrary(); + try { + return new StaxReader(qnameMap, createParser(xml)); + } + catch (XMLStreamException e) { + throw new StreamException(e); + } + } + + public HierarchicalStreamReader createReader(InputStream in) { + loadLibrary(); + try { + return new StaxReader(qnameMap, createParser(in)); + } + catch (XMLStreamException e) { + throw new StreamException(e); + } + } + + private void loadLibrary() { + if (!libraryPresent) { + try { + Class.forName("javax.xml.stream.XMLStreamReader"); + } + catch (ClassNotFoundException e) { + throw new IllegalArgumentException("StAX API is not present. Specify another driver." + + " For example: new XStream(new DomDriver())"); + } + libraryPresent = true; + } + } + + public HierarchicalStreamWriter createWriter(Writer out) { + try { + return new StaxWriter(qnameMap, getOutputFactory().createXMLStreamWriter(out), true, isRepairingNamespace()); + } + catch (XMLStreamException e) { + throw new StreamException(e); + } + } + + public HierarchicalStreamWriter createWriter(OutputStream out) { + try { + return new StaxWriter(qnameMap, getOutputFactory().createXMLStreamWriter(out), true, isRepairingNamespace()); + } + catch (XMLStreamException e) { + throw new StreamException(e); + } + } + + public AbstractPullReader createStaxReader(XMLStreamReader in) { + return new StaxReader(qnameMap, in); + } + + public StaxWriter createStaxWriter(XMLStreamWriter out, boolean writeStartEndDocument) throws XMLStreamException { + return new StaxWriter(qnameMap, out, writeStartEndDocument, repairingNamespace); + } + + public StaxWriter createStaxWriter(XMLStreamWriter out) throws XMLStreamException { + return createStaxWriter(out, true); + } + + + // Properties + //------------------------------------------------------------------------- + public QNameMap getQnameMap() { + return qnameMap; + } + + public void setQnameMap(QNameMap qnameMap) { + this.qnameMap = qnameMap; + } + + public XMLInputFactory getInputFactory() { + if (inputFactory == null) { + inputFactory = XMLInputFactory.newInstance(); + } + return inputFactory; + } + + public XMLOutputFactory getOutputFactory() { + if (outputFactory == null) { + outputFactory = XMLOutputFactory.newInstance(); + outputFactory.setProperty("javax.xml.stream.isRepairingNamespaces", isRepairingNamespace() ? Boolean.TRUE : Boolean.FALSE); + } + return outputFactory; + } + + public boolean isRepairingNamespace() { + return repairingNamespace; + } + + + // Implementation methods + //------------------------------------------------------------------------- + protected XMLStreamReader createParser(Reader xml) throws XMLStreamException { + return getInputFactory().createXMLStreamReader(xml); + } + + protected XMLStreamReader createParser(InputStream xml) throws XMLStreamException { + return getInputFactory().createXMLStreamReader(xml); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxReader.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,87 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.converters.ErrorWriter; +import com.thoughtworks.xstream.io.StreamException; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +/** + * A reader using the StAX API. + * + * @author James Strachan + * @version $Revision$ + */ +public class StaxReader extends AbstractPullReader { + + private final QNameMap qnameMap; + private final XMLStreamReader in; + + public StaxReader(QNameMap qnameMap, XMLStreamReader in) { + this.qnameMap = qnameMap; + this.in = in; + moveDown(); + } + + protected int pullNextEvent() { + try { + switch(in.next()) { + case XMLStreamConstants.START_DOCUMENT: + case XMLStreamConstants.START_ELEMENT: + return START_NODE; + case XMLStreamConstants.END_DOCUMENT: + case XMLStreamConstants.END_ELEMENT: + return END_NODE; + case XMLStreamConstants.CHARACTERS: + return TEXT; + case XMLStreamConstants.COMMENT: + return COMMENT; + default: + return OTHER; + } + } catch (XMLStreamException e) { + throw new StreamException(e); + } + } + + protected String pullElementName() { + // let the QNameMap handle any mapping of QNames to Java class names + QName qname = in.getName(); + return qnameMap.getJavaClassName(qname); + } + + protected String pullText() { + return in.getText(); + } + + public String getAttribute(String name) { + return in.getAttributeValue(null, name); + } + + public String getAttribute(int index) { + return in.getAttributeValue(index); + } + + public int getAttributeCount() { + return in.getAttributeCount(); + } + + public String getAttributeName(int index) { + return in.getAttributeLocalName(index); + } + + public void appendErrors(ErrorWriter errorWriter) { + errorWriter.add("line number", String.valueOf(in.getLocation().getLineNumber())); + } + + public void close() { + try { + in.close(); + } catch (XMLStreamException e) { + throw new StreamException(e); + } + } + +} \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxWriter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,163 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +/** + * A stream writing that outputs to a StAX stream writer + * + * @author James Strachan + * @version $Revision$ + */ +public class StaxWriter implements HierarchicalStreamWriter { + private final QNameMap qnameMap; + private final XMLStreamWriter out; + private final boolean writeEnclosingDocument; + private boolean namespaceRepairingMode; + + private int tagDepth; + + public StaxWriter(QNameMap qnameMap, XMLStreamWriter out) throws XMLStreamException { + this(qnameMap, out, true, true); + } + + /** + * Allows a StaxWriter to be created for partial XML output + * + * @param qnameMap is the mapper of Java class names to QNames + * @param out the stream to output to + * @param writeEnclosingDocument a flag to indicate whether or not the start/end document events should be written + * @throws XMLStreamException if the events could not be written to the output + */ + public StaxWriter(QNameMap qnameMap, XMLStreamWriter out, boolean writeEnclosingDocument, boolean namespaceRepairingMode) throws XMLStreamException { + this.qnameMap = qnameMap; + this.out = out; + this.writeEnclosingDocument = writeEnclosingDocument; + this.namespaceRepairingMode = namespaceRepairingMode; + if (writeEnclosingDocument) { + out.writeStartDocument(); + } + } + + public void flush() { + try { + out.close(); + } + catch (XMLStreamException e) { + throw new StreamException(e); + } + } + + /** + * Call this method when you're finished with me + */ + public void close() { + try { + out.close(); + } + catch (XMLStreamException e) { + throw new StreamException(e); + } + } + + public void addAttribute(String name, String value) { + try { + out.writeAttribute(name, value); + } + catch (XMLStreamException e) { + throw new StreamException(e); + } + } + + public void endNode() { + try { + tagDepth--; + out.writeEndElement(); + if (tagDepth == 0 && writeEnclosingDocument) { + out.writeEndDocument(); + } + } + catch (XMLStreamException e) { + throw new StreamException(e); + } + } + + public void setValue(String text) { + try { + out.writeCharacters(text); + } + catch (XMLStreamException e) { + throw new StreamException(e); + } + } + + public void startNode(String name) { + try { + QName qname = qnameMap.getQName(name); + String prefix = qname.getPrefix(); + String uri = qname.getNamespaceURI(); + + // before you ask - yes it really is this complicated to output QNames to StAX + // handling both repair namespace modes :) + + boolean hasPrefix = prefix != null && prefix.length() > 0; + boolean hasURI = uri != null && uri.length() > 0; + boolean writeNamespace = false; + + if (hasURI) { + if (hasPrefix) { + String currentNamespace = out.getNamespaceContext().getNamespaceURI(prefix); + if (currentNamespace == null || !currentNamespace.equals(uri)) { + writeNamespace = true; + } + } + else { + String defaultNamespace = out.getNamespaceContext().getNamespaceURI(""); + if (defaultNamespace == null || !defaultNamespace.equals(uri)) { + writeNamespace = true; + } + } + } + + if (hasPrefix) { + out.setPrefix(prefix, uri); + } + else if (hasURI) { + if (writeNamespace) { + out.setDefaultNamespace(uri); + } + } + out.writeStartElement(prefix, qname.getLocalPart(), uri); + if (hasURI && writeNamespace && !isNamespaceRepairingMode()) { + if (hasPrefix) { + out.writeNamespace(prefix, uri); + } + else { + out.writeDefaultNamespace(uri); + } + } + tagDepth++; + } + catch (XMLStreamException e) { + throw new StreamException(e); + } + } + + public HierarchicalStreamWriter underlyingWriter() { + return this; + } + + /** + * Is StAX namespace repairing mode on or off? + * + * @return + */ + public boolean isNamespaceRepairingMode() { + return namespaceRepairingMode; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/TraxSource.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/TraxSource.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/TraxSource.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,309 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.XStream; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLFilter; +import org.xml.sax.XMLReader; + +import javax.xml.transform.sax.SAXSource; +import java.util.ArrayList; +import java.util.List; + +/** + * A {@link SAXSource JAXP TrAX Source} that enables using XStream + * object serialization as direct input for XSLT processors without + * resorting to an intermediate representation such as text XML, DOM + * or DOM4J. + *

            + * The following example shows how to apply an XSL Transformation + * to a set of Java objects gathered into a List + * (source):

            + *
            
            + *   public static String transform(List source, String stylesheet) {
            + *     try {
            + *       Transformer transformer = TransformerFactory.newInstance()
            + *                             .newTransformer(new StreamSource(stylesheet));
            + *       XStreamSource in = new XStreamSource(source);
            + *       Writer out = new StringWriter();
            + *       transformer.transform(in, new StreamResult(out));
            + *       return out.toString();
            + *     }
            + *     catch (TransformerException e) {
            + *       throw new RuntimeException("XSLT Transformation failed", e);
            + *     }
            + *   }
            + * 
            + * + * @author Laurent Bihanic + */ +public class TraxSource extends SAXSource { + + /** + * If {@link javax.xml.transform.TransformerFactory#getFeature} + * returns true when passed this value as an + * argument, the Transformer natively supports XStream. + *

            + * Note: This implementation does not override + * the {@link SAXSource#FEATURE} value defined by its superclass + * to be considered as a SAXSource by Transformer implementations + * not natively supporting this XStream-specific source + *

            + */ + public final static String XSTREAM_FEATURE = + "http://com.thoughtworks.xstream/XStreamSource/feature"; + + /** + * The XMLReader object associated to this source or + * null if no XMLReader has yet been requested. + * + * @see #getXMLReader + */ + private XMLReader xmlReader = null; + + /** + * The configured XStream facade to use for serializing objects. + */ + private XStream xstream = null; + + /** + * The list of Java objects to be serialized. + */ + private List source = null; + + + //------------------------------------------------------------------------- + // Constructors + //------------------------------------------------------------------------- + + /** + * Creates a XStream TrAX source. + */ + public TraxSource() { + super(new InputSource()); + } + + /** + * Creates a XStream TrAX source, specifying the object to + * marshal. + * + * @param source the object to marshal. + * @throws IllegalArgumentException if source is + * null. + * @see #setSource(java.lang.Object) + */ + public TraxSource(Object source) { + super(new InputSource()); + + this.setSource(source); + } + + /** + * Creates a XStream TrAX source, specifying the object to + * marshal and a configured (with aliases) XStream facade. + * + * @param source the object to marshal. + * @param xstream a configured XStream facade. + * @throws IllegalArgumentException if source or + * xstream is null. + * @see #setSource(java.lang.Object) + * @see #setXStream(com.thoughtworks.xstream.XStream) + */ + public TraxSource(Object source, XStream xstream) { + super(new InputSource()); + + this.setSource(source); + this.setXStream(xstream); + } + + /** + * Creates a XStream TrAX source, setting the objects to + * marshal. + * + * @param source the list of objects to marshal. + * @throws IllegalArgumentException if source is + * null or empty. + * @see #setSourceAsList(java.util.List) + */ + public TraxSource(List source) { + super(new InputSource()); + + this.setSourceAsList(source); + } + + /** + * Creates a XStream TrAX source, setting the objects to + * marshal and a configured (with aliases) XStream facade. + * + * @param source the list of objects to marshal. + * @param xstream a configured XStream facade. + * @throws IllegalArgumentException if source or + * xstream is null or + * source is empty. + * @see #setSourceAsList(java.util.List) + * @see #setXStream(com.thoughtworks.xstream.XStream) + */ + public TraxSource(List source, XStream xstream) { + super(new InputSource()); + + this.setSourceAsList(source); + this.setXStream(xstream); + } + + //------------------------------------------------------------------------- + // SAXSource overwritten methods + //------------------------------------------------------------------------- + + /** + * Sets the SAX InputSource to be used for the Source. + *

            + * As this implementation only supports object lists as data + * source, this method always throws an + * {@link UnsupportedOperationException}. + *

            + * + * @param inputSource a valid InputSource reference. + * @throws UnsupportedOperationException always! + */ + public void setInputSource(InputSource inputSource) { + throw new UnsupportedOperationException(); + } + + /** + * Set the XMLReader to be used for the Source. + *

            + * As this implementation only supports object lists as data + * source, this method throws an + * {@link UnsupportedOperationException} if the provided reader + * object does not implement the SAX {@link XMLFilter} + * interface. Otherwise, a {@link SaxWriter} instance will be + * attached as parent of the filter chain.

            + * + * @param reader a valid XMLReader or XMLFilter reference. + * @throws UnsupportedOperationException if reader + * is not a SAX + * {@link XMLFilter}. + * @see #getXMLReader + */ + public void setXMLReader(XMLReader reader) { + this.createXMLReader(reader); + } + + /** + * Returns the XMLReader to be used for the Source. + *

            + * This implementation returns a specific XMLReader + * ({@link SaxWriter}) generating the XML from a list of input + * objects. + *

            + * + * @return an XMLReader generating the XML from a list of input + * objects. + */ + public XMLReader getXMLReader() { + if (this.xmlReader == null) { + this.createXMLReader(null); + } + return this.xmlReader; + } + + + //------------------------------------------------------------------------- + // Specific implementation + //------------------------------------------------------------------------- + + /** + * Sets the XStream facade to use when marshalling objects. + * + * @param xstream a configured XStream facade. + * @throws IllegalArgumentException if xstream is + * null. + */ + public void setXStream(XStream xstream) { + if (xstream == null) { + throw new IllegalArgumentException("xstream"); + } + this.xstream = xstream; + + this.configureXMLReader(); + } + + /** + * Sets the object to marshal. + * + * @param obj the object to marshal. + * @throws IllegalArgumentException if source is + * null. + */ + public void setSource(Object obj) { + if (obj == null) { + throw new IllegalArgumentException("obj"); + } + List list = new ArrayList(1); + list.add(obj); + + this.setSourceAsList(list); + } + + /** + * Sets the list of objects to marshal. + *

            + * When dealing with non-text input (such as SAX or DOM), XSLT + * processors support multiple root node children for the source + * tree (see + * section 3.1 + * of the "XSL Transformations (XSLT) Version 1.0" + * specification. Using a list of objects as source makes use + * of this feature and allows creating XML documents merging + * the XML serialization of several Java objects. + * + * @param list the list of objects to marshal. + * @throws IllegalArgumentException if source is + * null or empty. + */ + public void setSourceAsList(List list) { + if ((list == null) || (list.isEmpty())) { + throw new IllegalArgumentException("list"); + } + this.source = list; + + this.configureXMLReader(); + } + + private void createXMLReader(XMLReader filterChain) { + if (filterChain == null) { + this.xmlReader = new SaxWriter(); + } else { + if (filterChain instanceof XMLFilter) { + // Connect the filter chain to a document reader. + XMLFilter filter = (XMLFilter) filterChain; + while (filter.getParent() instanceof XMLFilter) { + filter = (XMLFilter) (filter.getParent()); + } + filter.setParent(new SaxWriter()); + + // Read XML data from filter chain. + this.xmlReader = filterChain; + } else { + throw new UnsupportedOperationException(); + } + } + this.configureXMLReader(); + } + + private void configureXMLReader() { + if (this.xmlReader != null) { + try { + if (this.xstream != null) { + this.xmlReader.setProperty(SaxWriter.CONFIGURED_XSTREAM_PROPERTY, this.xstream); + } + if (this.source != null) { + this.xmlReader.setProperty(SaxWriter.SOURCE_OBJECT_LIST_PROPERTY, this.source); + } + } catch (SAXException e) { + throw new IllegalArgumentException(e.getMessage()); + } + } + } +} + Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomReader.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,66 @@ +package com.thoughtworks.xstream.io.xml; + +import nu.xom.*; + +public class XomReader extends AbstractDocumentReader { + + private Element currentElement; + + public XomReader(Element rootElement) { + super(rootElement); + } + + public XomReader(Document document) { + super(document.getRootElement()); + } + + public String getNodeName() { + return currentElement.getLocalName(); + } + + public String getValue() { + // currentElement.getValue() not used as this includes text of child elements, which we don't want. + StringBuffer result = new StringBuffer(); + int childCount = currentElement.getChildCount(); + for(int i = 0; i < childCount; i++) { + Node child = currentElement.getChild(i); + if (child instanceof Text) { + Text text = (Text) child; + result.append(text.getValue()); + } + } + return result.toString(); + } + + public String getAttribute(String name) { + return currentElement.getAttributeValue(name); + } + + public String getAttribute(int index) { + return currentElement.getAttribute(index).getValue(); + } + + public int getAttributeCount() { + return currentElement.getAttributeCount(); + } + + public String getAttributeName(int index) { + return currentElement.getAttribute(index).getQualifiedName(); + } + + protected int getChildCount() { + return currentElement.getChildElements().size(); + } + + protected Object getParent() { + return currentElement.getParent(); + } + + protected Object getChild(int index) { + return currentElement.getChildElements().get(index); + } + + protected void reassignCurrentElement(Object current) { + currentElement = (Element) current; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomWriter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,44 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import nu.xom.Element; +import nu.xom.Attribute; + +public class XomWriter implements HierarchicalStreamWriter { + + private Element node; + + public XomWriter(Element parentElement) { + this.node = parentElement; + } + + public void startNode(String name) { + Element newNode = new Element(name); + node.appendChild(newNode); + node = newNode; + } + + public void addAttribute(String name, String value) { + node.addAttribute(new Attribute(name, value)); + } + + public void setValue(String text) { + node.appendChild(text); + } + + public void endNode() { + node = (Element) node.getParent(); + } + + public void flush() { + // don't need to do anything + } + + public void close() { + // don't need to do anything + } + + public HierarchicalStreamWriter underlyingWriter() { + return this; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomDriver.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,32 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.xml.xppdom.Xpp3DomBuilder; + +import java.io.*; + +public class XppDomDriver implements HierarchicalStreamDriver { + + public HierarchicalStreamReader createReader(Reader xml) { + try { + return new XppDomReader(Xpp3DomBuilder.build(xml)); + } catch (Exception e) { + throw new StreamException(e); + } + } + + public HierarchicalStreamReader createReader(InputStream in) { + return createReader(new InputStreamReader(in)); + } + + public HierarchicalStreamWriter createWriter(Writer out) { + return new PrettyPrintWriter(out); + } + + public HierarchicalStreamWriter createWriter(OutputStream out) { + return createWriter(new OutputStreamWriter(out)); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomReader.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,65 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.xml.xppdom.Xpp3Dom; + +/** + * @author Jason van Zyl + * @version $Id$ + */ +public class XppDomReader extends AbstractDocumentReader { + + private Xpp3Dom currentElement; + + public XppDomReader(Xpp3Dom xpp3Dom) { + super(xpp3Dom); + } + + public String getNodeName() { + return currentElement.getName(); + } + + public String getValue() { + String text = null; + + try { + text = currentElement.getValue(); + } catch (Exception e) { + // do nothing. + } + + return text == null ? "" : text; + } + + public String getAttribute(String attributeName) { + return currentElement.getAttribute(attributeName); + } + + public String getAttribute(int index) { + return currentElement.getAttribute(currentElement.getAttributeNames()[index]); + } + + public int getAttributeCount() { + return currentElement.getAttributeNames().length; + } + + public String getAttributeName(int index) { + return currentElement.getAttributeNames()[index]; + } + + protected Object getParent() { + return currentElement.getParent(); + } + + protected Object getChild(int index) { + return currentElement.getChild(index); + } + + protected int getChildCount() { + return currentElement.getChildCount(); + } + + protected void reassignCurrentElement(Object current) { + this.currentElement = (Xpp3Dom) current; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomWriter.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,60 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.xml.xppdom.Xpp3Dom; + +import java.util.LinkedList; + +public class XppDomWriter implements HierarchicalStreamWriter { + private LinkedList elementStack = new LinkedList(); + + private Xpp3Dom configuration; + + public XppDomWriter() { + } + + public Xpp3Dom getConfiguration() { + return configuration; + } + + public void startNode(String name) { + Xpp3Dom configuration = new Xpp3Dom(name); + + if (this.configuration == null) { + this.configuration = configuration; + } else { + top().addChild(configuration); + } + + elementStack.addLast(configuration); + } + + public void setValue(String text) { + top().setValue(text); + } + + public void addAttribute(String key, String value) { + top().setAttribute(key, value); + } + + public void endNode() { + elementStack.removeLast(); + } + + private Xpp3Dom top() { + return (Xpp3Dom) elementStack.getLast(); + } + + public void flush() { + // don't need to do anything + } + + public void close() { + // don't need to do anything + } + + public HierarchicalStreamWriter underlyingWriter() { + return this; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDriver.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,41 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +import java.io.*; + +public class XppDriver implements HierarchicalStreamDriver { + + private static boolean xppLibraryPresent; + + public HierarchicalStreamReader createReader(Reader xml) { + loadLibrary(); + return new XppReader(xml); + } + + public HierarchicalStreamReader createReader(InputStream in) { + return createReader(new InputStreamReader(in)); + } + + private void loadLibrary() { + if (!xppLibraryPresent) { + try { + Class.forName("org.xmlpull.mxp1.MXParser"); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("XPP3 pull parser library not present. Specify another driver." + + " For example: new XStream(new DomDriver())"); + } + xppLibraryPresent = true; + } + } + + public HierarchicalStreamWriter createWriter(Writer out) { + return new PrettyPrintWriter(out); + } + + public HierarchicalStreamWriter createWriter(OutputStream out) { + return createWriter(new OutputStreamWriter(out)); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppReader.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,100 @@ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.converters.ErrorWriter; +import com.thoughtworks.xstream.io.StreamException; +import org.xmlpull.mxp1.MXParser; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; + +/** + * XStream reader that pulls directly from the stream using the XmlPullParser API. + * + * @author Joe Walnes + */ +public class XppReader extends AbstractPullReader { + + private final XmlPullParser parser; + private final BufferedReader reader; + + public XppReader(Reader reader) { + try { + parser = createParser(); + this.reader = new BufferedReader(reader); + parser.setInput(this.reader); + moveDown(); + } catch (XmlPullParserException e) { + throw new StreamException(e); + } + } + + /** + * To use another implementation of org.xmlpull.v1.XmlPullParser, override this method. + */ + protected XmlPullParser createParser() { + return new MXParser(); + } + + protected int pullNextEvent() { + try { + switch(parser.next()) { + case XmlPullParser.START_DOCUMENT: + case XmlPullParser.START_TAG: + return START_NODE; + case XmlPullParser.END_DOCUMENT: + case XmlPullParser.END_TAG: + return END_NODE; + case XmlPullParser.TEXT: + return TEXT; + case XmlPullParser.COMMENT: + return COMMENT; + default: + return OTHER; + } + } catch (XmlPullParserException e) { + throw new StreamException(e); + } catch (IOException e) { + throw new StreamException(e); + } + } + + protected String pullElementName() { + return parser.getName(); + } + + protected String pullText() { + return parser.getText(); + } + + public String getAttribute(String name) { + return parser.getAttributeValue(null, name); + } + + public String getAttribute(int index) { + return parser.getAttributeValue(index); + } + + public int getAttributeCount() { + return parser.getAttributeCount(); + } + + public String getAttributeName(int index) { + return parser.getAttributeName(index); + } + + public void appendErrors(ErrorWriter errorWriter) { + errorWriter.add("line number", String.valueOf(parser.getLineNumber())); + } + + public void close() { + try { + reader.close(); + } catch (IOException e) { + throw new StreamException(e); + } + } + +} \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/Xpp3Dom.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/Xpp3Dom.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/Xpp3Dom.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,137 @@ +package com.thoughtworks.xstream.io.xml.xppdom; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Xpp3Dom { + protected String name; + + protected String value; + + protected Map attributes; + + protected List childList; + + protected Map childMap; + + protected Xpp3Dom parent; + + public Xpp3Dom(String name) { + this.name = name; + childList = new ArrayList(); + childMap = new HashMap(); + } + + // ---------------------------------------------------------------------- + // Name handling + // ---------------------------------------------------------------------- + + public String getName() { + return name; + } + + // ---------------------------------------------------------------------- + // Value handling + // ---------------------------------------------------------------------- + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + // ---------------------------------------------------------------------- + // Attribute handling + // ---------------------------------------------------------------------- + + public String[] getAttributeNames() { + if ( null == attributes ) { + return new String[0]; + } + else { + return (String[]) attributes.keySet().toArray( new String[0] ); + } + } + + public String getAttribute(String name) { + return (null != attributes) ? (String) attributes.get(name) : null; + } + + public void setAttribute(String name, String value) { + if (null == attributes) { + attributes = new HashMap(); + } + + attributes.put(name, value); + } + + // ---------------------------------------------------------------------- + // Child handling + // ---------------------------------------------------------------------- + + public Xpp3Dom getChild(int i) { + return (Xpp3Dom) childList.get(i); + } + + public Xpp3Dom getChild(String name) { + return (Xpp3Dom) childMap.get(name); + } + + public void addChild(Xpp3Dom xpp3Dom) { + xpp3Dom.setParent(this); + childList.add(xpp3Dom); + childMap.put(xpp3Dom.getName(), xpp3Dom); + } + + public Xpp3Dom[] getChildren() { + if ( null == childList ) { + return new Xpp3Dom[0]; + } + else { + return (Xpp3Dom[]) childList.toArray( new Xpp3Dom[0] ); + } + } + + public Xpp3Dom[] getChildren( String name ) { + if ( null == childList ) { + return new Xpp3Dom[0]; + } + else { + ArrayList children = new ArrayList(); + int size = this.childList.size(); + + for ( int i = 0; i < size; i++ ) { + Xpp3Dom configuration = (Xpp3Dom) this.childList.get( i ); + if ( name.equals( configuration.getName() ) ) { + children.add( configuration ); + } + } + + return (Xpp3Dom[]) children.toArray( new Xpp3Dom[0] ); + } + } + + public int getChildCount() { + if (null == childList) { + return 0; + } + + return childList.size(); + } + + // ---------------------------------------------------------------------- + // Parent handling + // ---------------------------------------------------------------------- + + public Xpp3Dom getParent() { + return parent; + } + + public void setParent(Xpp3Dom parent) { + this.parent = parent; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/Xpp3DomBuilder.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/Xpp3DomBuilder.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/Xpp3DomBuilder.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,88 @@ +package com.thoughtworks.xstream.io.xml.xppdom; + +import org.xmlpull.mxp1.MXParser; +import org.xmlpull.v1.XmlPullParser; + +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; + +public class Xpp3DomBuilder { + public static Xpp3Dom build(Reader reader) + throws Exception { + List elements = new ArrayList(); + + List values = new ArrayList(); + + Xpp3Dom node = null; + + XmlPullParser parser = new MXParser(); + + parser.setInput(reader); + + int eventType = parser.getEventType(); + + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + String rawName = parser.getName(); + + Xpp3Dom child = new Xpp3Dom(rawName); + + int depth = elements.size(); + + if (depth > 0) { + Xpp3Dom parent = (Xpp3Dom) elements.get(depth - 1); + + parent.addChild(child); + } + + elements.add(child); + + values.add(new StringBuffer()); + + int attributesSize = parser.getAttributeCount(); + + for (int i = 0; i < attributesSize; i++) { + String name = parser.getAttributeName(i); + + String value = parser.getAttributeValue(i); + + child.setAttribute(name, value); + } + } else if (eventType == XmlPullParser.TEXT) { + int depth = values.size() - 1; + + StringBuffer valueBuffer = (StringBuffer) values.get(depth); + + valueBuffer.append(parser.getText()); + } else if (eventType == XmlPullParser.END_TAG) { + int depth = elements.size() - 1; + + Xpp3Dom finalNode = (Xpp3Dom) elements.remove(depth); + + String accumulatedValue = (values.remove(depth)).toString(); + + String finishedValue; + + if (0 == accumulatedValue.length()) { + finishedValue = null; + } else { + finishedValue = accumulatedValue; + } + + finalNode.setValue(finishedValue); + + if (0 == depth) { + node = finalNode; + } + } + + eventType = parser.next(); + } + + reader.close(); + + return node; + } + +} \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ArrayMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ArrayMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ArrayMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,118 @@ +package com.thoughtworks.xstream.mapper; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.alias.CannotResolveClassException; + +import java.util.Arrays; +import java.util.Collection; + +/** + * Mapper that detects arrays and changes the name so it can identified as an array + * (for example Foo[] gets serialized as foo-array). Supports multi-dimensional arrays. + * + * @author Joe Walnes + */ +public class ArrayMapper extends MapperWrapper { + + private final static Collection BOXED_TYPES = Arrays.asList( + new Class[] { + Boolean.class, + Byte.class, + Character.class, + Short.class, + Integer.class, + Long.class, + Float.class, + Double.class + }); + + public ArrayMapper(ClassMapper wrapped) { + super(wrapped); + } + + public String serializedClass(Class type) { + StringBuffer arraySuffix = new StringBuffer(); + while (type.isArray()) { + type = type.getComponentType(); + arraySuffix.append("-array"); + } + String name = boxedTypeName(type); + if (name == null) { + name = super.serializedClass(type); + } + if (arraySuffix.length() > 0) { + return name + arraySuffix; + } else { + return name; + } + } + + public Class realClass(String elementName) { + int dimensions = 0; + + // strip off "-array" suffix + while (elementName.endsWith("-array")) { + elementName = elementName.substring(0, elementName.length() - 6); // cut off -array + dimensions++; + } + + if (dimensions > 0) { + Class componentType = primitiveClassNamed(elementName); + if (componentType == null) { + componentType = super.realClass(elementName); + } + try { + return arrayType(dimensions, componentType); + } catch (ClassNotFoundException e) { + throw new CannotResolveClassException(elementName + " : " + e.getMessage()); + } + } else { + return super.realClass(elementName); + } + } + + private Class arrayType(int dimensions, Class componentType) throws ClassNotFoundException { + StringBuffer className = new StringBuffer(); + for (int i = 0; i < dimensions; i++) { + className.append('['); + } + if (componentType.isPrimitive()) { + className.append(charThatJavaUsesToRepresentPrimitiveArrayType(componentType)); + return Class.forName(className.toString()); + } else { + className.append('L').append(componentType.getName()).append(';'); + return Class.forName(className.toString(), false, componentType.getClassLoader()); + } + } + + private Class primitiveClassNamed(String name) { + return + name.equals("void") ? Void.TYPE : + name.equals("boolean") ? Boolean.TYPE : + name.equals("byte") ? Byte.TYPE : + name.equals("char") ? Character.TYPE : + name.equals("short") ? Short.TYPE : + name.equals("int") ? Integer.TYPE : + name.equals("long") ? Long.TYPE : + name.equals("float") ? Float.TYPE : + name.equals("double") ? Double.TYPE : + null; + } + + private char charThatJavaUsesToRepresentPrimitiveArrayType(Class primvCls) { + return + (primvCls == boolean.class) ? 'Z' : + (primvCls == byte.class) ? 'B' : + (primvCls == char.class) ? 'C' : + (primvCls == short.class) ? 'S' : + (primvCls == int.class) ? 'I' : + (primvCls == long.class) ? 'J' : + (primvCls == float.class) ? 'F' : + (primvCls == double.class) ? 'D' : + 0; + } + + private String boxedTypeName(Class type) { + return BOXED_TYPES.contains(type) ? type.getName() : null; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/CachingMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/CachingMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/CachingMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,33 @@ +package com.thoughtworks.xstream.mapper; + +import com.thoughtworks.xstream.alias.ClassMapper; + +import java.util.Map; +import java.util.Collections; +import java.util.HashMap; + +/** + * Mapper that caches which names map to which classes. Prevents repetitive searching and class loading. + * + * @author Joe Walnes + */ +public class CachingMapper extends MapperWrapper { + + private final Map cache = Collections.synchronizedMap(new HashMap()); + + public CachingMapper(ClassMapper wrapped) { + super(wrapped); + } + + public Class realClass(String elementName) { + Class cached = (Class) cache.get(elementName); + if (cached != null) { + return cached; + } else { + Class result = super.realClass(elementName); + cache.put(elementName, result); + return result; + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ClassAliasingMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ClassAliasingMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ClassAliasingMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,52 @@ +package com.thoughtworks.xstream.mapper; + +import com.thoughtworks.xstream.alias.ClassMapper; + +import java.util.Map; +import java.util.Collections; +import java.util.HashMap; + +/** + * Mapper that allows a fully qualified class name to be replaced with a shorter alias. + * + * @author Joe Walnes + */ +public class ClassAliasingMapper extends MapperWrapper { + + protected final Map typeToNameMap = Collections.synchronizedMap(new HashMap()); + protected final Map nameToTypeMap = Collections.synchronizedMap(new HashMap()); + + public ClassAliasingMapper(ClassMapper wrapped) { + super(wrapped); + } + + public void addClassAlias(String name, Class type) { + nameToTypeMap.put(name, type.getName()); + typeToNameMap.put(type.getName(), name); + } + + public String serializedClass(Class type) { + String name = super.serializedClass(type); + String alias = (String) typeToNameMap.get(type.getName()); + if (alias != null) { + return alias; + } else { + return name; + } + } + + public Class realClass(String elementName) { + if (elementName.equals("null")) { // TODO: This is probably the wrong place for this. + return null; + } + + String mappedName = (String) nameToTypeMap.get(mapNameFromXML(elementName)); + + if (mappedName != null) { + elementName = mappedName; + } + + return super.realClass(elementName); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DefaultImplementationsMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DefaultImplementationsMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DefaultImplementationsMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,52 @@ +package com.thoughtworks.xstream.mapper; + +import com.thoughtworks.xstream.alias.ClassMapper; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Mapper that resolves default implementations of classes. For example, mapper.lookupName(ArrayList.class) will return + * java.util.List. Calling mapper.defaultImplementationOf(List.class) will return ArrayList. + * + * @author Joe Walnes + */ +public class DefaultImplementationsMapper extends MapperWrapper { + + private final Map typeToImpl = Collections.synchronizedMap(new HashMap()); + private final Map implToType = Collections.synchronizedMap(new HashMap()); + + public DefaultImplementationsMapper(ClassMapper wrapped) { + super(wrapped); + addDefaults(); + } + + protected void addDefaults() { + // register primitive types + addDefaultImplementation(Boolean.class, boolean.class); + addDefaultImplementation(Character.class, char.class); + addDefaultImplementation(Integer.class, int.class); + addDefaultImplementation(Float.class, float.class); + addDefaultImplementation(Double.class, double.class); + addDefaultImplementation(Short.class, short.class); + addDefaultImplementation(Byte.class, byte.class); + addDefaultImplementation(Long.class, long.class); + } + + public void addDefaultImplementation(Class defaultImplementation, Class ofType) { + typeToImpl.put(ofType, defaultImplementation); + implToType.put(defaultImplementation, ofType); + } + + public String serializedClass(Class type) { + Class baseType = (Class) implToType.get(type); + return baseType == null ? super.serializedClass(type) : super.serializedClass(baseType); + } + + public Class defaultImplementationOf(Class type) { + Class result = (Class) typeToImpl.get(type); + return result == null ? super.defaultImplementationOf(type) : result; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DefaultMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DefaultMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DefaultMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,110 @@ +package com.thoughtworks.xstream.mapper; + +import com.thoughtworks.xstream.alias.CannotResolveClassException; +import com.thoughtworks.xstream.alias.ClassMapper; + +/** + * Default mapper implementation with 'vanilla' functionality. To build up the functionality required, wrap this mapper + * with other mapper implementations. + * + * @author Joe Walnes + */ +public class DefaultMapper extends MapperWrapper { + + private final ClassLoader classLoader; + private final String classAttributeIdentifier; + + public DefaultMapper(ClassLoader classLoader) { + this(classLoader, "class"); + } + + public DefaultMapper(ClassLoader classLoader, String classAttributeIdentifier) { + super(null); + this.classLoader = classLoader; + this.classAttributeIdentifier = classAttributeIdentifier == null ? "class" : classAttributeIdentifier; + } + + public String serializedClass(Class type) { + return type.getName(); + } + + public Class realClass(String elementName) { + try { + return classLoader.loadClass(elementName); + } catch (ClassNotFoundException e) { + throw new CannotResolveClassException(elementName + " : " + e.getMessage()); + } + } + + public Class lookupDefaultType(Class baseType) { + return baseType; + } + + public Class defaultImplementationOf(Class type) { + return type; + } + + public String attributeForClassDefiningField() { + return "defined-in"; + } + + public String attributeForReadResolveField() { + return "resolves-to"; + } + + public String attributeForEnumType() { + return "enum-type"; + } + + public String attributeForImplementationClass() { + return classAttributeIdentifier; + } + + public boolean isImmutableValueType(Class type) { + return false; + } + + public String getFieldNameForItemTypeAndName(Class definedIn, Class itemType, String itemFieldName) { + return null; + } + + public Class getItemTypeForItemFieldName(Class definedIn, String itemFieldName) { + return null; + } + + public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(Class itemType, String fieldName) { + return null; + } + + public boolean shouldSerializeMember(Class definedIn, String fieldName) { + return true; + } + + public String lookupName(Class type) { + return serializedClass(type); + } + + public Class lookupType(String elementName) { + return realClass(elementName); + } + + public String serializedMember(Class type, String memberName) { + return memberName; + } + + public String realMember(Class type, String serialized) { + return serialized; + } + + public String mapNameFromXML(String xmlName) { + return xmlName; + } + + public String mapNameToXML(String javaName) { + return javaName; + } + + public void alias(String elementName, Class type, Class defaultImplementation) { + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DynamicProxyMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DynamicProxyMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DynamicProxyMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,55 @@ +package com.thoughtworks.xstream.mapper; + +import com.thoughtworks.xstream.alias.ClassMapper; + +import java.lang.reflect.Proxy; + +/** + * Mapper for handling special cases of aliasing dynamic proxies. The alias property specifies the name an instance + * of a dynamic proxy should be serialized with. + * + * @author Joe Walnes + */ +public class DynamicProxyMapper extends MapperWrapper { + + private String alias = "dynamic-proxy"; + + public DynamicProxyMapper(ClassMapper wrapped) { + super(wrapped); + } + + public DynamicProxyMapper(ClassMapper wrapped, String alias) { + super(wrapped); + this.alias = alias; + } + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public String serializedClass(Class type) { + if (Proxy.isProxyClass(type)) { + return alias; + } else { + return super.serializedClass(type); + } + } + + public Class realClass(String elementName) { + if (elementName.equals(alias)) { + return DynamicProxy.class; + } else { + return super.realClass(elementName); + } + } + + /** + * Place holder type used for dynamic proxies. + */ + public static class DynamicProxy {} + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/EnumMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/EnumMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/EnumMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,40 @@ +package com.thoughtworks.xstream.mapper; + +import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.core.JVM; + +/** + * Mapper that handles the special case of polymorphic enums in Java 1.5. This renames MyEnum$1 to MyEnum making it + * less bloaty in the XML and avoiding the need for an alias per enum value to be specified. + * + * @author Joe Walnes + */ +public class EnumMapper extends MapperWrapper { + + // Dynamically try to load Enum class. Pre JDK1.5 will silently fail. + private static JVM jvm = new JVM(); + private static final Class enumClass = jvm.loadClass("java.lang.Enum"); + + private static final boolean active = enumClass != null; + + private static final Class enumSetClass = active ? jvm.loadClass("java.util.EnumSet") : null; + + public EnumMapper(ClassMapper wrapped) { + super(wrapped); + } + + public String serializedClass(Class type) { + if (!active) { + return super.serializedClass(type); + } else { + if (enumClass.isAssignableFrom(type) && type.getSuperclass() != enumClass) { + return super.serializedClass(type.getSuperclass()); + } else if (enumSetClass.isAssignableFrom(type)) { + return super.serializedClass(enumSetClass); + } else { + return super.serializedClass(type); + } + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/FieldAliasingMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/FieldAliasingMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/FieldAliasingMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,57 @@ +package com.thoughtworks.xstream.mapper; + +import com.thoughtworks.xstream.alias.ClassMapper; + +import java.util.*; + +/** + * Mapper that allows a field of a specific class to be replaced with a shorter alias, or omitted + * entirely. + * + * @author Joe Walnes + */ +public class FieldAliasingMapper extends MapperWrapper { + + protected final Map fieldToAliasMap = Collections.synchronizedMap(new HashMap()); + protected final Map aliasToFieldMap = Collections.synchronizedMap(new HashMap()); + protected final Set fieldsToOmit = Collections.synchronizedSet(new HashSet()); + + public FieldAliasingMapper(ClassMapper wrapped) { + super(wrapped); + } + + public void addFieldAlias(String alias, Class type, String fieldName) { + fieldToAliasMap.put(key(type, fieldName), alias); + aliasToFieldMap.put(key(type, alias), fieldName); + } + + private Object key(Class type, String value) { + return type.getName() + '.' + value; + } + + public String serializedMember(Class type, String memberName) { + String alias = (String) fieldToAliasMap.get(key(type, memberName)); + if (alias == null) { + return super.serializedMember(type, memberName); + } else { + return alias; + } + } + + public String realMember(Class type, String serialized) { + String real = (String) aliasToFieldMap.get(key(type, serialized)); + if (real == null) { + return super.realMember(type, serialized); + } else { + return real; + } + } + + public boolean shouldSerializeMember(Class definedIn, String fieldName) { + return !fieldsToOmit.contains(key(definedIn, fieldName)); + } + + public void omitField(Class type, String fieldName) { + fieldsToOmit.add(key(type, fieldName)); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ImmutableTypesMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ImmutableTypesMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ImmutableTypesMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,35 @@ +package com.thoughtworks.xstream.mapper; + +import com.thoughtworks.xstream.alias.ClassMapper; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * Mapper that specifies which types are basic immutable types. Types that are marked as immutable will be written + * multiple times in the serialization stream without using references. + * + * @author Joe Walnes + */ +public class ImmutableTypesMapper extends MapperWrapper { + + private final Set immutableTypes = Collections.synchronizedSet(new HashSet()); + + public ImmutableTypesMapper(ClassMapper wrapped) { + super(wrapped); + } + + public void addImmutableType(Class type) { + immutableTypes.add(type); + } + + public boolean isImmutableValueType(Class type) { + if (immutableTypes.contains(type)) { + return true; + } else { + return super.isImmutableValueType(type); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ImplicitCollectionMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ImplicitCollectionMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ImplicitCollectionMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,233 @@ +package com.thoughtworks.xstream.mapper; + +import com.thoughtworks.xstream.alias.ClassMapper; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class ImplicitCollectionMapper extends MapperWrapper { + + public ImplicitCollectionMapper(ClassMapper wrapped) { + super(wrapped); + } + + // { definedIn (Class) -> (ImplicitCollectionMapperForClass) } + private Map classNameToMapper = Collections.synchronizedMap(new HashMap()); + + private ImplicitCollectionMapperForClass getMapper(Class definedIn) { + while (definedIn != null) { + ImplicitCollectionMapperForClass mapper = (ImplicitCollectionMapperForClass) classNameToMapper.get(definedIn); + if (mapper != null) { + return mapper; + } + definedIn = definedIn.getSuperclass(); + } + return null; + } + + private ImplicitCollectionMapperForClass getOrCreateMapper(Class definedIn) { + ImplicitCollectionMapperForClass mapper = getMapper(definedIn); + if (mapper == null) { + mapper = new ImplicitCollectionMapperForClass(definedIn); + classNameToMapper.put(definedIn, mapper); + } + return mapper; + } + + public String getFieldNameForItemTypeAndName(Class definedIn, Class itemType, String itemFieldName) { + ImplicitCollectionMapperForClass mapper = getMapper(definedIn); + if (mapper != null) { + return mapper.getFieldNameForItemTypeAndName(itemType, itemFieldName); + } else { + return null; + } + } + + public Class getItemTypeForItemFieldName(Class definedIn, String itemFieldName) { + ImplicitCollectionMapperForClass mapper = getMapper(definedIn); + if (mapper != null) { + return mapper.getItemTypeForItemFieldName(itemFieldName); + } else { + return null; + } + } + + public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(Class itemType, String fieldName) { + ImplicitCollectionMapperForClass mapper = getMapper(itemType); + if (mapper != null) { + return mapper.getImplicitCollectionDefForFieldName(fieldName); + } else { + return null; + } + } + + public void add(Class definedIn, String fieldName, Class itemType) { + add(definedIn, fieldName, null, itemType); + } + + public void add(Class definedIn, String fieldName, String itemFieldName, Class itemType) { + ImplicitCollectionMapperForClass mapper = getOrCreateMapper(definedIn); + mapper.add(new ImplicitCollectionMappingImpl(fieldName, itemType, itemFieldName)); + } + + private static class ImplicitCollectionMapperForClass { + //private Class definedIn; + private Map namedItemTypeToDef = new HashMap(); // { (NamedItemType) -> (ImplicitCollectionDefImpl) } + private Map itemFieldNameToDef = new HashMap(); // { itemFieldName (String) -> (ImplicitCollectionDefImpl) } + private Map fieldNameToDef = new HashMap(); // { fieldName (String) -> (ImplicitCollectionDefImpl) } + + public ImplicitCollectionMapperForClass(Class definedIn) { + //this.definedIn = definedIn; + } + + public String getFieldNameForItemTypeAndName(Class itemType, String itemFieldName) { + ImplicitCollectionMappingImpl unnamed = null; + for (Iterator iterator = namedItemTypeToDef.keySet().iterator(); iterator.hasNext();) { + NamedItemType itemTypeForFieldName = (NamedItemType) iterator.next(); + if (itemTypeForFieldName.itemType.isAssignableFrom(itemType)) { + ImplicitCollectionMappingImpl def = (ImplicitCollectionMappingImpl) namedItemTypeToDef.get(itemTypeForFieldName); + if (def.getItemFieldName() != null) { + if (def.getItemFieldName().equals(itemFieldName)) { + return def.getFieldName(); + } + } else { + unnamed = def; + if (itemFieldName == null) { + break; + } + } + } + } + return unnamed != null ? unnamed.getFieldName() : null; + } + + public Class getItemTypeForItemFieldName(String itemFieldName) { + ImplicitCollectionMappingImpl def = getImplicitCollectionDefByItemFieldName(itemFieldName); + if (def != null) { + return def.getItemType(); + } else { + return null; + } + } + + private ImplicitCollectionMappingImpl getImplicitCollectionDefByItemFieldName(String itemFieldName) { + if (itemFieldName == null) { + return null; + } else { + return (ImplicitCollectionMappingImpl) itemFieldNameToDef.get(itemFieldName); + } + } + + public ImplicitCollectionMappingImpl getImplicitCollectionDefByFieldName(String fieldName) { + return (ImplicitCollectionMappingImpl) fieldNameToDef.get(fieldName); + } + + public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(String fieldName) { + return (ImplicitCollectionMapping) fieldNameToDef.get(fieldName); + } + + public void add(ImplicitCollectionMappingImpl def) { + fieldNameToDef.put(def.getFieldName(), def); + namedItemTypeToDef.put(def.createNamedItemType(), def); + if (def.getItemFieldName() != null) { + itemFieldNameToDef.put(def.getItemFieldName(), def); + } + } + + } + + private static class ImplicitCollectionMappingImpl implements ImplicitCollectionMapping { + private String fieldName; + private String itemFieldName; + private Class itemType; + + ImplicitCollectionMappingImpl(String fieldName, Class itemType, String itemFieldName) { + this.fieldName = fieldName; + this.itemFieldName = itemFieldName; + this.itemType = itemType; + } + + + public boolean equals(Object obj) { + if (obj instanceof ImplicitCollectionMappingImpl) { + ImplicitCollectionMappingImpl b = (ImplicitCollectionMappingImpl) obj; + return fieldName.equals(b.fieldName) + && isEquals(itemFieldName, b.itemFieldName); + } else { + return false; + } + } + + public NamedItemType createNamedItemType() { + return new NamedItemType(itemType, itemFieldName); + } + + private static boolean isEquals(Object a, Object b) { + if (a == null) { + return b == null; + } else { + return a.equals(b); + } + } + + public int hashCode() { + int hash = fieldName.hashCode(); + if (itemFieldName != null) { + hash += itemFieldName.hashCode() << 7; + } + return hash; + } + + public String getFieldName() { + return fieldName; + } + + public String getItemFieldName() { + return itemFieldName; + } + + public Class getItemType() { + return itemType; + } + } + + private static class NamedItemType { + Class itemType; + String itemFieldName; + + NamedItemType(Class itemType, String itemFieldName) { + this.itemType = itemType; + this.itemFieldName = itemFieldName; + } + + + public boolean equals(Object obj) { + if (obj instanceof NamedItemType) { + NamedItemType b = (NamedItemType) obj; + return itemType.equals(b.itemType) + && isEquals(itemFieldName, b.itemFieldName); + } else { + return false; + } + } + + private static boolean isEquals(Object a, Object b) { + if (a == null) { + return b == null; + } else { + return a.equals(b); + } + } + + public int hashCode() { + int hash = itemType.hashCode() << 7; + if (itemFieldName != null) { + hash += itemFieldName.hashCode(); + } + return hash; + } + } +} + Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/Mapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/Mapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/Mapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,67 @@ +package com.thoughtworks.xstream.mapper; + +public interface Mapper { + + /** + * How a class name should be represented in its serialized form. + */ + String serializedClass(Class type); + + /** + * How a serialized class representation should be mapped back to a real class. + */ + Class realClass(String elementName); + + /** + * How a class member should be represented in its serialized form. + */ + String serializedMember(Class type, String memberName); + + /** + * How a serialized member representation should be mapped back to a real member. + */ + String realMember(Class type, String serialized); + + /** + * Whether this type is a simple immutable value (int, boolean, String, URL, etc. + * Immutable types will be repeatedly written in the serialized stream, instead of using object references. + */ + boolean isImmutableValueType(Class type); + + Class defaultImplementationOf(Class type); + + String attributeForImplementationClass(); + + String attributeForClassDefiningField(); + + String attributeForReadResolveField(); + + String attributeForEnumType(); + + /** + * Get the name of the field that acts as the default collection for an object, or return null if there is none. + * + * @param definedIn owning type + * @param itemType item type + * @param itemFieldName optional item element name + */ + String getFieldNameForItemTypeAndName(Class definedIn, Class itemType, String itemFieldName); + + Class getItemTypeForItemFieldName(Class definedIn, String itemFieldName); + + ImplicitCollectionMapping getImplicitCollectionDefForFieldName(Class itemType, String fieldName); + + /** + * Determine whether a specific member should be serialized. + * + * @since 1.2 + */ + boolean shouldSerializeMember(Class definedIn, String fieldName); + + interface ImplicitCollectionMapping { + String getFieldName(); + String getItemFieldName(); + Class getItemType(); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/MapperWrapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/MapperWrapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/MapperWrapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,127 @@ +package com.thoughtworks.xstream.mapper; + +import com.thoughtworks.xstream.alias.ClassMapper; + +public abstract class MapperWrapper implements ClassMapper { + + private final ClassMapper wrapped; + + public MapperWrapper(ClassMapper wrapped) { + this.wrapped = wrapped; + } + + public String serializedClass(Class type) { + return wrapped.serializedClass(type); + } + + public Class realClass(String elementName) { + return wrapped.realClass(elementName); + } + + public String serializedMember(Class type, String memberName) { + return wrapped.serializedMember(type, memberName); + } + + public String realMember(Class type, String serialized) { + return wrapped.realMember(type, serialized); + } + + public String mapNameFromXML(String xmlName) { + return wrapped.mapNameFromXML(xmlName); + } + + public String mapNameToXML(String javaName) { + return wrapped.mapNameToXML(javaName); + } + + public boolean isImmutableValueType(Class type) { + return wrapped.isImmutableValueType(type); + } + + public Class defaultImplementationOf(Class type) { + return wrapped.defaultImplementationOf(type); + } + + public String attributeForClassDefiningField() { + return wrapped.attributeForClassDefiningField(); + } + + public String attributeForImplementationClass() { + return wrapped.attributeForImplementationClass(); + } + + public String attributeForReadResolveField() { + return wrapped.attributeForReadResolveField(); + } + + public String attributeForEnumType() { + return wrapped.attributeForEnumType(); + } + + public String getFieldNameForItemTypeAndName(Class definedIn, Class itemType, String itemFieldName) { + return wrapped.getFieldNameForItemTypeAndName(definedIn, itemType, itemFieldName); + } + + public Class getItemTypeForItemFieldName(Class definedIn, String itemFieldName) { + return wrapped.getItemTypeForItemFieldName(definedIn, itemFieldName); + } + + public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(Class itemType, String fieldName) { + return wrapped.getImplicitCollectionDefForFieldName(itemType, fieldName); + } + + public boolean shouldSerializeMember(Class definedIn, String fieldName) { + return wrapped.shouldSerializeMember(definedIn, fieldName); + } + + /** + * @deprecated As of 1.1.1, use {@link #defaultImplementationOf(Class)} + */ + public Class lookupDefaultType(Class baseType) { + return defaultImplementationOf(baseType); + } + + public String lookupName(Class type) { + return serializedClass(type); + } + + public Class lookupType(String elementName) { + return realClass(elementName); + } + + /** + * @deprecated As of 1.1.1, use {@link com.thoughtworks.xstream.mapper.ClassAliasingMapper#addClassAlias(String, Class)} for creating an alias and + * {@link DefaultImplementationsMapper#addDefaultImplementation(Class, Class)} for specifiny a + * default implementation. + */ + public void alias(String elementName, Class type, Class defaultImplementation) { + ClassAliasingMapper classAliasingMapper = (ClassAliasingMapper) findWrapped(ClassAliasingMapper.class); + if (classAliasingMapper == null) { + throw new UnsupportedOperationException("ClassMapper.alias() longer supported. Use ClassAliasingMapper.alias() instead."); + } else { + classAliasingMapper.addClassAlias(elementName, type); + } + if (defaultImplementation != null && defaultImplementation != type) { + DefaultImplementationsMapper defaultImplementationsMapper = (DefaultImplementationsMapper) findWrapped(DefaultImplementationsMapper.class); + if (defaultImplementationsMapper == null) { + throw new UnsupportedOperationException("ClassMapper.alias() longer supported. Use DefaultImplementatoinsMapper.add() instead."); + } else { + defaultImplementationsMapper.addDefaultImplementation(defaultImplementation, type); + } + } + } + + private ClassMapper findWrapped(Class typeOfMapper) { + ClassMapper current = this; + while (true) { + if (current.getClass().isAssignableFrom(typeOfMapper)) { + return current; + } else if (current instanceof MapperWrapper) { + MapperWrapper wrapper = (MapperWrapper) current; + current = wrapper.wrapped; + } else { + return null; + } + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/OuterClassMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/OuterClassMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/OuterClassMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,57 @@ +package com.thoughtworks.xstream.mapper; + +import com.thoughtworks.xstream.alias.ClassMapper; + +/** + * Mapper that uses a more meaningful alias for the field in an inner class (this$0) that refers to the outer class. + * + * @author Joe Walnes + */ +public class OuterClassMapper extends MapperWrapper { + + private final String alias; + + public OuterClassMapper(ClassMapper wrapped, String alias) { + super(wrapped); + this.alias = alias; + } + + public OuterClassMapper(ClassMapper wrapped) { + this(wrapped, "outer-class"); + } + + public String serializedMember(Class type, String memberName) { + if (memberName.equals("this$0")) { + return alias; + } else { + return super.serializedMember(type, memberName); + } + } + + public String realMember(Class type, String serialized) { + if (serialized.equals(alias)) { + return "this$0"; + } else { + return super.realMember(type, serialized); + } + } + + // --- Maintain backwards compatability + + public String mapNameToXML(String javaName) { + if (javaName.equals("this$0")) { + return alias; + } else { + return super.mapNameToXML(javaName); + } + } + + public String mapNameFromXML(String xmlName) { + if (xmlName.equals(alias)) { + return "this$0"; + } else { + return super.mapNameFromXML(xmlName); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/XmlFriendlyMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/XmlFriendlyMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/XmlFriendlyMapper.java (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -0,0 +1,99 @@ +package com.thoughtworks.xstream.mapper; + +import com.thoughtworks.xstream.alias.ClassMapper; + +/** + * Mapper that ensures that all names in the serialization stream are XML friendly. + * + * $ (dollar) chars appearing in class names are replaced with _ (underscore) chars.
            + * $ (dollar) chars appearing in field names are replaced with _DOLLAR_ string.
            + * _ (underscore) chars appearing in field names are replaced with __ (double underscore) string.
            + * + * @author Joe Walnes + */ +public class XmlFriendlyMapper extends MapperWrapper { + + public XmlFriendlyMapper(ClassMapper wrapped) { + super(wrapped); + } + + public String serializedClass(Class type) { + String name = super.serializedClass(type); + + // the $ used in inner class names is illegal as an xml element getNodeName + name = name.replace('$', '-'); + + // special case for classes named $Blah with no package; <-Blah> is illegal XML + if (name.charAt(0) == '-') { + name = "default" + name; + } + + return name; + } + + public Class realClass(String elementName) { + + // special case for classes named $Blah with no package; <-Blah> is illegal XML + if (elementName.startsWith("default-")) { + elementName = elementName.substring(7); + } + + // the $ used in inner class names is illegal as an xml element getNodeName + elementName = elementName.replace('-', '$'); + + return super.realClass(elementName); + } + + public String serializedMember(Class type, String memberName) { + return escape(super.serializedMember(type, memberName)); + } + + public String realMember(Class type, String serialized) { + return unescape(super.realMember(type, serialized)); + } + + public String mapNameToXML(String javaName) { + return escape(javaName); + } + + public String mapNameFromXML(String xmlName) { + return unescape(xmlName); + } + + private String unescape(String xmlName) { + StringBuffer result = new StringBuffer(); + int length = xmlName.length(); + for(int i = 0; i < length; i++) { + char c = xmlName.charAt(i); + if (c == '_') { + if (xmlName.charAt(i + 1) == '_') { + i++; + result.append('_'); + } else if (xmlName.length() >= i + 8 && xmlName.substring(i + 1, i + 8).equals("DOLLAR_")) { + i += 7; + result.append('$'); + } + } else { + result.append(c); + } + } + return result.toString(); + } + + private String escape(String javaName) { + StringBuffer result = new StringBuffer(); + int length = javaName.length(); + for(int i = 0; i < length; i++) { + char c = javaName.charAt(i); + if (c == '$') { + result.append("_DOLLAR_"); + } else if (c == '_') { + result.append("__"); + } else { + result.append(c); + } + } + return result.toString(); + } + +} Index: lams_build/3rdParty.userlibraries =================================================================== diff -u -r3d0166b43ce990fd9f27c433a1c58cc61085ecf4 -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d --- lams_build/3rdParty.userlibraries (.../3rdParty.userlibraries) (revision 3d0166b43ce990fd9f27c433a1c58cc61085ecf4) +++ lams_build/3rdParty.userlibraries (.../3rdParty.userlibraries) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) @@ -91,9 +91,8 @@ - + - @@ -117,5 +116,6 @@ + Index: lams_build/lib/xstream/joda-time-0.98.jar =================================================================== diff -u -r3c4881947fb505c405de8165f49ebce7c3c674ac -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d Binary files differ Index: lams_build/lib/xstream/joda-time-2.1.jar =================================================================== diff -u Binary files differ