EMMA Coverage Report (generated Tue Oct 28 00:01:11 GMT 2008)
[all classes][org.joda.time.chrono]

COVERAGE SUMMARY FOR SOURCE FILE [GJChronology.java]

nameclass, %method, %block, %line, %
GJChronology.java100% (4/4)79%  (59/75)81%  (1458/1803)80%  (253/315)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class GJChronology$ImpreciseCutoverField100% (1/1)78%  (7/9)64%  (178/277)67%  (36/54)
getDifferenceAsLong (long, long): long 0%   (0/1)0%   (0/47)0%   (0/9)
getMinimumValue (long): int 0%   (0/1)0%   (0/15)0%   (0/3)
add (long, long): long 100% (1/1)52%  (29/56)60%  (6/10)
getDifference (long, long): int 100% (1/1)79%  (37/47)78%  (7/9)
GJChronology$ImpreciseCutoverField (GJChronology, DateTimeField, DateTimeFiel... 100% (1/1)100% (9/9)100% (2/2)
GJChronology$ImpreciseCutoverField (GJChronology, DateTimeField, DateTimeFiel... 100% (1/1)100% (23/23)100% (6/6)
GJChronology$ImpreciseCutoverField (GJChronology, DateTimeField, DateTimeFiel... 100% (1/1)100% (9/9)100% (2/2)
add (long, int): long 100% (1/1)100% (56/56)100% (10/10)
getMaximumValue (long): int 100% (1/1)100% (15/15)100% (3/3)
     
class GJChronology$CutoverField100% (1/1)62%  (21/34)66%  (413/624)69%  (83/121)
add (long, long): long 0%   (0/1)0%   (0/6)0%   (0/1)
getAsShortText (long, Locale): String 0%   (0/1)0%   (0/17)0%   (0/3)
getAsText (long, Locale): String 0%   (0/1)0%   (0/17)0%   (0/3)
getDifference (long, long): int 0%   (0/1)0%   (0/6)0%   (0/1)
getDifferenceAsLong (long, long): long 0%   (0/1)0%   (0/6)0%   (0/1)
getLeapAmount (long): int 0%   (0/1)0%   (0/15)0%   (0/3)
getMaximumShortTextLength (Locale): int 0%   (0/1)0%   (0/10)0%   (0/1)
getMaximumTextLength (Locale): int 0%   (0/1)0%   (0/10)0%   (0/1)
getMinimumValue (ReadablePartial): int 0%   (0/1)0%   (0/5)0%   (0/1)
getMinimumValue (long): int 0%   (0/1)0%   (0/34)0%   (0/7)
isLeap (long): boolean 0%   (0/1)0%   (0/15)0%   (0/3)
isLenient (): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
roundCeiling (long): long 0%   (0/1)0%   (0/36)0%   (0/7)
set (long, String, Locale): long 100% (1/1)57%  (33/58)60%  (6/10)
add (ReadablePartial, int, int [], int): int [] 100% (1/1)86%  (42/49)89%  (8/9)
GJChronology$CutoverField (GJChronology, DateTimeField, DateTimeField, long):... 100% (1/1)100% (8/8)100% (2/2)
GJChronology$CutoverField (GJChronology, DateTimeField, DateTimeField, long, ... 100% (1/1)100% (35/35)100% (12/12)
add (long, int): long 100% (1/1)100% (6/6)100% (1/1)
get (long): int 100% (1/1)100% (15/15)100% (3/3)
getAsShortText (int, Locale): String 100% (1/1)100% (6/6)100% (1/1)
getAsText (int, Locale): String 100% (1/1)100% (6/6)100% (1/1)
getDurationField (): DurationField 100% (1/1)100% (3/3)100% (1/1)
getLeapDurationField (): DurationField 100% (1/1)100% (4/4)100% (1/1)
getMaximumValue (): int 100% (1/1)100% (4/4)100% (1/1)
getMaximumValue (ReadablePartial): int 100% (1/1)100% (9/9)100% (2/2)
getMaximumValue (ReadablePartial, int []): int 100% (1/1)100% (38/38)100% (7/7)
getMaximumValue (long): int 100% (1/1)100% (38/38)100% (7/7)
getMinimumValue (): int 100% (1/1)100% (4/4)100% (1/1)
getMinimumValue (ReadablePartial, int []): int 100% (1/1)100% (6/6)100% (1/1)
getRangeDurationField (): DurationField 100% (1/1)100% (3/3)100% (1/1)
gregorianToJulian (long): long 100% (1/1)100% (13/13)100% (3/3)
julianToGregorian (long): long 100% (1/1)100% (13/13)100% (3/3)
roundFloor (long): long 100% (1/1)100% (36/36)100% (7/7)
set (long, int): long 100% (1/1)100% (91/91)100% (14/14)
     
class GJChronology$LinkedDurationField100% (1/1)80%  (4/5)82%  (27/33)86%  (6/7)
getDifferenceAsLong (long, long): long 0%   (0/1)0%   (0/6)0%   (0/1)
GJChronology$LinkedDurationField (DurationField, GJChronology$ImpreciseCutove... 100% (1/1)100% (9/9)100% (3/3)
add (long, int): long 100% (1/1)100% (6/6)100% (1/1)
add (long, long): long 100% (1/1)100% (6/6)100% (1/1)
getDifference (long, long): int 100% (1/1)100% (6/6)100% (1/1)
     
class GJChronology100% (1/1)100% (27/27)97%  (840/869)96%  (128/133)
getDateTimeMillis (int, int, int, int): long 100% (1/1)44%  (20/45)50%  (4/8)
assemble (AssembledChronology$Fields): void 100% (1/1)99%  (369/373)98%  (45/46)
<static initializer> 100% (1/1)100% (10/10)100% (2/2)
GJChronology (Chronology, JulianChronology, GregorianChronology, Instant): void 100% (1/1)100% (18/18)100% (2/2)
GJChronology (JulianChronology, GregorianChronology, Instant): void 100% (1/1)100% (18/18)100% (2/2)
convertByWeekyear (long, Chronology, Chronology): long 100% (1/1)100% (38/38)100% (5/5)
convertByYear (long, Chronology, Chronology): long 100% (1/1)100% (19/19)100% (1/1)
equals (Object): boolean 100% (1/1)100% (4/4)100% (1/1)
getDateTimeMillis (int, int, int, int, int, int, int): long 100% (1/1)100% (54/54)100% (8/8)
getGregorianCutover (): Instant 100% (1/1)100% (3/3)100% (1/1)
getInstance (): GJChronology 100% (1/1)100% (5/5)100% (1/1)
getInstance (DateTimeZone): GJChronology 100% (1/1)100% (5/5)100% (1/1)
getInstance (DateTimeZone, ReadableInstant): GJChronology 100% (1/1)100% (5/5)100% (1/1)
getInstance (DateTimeZone, ReadableInstant, int): GJChronology 100% (1/1)100% (90/90)100% (18/18)
getInstance (DateTimeZone, long, int): GJChronology 100% (1/1)100% (18/18)100% (4/4)
getInstanceUTC (): GJChronology 100% (1/1)100% (5/5)100% (1/1)
getMinimumDaysInFirstWeek (): int 100% (1/1)100% (4/4)100% (1/1)
getZone (): DateTimeZone 100% (1/1)100% (10/10)100% (3/3)
gregorianToJulianByWeekyear (long): long 100% (1/1)100% (7/7)100% (1/1)
gregorianToJulianByYear (long): long 100% (1/1)100% (7/7)100% (1/1)
hashCode (): int 100% (1/1)100% (17/17)100% (1/1)
julianToGregorianByWeekyear (long): long 100% (1/1)100% (7/7)100% (1/1)
julianToGregorianByYear (long): long 100% (1/1)100% (7/7)100% (1/1)
readResolve (): Object 100% (1/1)100% (8/8)100% (1/1)
toString (): String 100% (1/1)100% (71/71)100% (15/15)
withUTC (): Chronology 100% (1/1)100% (4/4)100% (1/1)
withZone (DateTimeZone): Chronology 100% (1/1)100% (17/17)100% (5/5)

1/*
2 *  Copyright 2001-2005 Stephen Colebourne
3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *  Unless required by applicable law or agreed to in writing, software
11 *  distributed under the License is distributed on an "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *  See the License for the specific language governing permissions and
14 *  limitations under the License.
15 */
16package org.joda.time.chrono;
17 
18import java.util.ArrayList;
19import java.util.HashMap;
20import java.util.Locale;
21import java.util.Map;
22 
23import org.joda.time.Chronology;
24import org.joda.time.DateTimeField;
25import org.joda.time.DateTimeUtils;
26import org.joda.time.DateTimeZone;
27import org.joda.time.DurationField;
28import org.joda.time.IllegalFieldValueException;
29import org.joda.time.Instant;
30import org.joda.time.ReadableInstant;
31import org.joda.time.ReadablePartial;
32import org.joda.time.field.BaseDateTimeField;
33import org.joda.time.field.DecoratedDurationField;
34import org.joda.time.format.DateTimeFormatter;
35import org.joda.time.format.ISODateTimeFormat;
36 
37/**
38 * Implements the Gregorian/Julian calendar system which is the calendar system
39 * used in most of the world. Wherever possible, it is recommended to use the
40 * {@link ISOChronology} instead.
41 * <p>
42 * The Gregorian calendar replaced the Julian calendar, and the point in time
43 * when this chronology switches can be controlled using the second parameter
44 * of the getInstance method. By default this cutover is set to the date the
45 * Gregorian calendar was first instituted, October 15, 1582.
46 * <p>
47 * Before this date, this chronology uses the proleptic Julian calendar
48 * (proleptic means extending indefinitely). The Julian calendar has leap years
49 * every four years, whereas the Gregorian has special rules for 100 and 400
50 * years. A meaningful result will thus be obtained for all input values.
51 * However before 8 CE, Julian leap years were irregular, and before 45 BCE
52 * there was no Julian calendar.
53 * <p>
54 * This chronology differs from
55 * {@link java.util.GregorianCalendar GregorianCalendar} in that years
56 * in BCE are returned correctly. Thus year 1 BCE is returned as -1 instead of 1.
57 * The yearOfEra field produces results compatible with GregorianCalendar.
58 * <p>
59 * The Julian calendar does not have a year zero, and so year -1 is followed by
60 * year 1. If the Gregorian cutover date is specified at or before year -1
61 * (Julian), year zero is defined. In other words, the proleptic Gregorian
62 * chronology used by this class has a year zero.
63 * <p>
64 * To create a pure proleptic Julian chronology, use {@link JulianChronology},
65 * and to create a pure proleptic Gregorian chronology, use
66 * {@link GregorianChronology}.
67 * <p>
68 * GJChronology is thread-safe and immutable.
69 * 
70 * @author Brian S O'Neill
71 * @author Stephen Colebourne
72 * @since 1.0
73 */
74public final class GJChronology extends AssembledChronology {
75 
76    /** Serialization lock */
77    private static final long serialVersionUID = -2545574827706931671L;
78 
79    /**
80     * Convert a datetime from one chronology to another.
81     */
82    private static long convertByYear(long instant, Chronology from, Chronology to) {
83        return to.getDateTimeMillis
84            (from.year().get(instant),
85             from.monthOfYear().get(instant),
86             from.dayOfMonth().get(instant),
87             from.millisOfDay().get(instant));
88    }
89 
90    /**
91     * Convert a datetime from one chronology to another.
92     */
93    private static long convertByWeekyear(final long instant, Chronology from, Chronology to) {
94        long newInstant;
95        newInstant = to.weekyear().set(0, from.weekyear().get(instant));
96        newInstant = to.weekOfWeekyear().set(newInstant, from.weekOfWeekyear().get(instant));
97        newInstant = to.dayOfWeek().set(newInstant, from.dayOfWeek().get(instant));
98        newInstant = to.millisOfDay().set(newInstant, from.millisOfDay().get(instant));
99        return newInstant;
100    }
101 
102    /**
103     * The default GregorianJulian cutover point.
104     */
105    static final Instant DEFAULT_CUTOVER = new Instant(-12219292800000L);
106 
107    /** Cache of zone to chronology list */
108    private static final Map cCache = new HashMap();
109 
110    /**
111     * Factory method returns instances of the default GJ cutover
112     * chronology. This uses a cutover date of October 15, 1582 (Gregorian)
113     * 00:00:00 UTC. For this value, October 4, 1582 (Julian) is followed by
114     * October 15, 1582 (Gregorian).
115     *
116     * <p>The first day of the week is designated to be
117     * {@link org.joda.time.DateTimeConstants#MONDAY Monday},
118     * and the minimum days in the first week of the year is 4.
119     *
120     * <p>The time zone of the returned instance is UTC.
121     */
122    public static GJChronology getInstanceUTC() {
123        return getInstance(DateTimeZone.UTC, DEFAULT_CUTOVER, 4);
124    }
125 
126    /**
127     * Factory method returns instances of the default GJ cutover
128     * chronology. This uses a cutover date of October 15, 1582 (Gregorian)
129     * 00:00:00 UTC. For this value, October 4, 1582 (Julian) is followed by
130     * October 15, 1582 (Gregorian).
131     *
132     * <p>The first day of the week is designated to be
133     * {@link org.joda.time.DateTimeConstants#MONDAY Monday},
134     * and the minimum days in the first week of the year is 4.
135     *
136     * <p>The returned chronology is in the default time zone.
137     */
138    public static GJChronology getInstance() {
139        return getInstance(DateTimeZone.getDefault(), DEFAULT_CUTOVER, 4);
140    }
141 
142    /**
143     * Factory method returns instances of the GJ cutover chronology. This uses
144     * a cutover date of October 15, 1582 (Gregorian) 00:00:00 UTC. For this
145     * value, October 4, 1582 (Julian) is followed by October 15, 1582
146     * (Gregorian).
147     *
148     * <p>The first day of the week is designated to be
149     * {@link org.joda.time.DateTimeConstants#MONDAY Monday},
150     * and the minimum days in the first week of the year is 4.
151     *
152     * @param zone  the time zone to use, null is default
153     */
154    public static GJChronology getInstance(DateTimeZone zone) {
155        return getInstance(zone, DEFAULT_CUTOVER, 4);
156    }
157 
158    /**
159     * Factory method returns instances of the GJ cutover chronology. Any
160     * cutover date may be specified.
161     *
162     * <p>The first day of the week is designated to be
163     * {@link org.joda.time.DateTimeConstants#MONDAY Monday},
164     * and the minimum days in the first week of the year is 4.
165     *
166     * @param zone  the time zone to use, null is default
167     * @param gregorianCutover  the cutover to use, null means default
168     */
169    public static GJChronology getInstance(
170            DateTimeZone zone,
171            ReadableInstant gregorianCutover) {
172        
173        return getInstance(zone, gregorianCutover, 4);
174    }
175    
176    /**
177     * Factory method returns instances of the GJ cutover chronology. Any
178     * cutover date may be specified.
179     *
180     * @param zone  the time zone to use, null is default
181     * @param gregorianCutover  the cutover to use, null means default
182     * @param minDaysInFirstWeek  minimum number of days in first week of the year; default is 4
183     */
184    public static synchronized GJChronology getInstance(
185            DateTimeZone zone,
186            ReadableInstant gregorianCutover,
187            int minDaysInFirstWeek) {
188        
189        zone = DateTimeUtils.getZone(zone);
190        Instant cutoverInstant;
191        if (gregorianCutover == null) {
192            cutoverInstant = DEFAULT_CUTOVER;
193        } else {
194            cutoverInstant = gregorianCutover.toInstant();
195        }
196 
197        GJChronology chrono;
198 
199        ArrayList chronos = (ArrayList)cCache.get(zone);
200        if (chronos == null) {
201            chronos = new ArrayList(2);
202            cCache.put(zone, chronos);
203        } else {
204            for (int i=chronos.size(); --i>=0; ) {
205                chrono = (GJChronology)chronos.get(i);
206                if (minDaysInFirstWeek == chrono.getMinimumDaysInFirstWeek() &&
207                    cutoverInstant.equals(chrono.getGregorianCutover())) {
208                    
209                    return chrono;
210                }
211            }
212        }
213 
214        if (zone == DateTimeZone.UTC) {
215            chrono = new GJChronology
216                (JulianChronology.getInstance(zone, minDaysInFirstWeek),
217                 GregorianChronology.getInstance(zone, minDaysInFirstWeek),
218                 cutoverInstant);
219        } else {
220            chrono = getInstance(DateTimeZone.UTC, cutoverInstant, minDaysInFirstWeek);
221            chrono = new GJChronology
222                (ZonedChronology.getInstance(chrono, zone),
223                 chrono.iJulianChronology,
224                 chrono.iGregorianChronology,
225                 chrono.iCutoverInstant);
226        }
227 
228        chronos.add(chrono);
229 
230        return chrono;
231    }
232 
233    /**
234     * Factory method returns instances of the GJ cutover chronology. Any
235     * cutover date may be specified.
236     *
237     * @param zone  the time zone to use, null is default
238     * @param gregorianCutover  the cutover to use
239     * @param minDaysInFirstWeek  minimum number of days in first week of the year; default is 4
240     */
241    public static GJChronology getInstance(
242            DateTimeZone zone,
243            long gregorianCutover,
244            int minDaysInFirstWeek) {
245        
246        Instant cutoverInstant;
247        if (gregorianCutover == DEFAULT_CUTOVER.getMillis()) {
248            cutoverInstant = null;
249        } else {
250            cutoverInstant = new Instant(gregorianCutover);
251        }
252        return getInstance(zone, cutoverInstant, minDaysInFirstWeek);
253    }
254 
255    //-----------------------------------------------------------------------
256    private JulianChronology iJulianChronology;
257    private GregorianChronology iGregorianChronology;
258    private Instant iCutoverInstant;
259 
260    private long iCutoverMillis;
261    private long iGapDuration;
262 
263    /**
264     * @param julian chronology used before the cutover instant
265     * @param gregorian chronology used at and after the cutover instant
266     * @param cutoverInstant instant when the gregorian chronology began
267     */
268    private GJChronology(JulianChronology julian,
269                         GregorianChronology gregorian,
270                         Instant cutoverInstant) {
271        super(null, new Object[] {julian, gregorian, cutoverInstant});
272    }
273 
274    /**
275     * Called when applying a time zone.
276     */
277    private GJChronology(Chronology base,
278                         JulianChronology julian,
279                         GregorianChronology gregorian,
280                         Instant cutoverInstant) {
281        super(base, new Object[] {julian, gregorian, cutoverInstant});
282    }
283 
284    /**
285     * Serialization singleton
286     */
287    private Object readResolve() {
288        return getInstance(getZone(), iCutoverInstant, getMinimumDaysInFirstWeek());
289    }
290 
291    public DateTimeZone getZone() {
292        Chronology base;
293        if ((base = getBase()) != null) {
294            return base.getZone();
295        }
296        return DateTimeZone.UTC;
297    }
298 
299    // Conversion
300    //-----------------------------------------------------------------------
301    /**
302     * Gets the Chronology in the UTC time zone.
303     * 
304     * @return the chronology in UTC
305     */
306    public Chronology withUTC() {
307        return withZone(DateTimeZone.UTC);
308    }
309 
310    /**
311     * Gets the Chronology in a specific time zone.
312     * 
313     * @param zone  the zone to get the chronology in, null is default
314     * @return the chronology
315     */
316    public Chronology withZone(DateTimeZone zone) {
317        if (zone == null) {
318            zone = DateTimeZone.getDefault();
319        }
320        if (zone == getZone()) {
321            return this;
322        }
323        return getInstance(zone, iCutoverInstant, getMinimumDaysInFirstWeek());
324    }
325 
326    public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth,
327                                  int millisOfDay)
328        throws IllegalArgumentException
329    {
330        Chronology base;
331        if ((base = getBase()) != null) {
332            return base.getDateTimeMillis(year, monthOfYear, dayOfMonth, millisOfDay);
333        }
334 
335        // Assume date is Gregorian.
336        long instant = iGregorianChronology.getDateTimeMillis
337            (year, monthOfYear, dayOfMonth, millisOfDay);
338        if (instant < iCutoverMillis) {
339            // Maybe it's Julian.
340            instant = iJulianChronology.getDateTimeMillis
341                (year, monthOfYear, dayOfMonth, millisOfDay);
342            if (instant >= iCutoverMillis) {
343                // Okay, it's in the illegal cutover gap.
344                throw new IllegalArgumentException("Specified date does not exist");
345            }
346        }
347        return instant;
348    }
349 
350    public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth,
351                                  int hourOfDay, int minuteOfHour,
352                                  int secondOfMinute, int millisOfSecond)
353        throws IllegalArgumentException
354    {
355        Chronology base;
356        if ((base = getBase()) != null) {
357            return base.getDateTimeMillis
358                (year, monthOfYear, dayOfMonth,
359                 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
360        }
361 
362        // Assume date is Gregorian.
363        long instant = iGregorianChronology.getDateTimeMillis
364            (year, monthOfYear, dayOfMonth,
365             hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
366        if (instant < iCutoverMillis) {
367            // Maybe it's Julian.
368            instant = iJulianChronology.getDateTimeMillis
369                (year, monthOfYear, dayOfMonth,
370                 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
371            if (instant >= iCutoverMillis) {
372                // Okay, it's in the illegal cutover gap.
373                throw new IllegalArgumentException("Specified date does not exist");
374            }
375        }
376        return instant;
377    }
378 
379    /**
380     * Gets the cutover instant between Gregorian and Julian chronologies.
381     * @return the cutover instant
382     */
383    public Instant getGregorianCutover() {
384        return iCutoverInstant;
385    }
386 
387    /**
388     * Gets the minimum days needed for a week to be the first week in a year.
389     * 
390     * @return the minimum days
391     */
392    public int getMinimumDaysInFirstWeek() {
393        return iGregorianChronology.getMinimumDaysInFirstWeek();
394    }
395 
396    /**
397     * Checks if this chronology instance equals another.
398     * 
399     * @param obj  the object to compare to
400     * @return true if equal
401     * @since 1.6
402     */
403    public boolean equals(Object obj) {
404        return super.equals(obj);
405    }
406 
407    /**
408     * A suitable hash code for the chronology.
409     * 
410     * @return the hash code
411     * @since 1.6
412     */
413    public int hashCode() {
414        return "GJ".hashCode() * 11 + iJulianChronology.hashCode() +
415            iGregorianChronology.hashCode() + iCutoverInstant.hashCode();
416    }
417 
418    // Output
419    //-----------------------------------------------------------------------
420    /**
421     * Gets a debugging toString.
422     * 
423     * @return a debugging string
424     */
425    public String toString() {
426        StringBuffer sb = new StringBuffer(60);
427        sb.append("GJChronology");
428        sb.append('[');
429        sb.append(getZone().getID());
430        
431        if (iCutoverMillis != DEFAULT_CUTOVER.getMillis()) {
432            sb.append(",cutover=");
433            DateTimeFormatter printer;
434            if (withUTC().dayOfYear().remainder(iCutoverMillis) == 0) {
435                printer = ISODateTimeFormat.date();
436            } else {
437                printer = ISODateTimeFormat.dateTime();
438            }
439            printer.withChronology(withUTC()).printTo(sb, iCutoverMillis);
440        }
441        
442        if (getMinimumDaysInFirstWeek() != 4) {
443            sb.append(",mdfw=");
444            sb.append(getMinimumDaysInFirstWeek());
445        }
446        sb.append(']');
447        
448        return sb.toString();
449    }
450 
451    protected void assemble(Fields fields) {
452        Object[] params = (Object[])getParam();
453 
454        JulianChronology julian = (JulianChronology)params[0];
455        GregorianChronology gregorian = (GregorianChronology)params[1];
456        Instant cutoverInstant = (Instant)params[2];
457        iCutoverMillis = cutoverInstant.getMillis();
458 
459        iJulianChronology = julian;
460        iGregorianChronology = gregorian;
461        iCutoverInstant = cutoverInstant;
462 
463        if (getBase() != null) {
464            return;
465        }
466 
467        if (julian.getMinimumDaysInFirstWeek() != gregorian.getMinimumDaysInFirstWeek()) {
468            throw new IllegalArgumentException();
469        }
470 
471        // Compute difference between the chronologies at the cutover instant
472        iGapDuration = iCutoverMillis - julianToGregorianByYear(iCutoverMillis);
473 
474        // Begin field definitions.
475 
476        // First just copy all the Gregorian fields and then override those
477        // that need special attention.
478        fields.copyFieldsFrom(gregorian);
479        
480        // Assuming cutover is at midnight, all time of day fields can be
481        // gregorian since they are unaffected by cutover.
482 
483        // Verify assumption.
484        if (gregorian.millisOfDay().get(iCutoverMillis) == 0) {
485            // Cutover is sometime in the day, so cutover fields are required
486            // for time of day.
487 
488            fields.millisOfSecond = new CutoverField(julian.millisOfSecond(), fields.millisOfSecond, iCutoverMillis);
489            fields.millisOfDay = new CutoverField(julian.millisOfDay(), fields.millisOfDay, iCutoverMillis);
490            fields.secondOfMinute = new CutoverField(julian.secondOfMinute(), fields.secondOfMinute, iCutoverMillis);
491            fields.secondOfDay = new CutoverField(julian.secondOfDay(), fields.secondOfDay, iCutoverMillis);
492            fields.minuteOfHour = new CutoverField(julian.minuteOfHour(), fields.minuteOfHour, iCutoverMillis);
493            fields.minuteOfDay = new CutoverField(julian.minuteOfDay(), fields.minuteOfDay, iCutoverMillis);
494            fields.hourOfDay = new CutoverField(julian.hourOfDay(), fields.hourOfDay, iCutoverMillis);
495            fields.hourOfHalfday = new CutoverField(julian.hourOfHalfday(), fields.hourOfHalfday, iCutoverMillis);
496            fields.clockhourOfDay = new CutoverField(julian.clockhourOfDay(), fields.clockhourOfDay, iCutoverMillis);
497            fields.clockhourOfHalfday = new CutoverField(julian.clockhourOfHalfday(),
498                                                         fields.clockhourOfHalfday, iCutoverMillis);
499            fields.halfdayOfDay = new CutoverField(julian.halfdayOfDay(), fields.halfdayOfDay, iCutoverMillis);
500        }
501 
502        // These fields just require basic cutover support.
503        {
504            fields.era = new CutoverField(julian.era(), fields.era, iCutoverMillis);
505        }
506 
507        // DayOfYear and weekOfWeekyear require special handling since cutover
508        // year has fewer days and weeks. Extend the cutover to the start of
509        // the next year or weekyear. This keeps the sequence unbroken during
510        // the cutover year.
511 
512        {
513            long cutover = gregorian.year().roundCeiling(iCutoverMillis);
514            fields.dayOfYear = new CutoverField(
515                julian.dayOfYear(), fields.dayOfYear, cutover);
516        }
517 
518        {
519            long cutover = gregorian.weekyear().roundCeiling(iCutoverMillis);
520            fields.weekOfWeekyear = new CutoverField(
521                julian.weekOfWeekyear(), fields.weekOfWeekyear, cutover, true);
522        }
523 
524        // These fields are special because they have imprecise durations. The
525        // family of addition methods need special attention. Override affected
526        // duration fields as well.
527        {
528            fields.year = new ImpreciseCutoverField(
529                julian.year(), fields.year, iCutoverMillis);
530            fields.years = fields.year.getDurationField();
531            fields.yearOfEra = new ImpreciseCutoverField(
532                julian.yearOfEra(), fields.yearOfEra, fields.years, iCutoverMillis);
533            fields.yearOfCentury = new ImpreciseCutoverField(
534                julian.yearOfCentury(), fields.yearOfCentury, fields.years, iCutoverMillis);
535            
536            fields.centuryOfEra = new ImpreciseCutoverField(
537                julian.centuryOfEra(), fields.centuryOfEra, iCutoverMillis);
538            fields.centuries = fields.centuryOfEra.getDurationField();
539            
540            fields.monthOfYear = new ImpreciseCutoverField(
541                julian.monthOfYear(), fields.monthOfYear, iCutoverMillis);
542            fields.months = fields.monthOfYear.getDurationField();
543            
544            fields.weekyear = new ImpreciseCutoverField(
545                julian.weekyear(), fields.weekyear, null, iCutoverMillis, true);
546            fields.weekyearOfCentury = new ImpreciseCutoverField(
547                julian.weekyearOfCentury(), fields.weekyearOfCentury, fields.weekyears, iCutoverMillis);
548            fields.weekyears = fields.weekyear.getDurationField();
549        }
550 
551        // These fields require basic cutover support, except they must link to
552        // imprecise durations.
553        {
554            CutoverField cf = new CutoverField
555                (julian.dayOfMonth(), fields.dayOfMonth, iCutoverMillis);
556            cf.iRangeDurationField = fields.months;
557            fields.dayOfMonth = cf;
558        }
559    }
560 
561    long julianToGregorianByYear(long instant) {
562        return convertByYear(instant, iJulianChronology, iGregorianChronology);
563    }
564 
565    long gregorianToJulianByYear(long instant) {
566        return convertByYear(instant, iGregorianChronology, iJulianChronology);
567    }
568 
569    long julianToGregorianByWeekyear(long instant) {
570        return convertByWeekyear(instant, iJulianChronology, iGregorianChronology);
571    }
572 
573    long gregorianToJulianByWeekyear(long instant) {
574        return convertByWeekyear(instant, iGregorianChronology, iJulianChronology);
575    }
576 
577    //-----------------------------------------------------------------------
578    /**
579     * This basic cutover field adjusts calls to 'get' and 'set' methods, and
580     * assumes that calls to add and addWrapField are unaffected by the cutover.
581     */
582    private class CutoverField extends BaseDateTimeField {
583        private static final long serialVersionUID = 3528501219481026402L;
584 
585        final DateTimeField iJulianField;
586        final DateTimeField iGregorianField;
587        final long iCutover;
588        final boolean iConvertByWeekyear;
589 
590        protected DurationField iDurationField;
591        protected DurationField iRangeDurationField;
592 
593        /**
594         * @param julianField field from the chronology used before the cutover instant
595         * @param gregorianField field from the chronology used at and after the cutover
596         * @param cutoverMillis  the millis of the cutover
597         */
598        CutoverField(DateTimeField julianField, DateTimeField gregorianField, long cutoverMillis) {
599            this(julianField, gregorianField, cutoverMillis, false);
600        }
601 
602        /**
603         * @param julianField field from the chronology used before the cutover instant
604         * @param gregorianField field from the chronology used at and after the cutover
605         * @param cutoverMillis  the millis of the cutover
606         * @param convertByWeekyear
607         */
608        CutoverField(DateTimeField julianField, DateTimeField gregorianField,
609                     long cutoverMillis, boolean convertByWeekyear) {
610            super(gregorianField.getType());
611            iJulianField = julianField;
612            iGregorianField = gregorianField;
613            iCutover = cutoverMillis;
614            iConvertByWeekyear = convertByWeekyear;
615            // Although average length of Julian and Gregorian years differ,
616            // use the Gregorian duration field because it is more accurate.
617            iDurationField = gregorianField.getDurationField();
618 
619            DurationField rangeField = gregorianField.getRangeDurationField();
620            if (rangeField == null) {
621                rangeField = julianField.getRangeDurationField();
622            }
623            iRangeDurationField = rangeField;
624        }
625 
626        public boolean isLenient() {
627            return false;
628        }
629 
630        public int get(long instant) {
631            if (instant >= iCutover) {
632                return iGregorianField.get(instant);
633            } else {
634                return iJulianField.get(instant);
635            }
636        }
637 
638        public String getAsText(long instant, Locale locale) {
639            if (instant >= iCutover) {
640                return iGregorianField.getAsText(instant, locale);
641            } else {
642                return iJulianField.getAsText(instant, locale);
643            }
644        }
645 
646        public String getAsText(int fieldValue, Locale locale) {
647            return iGregorianField.getAsText(fieldValue, locale);
648        }
649 
650        public String getAsShortText(long instant, Locale locale) {
651            if (instant >= iCutover) {
652                return iGregorianField.getAsShortText(instant, locale);
653            } else {
654                return iJulianField.getAsShortText(instant, locale);
655            }
656        }
657 
658        public String getAsShortText(int fieldValue, Locale locale) {
659            return iGregorianField.getAsShortText(fieldValue, locale);
660        }
661 
662        public long add(long instant, int value) {
663            return iGregorianField.add(instant, value);
664        }
665 
666        public long add(long instant, long value) {
667            return iGregorianField.add(instant, value);
668        }
669 
670        public int[] add(ReadablePartial partial, int fieldIndex, int[] values, int valueToAdd) {
671            // overridden as superclass algorithm can't handle
672            // 2004-02-29 + 48 months -> 2008-02-29 type dates
673            if (valueToAdd == 0) {
674                return values;
675            }
676            if (DateTimeUtils.isContiguous(partial)) {
677                long instant = 0L;
678                for (int i = 0, isize = partial.size(); i < isize; i++) {
679                    instant = partial.getFieldType(i).getField(GJChronology.this).set(instant, values[i]);
680                }
681                instant = add(instant, valueToAdd);
682                return GJChronology.this.get(partial, instant);
683            } else {
684                return super.add(partial, fieldIndex, values, valueToAdd);
685            }
686        }
687 
688        public int getDifference(long minuendInstant, long subtrahendInstant) {
689            return iGregorianField.getDifference(minuendInstant, subtrahendInstant);
690        }
691 
692        public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
693            return iGregorianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
694        }
695 
696        public long set(long instant, int value) {
697            if (instant >= iCutover) {
698                instant = iGregorianField.set(instant, value);
699                if (instant < iCutover) {
700                    // Only adjust if gap fully crossed.
701                    if (instant + iGapDuration < iCutover) {
702                        instant = gregorianToJulian(instant);
703                    }
704                    // Verify that new value stuck.
705                    if (get(instant) != value) {
706                        throw new IllegalFieldValueException
707                            (iGregorianField.getType(), new Integer(value), null, null);
708                    }
709                }
710            } else {
711                instant = iJulianField.set(instant, value);
712                if (instant >= iCutover) {
713                    // Only adjust if gap fully crossed.
714                    if (instant - iGapDuration >= iCutover) {
715                        instant = julianToGregorian(instant);
716                    }
717                    // Verify that new value stuck.
718                    if (get(instant) != value) {
719                       throw new IllegalFieldValueException
720                            (iJulianField.getType(), new Integer(value), null, null);
721                    }
722                }
723            }
724            return instant;
725        }
726 
727        public long set(long instant, String text, Locale locale) {
728            if (instant >= iCutover) {
729                instant = iGregorianField.set(instant, text, locale);
730                if (instant < iCutover) {
731                    // Only adjust if gap fully crossed.
732                    if (instant + iGapDuration < iCutover) {
733                        instant = gregorianToJulian(instant);
734                    }
735                    // Cannot verify that new value stuck because set may be lenient.
736                }
737            } else {
738                instant = iJulianField.set(instant, text, locale);
739                if (instant >= iCutover) {
740                    // Only adjust if gap fully crossed.
741                    if (instant - iGapDuration >= iCutover) {
742                        instant = julianToGregorian(instant);
743                    }
744                    // Cannot verify that new value stuck because set may be lenient.
745                }
746            }
747            return instant;
748        }
749 
750        public DurationField getDurationField() {
751            return iDurationField;
752        }
753 
754        public DurationField getRangeDurationField() {
755            return iRangeDurationField;
756        }
757 
758        public boolean isLeap(long instant) {
759            if (instant >= iCutover) {
760                return iGregorianField.isLeap(instant);
761            } else {
762                return iJulianField.isLeap(instant);
763            }
764        }
765 
766        public int getLeapAmount(long instant) {
767            if (instant >= iCutover) {
768                return iGregorianField.getLeapAmount(instant);
769            } else {
770                return iJulianField.getLeapAmount(instant);
771            }
772        }
773 
774        public DurationField getLeapDurationField() {
775            return iGregorianField.getLeapDurationField();
776        }
777 
778 
779        public int getMinimumValue() {
780            // For all precise fields, the Julian and Gregorian limits are
781            // identical. Choose Julian to tighten up the year limits.
782            return iJulianField.getMinimumValue();
783        }
784 
785        public int getMinimumValue(ReadablePartial partial) {
786            return iJulianField.getMinimumValue(partial);
787        }
788 
789        public int getMinimumValue(ReadablePartial partial, int[] values) {
790            return iJulianField.getMinimumValue(partial, values);
791        }
792 
793        public int getMinimumValue(long instant) {
794            if (instant < iCutover) {
795                return iJulianField.getMinimumValue(instant);
796            }
797 
798            int min = iGregorianField.getMinimumValue(instant);
799 
800            // Because the cutover may reduce the length of this field, verify
801            // the minimum by setting it.
802            instant = iGregorianField.set(instant, min);
803            if (instant < iCutover) {
804                min = iGregorianField.get(iCutover);
805            }
806 
807            return min;
808        }
809 
810        public int getMaximumValue() {
811            // For all precise fields, the Julian and Gregorian limits are
812            // identical.
813            return iGregorianField.getMaximumValue();
814        }
815 
816        public int getMaximumValue(long instant) {
817            if (instant >= iCutover) {
818                return iGregorianField.getMaximumValue(instant);
819            }
820 
821            int max = iJulianField.getMaximumValue(instant);
822 
823            // Because the cutover may reduce the length of this field, verify
824            // the maximum by setting it.
825            instant = iJulianField.set(instant, max);
826            if (instant >= iCutover) {
827                max = iJulianField.get(iJulianField.add(iCutover, -1));
828            }
829 
830            return max;
831        }
832 
833        public int getMaximumValue(ReadablePartial partial) {
834            long instant = GJChronology.getInstanceUTC().set(partial, 0L);
835            return getMaximumValue(instant);
836        }
837 
838        public int getMaximumValue(ReadablePartial partial, int[] values) {
839            Chronology chrono = GJChronology.getInstanceUTC();
840            long instant = 0L;
841            for (int i = 0, isize = partial.size(); i < isize; i++) {
842                DateTimeField field = partial.getFieldType(i).getField(chrono);
843                if (values[i] <= field.getMaximumValue(instant)) {
844                    instant = field.set(instant, values[i]);
845                }
846            }
847            return getMaximumValue(instant);
848        }
849 
850        public long roundFloor(long instant) {
851            if (instant >= iCutover) {
852                instant = iGregorianField.roundFloor(instant);
853                if (instant < iCutover) {
854                    // Only adjust if gap fully crossed.
855                    if (instant + iGapDuration < iCutover) {
856                        instant = gregorianToJulian(instant);
857                    }
858                }
859            } else {
860                instant = iJulianField.roundFloor(instant);
861            }
862            return instant;
863        }
864 
865        public long roundCeiling(long instant) {
866            if (instant >= iCutover) {
867                instant = iGregorianField.roundCeiling(instant);
868            } else {
869                instant = iJulianField.roundCeiling(instant);
870                if (instant >= iCutover) {
871                    // Only adjust if gap fully crossed.
872                    if (instant - iGapDuration >= iCutover) {
873                        instant = julianToGregorian(instant);
874                    }
875                }
876            }
877            return instant;
878        }
879 
880        public int getMaximumTextLength(Locale locale) {
881            return Math.max(iJulianField.getMaximumTextLength(locale),
882                            iGregorianField.getMaximumTextLength(locale));
883        }
884 
885        public int getMaximumShortTextLength(Locale locale) {
886            return Math.max(iJulianField.getMaximumShortTextLength(locale),
887                            iGregorianField.getMaximumShortTextLength(locale));
888        }
889 
890        protected long julianToGregorian(long instant) {
891            if (iConvertByWeekyear) {
892                return julianToGregorianByWeekyear(instant);
893            } else {
894                return julianToGregorianByYear(instant);
895            }
896        }
897 
898        protected long gregorianToJulian(long instant) {
899            if (iConvertByWeekyear) {
900                return gregorianToJulianByWeekyear(instant);
901            } else {
902                return gregorianToJulianByYear(instant);
903            }
904        }
905    }
906 
907    //-----------------------------------------------------------------------
908    /**
909     * Cutover field for variable length fields. These fields internally call
910     * set whenever add is called. As a result, the same correction applied to
911     * set must be applied to add and addWrapField. Knowing when to use this
912     * field requires specific knowledge of how the GJ fields are implemented.
913     */
914    private final class ImpreciseCutoverField extends CutoverField {
915        private static final long serialVersionUID = 3410248757173576441L;
916 
917        /**
918         * Creates a duration field that links back to this.
919         */
920        ImpreciseCutoverField(DateTimeField julianField, DateTimeField gregorianField, long cutoverMillis) {
921            this(julianField, gregorianField, null, cutoverMillis, false);
922        }
923 
924        /**
925         * Uses a shared duration field rather than creating a new one.
926         *
927         * @param durationField shared duration field
928         */
929        ImpreciseCutoverField(DateTimeField julianField, DateTimeField gregorianField,
930                              DurationField durationField, long cutoverMillis)
931        {
932            this(julianField, gregorianField, durationField, cutoverMillis, false);
933        }
934 
935        /**
936         * Uses a shared duration field rather than creating a new one.
937         *
938         * @param durationField shared duration field
939         */
940        ImpreciseCutoverField(DateTimeField julianField, DateTimeField gregorianField,
941                              DurationField durationField,
942                              long cutoverMillis, boolean convertByWeekyear)
943        {
944            super(julianField, gregorianField, cutoverMillis, convertByWeekyear);
945            if (durationField == null) {
946                durationField = new LinkedDurationField(iDurationField, this);
947            }
948            iDurationField = durationField;
949        }
950 
951        public long add(long instant, int value) {
952            if (instant >= iCutover) {
953                instant = iGregorianField.add(instant, value);
954                if (instant < iCutover) {
955                    // Only adjust if gap fully crossed.
956                    if (instant + iGapDuration < iCutover) {
957                        instant = gregorianToJulian(instant);
958                    }
959                }
960            } else {
961                instant = iJulianField.add(instant, value);
962                if (instant >= iCutover) {
963                    // Only adjust if gap fully crossed.
964                    if (instant - iGapDuration >= iCutover) {
965                        instant = julianToGregorian(instant);
966                    }
967                }
968            }
969            return instant;
970        }
971        
972        public long add(long instant, long value) {
973            if (instant >= iCutover) {
974                instant = iGregorianField.add(instant, value);
975                if (instant < iCutover) {
976                    // Only adjust if gap fully crossed.
977                    if (instant + iGapDuration < iCutover) {
978                        instant = gregorianToJulian(instant);
979                    }
980                }
981            } else {
982                instant = iJulianField.add(instant, value);
983                if (instant >= iCutover) {
984                    // Only adjust if gap fully crossed.
985                    if (instant - iGapDuration >= iCutover) {
986                        instant = julianToGregorian(instant);
987                    }
988                }
989            }
990            return instant;
991        }
992 
993        public int getDifference(long minuendInstant, long subtrahendInstant) {
994            if (minuendInstant >= iCutover) {
995                if (subtrahendInstant >= iCutover) {
996                    return iGregorianField.getDifference(minuendInstant, subtrahendInstant);
997                }
998                // Remember, the add is being reversed. Since subtrahend is
999                // Julian, convert minuend to Julian to match.
1000                minuendInstant = gregorianToJulian(minuendInstant);
1001                return iJulianField.getDifference(minuendInstant, subtrahendInstant);
1002            } else {
1003                if (subtrahendInstant < iCutover) {
1004                    return iJulianField.getDifference(minuendInstant, subtrahendInstant);
1005                }
1006                // Remember, the add is being reversed. Since subtrahend is
1007                // Gregorian, convert minuend to Gregorian to match.
1008                minuendInstant = julianToGregorian(minuendInstant);
1009                return iGregorianField.getDifference(minuendInstant, subtrahendInstant);
1010            }
1011        }
1012 
1013        public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
1014            if (minuendInstant >= iCutover) {
1015                if (subtrahendInstant >= iCutover) {
1016                    return iGregorianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
1017                }
1018                // Remember, the add is being reversed. Since subtrahend is
1019                // Julian, convert minuend to Julian to match.
1020                minuendInstant = gregorianToJulian(minuendInstant);
1021                return iJulianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
1022            } else {
1023                if (subtrahendInstant < iCutover) {
1024                    return iJulianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
1025                }
1026                // Remember, the add is being reversed. Since subtrahend is
1027                // Gregorian, convert minuend to Gregorian to match.
1028                minuendInstant = julianToGregorian(minuendInstant);
1029                return iGregorianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
1030            }
1031        }
1032 
1033        // Since the imprecise fields have durations longer than the gap
1034        // duration, keep these methods simple. The inherited implementations
1035        // produce incorrect results.
1036        //
1037        // Degenerate case: If this field is a month, and the cutover is set
1038        // far into the future, then the gap duration may be so large as to
1039        // reduce the number of months in a year. If the missing month(s) are
1040        // at the beginning or end of the year, then the minimum and maximum
1041        // values are not 1 and 12. I don't expect this case to ever occur.
1042 
1043        public int getMinimumValue(long instant) {
1044            if (instant >= iCutover) {
1045                return iGregorianField.getMinimumValue(instant);
1046            } else {
1047                return iJulianField.getMinimumValue(instant);
1048            }
1049        }
1050 
1051        public int getMaximumValue(long instant) {
1052            if (instant >= iCutover) {
1053                return iGregorianField.getMaximumValue(instant);
1054            } else {
1055                return iJulianField.getMaximumValue(instant);
1056            }
1057        }
1058    }
1059 
1060    //-----------------------------------------------------------------------
1061    /**
1062     * Links the duration back to a ImpreciseCutoverField.
1063     */
1064    private static class LinkedDurationField extends DecoratedDurationField {
1065        private static final long serialVersionUID = 4097975388007713084L;
1066 
1067        private final ImpreciseCutoverField iField;
1068 
1069        LinkedDurationField(DurationField durationField, ImpreciseCutoverField dateTimeField) {
1070            super(durationField, durationField.getType());
1071            iField = dateTimeField;
1072        }
1073 
1074        public long add(long instant, int value) {
1075            return iField.add(instant, value);
1076        }
1077 
1078        public long add(long instant, long value) {
1079            return iField.add(instant, value);
1080        }
1081 
1082        public int getDifference(long minuendInstant, long subtrahendInstant) {
1083            return iField.getDifference(minuendInstant, subtrahendInstant);
1084        }
1085 
1086        public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
1087            return iField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
1088        }
1089    }
1090 
1091}

[all classes][org.joda.time.chrono]
EMMA 2.0.5312 (C) Vladimir Roubtsov