diff --git a/projects/Time/6/org/joda/time/chrono/GJChronology.java b/projects/Time/6/org/joda/time/chrono/GJChronology.java
new file mode 100644
index 0000000..b970403
--- /dev/null
+++ b/projects/Time/6/org/joda/time/chrono/GJChronology.java
@@ -0,0 +1,1115 @@
+/*
+ * Copyright 2001-2013 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.ArrayList;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.joda.time.Chronology;
+import org.joda.time.DateTimeField;
+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.LocalDate;
+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.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+
+/**
+ * Implements the Gregorian/Julian calendar system which is the calendar system
+ * used in most of the world. Wherever possible, it is recommended to use the
+ * {@link ISOChronology} instead.
+ *
+ * The Gregorian calendar replaced the Julian calendar, and the point in time
+ * when this chronology switches can be controlled using the second parameter
+ * of the getInstance method. By default this cutover is set to the date the
+ * Gregorian calendar was first instituted, October 15, 1582.
+ *
+ * Before this date, this chronology uses the proleptic Julian calendar
+ * (proleptic means extending indefinitely). The Julian calendar has leap years
+ * every four years, whereas the Gregorian has special rules for 100 and 400
+ * years. A meaningful result will thus be obtained for all input values.
+ * However before 8 CE, Julian leap years were irregular, and before 45 BCE
+ * there was no Julian calendar.
+ *
+ * This chronology differs from
+ * {@link java.util.GregorianCalendar GregorianCalendar} in that years
+ * in BCE are returned correctly. Thus year 1 BCE is returned as -1 instead of 1.
+ * The yearOfEra field produces results compatible with GregorianCalendar.
+ *
+ * The Julian calendar does not have a year zero, and so year -1 is followed by
+ * year 1. If the Gregorian cutover date is specified at or before year -1
+ * (Julian), year zero is defined. In other words, the proleptic Gregorian
+ * chronology used by this class has a year zero.
+ *
+ * To create a pure proleptic Julian chronology, use {@link JulianChronology},
+ * and to create a pure proleptic Gregorian chronology, use
+ * {@link GregorianChronology}.
+ *
+ * GJChronology is thread-safe and immutable.
+ *
+ * @author Brian S O'Neill
+ * @author Stephen Colebourne
+ * @since 1.0
+ */
+public final class GJChronology extends AssembledChronology {
+
+ /** Serialization lock */
+ private static final long serialVersionUID = -2545574827706931671L;
+
+ /**
+ * Convert a datetime from one chronology to another.
+ */
+ private static long convertByYear(long instant, Chronology from, Chronology to) {
+ return to.getDateTimeMillis
+ (from.year().get(instant),
+ from.monthOfYear().get(instant),
+ from.dayOfMonth().get(instant),
+ from.millisOfDay().get(instant));
+ }
+
+ /**
+ * Convert a datetime from one chronology to another.
+ */
+ private static long convertByWeekyear(final long instant, Chronology from, Chronology to) {
+ long newInstant;
+ newInstant = to.weekyear().set(0, from.weekyear().get(instant));
+ newInstant = to.weekOfWeekyear().set(newInstant, from.weekOfWeekyear().get(instant));
+ newInstant = to.dayOfWeek().set(newInstant, from.dayOfWeek().get(instant));
+ newInstant = to.millisOfDay().set(newInstant, from.millisOfDay().get(instant));
+ return newInstant;
+ }
+
+ /**
+ * The default GregorianJulian cutover point.
+ */
+ static final Instant DEFAULT_CUTOVER = new Instant(-12219292800000L);
+
+ /** Cache of zone to chronology list */
+ private static final Map> cCache = new HashMap>();
+
+ /**
+ * Factory method returns instances of the default GJ cutover
+ * chronology. This uses a cutover date of October 15, 1582 (Gregorian)
+ * 00:00:00 UTC. For this value, October 4, 1582 (Julian) is followed by
+ * October 15, 1582 (Gregorian).
+ *
+ * The first day of the week is designated to be
+ * {@link org.joda.time.DateTimeConstants#MONDAY Monday},
+ * and the minimum days in the first week of the year is 4.
+ *
+ *
The time zone of the returned instance is UTC.
+ */
+ public static GJChronology getInstanceUTC() {
+ return getInstance(DateTimeZone.UTC, DEFAULT_CUTOVER, 4);
+ }
+
+ /**
+ * Factory method returns instances of the default GJ cutover
+ * chronology. This uses a cutover date of October 15, 1582 (Gregorian)
+ * 00:00:00 UTC. For this value, October 4, 1582 (Julian) is followed by
+ * October 15, 1582 (Gregorian).
+ *
+ *
The first day of the week is designated to be
+ * {@link org.joda.time.DateTimeConstants#MONDAY Monday},
+ * and the minimum days in the first week of the year is 4.
+ *
+ *
The returned chronology is in the default time zone.
+ */
+ public static GJChronology getInstance() {
+ return getInstance(DateTimeZone.getDefault(), DEFAULT_CUTOVER, 4);
+ }
+
+ /**
+ * Factory method returns instances of the GJ cutover chronology. This uses
+ * a cutover date of October 15, 1582 (Gregorian) 00:00:00 UTC. For this
+ * value, October 4, 1582 (Julian) is followed by October 15, 1582
+ * (Gregorian).
+ *
+ *
The first day of the week is designated to be
+ * {@link org.joda.time.DateTimeConstants#MONDAY Monday},
+ * and the minimum days in the first week of the year is 4.
+ *
+ * @param zone the time zone to use, null is default
+ */
+ public static GJChronology getInstance(DateTimeZone zone) {
+ return getInstance(zone, DEFAULT_CUTOVER, 4);
+ }
+
+ /**
+ * Factory method returns instances of the GJ cutover chronology. Any
+ * cutover date may be specified.
+ *
+ *
The first day of the week is designated to be
+ * {@link org.joda.time.DateTimeConstants#MONDAY Monday},
+ * and the minimum days in the first week of the year is 4.
+ *
+ * @param zone the time zone to use, null is default
+ * @param gregorianCutover the cutover to use, null means default
+ */
+ public static GJChronology getInstance(
+ DateTimeZone zone,
+ ReadableInstant gregorianCutover) {
+
+ return getInstance(zone, gregorianCutover, 4);
+ }
+
+ /**
+ * Factory method returns instances of the GJ cutover chronology. Any
+ * cutover date may be specified.
+ *
+ * @param zone the time zone to use, null is default
+ * @param gregorianCutover the cutover to use, null means default
+ * @param minDaysInFirstWeek minimum number of days in first week of the year; default is 4
+ */
+ public static synchronized GJChronology getInstance(
+ DateTimeZone zone,
+ ReadableInstant gregorianCutover,
+ int minDaysInFirstWeek) {
+
+ zone = DateTimeUtils.getZone(zone);
+ Instant cutoverInstant;
+ if (gregorianCutover == null) {
+ cutoverInstant = DEFAULT_CUTOVER;
+ } else {
+ cutoverInstant = gregorianCutover.toInstant();
+ }
+
+ GJChronology chrono;
+ synchronized (cCache) {
+ ArrayList chronos = cCache.get(zone);
+ if (chronos == null) {
+ chronos = new ArrayList(2);
+ cCache.put(zone, chronos);
+ } else {
+ for (int i = chronos.size(); --i >= 0;) {
+ chrono = chronos.get(i);
+ if (minDaysInFirstWeek == chrono.getMinimumDaysInFirstWeek() &&
+ cutoverInstant.equals(chrono.getGregorianCutover())) {
+
+ return chrono;
+ }
+ }
+ }
+ if (zone == DateTimeZone.UTC) {
+ chrono = new GJChronology
+ (JulianChronology.getInstance(zone, minDaysInFirstWeek),
+ GregorianChronology.getInstance(zone, minDaysInFirstWeek),
+ cutoverInstant);
+ } else {
+ chrono = getInstance(DateTimeZone.UTC, cutoverInstant, minDaysInFirstWeek);
+ chrono = new GJChronology
+ (ZonedChronology.getInstance(chrono, zone),
+ chrono.iJulianChronology,
+ chrono.iGregorianChronology,
+ chrono.iCutoverInstant);
+ }
+ chronos.add(chrono);
+ }
+ return chrono;
+ }
+
+ /**
+ * Factory method returns instances of the GJ cutover chronology. Any
+ * cutover date may be specified.
+ *
+ * @param zone the time zone to use, null is default
+ * @param gregorianCutover the cutover to use
+ * @param minDaysInFirstWeek minimum number of days in first week of the year; default is 4
+ */
+ public static GJChronology getInstance(
+ DateTimeZone zone,
+ long gregorianCutover,
+ int minDaysInFirstWeek) {
+
+ Instant cutoverInstant;
+ if (gregorianCutover == DEFAULT_CUTOVER.getMillis()) {
+ cutoverInstant = null;
+ } else {
+ cutoverInstant = new Instant(gregorianCutover);
+ }
+ return getInstance(zone, cutoverInstant, minDaysInFirstWeek);
+ }
+
+ //-----------------------------------------------------------------------
+ private JulianChronology iJulianChronology;
+ private GregorianChronology iGregorianChronology;
+ private Instant iCutoverInstant;
+
+ private long iCutoverMillis;
+ private long iGapDuration;
+
+ /**
+ * @param julian chronology used before the cutover instant
+ * @param gregorian chronology used at and after the cutover instant
+ * @param cutoverInstant instant when the gregorian chronology began
+ */
+ private GJChronology(JulianChronology julian,
+ GregorianChronology gregorian,
+ Instant cutoverInstant) {
+ super(null, new Object[] {julian, gregorian, cutoverInstant});
+ }
+
+ /**
+ * Called when applying a time zone.
+ */
+ private GJChronology(Chronology base,
+ JulianChronology julian,
+ GregorianChronology gregorian,
+ Instant cutoverInstant) {
+ super(base, new Object[] {julian, gregorian, cutoverInstant});
+ }
+
+ /**
+ * Serialization singleton
+ */
+ private Object readResolve() {
+ return getInstance(getZone(), iCutoverInstant, getMinimumDaysInFirstWeek());
+ }
+
+ public DateTimeZone getZone() {
+ Chronology base;
+ if ((base = getBase()) != null) {
+ return base.getZone();
+ }
+ return DateTimeZone.UTC;
+ }
+
+ // Conversion
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the Chronology in the UTC time zone.
+ *
+ * @return the chronology in UTC
+ */
+ public Chronology withUTC() {
+ return withZone(DateTimeZone.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, iCutoverInstant, getMinimumDaysInFirstWeek());
+ }
+
+ 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);
+ }
+
+ // Assume date is Gregorian.
+ long instant = iGregorianChronology.getDateTimeMillis
+ (year, monthOfYear, dayOfMonth, millisOfDay);
+ if (instant < iCutoverMillis) {
+ // Maybe it's Julian.
+ instant = iJulianChronology.getDateTimeMillis
+ (year, monthOfYear, dayOfMonth, millisOfDay);
+ if (instant >= iCutoverMillis) {
+ // Okay, it's in the illegal cutover gap.
+ throw new IllegalArgumentException("Specified date does not exist");
+ }
+ }
+ return instant;
+ }
+
+ 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);
+ }
+
+ // Assume date is Gregorian.
+ 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
+ (year, monthOfYear, dayOfMonth,
+ hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
+ if (instant >= iCutoverMillis) {
+ // Okay, it's in the illegal cutover gap.
+ throw new IllegalArgumentException("Specified date does not exist");
+ }
+ }
+ return instant;
+ }
+
+ /**
+ * Gets the cutover instant between Gregorian and Julian chronologies.
+ * @return the cutover instant
+ */
+ public Instant getGregorianCutover() {
+ return iCutoverInstant;
+ }
+
+ /**
+ * Gets the minimum days needed for a week to be the first week in a year.
+ *
+ * @return the minimum days
+ */
+ public int getMinimumDaysInFirstWeek() {
+ 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) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof GJChronology) {
+ GJChronology chrono = (GJChronology) obj;
+ return iCutoverMillis == chrono.iCutoverMillis &&
+ getMinimumDaysInFirstWeek() == chrono.getMinimumDaysInFirstWeek() &&
+ getZone().equals(chrono.getZone());
+ }
+ return false;
+ }
+
+ /**
+ * A suitable hash code for the chronology.
+ *
+ * @return the hash code
+ * @since 1.6
+ */
+ public int hashCode() {
+ return "GJ".hashCode() * 11 + getZone().hashCode() +
+ getMinimumDaysInFirstWeek() + iCutoverInstant.hashCode();
+ }
+
+ // Output
+ //-----------------------------------------------------------------------
+ /**
+ * Gets a debugging toString.
+ *
+ * @return a debugging string
+ */
+ public String toString() {
+ StringBuffer sb = new StringBuffer(60);
+ sb.append("GJChronology");
+ sb.append('[');
+ sb.append(getZone().getID());
+
+ if (iCutoverMillis != DEFAULT_CUTOVER.getMillis()) {
+ sb.append(",cutover=");
+ DateTimeFormatter printer;
+ if (withUTC().dayOfYear().remainder(iCutoverMillis) == 0) {
+ printer = ISODateTimeFormat.date();
+ } else {
+ printer = ISODateTimeFormat.dateTime();
+ }
+ printer.withChronology(withUTC()).printTo(sb, iCutoverMillis);
+ }
+
+ if (getMinimumDaysInFirstWeek() != 4) {
+ sb.append(",mdfw=");
+ sb.append(getMinimumDaysInFirstWeek());
+ }
+ sb.append(']');
+
+ return sb.toString();
+ }
+
+ protected void assemble(Fields fields) {
+ Object[] params = (Object[])getParam();
+
+ JulianChronology julian = (JulianChronology)params[0];
+ GregorianChronology gregorian = (GregorianChronology)params[1];
+ Instant cutoverInstant = (Instant)params[2];
+ iCutoverMillis = cutoverInstant.getMillis();
+
+ iJulianChronology = julian;
+ iGregorianChronology = gregorian;
+ iCutoverInstant = cutoverInstant;
+
+ if (getBase() != null) {
+ return;
+ }
+
+ if (julian.getMinimumDaysInFirstWeek() != gregorian.getMinimumDaysInFirstWeek()) {
+ throw new IllegalArgumentException();
+ }
+
+ // Compute difference between the chronologies at the cutover instant
+ iGapDuration = iCutoverMillis - julianToGregorianByYear(iCutoverMillis);
+
+ // Begin field definitions.
+
+ // First just copy all the Gregorian fields and then override those
+ // that need special attention.
+ fields.copyFieldsFrom(gregorian);
+
+ // Assuming cutover is at midnight, all time of day fields can be
+ // gregorian since they are unaffected by cutover.
+
+ // Verify assumption.
+ if (gregorian.millisOfDay().get(iCutoverMillis) == 0) {
+ // Cutover is sometime in the day, so cutover fields are required
+ // for time of day.
+
+ fields.millisOfSecond = new CutoverField(julian.millisOfSecond(), fields.millisOfSecond, iCutoverMillis);
+ fields.millisOfDay = new CutoverField(julian.millisOfDay(), fields.millisOfDay, iCutoverMillis);
+ fields.secondOfMinute = new CutoverField(julian.secondOfMinute(), fields.secondOfMinute, iCutoverMillis);
+ fields.secondOfDay = new CutoverField(julian.secondOfDay(), fields.secondOfDay, iCutoverMillis);
+ fields.minuteOfHour = new CutoverField(julian.minuteOfHour(), fields.minuteOfHour, iCutoverMillis);
+ fields.minuteOfDay = new CutoverField(julian.minuteOfDay(), fields.minuteOfDay, iCutoverMillis);
+ fields.hourOfDay = new CutoverField(julian.hourOfDay(), fields.hourOfDay, iCutoverMillis);
+ fields.hourOfHalfday = new CutoverField(julian.hourOfHalfday(), fields.hourOfHalfday, iCutoverMillis);
+ fields.clockhourOfDay = new CutoverField(julian.clockhourOfDay(), fields.clockhourOfDay, iCutoverMillis);
+ fields.clockhourOfHalfday = new CutoverField(julian.clockhourOfHalfday(),
+ fields.clockhourOfHalfday, iCutoverMillis);
+ fields.halfdayOfDay = new CutoverField(julian.halfdayOfDay(), fields.halfdayOfDay, iCutoverMillis);
+ }
+
+ // These fields just require basic cutover support.
+ {
+ fields.era = new CutoverField(julian.era(), fields.era, iCutoverMillis);
+ }
+
+ // DayOfYear and weekOfWeekyear require special handling since cutover
+ // year has fewer days and weeks. Extend the cutover to the start of
+ // the next year or weekyear. This keeps the sequence unbroken during
+ // the cutover year.
+
+ {
+ long cutover = gregorian.year().roundCeiling(iCutoverMillis);
+ fields.dayOfYear = new CutoverField(
+ julian.dayOfYear(), fields.dayOfYear, cutover);
+ }
+
+ {
+ long cutover = gregorian.weekyear().roundCeiling(iCutoverMillis);
+ fields.weekOfWeekyear = new CutoverField(
+ julian.weekOfWeekyear(), fields.weekOfWeekyear, cutover, true);
+ }
+
+ // These fields are special because they have imprecise durations. The
+ // family of addition methods need special attention. Override affected
+ // duration fields as well.
+ {
+ fields.year = new ImpreciseCutoverField(
+ julian.year(), fields.year, iCutoverMillis);
+ fields.years = fields.year.getDurationField();
+ fields.yearOfEra = new ImpreciseCutoverField(
+ julian.yearOfEra(), fields.yearOfEra, fields.years, iCutoverMillis);
+ fields.yearOfCentury = new ImpreciseCutoverField(
+ julian.yearOfCentury(), fields.yearOfCentury, fields.years, iCutoverMillis);
+
+ fields.centuryOfEra = new ImpreciseCutoverField(
+ julian.centuryOfEra(), fields.centuryOfEra, iCutoverMillis);
+ fields.centuries = fields.centuryOfEra.getDurationField();
+
+ fields.monthOfYear = new ImpreciseCutoverField(
+ julian.monthOfYear(), fields.monthOfYear, iCutoverMillis);
+ fields.months = fields.monthOfYear.getDurationField();
+
+ fields.weekyear = new ImpreciseCutoverField(
+ julian.weekyear(), fields.weekyear, null, iCutoverMillis, true);
+ fields.weekyearOfCentury = new ImpreciseCutoverField(
+ 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) {
+ return convertByYear(instant, iJulianChronology, iGregorianChronology);
+ }
+
+ long gregorianToJulianByYear(long instant) {
+ return convertByYear(instant, iGregorianChronology, iJulianChronology);
+ }
+
+ long julianToGregorianByWeekyear(long instant) {
+ return convertByWeekyear(instant, iJulianChronology, iGregorianChronology);
+ }
+
+ long gregorianToJulianByWeekyear(long instant) {
+ return convertByWeekyear(instant, iGregorianChronology, iJulianChronology);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * This basic cutover field adjusts calls to 'get' and 'set' methods, and
+ * assumes that calls to add and addWrapField are unaffected by the cutover.
+ */
+ private class CutoverField extends BaseDateTimeField {
+ private static final long serialVersionUID = 3528501219481026402L;
+
+ final DateTimeField iJulianField;
+ final DateTimeField iGregorianField;
+ final long iCutover;
+ final boolean iConvertByWeekyear;
+
+ protected DurationField iDurationField;
+ protected DurationField iRangeDurationField;
+
+ /**
+ * @param julianField field from the chronology used before the cutover instant
+ * @param gregorianField field from the chronology used at and after the cutover
+ * @param cutoverMillis the millis of the cutover
+ */
+ CutoverField(DateTimeField julianField, DateTimeField gregorianField, long cutoverMillis) {
+ this(julianField, gregorianField, cutoverMillis, false);
+ }
+
+ /**
+ * @param julianField field from the chronology used before the cutover instant
+ * @param gregorianField field from the chronology used at and after the cutover
+ * @param cutoverMillis the millis of the cutover
+ * @param convertByWeekyear
+ */
+ CutoverField(DateTimeField julianField, DateTimeField gregorianField,
+ long cutoverMillis, boolean convertByWeekyear) {
+ super(gregorianField.getType());
+ iJulianField = julianField;
+ iGregorianField = gregorianField;
+ iCutover = cutoverMillis;
+ iConvertByWeekyear = convertByWeekyear;
+ // 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() {
+ return false;
+ }
+
+ public int get(long instant) {
+ if (instant >= iCutover) {
+ return iGregorianField.get(instant);
+ } else {
+ return iJulianField.get(instant);
+ }
+ }
+
+ public String getAsText(long instant, Locale locale) {
+ if (instant >= iCutover) {
+ return iGregorianField.getAsText(instant, locale);
+ } else {
+ return iJulianField.getAsText(instant, locale);
+ }
+ }
+
+ 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);
+ } else {
+ return iJulianField.getAsShortText(instant, locale);
+ }
+ }
+
+ public String getAsShortText(int fieldValue, Locale locale) {
+ return iGregorianField.getAsShortText(fieldValue, locale);
+ }
+
+ public long add(long instant, int value) {
+ return iGregorianField.add(instant, value);
+ }
+
+ public long add(long instant, long value) {
+ 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);
+ }
+
+ public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
+ return iGregorianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
+ }
+
+ public long set(long instant, int value) {
+ if (instant >= iCutover) {
+ instant = iGregorianField.set(instant, value);
+ if (instant < iCutover) {
+ // Only adjust if gap fully crossed.
+ if (instant + iGapDuration < iCutover) {
+ instant = gregorianToJulian(instant);
+ }
+ // Verify that new value stuck.
+ if (get(instant) != value) {
+ throw new IllegalFieldValueException
+ (iGregorianField.getType(), Integer.valueOf(value), null, null);
+ }
+ }
+ } else {
+ instant = iJulianField.set(instant, value);
+ if (instant >= iCutover) {
+ // Only adjust if gap fully crossed.
+ if (instant - iGapDuration >= iCutover) {
+ instant = julianToGregorian(instant);
+ }
+ // Verify that new value stuck.
+ if (get(instant) != value) {
+ throw new IllegalFieldValueException
+ (iJulianField.getType(), Integer.valueOf(value), null, null);
+ }
+ }
+ }
+ return instant;
+ }
+
+ public long set(long instant, String text, Locale locale) {
+ if (instant >= iCutover) {
+ instant = iGregorianField.set(instant, text, locale);
+ if (instant < iCutover) {
+ // Only adjust if gap fully crossed.
+ if (instant + iGapDuration < iCutover) {
+ instant = gregorianToJulian(instant);
+ }
+ // Cannot verify that new value stuck because set may be lenient.
+ }
+ } else {
+ instant = iJulianField.set(instant, text, locale);
+ if (instant >= iCutover) {
+ // Only adjust if gap fully crossed.
+ if (instant - iGapDuration >= iCutover) {
+ instant = julianToGregorian(instant);
+ }
+ // Cannot verify that new value stuck because set may be lenient.
+ }
+ }
+ return instant;
+ }
+
+ public DurationField getDurationField() {
+ return iDurationField;
+ }
+
+ public DurationField getRangeDurationField() {
+ return iRangeDurationField;
+ }
+
+ public boolean isLeap(long instant) {
+ if (instant >= iCutover) {
+ return iGregorianField.isLeap(instant);
+ } else {
+ return iJulianField.isLeap(instant);
+ }
+ }
+
+ public int getLeapAmount(long instant) {
+ if (instant >= iCutover) {
+ return iGregorianField.getLeapAmount(instant);
+ } else {
+ return iJulianField.getLeapAmount(instant);
+ }
+ }
+
+ public DurationField getLeapDurationField() {
+ return iGregorianField.getLeapDurationField();
+ }
+
+
+ public int getMinimumValue() {
+ // For all precise fields, the Julian and Gregorian limits are
+ // 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);
+ }
+
+ int min = iGregorianField.getMinimumValue(instant);
+
+ // Because the cutover may reduce the length of this field, verify
+ // the minimum by setting it.
+ instant = iGregorianField.set(instant, min);
+ if (instant < iCutover) {
+ min = iGregorianField.get(iCutover);
+ }
+
+ return min;
+ }
+
+ public int getMaximumValue() {
+ // For all precise fields, the Julian and Gregorian limits are
+ // identical.
+ return iGregorianField.getMaximumValue();
+ }
+
+ public int getMaximumValue(long instant) {
+ if (instant >= iCutover) {
+ return iGregorianField.getMaximumValue(instant);
+ }
+
+ int max = iJulianField.getMaximumValue(instant);
+
+ // Because the cutover may reduce the length of this field, verify
+ // the maximum by setting it.
+ instant = iJulianField.set(instant, max);
+ if (instant >= iCutover) {
+ max = iJulianField.get(iJulianField.add(iCutover, -1));
+ }
+
+ 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);
+ if (instant < iCutover) {
+ // Only adjust if gap fully crossed.
+ if (instant + iGapDuration < iCutover) {
+ instant = gregorianToJulian(instant);
+ }
+ }
+ } else {
+ instant = iJulianField.roundFloor(instant);
+ }
+ return instant;
+ }
+
+ public long roundCeiling(long instant) {
+ if (instant >= iCutover) {
+ instant = iGregorianField.roundCeiling(instant);
+ } else {
+ instant = iJulianField.roundCeiling(instant);
+ if (instant >= iCutover) {
+ // Only adjust if gap fully crossed.
+ if (instant - iGapDuration >= iCutover) {
+ instant = julianToGregorian(instant);
+ }
+ }
+ }
+ return instant;
+ }
+
+ public int getMaximumTextLength(Locale locale) {
+ return Math.max(iJulianField.getMaximumTextLength(locale),
+ iGregorianField.getMaximumTextLength(locale));
+ }
+
+ public int getMaximumShortTextLength(Locale locale) {
+ return Math.max(iJulianField.getMaximumShortTextLength(locale),
+ iGregorianField.getMaximumShortTextLength(locale));
+ }
+
+ protected long julianToGregorian(long instant) {
+ if (iConvertByWeekyear) {
+ return julianToGregorianByWeekyear(instant);
+ } else {
+ return julianToGregorianByYear(instant);
+ }
+ }
+
+ protected long gregorianToJulian(long instant) {
+ if (iConvertByWeekyear) {
+ return gregorianToJulianByWeekyear(instant);
+ } else {
+ return gregorianToJulianByYear(instant);
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Cutover field for variable length fields. These fields internally call
+ * set whenever add is called. As a result, the same correction applied to
+ * set must be applied to add and addWrapField. Knowing when to use this
+ * field requires specific knowledge of how the GJ fields are implemented.
+ */
+ private final class ImpreciseCutoverField extends CutoverField {
+ private static final long serialVersionUID = 3410248757173576441L;
+
+ /**
+ * Creates a duration field that links back to this.
+ */
+ ImpreciseCutoverField(DateTimeField julianField, DateTimeField gregorianField, long cutoverMillis) {
+ this(julianField, gregorianField, null, cutoverMillis, false);
+ }
+
+ /**
+ * Uses a shared duration field rather than creating a new one.
+ *
+ * @param durationField shared duration field
+ */
+ ImpreciseCutoverField(DateTimeField julianField, DateTimeField gregorianField,
+ DurationField durationField, long cutoverMillis)
+ {
+ this(julianField, gregorianField, durationField, cutoverMillis, false);
+ }
+
+ /**
+ * Uses a shared duration field rather than creating a new one.
+ *
+ * @param durationField shared duration field
+ */
+ ImpreciseCutoverField(DateTimeField julianField, DateTimeField gregorianField,
+ DurationField durationField,
+ long cutoverMillis, boolean convertByWeekyear)
+ {
+ super(julianField, gregorianField, cutoverMillis, convertByWeekyear);
+ if (durationField == null) {
+ durationField = new LinkedDurationField(iDurationField, this);
+ }
+ iDurationField = durationField;
+ }
+
+ public long add(long instant, int value) {
+ if (instant >= iCutover) {
+ instant = iGregorianField.add(instant, value);
+ if (instant < iCutover) {
+ // Only adjust if gap fully crossed.
+ if (instant + iGapDuration < iCutover) {
+ instant = gregorianToJulian(instant);
+ }
+ }
+ } else {
+ instant = iJulianField.add(instant, value);
+ if (instant >= iCutover) {
+ // Only adjust if gap fully crossed.
+ if (instant - iGapDuration >= iCutover) {
+ // no special handling for year zero as cutover always after year zero
+ instant = julianToGregorian(instant);
+ }
+ }
+ }
+ return instant;
+ }
+
+ public long add(long instant, long value) {
+ if (instant >= iCutover) {
+ instant = iGregorianField.add(instant, value);
+ if (instant < iCutover) {
+ // Only adjust if gap fully crossed.
+ if (instant + iGapDuration < iCutover) {
+ instant = gregorianToJulian(instant);
+ }
+ }
+ } else {
+ instant = iJulianField.add(instant, value);
+ if (instant >= iCutover) {
+ // Only adjust if gap fully crossed.
+ if (instant - iGapDuration >= iCutover) {
+ // no special handling for year zero as cutover always after year zero
+ instant = julianToGregorian(instant);
+ }
+ }
+ }
+ return instant;
+ }
+
+ public int getDifference(long minuendInstant, long subtrahendInstant) {
+ if (minuendInstant >= iCutover) {
+ if (subtrahendInstant >= iCutover) {
+ return iGregorianField.getDifference(minuendInstant, subtrahendInstant);
+ }
+ // Remember, the add is being reversed. Since subtrahend is
+ // Julian, convert minuend to Julian to match.
+ minuendInstant = gregorianToJulian(minuendInstant);
+ return iJulianField.getDifference(minuendInstant, subtrahendInstant);
+ } else {
+ if (subtrahendInstant < iCutover) {
+ return iJulianField.getDifference(minuendInstant, subtrahendInstant);
+ }
+ // Remember, the add is being reversed. Since subtrahend is
+ // Gregorian, convert minuend to Gregorian to match.
+ minuendInstant = julianToGregorian(minuendInstant);
+ return iGregorianField.getDifference(minuendInstant, subtrahendInstant);
+ }
+ }
+
+ public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
+ if (minuendInstant >= iCutover) {
+ if (subtrahendInstant >= iCutover) {
+ return iGregorianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
+ }
+ // Remember, the add is being reversed. Since subtrahend is
+ // Julian, convert minuend to Julian to match.
+ minuendInstant = gregorianToJulian(minuendInstant);
+ return iJulianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
+ } else {
+ if (subtrahendInstant < iCutover) {
+ return iJulianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
+ }
+ // Remember, the add is being reversed. Since subtrahend is
+ // Gregorian, convert minuend to Gregorian to match.
+ minuendInstant = julianToGregorian(minuendInstant);
+ return iGregorianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
+ }
+ }
+
+ // Since the imprecise fields have durations longer than the gap
+ // duration, keep these methods simple. The inherited implementations
+ // produce incorrect results.
+ //
+ // Degenerate case: If this field is a month, and the cutover is set
+ // far into the future, then the gap duration may be so large as to
+ // reduce the number of months in a year. If the missing month(s) are
+ // at the beginning or end of the year, then the minimum and maximum
+ // values are not 1 and 12. I don't expect this case to ever occur.
+
+ public int getMinimumValue(long instant) {
+ if (instant >= iCutover) {
+ return iGregorianField.getMinimumValue(instant);
+ } else {
+ return iJulianField.getMinimumValue(instant);
+ }
+ }
+
+ public int getMaximumValue(long instant) {
+ if (instant >= iCutover) {
+ return iGregorianField.getMaximumValue(instant);
+ } else {
+ return iJulianField.getMaximumValue(instant);
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Links the duration back to a ImpreciseCutoverField.
+ */
+ private static class LinkedDurationField extends DecoratedDurationField {
+ private static final long serialVersionUID = 4097975388007713084L;
+
+ private final ImpreciseCutoverField iField;
+
+ LinkedDurationField(DurationField durationField, ImpreciseCutoverField dateTimeField) {
+ super(durationField, durationField.getType());
+ iField = dateTimeField;
+ }
+
+ public long add(long instant, int value) {
+ return iField.add(instant, value);
+ }
+
+ public long add(long instant, long value) {
+ return iField.add(instant, value);
+ }
+
+ public int getDifference(long minuendInstant, long subtrahendInstant) {
+ return iField.getDifference(minuendInstant, subtrahendInstant);
+ }
+
+ public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
+ return iField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
+ }
+ }
+
+}