001/*
002 *  Copyright 2001-2005 Stephen Colebourne
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.joda.time.chrono;
017
018import org.joda.time.Chronology;
019import org.joda.time.DateTimeField;
020import org.joda.time.DateTimeZone;
021import org.joda.time.field.StrictDateTimeField;
022
023/**
024 * Wraps another Chronology, ensuring all the fields are strict.
025 * <p>
026 * StrictChronology is thread-safe and immutable.
027 *
028 * @author Brian S O'Neill
029 * @since 1.0
030 * @see StrictDateTimeField
031 * @see LenientChronology
032 */
033public final class StrictChronology extends AssembledChronology {
034
035    /** Serialization lock */
036    private static final long serialVersionUID = 6633006628097111960L;
037
038    /**
039     * Create a StrictChronology for any chronology.
040     *
041     * @param base the chronology to wrap
042     * @throws IllegalArgumentException if chronology is null
043     */
044    public static StrictChronology getInstance(Chronology base) {
045        if (base == null) {
046            throw new IllegalArgumentException("Must supply a chronology");
047        }
048        return new StrictChronology(base);
049    }
050
051    private transient Chronology iWithUTC;
052
053    /**
054     * Create a StrictChronology for any chronology.
055     *
056     * @param base the chronology to wrap
057     */
058    private StrictChronology(Chronology base) {
059        super(base, null);
060    }
061
062    public Chronology withUTC() {
063        if (iWithUTC == null) {
064            if (getZone() == DateTimeZone.UTC) {
065                iWithUTC = this;
066            } else {
067                iWithUTC = StrictChronology.getInstance(getBase().withUTC());
068            }
069        }
070        return iWithUTC;
071    }
072
073    public Chronology withZone(DateTimeZone zone) {
074        if (zone == null) {
075            zone = DateTimeZone.getDefault();
076        }
077        if (zone == DateTimeZone.UTC) {
078            return withUTC();
079        }
080        if (zone == getZone()) {
081            return this;
082        }
083        return StrictChronology.getInstance(getBase().withZone(zone));
084    }
085
086    protected void assemble(Fields fields) {
087        fields.year = convertField(fields.year);
088        fields.yearOfEra = convertField(fields.yearOfEra);
089        fields.yearOfCentury = convertField(fields.yearOfCentury);
090        fields.centuryOfEra = convertField(fields.centuryOfEra);
091        fields.era = convertField(fields.era);
092        fields.dayOfWeek = convertField(fields.dayOfWeek);
093        fields.dayOfMonth = convertField(fields.dayOfMonth);
094        fields.dayOfYear = convertField(fields.dayOfYear);
095        fields.monthOfYear = convertField(fields.monthOfYear);
096        fields.weekOfWeekyear = convertField(fields.weekOfWeekyear);
097        fields.weekyear = convertField(fields.weekyear);
098        fields.weekyearOfCentury = convertField(fields.weekyearOfCentury);
099
100        fields.millisOfSecond = convertField(fields.millisOfSecond);
101        fields.millisOfDay = convertField(fields.millisOfDay);
102        fields.secondOfMinute = convertField(fields.secondOfMinute);
103        fields.secondOfDay = convertField(fields.secondOfDay);
104        fields.minuteOfHour = convertField(fields.minuteOfHour);
105        fields.minuteOfDay = convertField(fields.minuteOfDay);
106        fields.hourOfDay = convertField(fields.hourOfDay);
107        fields.hourOfHalfday = convertField(fields.hourOfHalfday);
108        fields.clockhourOfDay = convertField(fields.clockhourOfDay);
109        fields.clockhourOfHalfday = convertField(fields.clockhourOfHalfday);
110        fields.halfdayOfDay = convertField(fields.halfdayOfDay);
111    }
112
113    private static final DateTimeField convertField(DateTimeField field) {
114        return StrictDateTimeField.getInstance(field);
115    }
116
117    //-----------------------------------------------------------------------
118    /**
119     * A strict chronology is only equal to a strict chronology with the
120     * same base chronology.
121     * 
122     * @param obj  the object to compare to
123     * @return true if equal
124     * @since 1.4
125     */
126    public boolean equals(Object obj) {
127        if (this == obj) {
128            return true;
129        }
130        if (obj instanceof StrictChronology == false) {
131            return false;
132        }
133        StrictChronology chrono = (StrictChronology) obj;
134        return getBase().equals(chrono.getBase());
135    }
136
137    /**
138     * A suitable hashcode for the chronology.
139     * 
140     * @return the hashcode
141     * @since 1.4
142     */
143    public int hashCode() {
144        return 352831696 + getBase().hashCode() * 7;
145    }
146
147    /**
148     * A debugging string for the chronology.
149     * 
150     * @return the debugging string
151     */
152    public String toString() {
153        return "StrictChronology[" + getBase().toString() + ']';
154    }
155
156}