0001: /*
0002: * Copyright 2001-2007 Stephen Colebourne
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: package org.joda.time;
0017:
0018: import java.io.IOException;
0019: import java.io.ObjectInputStream;
0020: import java.io.ObjectOutputStream;
0021: import java.io.Serializable;
0022: import java.util.Calendar;
0023: import java.util.Date;
0024: import java.util.HashSet;
0025: import java.util.Locale;
0026: import java.util.Set;
0027:
0028: import org.joda.time.base.BaseLocal;
0029: import org.joda.time.chrono.ISOChronology;
0030: import org.joda.time.convert.ConverterManager;
0031: import org.joda.time.convert.PartialConverter;
0032: import org.joda.time.field.AbstractReadableInstantFieldProperty;
0033: import org.joda.time.field.FieldUtils;
0034: import org.joda.time.format.DateTimeFormat;
0035: import org.joda.time.format.ISODateTimeFormat;
0036:
0037: /**
0038: * LocalDate is an immutable datetime class representing a date
0039: * without a time zone.
0040: * <p>
0041: * LocalDate implements the {@link ReadablePartial} interface.
0042: * To do this, the interface methods focus on the key fields -
0043: * Year, MonthOfYear and DayOfMonth.
0044: * However, <b>all</b> date fields may in fact be queried.
0045: * <p>
0046: * LocalDate differs from DateMidnight in that this class does not
0047: * have a time zone and does not represent a single instant in time.
0048: * <p>
0049: * Calculations on LocalDate are performed using a {@link Chronology}.
0050: * This chronology will be set internally to be in the UTC time zone
0051: * for all calculations.
0052: *
0053: * <p>Each individual field can be queried in two ways:
0054: * <ul>
0055: * <li><code>getMonthOfYear()</code>
0056: * <li><code>monthOfYear().get()</code>
0057: * </ul>
0058: * The second technique also provides access to other useful methods on the
0059: * field:
0060: * <ul>
0061: * <li>numeric value
0062: * <li>text value
0063: * <li>short text value
0064: * <li>maximum/minimum values
0065: * <li>add/subtract
0066: * <li>set
0067: * <li>rounding
0068: * </ul>
0069: *
0070: * <p>
0071: * LocalDate is thread-safe and immutable, provided that the Chronology is as well.
0072: * All standard Chronology classes supplied are thread-safe and immutable.
0073: *
0074: * @author Stephen Colebourne
0075: * @since 1.3
0076: */
0077: public final class LocalDate extends BaseLocal implements
0078: ReadablePartial, Serializable {
0079:
0080: /** Serialization lock */
0081: private static final long serialVersionUID = -8775358157899L;
0082:
0083: /** The index of the year field in the field array */
0084: private static final int YEAR = 0;
0085: /** The index of the monthOfYear field in the field array */
0086: private static final int MONTH_OF_YEAR = 1;
0087: /** The index of the dayOfMonth field in the field array */
0088: private static final int DAY_OF_MONTH = 2;
0089: /** Set of known duration types. */
0090: private static final Set DATE_DURATION_TYPES = new HashSet();
0091: static {
0092: DATE_DURATION_TYPES.add(DurationFieldType.days());
0093: DATE_DURATION_TYPES.add(DurationFieldType.weeks());
0094: DATE_DURATION_TYPES.add(DurationFieldType.months());
0095: DATE_DURATION_TYPES.add(DurationFieldType.weekyears());
0096: DATE_DURATION_TYPES.add(DurationFieldType.years());
0097: DATE_DURATION_TYPES.add(DurationFieldType.centuries());
0098: // eras are supported, although the DurationField generally isn't
0099: DATE_DURATION_TYPES.add(DurationFieldType.eras());
0100: }
0101:
0102: /** The local millis from 1970-01-01T00:00:00 */
0103: private long iLocalMillis;
0104: /** The chronology to use in UTC */
0105: private Chronology iChronology;
0106:
0107: //-----------------------------------------------------------------------
0108: /**
0109: * Constructs a LocalDate from a <code>java.util.Calendar</code>
0110: * using exactly the same field values avoiding any time zone effects.
0111: * <p>
0112: * Each field is queried from the Calendar and assigned to the LocalDate.
0113: * This is useful if you have been using the Calendar as a local date,
0114: * ignoing the zone.
0115: * <p>
0116: * This factory method ignores the type of the calendar and always
0117: * creates a LocalDate with ISO chronology. It is expected that you
0118: * will only pass in instances of <code>GregorianCalendar</code> however
0119: * this is not validated.
0120: *
0121: * @param calendar the Calendar to extract fields from
0122: * @return the created LocalDate
0123: * @throws IllegalArgumentException if the calendar is null
0124: * @throws IllegalArgumentException if the date is invalid for the ISO chronology
0125: */
0126: public static LocalDate fromCalendarFields(Calendar calendar) {
0127: if (calendar == null) {
0128: throw new IllegalArgumentException(
0129: "The calendar must not be null");
0130: }
0131: return new LocalDate(calendar.get(Calendar.YEAR), calendar
0132: .get(Calendar.MONTH) + 1, calendar
0133: .get(Calendar.DAY_OF_MONTH));
0134: }
0135:
0136: /**
0137: * Constructs a LocalDate from a <code>java.util.Date</code>
0138: * using exactly the same field values avoiding any time zone effects.
0139: * <p>
0140: * Each field is queried from the Date and assigned to the LocalDate.
0141: * This is useful if you have been using the Date as a local date,
0142: * ignoing the zone.
0143: * <p>
0144: * This factory method always creates a LocalDate with ISO chronology.
0145: *
0146: * @param date the Date to extract fields from
0147: * @return the created LocalDate
0148: * @throws IllegalArgumentException if the calendar is null
0149: * @throws IllegalArgumentException if the date is invalid for the ISO chronology
0150: */
0151: public static LocalDate fromDateFields(Date date) {
0152: if (date == null) {
0153: throw new IllegalArgumentException(
0154: "The date must not be null");
0155: }
0156: return new LocalDate(date.getYear() + 1900,
0157: date.getMonth() + 1, date.getDate());
0158: }
0159:
0160: //-----------------------------------------------------------------------
0161: /**
0162: * Constructs an instance set to the current local time evaluated using
0163: * ISO chronology in the default zone.
0164: * <p>
0165: * Once the constructor is completed, the zone is no longer used.
0166: */
0167: public LocalDate() {
0168: this (DateTimeUtils.currentTimeMillis(), ISOChronology
0169: .getInstance());
0170: }
0171:
0172: /**
0173: * Constructs an instance set to the current local time evaluated using
0174: * ISO chronology in the specified zone.
0175: * <p>
0176: * If the specified time zone is null, the default zone is used.
0177: * Once the constructor is completed, the zone is no longer used.
0178: *
0179: * @param zone the time zone, null means default zone
0180: */
0181: public LocalDate(DateTimeZone zone) {
0182: this (DateTimeUtils.currentTimeMillis(), ISOChronology
0183: .getInstance(zone));
0184: }
0185:
0186: /**
0187: * Constructs an instance set to the current local time evaluated using
0188: * specified chronology.
0189: * <p>
0190: * If the chronology is null, ISO chronology in the default time zone is used.
0191: * Once the constructor is completed, the zone is no longer used.
0192: *
0193: * @param chronology the chronology, null means ISOChronology in default zone
0194: */
0195: public LocalDate(Chronology chronology) {
0196: this (DateTimeUtils.currentTimeMillis(), chronology);
0197: }
0198:
0199: //-----------------------------------------------------------------------
0200: /**
0201: * Constructs an instance set to the local time defined by the specified
0202: * instant evaluated using ISO chronology in the default zone.
0203: * <p>
0204: * Once the constructor is completed, the zone is no longer used.
0205: *
0206: * @param instant the milliseconds from 1970-01-01T00:00:00Z
0207: */
0208: public LocalDate(long instant) {
0209: this (instant, ISOChronology.getInstance());
0210: }
0211:
0212: /**
0213: * Constructs an instance set to the local time defined by the specified
0214: * instant evaluated using ISO chronology in the specified zone.
0215: * <p>
0216: * If the specified time zone is null, the default zone is used.
0217: * Once the constructor is completed, the zone is no longer used.
0218: *
0219: * @param instant the milliseconds from 1970-01-01T00:00:00Z
0220: * @param zone the time zone, null means default zone
0221: */
0222: public LocalDate(long instant, DateTimeZone zone) {
0223: this (instant, ISOChronology.getInstance(zone));
0224: }
0225:
0226: /**
0227: * Constructs an instance set to the local time defined by the specified
0228: * instant evaluated using the specified chronology.
0229: * <p>
0230: * If the chronology is null, ISO chronology in the default zone is used.
0231: * Once the constructor is completed, the zone is no longer used.
0232: *
0233: * @param instant the milliseconds from 1970-01-01T00:00:00Z
0234: * @param chronology the chronology, null means ISOChronology in default zone
0235: */
0236: public LocalDate(long instant, Chronology chronology) {
0237: chronology = DateTimeUtils.getChronology(chronology);
0238:
0239: long localMillis = chronology.getZone().getMillisKeepLocal(
0240: DateTimeZone.UTC, instant);
0241: chronology = chronology.withUTC();
0242: iLocalMillis = chronology.dayOfMonth().roundFloor(localMillis);
0243: iChronology = chronology;
0244: }
0245:
0246: //-----------------------------------------------------------------------
0247: /**
0248: * Constructs an instance from an Object that represents a datetime.
0249: * The time zone will be retrieved from the object if possible,
0250: * otherwise the default time zone will be used.
0251: * <p>
0252: * If the object contains no chronology, <code>ISOChronology</code> is used.
0253: * Once the constructor is completed, the zone is no longer used.
0254: * <p>
0255: * The recognised object types are defined in
0256: * {@link org.joda.time.convert.ConverterManager ConverterManager} and
0257: * include ReadablePartial, ReadableInstant, String, Calendar and Date.
0258: * The String formats are described by {@link ISODateTimeFormat#localDateParser()}.
0259: * The default String converter ignores the zone and only parses the field values.
0260: *
0261: * @param instant the datetime object
0262: * @throws IllegalArgumentException if the instant is invalid
0263: */
0264: public LocalDate(Object instant) {
0265: this (instant, (Chronology) null);
0266: }
0267:
0268: /**
0269: * Constructs an instance from an Object that represents a datetime,
0270: * forcing the time zone to that specified.
0271: * <p>
0272: * If the object contains no chronology, <code>ISOChronology</code> is used.
0273: * If the specified time zone is null, the default zone is used.
0274: * Once the constructor is completed, the zone is no longer used.
0275: * <p>
0276: * The recognised object types are defined in
0277: * {@link org.joda.time.convert.ConverterManager ConverterManager} and
0278: * include ReadablePartial, ReadableInstant, String, Calendar and Date.
0279: * The String formats are described by {@link ISODateTimeFormat#localDateParser()}.
0280: * The default String converter ignores the zone and only parses the field values.
0281: *
0282: * @param instant the datetime object
0283: * @param zone the time zone
0284: * @throws IllegalArgumentException if the instant is invalid
0285: */
0286: public LocalDate(Object instant, DateTimeZone zone) {
0287: PartialConverter converter = ConverterManager.getInstance()
0288: .getPartialConverter(instant);
0289: Chronology chronology = converter.getChronology(instant, zone);
0290: chronology = DateTimeUtils.getChronology(chronology);
0291: iChronology = chronology.withUTC();
0292: int[] values = converter.getPartialValues(this , instant,
0293: chronology, ISODateTimeFormat.localDateParser());
0294: iLocalMillis = iChronology.getDateTimeMillis(values[0],
0295: values[1], values[2], 0);
0296: }
0297:
0298: /**
0299: * Constructs an instance from an Object that represents a datetime,
0300: * using the specified chronology.
0301: * <p>
0302: * If the chronology is null, ISO in the default time zone is used.
0303: * Once the constructor is completed, the zone is no longer used.
0304: * <p>
0305: * The recognised object types are defined in
0306: * {@link org.joda.time.convert.ConverterManager ConverterManager} and
0307: * include ReadablePartial, ReadableInstant, String, Calendar and Date.
0308: * The String formats are described by {@link ISODateTimeFormat#localDateParser()}.
0309: * The default String converter ignores the zone and only parses the field values.
0310: *
0311: * @param instant the datetime object
0312: * @param chronology the chronology
0313: * @throws IllegalArgumentException if the instant is invalid
0314: */
0315: public LocalDate(Object instant, Chronology chronology) {
0316: PartialConverter converter = ConverterManager.getInstance()
0317: .getPartialConverter(instant);
0318: chronology = converter.getChronology(instant, chronology);
0319: chronology = DateTimeUtils.getChronology(chronology);
0320: iChronology = chronology.withUTC();
0321: int[] values = converter.getPartialValues(this , instant,
0322: chronology, ISODateTimeFormat.localDateParser());
0323: iLocalMillis = iChronology.getDateTimeMillis(values[0],
0324: values[1], values[2], 0);
0325: }
0326:
0327: //-----------------------------------------------------------------------
0328: /**
0329: * Constructs an instance set to the specified date and time
0330: * using <code>ISOChronology</code>.
0331: *
0332: * @param year the year
0333: * @param monthOfYear the month of the year
0334: * @param dayOfMonth the day of the month
0335: */
0336: public LocalDate(int year, int monthOfYear, int dayOfMonth) {
0337: this (year, monthOfYear, dayOfMonth, ISOChronology
0338: .getInstanceUTC());
0339: }
0340:
0341: /**
0342: * Constructs an instance set to the specified date and time
0343: * using the specified chronology, whose zone is ignored.
0344: * <p>
0345: * If the chronology is null, <code>ISOChronology</code> is used.
0346: *
0347: * @param year the year
0348: * @param monthOfYear the month of the year
0349: * @param dayOfMonth the day of the month
0350: * @param chronology the chronology, null means ISOChronology in default zone
0351: */
0352: public LocalDate(int year, int monthOfYear, int dayOfMonth,
0353: Chronology chronology) {
0354: super ();
0355: chronology = DateTimeUtils.getChronology(chronology).withUTC();
0356: long instant = chronology.getDateTimeMillis(year, monthOfYear,
0357: dayOfMonth, 0);
0358: iChronology = chronology;
0359: iLocalMillis = instant;
0360: }
0361:
0362: //-----------------------------------------------------------------------
0363: /**
0364: * Gets the number of fields in this partial, which is three.
0365: * The supported fields are Year, MonthOfYear and DayOfMonth.
0366: * Note that all fields from day and above may in fact be queried via
0367: * other methods.
0368: *
0369: * @return the field count, three
0370: */
0371: public int size() {
0372: return 3;
0373: }
0374:
0375: /**
0376: * Gets the field for a specific index in the chronology specified.
0377: * <p>
0378: * This method must not use any instance variables.
0379: *
0380: * @param index the index to retrieve
0381: * @param chrono the chronology to use
0382: * @return the field
0383: */
0384: protected DateTimeField getField(int index, Chronology chrono) {
0385: switch (index) {
0386: case YEAR:
0387: return chrono.year();
0388: case MONTH_OF_YEAR:
0389: return chrono.monthOfYear();
0390: case DAY_OF_MONTH:
0391: return chrono.dayOfMonth();
0392: default:
0393: throw new IndexOutOfBoundsException("Invalid index: "
0394: + index);
0395: }
0396: }
0397:
0398: /**
0399: * Gets the value of the field at the specifed index.
0400: * <p>
0401: * This method is required to support the <code>ReadablePartial</code>
0402: * interface. The supported fields are Year, MonthOfYear and DayOfMonth.
0403: * Note that all fields from day and above may in fact be queried via
0404: * other methods.
0405: *
0406: * @param index the index, zero to two
0407: * @return the value
0408: * @throws IndexOutOfBoundsException if the index is invalid
0409: */
0410: public int getValue(int index) {
0411: switch (index) {
0412: case YEAR:
0413: return getChronology().year().get(getLocalMillis());
0414: case MONTH_OF_YEAR:
0415: return getChronology().monthOfYear().get(getLocalMillis());
0416: case DAY_OF_MONTH:
0417: return getChronology().dayOfMonth().get(getLocalMillis());
0418: default:
0419: throw new IndexOutOfBoundsException("Invalid index: "
0420: + index);
0421: }
0422: }
0423:
0424: //-----------------------------------------------------------------------
0425: /**
0426: * Get the value of one of the fields of a datetime.
0427: * <p>
0428: * This method gets the value of the specified field.
0429: * For example:
0430: * <pre>
0431: * LocalDate dt = LocalDate.nowDefaultZone();
0432: * int year = dt.get(DateTimeFieldType.year());
0433: * </pre>
0434: *
0435: * @param fieldType a field type, usually obtained from DateTimeFieldType, not null
0436: * @return the value of that field
0437: * @throws IllegalArgumentException if the field type is null or unsupported
0438: */
0439: public int get(DateTimeFieldType fieldType) {
0440: if (fieldType == null) {
0441: throw new IllegalArgumentException(
0442: "The DateTimeFieldType must not be null");
0443: }
0444: if (isSupported(fieldType) == false) {
0445: throw new IllegalArgumentException("Field '" + fieldType
0446: + "' is not supported");
0447: }
0448: return fieldType.getField(getChronology())
0449: .get(getLocalMillis());
0450: }
0451:
0452: /**
0453: * Checks if the field type specified is supported by this
0454: * local date and chronology.
0455: * This can be used to avoid exceptions in {@link #get(DateTimeFieldType)}.
0456: *
0457: * @param type a field type, usually obtained from DateTimeFieldType
0458: * @return true if the field type is supported
0459: */
0460: public boolean isSupported(DateTimeFieldType type) {
0461: if (type == null) {
0462: return false;
0463: }
0464: DurationFieldType durType = type.getDurationType();
0465: if (DATE_DURATION_TYPES.contains(durType)
0466: || durType.getField(getChronology()).getUnitMillis() >= getChronology()
0467: .days().getUnitMillis()) {
0468: return type.getField(getChronology()).isSupported();
0469: }
0470: return false;
0471: }
0472:
0473: /**
0474: * Checks if the duration type specified is supported by this
0475: * local date and chronology.
0476: *
0477: * @param type a duration type, usually obtained from DurationFieldType
0478: * @return true if the field type is supported
0479: */
0480: public boolean isSupported(DurationFieldType type) {
0481: if (type == null) {
0482: return false;
0483: }
0484: DurationField field = type.getField(getChronology());
0485: if (DATE_DURATION_TYPES.contains(type)
0486: || field.getUnitMillis() >= getChronology().days()
0487: .getUnitMillis()) {
0488: return field.isSupported();
0489: }
0490: return false;
0491: }
0492:
0493: //-----------------------------------------------------------------------
0494: /**
0495: * Gets the local milliseconds from the Java epoch
0496: * of 1970-01-01T00:00:00 (not fixed to any specific time zone).
0497: *
0498: * @return the number of milliseconds since 1970-01-01T00:00:00
0499: * @since 1.5 (previously private)
0500: */
0501: protected long getLocalMillis() {
0502: return iLocalMillis;
0503: }
0504:
0505: /**
0506: * Gets the chronology of the date.
0507: *
0508: * @return the Chronology that the date is using
0509: */
0510: public Chronology getChronology() {
0511: return iChronology;
0512: }
0513:
0514: //-----------------------------------------------------------------------
0515: /**
0516: * Compares this ReadablePartial with another returning true if the chronology,
0517: * field types and values are equal.
0518: *
0519: * @param partial an object to check against
0520: * @return true if fields and values are equal
0521: */
0522: public boolean equals(Object partial) {
0523: // override to perform faster
0524: if (this == partial) {
0525: return true;
0526: }
0527: if (partial instanceof LocalDate) {
0528: LocalDate other = (LocalDate) partial;
0529: if (iChronology.equals(other.iChronology)) {
0530: return iLocalMillis == other.iLocalMillis;
0531: }
0532: }
0533: return super .equals(partial);
0534: }
0535:
0536: /**
0537: * Compares this partial with another returning an integer
0538: * indicating the order.
0539: * <p>
0540: * The fields are compared in order, from largest to smallest.
0541: * The first field that is non-equal is used to determine the result.
0542: * <p>
0543: * The specified object must be a partial instance whose field types
0544: * match those of this partial.
0545: * <p>
0546: * NOTE: This implementation violates the Comparable contract.
0547: * This method will accept any instance of ReadablePartial as input.
0548: * However, it is possible that some implementations of ReadablePartial
0549: * exist that do not extend AbstractPartial, and thus will throw a
0550: * ClassCastException if compared in the opposite direction.
0551: * The cause of this problem is that ReadablePartial doesn't define
0552: * the compareTo() method, however we can't change that until v2.0.
0553: *
0554: * @param partial an object to check against
0555: * @return negative if this is less, zero if equal, positive if greater
0556: * @throws ClassCastException if the partial is the wrong class
0557: * or if it has field types that don't match
0558: * @throws NullPointerException if the partial is null
0559: */
0560: public int compareTo(Object partial) {
0561: // override to perform faster
0562: if (this == partial) {
0563: return 0;
0564: }
0565: if (partial instanceof LocalDate) {
0566: LocalDate other = (LocalDate) partial;
0567: if (iChronology.equals(other.iChronology)) {
0568: return (iLocalMillis < other.iLocalMillis ? -1
0569: : (iLocalMillis == other.iLocalMillis ? 0 : 1));
0570:
0571: }
0572: }
0573: return super .compareTo(partial);
0574: }
0575:
0576: //-----------------------------------------------------------------------
0577: /**
0578: * Converts this LocalDate to a full datetime at the earliest valid time
0579: * for the date using the default time zone.
0580: * <p>
0581: * The time will normally be midnight, as that is the earliest time on
0582: * any given day. However, in some time zones when Daylight Savings Time
0583: * starts, there is no midnight because time jumps from 11:59 to 01:00.
0584: * This method handles that situation by returning 01:00 on that date.
0585: * <p>
0586: * This instance is immutable and unaffected by this method call.
0587: *
0588: * @return this date as a datetime at the start of the day
0589: * @since 1.5
0590: */
0591: public DateTime toDateTimeAtStartOfDay() {
0592: return toDateTimeAtStartOfDay(null);
0593: }
0594:
0595: /**
0596: * Converts this LocalDate to a full datetime at the earliest valid time
0597: * for the date using the specified time zone.
0598: * <p>
0599: * The time will normally be midnight, as that is the earliest time on
0600: * any given day. However, in some time zones when Daylight Savings Time
0601: * starts, there is no midnight because time jumps from 11:59 to 01:00.
0602: * This method handles that situation by returning 01:00 on that date.
0603: * <p>
0604: * This method uses the chronology from this instance plus the time zone
0605: * specified.
0606: * <p>
0607: * This instance is immutable and unaffected by this method call.
0608: *
0609: * @param zone the zone to use, null means default zone
0610: * @return this date as a datetime at the start of the day
0611: * @since 1.5
0612: */
0613: public DateTime toDateTimeAtStartOfDay(DateTimeZone zone) {
0614: zone = DateTimeUtils.getZone(zone);
0615: Chronology chrono = getChronology().withZone(zone);
0616: long localMillis = getLocalMillis() + 6L
0617: * DateTimeConstants.MILLIS_PER_HOUR;
0618: long instant = zone.convertLocalToUTC(localMillis, false);
0619: instant = chrono.dayOfMonth().roundFloor(instant);
0620: return new DateTime(instant, chrono);
0621: }
0622:
0623: //-----------------------------------------------------------------------
0624: /**
0625: * Converts this LocalDate to a full datetime at midnight using the default
0626: * time zone.
0627: * <p>
0628: * This method will throw an exception if the default time zone switches
0629: * to Daylight Savings Time at midnight and this LocalDate represents
0630: * that switchover date. The problem is that there is no such time as
0631: * midnight on the required date, and as such an exception is thrown.
0632: * <p>
0633: * This instance is immutable and unaffected by this method call.
0634: *
0635: * @return this date as a datetime at midnight
0636: * @deprecated Use {@link #toDateTimeAtStartOfDay()} which won't throw an exception
0637: */
0638: public DateTime toDateTimeAtMidnight() {
0639: return toDateTimeAtMidnight(null);
0640: }
0641:
0642: /**
0643: * Converts this LocalDate to a full datetime at midnight using the
0644: * specified time zone.
0645: * <p>
0646: * This method will throw an exception if the time zone switches
0647: * to Daylight Savings Time at midnight and this LocalDate represents
0648: * that switchover date. The problem is that there is no such time as
0649: * midnight on the required date, and as such an exception is thrown.
0650: * <p>
0651: * This method uses the chronology from this instance plus the time zone
0652: * specified.
0653: * <p>
0654: * This instance is immutable and unaffected by this method call.
0655: *
0656: * @param zone the zone to use, null means default zone
0657: * @return this date as a datetime at midnight
0658: * @deprecated Use {@link #toDateTimeAtStartOfDay(DateTimeZone)} which won't throw an exception
0659: */
0660: public DateTime toDateTimeAtMidnight(DateTimeZone zone) {
0661: zone = DateTimeUtils.getZone(zone);
0662: Chronology chrono = getChronology().withZone(zone);
0663: return new DateTime(getYear(), getMonthOfYear(),
0664: getDayOfMonth(), 0, 0, 0, 0, chrono);
0665: }
0666:
0667: //-----------------------------------------------------------------------
0668: /**
0669: * Converts this LocalDate to a full datetime using the default time zone
0670: * setting the date fields from this instance and the time fields from
0671: * the current time.
0672: * <p>
0673: * This method will throw an exception if the datetime that would be
0674: * created does not exist when the time zone is taken into account.
0675: * <p>
0676: * This instance is immutable and unaffected by this method call.
0677: *
0678: * @return this date as a datetime with the time as the current time
0679: */
0680: public DateTime toDateTimeAtCurrentTime() {
0681: return toDateTimeAtCurrentTime(null);
0682: }
0683:
0684: /**
0685: * Converts this LocalDate to a full datetime using the specified time zone
0686: * setting the date fields from this instance and the time fields from
0687: * the current time.
0688: * <p>
0689: * This method uses the chronology from this instance plus the time zone
0690: * specified.
0691: * <p>
0692: * This method will throw an exception if the datetime that would be
0693: * created does not exist when the time zone is taken into account.
0694: * <p>
0695: * This instance is immutable and unaffected by this method call.
0696: *
0697: * @param zone the zone to use, null means default zone
0698: * @return this date as a datetime with the time as the current time
0699: */
0700: public DateTime toDateTimeAtCurrentTime(DateTimeZone zone) {
0701: zone = DateTimeUtils.getZone(zone);
0702: Chronology chrono = getChronology().withZone(zone);
0703: long instantMillis = DateTimeUtils.currentTimeMillis();
0704: long resolved = chrono.set(this , instantMillis);
0705: return new DateTime(resolved, chrono);
0706: }
0707:
0708: //-----------------------------------------------------------------------
0709: /**
0710: * Converts this LocalDate to a DateMidnight in the default time zone.
0711: * <p>
0712: * As from v1.5, you are recommended to avoid DateMidnight and use
0713: * {@link #toDateTimeAtStartOfDay()} instead because of the exception
0714: * detailed below.
0715: * <p>
0716: * This method will throw an exception if the default time zone switches
0717: * to Daylight Savings Time at midnight and this LocalDate represents
0718: * that switchover date. The problem is that there is no such time as
0719: * midnight on the required date, and as such an exception is thrown.
0720: * <p>
0721: * This instance is immutable and unaffected by this method call.
0722: *
0723: * @return the DateMidnight instance in the default zone
0724: */
0725: public DateMidnight toDateMidnight() {
0726: return toDateMidnight(null);
0727: }
0728:
0729: /**
0730: * Converts this LocalDate to a DateMidnight.
0731: * <p>
0732: * As from v1.5, you are recommended to avoid DateMidnight and use
0733: * {@link #toDateTimeAtStartOfDay()} instead because of the exception
0734: * detailed below.
0735: * <p>
0736: * This method will throw an exception if the time zone switches
0737: * to Daylight Savings Time at midnight and this LocalDate represents
0738: * that switchover date. The problem is that there is no such time as
0739: * midnight on the required date, and as such an exception is thrown.
0740: * <p>
0741: * This instance is immutable and unaffected by this method call.
0742: *
0743: * @param zone the zone to get the DateMidnight in, null means default zone
0744: * @return the DateMidnight instance
0745: */
0746: public DateMidnight toDateMidnight(DateTimeZone zone) {
0747: zone = DateTimeUtils.getZone(zone);
0748: Chronology chrono = getChronology().withZone(zone);
0749: return new DateMidnight(getYear(), getMonthOfYear(),
0750: getDayOfMonth(), chrono);
0751: }
0752:
0753: //-----------------------------------------------------------------------
0754: /**
0755: * Converts this object to a LocalDateTime using a LocalTime to fill in
0756: * the missing fields.
0757: * <p>
0758: * The resulting chronology is determined by the chronology of this
0759: * LocalDate. The chronology of the time must also match.
0760: * If the time is null an exception is thrown.
0761: * <p>
0762: * This instance is immutable and unaffected by this method call.
0763: *
0764: * @param time the time of day to use, must not be null
0765: * @return the LocalDateTime instance
0766: * @throws IllegalArgumentException if the time is null
0767: * @throws IllegalArgumentException if the chronology of the time does not match
0768: * @since 1.5
0769: */
0770: public LocalDateTime toLocalDateTime(LocalTime time) {
0771: if (time == null) {
0772: throw new IllegalArgumentException(
0773: "The time must not be null");
0774: }
0775: if (getChronology() != time.getChronology()) {
0776: throw new IllegalArgumentException(
0777: "The chronology of the time does not match");
0778: }
0779: long localMillis = getLocalMillis() + time.getLocalMillis();
0780: return new LocalDateTime(localMillis, getChronology());
0781: }
0782:
0783: //-----------------------------------------------------------------------
0784: /**
0785: * Converts this object to a DateTime using a LocalTime to fill in the
0786: * missing fields and using the default time zone.
0787: * <p>
0788: * The resulting chronology is determined by the chronology of this
0789: * LocalDate. The chronology of the time must match.
0790: * If the time is null, the current time in the date's chronology is used.
0791: * <p>
0792: * This method will throw an exception if the datetime that would be
0793: * created does not exist when the time zone is taken into account.
0794: * <p>
0795: * This instance is immutable and unaffected by this method call.
0796: *
0797: * @param time the time of day to use, null means current time
0798: * @return the DateTime instance
0799: * @throws IllegalArgumentException if the chronology of the time does not match
0800: */
0801: public DateTime toDateTime(LocalTime time) {
0802: return toDateTime(time, null);
0803: }
0804:
0805: /**
0806: * Converts this object to a DateTime using a LocalTime to fill in the
0807: * missing fields.
0808: * <p>
0809: * The resulting chronology is determined by the chronology of this
0810: * LocalDate plus the time zone. The chronology of the time must match.
0811: * If the time is null, the current time in the date's chronology is used.
0812: * <p>
0813: * This method will throw an exception if the datetime that would be
0814: * created does not exist when the time zone is taken into account.
0815: * <p>
0816: * This instance is immutable and unaffected by this method call.
0817: *
0818: * @param time the time of day to use, null means current time
0819: * @param zone the zone to get the DateTime in, null means default
0820: * @return the DateTime instance
0821: * @throws IllegalArgumentException if the chronology of the time does not match
0822: */
0823: public DateTime toDateTime(LocalTime time, DateTimeZone zone) {
0824: if (time != null && getChronology() != time.getChronology()) {
0825: throw new IllegalArgumentException(
0826: "The chronology of the time does not match");
0827: }
0828: Chronology chrono = getChronology().withZone(zone);
0829: long instant = DateTimeUtils.currentTimeMillis();
0830: instant = chrono.set(this , instant);
0831: if (time != null) {
0832: instant = chrono.set(time, instant);
0833: }
0834: return new DateTime(instant, chrono);
0835: }
0836:
0837: //-----------------------------------------------------------------------
0838: /**
0839: * Converts this object to an Interval representing the whole day
0840: * in the default time zone.
0841: * <p>
0842: * This instance is immutable and unaffected by this method call.
0843: *
0844: * @return a interval over the day
0845: */
0846: public Interval toInterval() {
0847: return toInterval(null);
0848: }
0849:
0850: /**
0851: * Converts this object to an Interval representing the whole day.
0852: * <p>
0853: * This instance is immutable and unaffected by this method call.
0854: *
0855: * @param zone the zone to get the Interval in, null means default
0856: * @return a interval over the day
0857: */
0858: public Interval toInterval(DateTimeZone zone) {
0859: zone = DateTimeUtils.getZone(zone);
0860: return toDateMidnight(zone).toInterval();
0861: }
0862:
0863: //-----------------------------------------------------------------------
0864: /**
0865: * Returns a copy of this date with different local millis.
0866: * <p>
0867: * The returned object will be a new instance of the same type.
0868: * Only the millis will change, the chronology is kept.
0869: * The returned object will be either be a new instance or <code>this</code>.
0870: *
0871: * @param newMillis the new millis, from 1970-01-01T00:00:00
0872: * @return a copy of this date with different millis
0873: */
0874: LocalDate withLocalMillis(long newMillis) {
0875: newMillis = iChronology.dayOfMonth().roundFloor(newMillis);
0876: return (newMillis == getLocalMillis() ? this : new LocalDate(
0877: newMillis, getChronology()));
0878: }
0879:
0880: //-----------------------------------------------------------------------
0881: /**
0882: * Returns a copy of this date with the partial set of fields replacing
0883: * those from this instance.
0884: * <p>
0885: * For example, if the partial contains a year and a month then those two
0886: * fields will be changed in the returned instance.
0887: * Unsupported fields are ignored.
0888: * If the partial is null, then <code>this</code> is returned.
0889: *
0890: * @param partial the partial set of fields to apply to this date, null ignored
0891: * @return a copy of this date with a different set of fields
0892: * @throws IllegalArgumentException if any value is invalid
0893: */
0894: public LocalDate withFields(ReadablePartial partial) {
0895: if (partial == null) {
0896: return this ;
0897: }
0898: return withLocalMillis(getChronology().set(partial,
0899: getLocalMillis()));
0900: }
0901:
0902: /**
0903: * Returns a copy of this date with the specified field set to a new value.
0904: * <p>
0905: * For example, if the field type is <code>monthOfYear</code> then the
0906: * month of year field will be changed in the returned instance.
0907: * If the field type is null, then <code>this</code> is returned.
0908: * <p>
0909: * These two lines are equivalent:
0910: * <pre>
0911: * LocalDate updated = dt.withDayOfMonth(6);
0912: * LocalDate updated = dt.withField(DateTimeFieldType.dayOfMonth(), 6);
0913: * </pre>
0914: *
0915: * @param fieldType the field type to set, not null
0916: * @param value the value to set
0917: * @return a copy of this date with the field set
0918: * @throws IllegalArgumentException if the field is null or unsupported
0919: */
0920: public LocalDate withField(DateTimeFieldType fieldType, int value) {
0921: if (fieldType == null) {
0922: throw new IllegalArgumentException("Field must not be null");
0923: }
0924: if (isSupported(fieldType) == false) {
0925: throw new IllegalArgumentException("Field '" + fieldType
0926: + "' is not supported");
0927: }
0928: long instant = fieldType.getField(getChronology()).set(
0929: getLocalMillis(), value);
0930: return withLocalMillis(instant);
0931: }
0932:
0933: /**
0934: * Returns a copy of this date with the value of the specified field increased.
0935: * <p>
0936: * If the addition is zero or the field is null, then <code>this</code> is returned.
0937: * <p>
0938: * These three lines are equivalent:
0939: * <pre>
0940: * LocalDate added = dt.withFieldAdded(DurationFieldType.years(), 6);
0941: * LocalDate added = dt.plusYears(6);
0942: * LocalDate added = dt.plus(Period.years(6));
0943: * </pre>
0944: *
0945: * @param fieldType the field type to add to, not null
0946: * @param amount the amount to add
0947: * @return a copy of this date with the field updated
0948: * @throws IllegalArgumentException if the field is null or unsupported
0949: * @throws ArithmeticException if the result exceeds the internal capacity
0950: */
0951: public LocalDate withFieldAdded(DurationFieldType fieldType,
0952: int amount) {
0953: if (fieldType == null) {
0954: throw new IllegalArgumentException("Field must not be null");
0955: }
0956: if (isSupported(fieldType) == false) {
0957: throw new IllegalArgumentException("Field '" + fieldType
0958: + "' is not supported");
0959: }
0960: if (amount == 0) {
0961: return this ;
0962: }
0963: long instant = fieldType.getField(getChronology()).add(
0964: getLocalMillis(), amount);
0965: return withLocalMillis(instant);
0966: }
0967:
0968: //-----------------------------------------------------------------------
0969: /**
0970: * Returns a copy of this date with the specified period added.
0971: * <p>
0972: * If the addition is zero, then <code>this</code> is returned.
0973: * <p>
0974: * This method is typically used to add multiple copies of complex
0975: * period instances. Adding one field is best achieved using methods
0976: * like {@link #withFieldAdded(DurationFieldType, int)}
0977: * or {@link #plusYears(int)}.
0978: * <p>
0979: * Unsupported time fields are ignored, thus adding a period of 24 hours
0980: * will not have any effect.
0981: *
0982: * @param period the period to add to this one, null means zero
0983: * @param scalar the amount of times to add, such as -1 to subtract once
0984: * @return a copy of this date with the period added
0985: * @throws ArithmeticException if the result exceeds the internal capacity
0986: */
0987: public LocalDate withPeriodAdded(ReadablePeriod period, int scalar) {
0988: if (period == null || scalar == 0) {
0989: return this ;
0990: }
0991: long instant = getLocalMillis();
0992: Chronology chrono = getChronology();
0993: for (int i = 0; i < period.size(); i++) {
0994: long value = FieldUtils.safeMultiply(period.getValue(i),
0995: scalar);
0996: DurationFieldType type = period.getFieldType(i);
0997: if (isSupported(type)) {
0998: instant = type.getField(chrono).add(instant, value);
0999: }
1000: }
1001: return withLocalMillis(instant);
1002: }
1003:
1004: //-----------------------------------------------------------------------
1005: /**
1006: * Returns a copy of this date with the specified period added.
1007: * <p>
1008: * If the amount is zero or null, then <code>this</code> is returned.
1009: * <p>
1010: * This method is typically used to add complex period instances.
1011: * Adding one field is best achieved using methods
1012: * like {@link #plusYears(int)}.
1013: * <p>
1014: * Unsupported time fields are ignored, thus adding a period of 24 hours
1015: * will not have any effect.
1016: *
1017: * @param period the period to add to this one, null means zero
1018: * @return a copy of this date with the period added
1019: * @throws ArithmeticException if the result exceeds the internal capacity
1020: */
1021: public LocalDate plus(ReadablePeriod period) {
1022: return withPeriodAdded(period, 1);
1023: }
1024:
1025: //-----------------------------------------------------------------------
1026: /**
1027: * Returns a copy of this date plus the specified number of years.
1028: * <p>
1029: * This LocalDate instance is immutable and unaffected by this method call.
1030: * <p>
1031: * The following three lines are identical in effect:
1032: * <pre>
1033: * LocalDate added = dt.plusYears(6);
1034: * LocalDate added = dt.plus(Period.years(6));
1035: * LocalDate added = dt.withFieldAdded(DurationFieldType.years(), 6);
1036: * </pre>
1037: *
1038: * @param years the amount of years to add, may be negative
1039: * @return the new LocalDate plus the increased years
1040: */
1041: public LocalDate plusYears(int years) {
1042: if (years == 0) {
1043: return this ;
1044: }
1045: long instant = getChronology().years().add(getLocalMillis(),
1046: years);
1047: return withLocalMillis(instant);
1048: }
1049:
1050: /**
1051: * Returns a copy of this date plus the specified number of months.
1052: * <p>
1053: * This LocalDate instance is immutable and unaffected by this method call.
1054: * <p>
1055: * The following three lines are identical in effect:
1056: * <pre>
1057: * LocalDate added = dt.plusMonths(6);
1058: * LocalDate added = dt.plus(Period.months(6));
1059: * LocalDate added = dt.withFieldAdded(DurationFieldType.months(), 6);
1060: * </pre>
1061: *
1062: * @param months the amount of months to add, may be negative
1063: * @return the new LocalDate plus the increased months
1064: */
1065: public LocalDate plusMonths(int months) {
1066: if (months == 0) {
1067: return this ;
1068: }
1069: long instant = getChronology().months().add(getLocalMillis(),
1070: months);
1071: return withLocalMillis(instant);
1072: }
1073:
1074: /**
1075: * Returns a copy of this date plus the specified number of weeks.
1076: * <p>
1077: * This LocalDate instance is immutable and unaffected by this method call.
1078: * <p>
1079: * The following three lines are identical in effect:
1080: * <pre>
1081: * LocalDate added = dt.plusWeeks(6);
1082: * LocalDate added = dt.plus(Period.weeks(6));
1083: * LocalDate added = dt.withFieldAdded(DurationFieldType.weeks(), 6);
1084: * </pre>
1085: *
1086: * @param weeks the amount of weeks to add, may be negative
1087: * @return the new LocalDate plus the increased weeks
1088: */
1089: public LocalDate plusWeeks(int weeks) {
1090: if (weeks == 0) {
1091: return this ;
1092: }
1093: long instant = getChronology().weeks().add(getLocalMillis(),
1094: weeks);
1095: return withLocalMillis(instant);
1096: }
1097:
1098: /**
1099: * Returns a copy of this date plus the specified number of days.
1100: * <p>
1101: * This LocalDate instance is immutable and unaffected by this method call.
1102: * <p>
1103: * The following three lines are identical in effect:
1104: * <pre>
1105: * LocalDate added = dt.plusDays(6);
1106: * LocalDate added = dt.plus(Period.days(6));
1107: * LocalDate added = dt.withFieldAdded(DurationFieldType.days(), 6);
1108: * </pre>
1109: *
1110: * @param days the amount of days to add, may be negative
1111: * @return the new LocalDate plus the increased days
1112: */
1113: public LocalDate plusDays(int days) {
1114: if (days == 0) {
1115: return this ;
1116: }
1117: long instant = getChronology().days().add(getLocalMillis(),
1118: days);
1119: return withLocalMillis(instant);
1120: }
1121:
1122: //-----------------------------------------------------------------------
1123: /**
1124: * Returns a copy of this date with the specified period taken away.
1125: * <p>
1126: * If the amount is zero or null, then <code>this</code> is returned.
1127: * <p>
1128: * This method is typically used to subtract complex period instances.
1129: * Subtracting one field is best achieved using methods
1130: * like {@link #minusYears(int)}.
1131: * <p>
1132: * Unsupported time fields are ignored, thus subtracting a period of 24 hours
1133: * will not have any effect.
1134: *
1135: * @param period the period to reduce this instant by
1136: * @return a copy of this LocalDate with the period taken away
1137: * @throws ArithmeticException if the result exceeds the internal capacity
1138: */
1139: public LocalDate minus(ReadablePeriod period) {
1140: return withPeriodAdded(period, -1);
1141: }
1142:
1143: //-----------------------------------------------------------------------
1144: /**
1145: * Returns a copy of this date minus the specified number of years.
1146: * <p>
1147: * This LocalDate instance is immutable and unaffected by this method call.
1148: * <p>
1149: * The following three lines are identical in effect:
1150: * <pre>
1151: * LocalDate subtracted = dt.minusYears(6);
1152: * LocalDate subtracted = dt.minus(Period.years(6));
1153: * LocalDate subtracted = dt.withFieldAdded(DurationFieldType.years(), -6);
1154: * </pre>
1155: *
1156: * @param years the amount of years to subtract, may be negative
1157: * @return the new LocalDate minus the increased years
1158: */
1159: public LocalDate minusYears(int years) {
1160: if (years == 0) {
1161: return this ;
1162: }
1163: long instant = getChronology().years().subtract(
1164: getLocalMillis(), years);
1165: return withLocalMillis(instant);
1166: }
1167:
1168: /**
1169: * Returns a copy of this date minus the specified number of months.
1170: * <p>
1171: * This LocalDate instance is immutable and unaffected by this method call.
1172: * <p>
1173: * The following three lines are identical in effect:
1174: * <pre>
1175: * LocalDate subtracted = dt.minusMonths(6);
1176: * LocalDate subtracted = dt.minus(Period.months(6));
1177: * LocalDate subtracted = dt.withFieldAdded(DurationFieldType.months(), -6);
1178: * </pre>
1179: *
1180: * @param months the amount of months to subtract, may be negative
1181: * @return the new LocalDate minus the increased months
1182: */
1183: public LocalDate minusMonths(int months) {
1184: if (months == 0) {
1185: return this ;
1186: }
1187: long instant = getChronology().months().subtract(
1188: getLocalMillis(), months);
1189: return withLocalMillis(instant);
1190: }
1191:
1192: /**
1193: * Returns a copy of this date minus the specified number of weeks.
1194: * <p>
1195: * This LocalDate instance is immutable and unaffected by this method call.
1196: * <p>
1197: * The following three lines are identical in effect:
1198: * <pre>
1199: * LocalDate subtracted = dt.minusWeeks(6);
1200: * LocalDate subtracted = dt.minus(Period.weeks(6));
1201: * LocalDate subtracted = dt.withFieldAdded(DurationFieldType.weeks(), -6);
1202: * </pre>
1203: *
1204: * @param weeks the amount of weeks to subtract, may be negative
1205: * @return the new LocalDate minus the increased weeks
1206: */
1207: public LocalDate minusWeeks(int weeks) {
1208: if (weeks == 0) {
1209: return this ;
1210: }
1211: long instant = getChronology().weeks().subtract(
1212: getLocalMillis(), weeks);
1213: return withLocalMillis(instant);
1214: }
1215:
1216: /**
1217: * Returns a copy of this date minus the specified number of days.
1218: * <p>
1219: * This LocalDate instance is immutable and unaffected by this method call.
1220: * <p>
1221: * The following three lines are identical in effect:
1222: * <pre>
1223: * LocalDate subtracted = dt.minusDays(6);
1224: * LocalDate subtracted = dt.minus(Period.days(6));
1225: * LocalDate subtracted = dt.withFieldAdded(DurationFieldType.days(), -6);
1226: * </pre>
1227: *
1228: * @param days the amount of days to subtract, may be negative
1229: * @return the new LocalDate minus the increased days
1230: */
1231: public LocalDate minusDays(int days) {
1232: if (days == 0) {
1233: return this ;
1234: }
1235: long instant = getChronology().days().subtract(
1236: getLocalMillis(), days);
1237: return withLocalMillis(instant);
1238: }
1239:
1240: //-----------------------------------------------------------------------
1241: /**
1242: * Gets the property object for the specified type, which contains many
1243: * useful methods.
1244: *
1245: * @param fieldType the field type to get the chronology for
1246: * @return the property object
1247: * @throws IllegalArgumentException if the field is null or unsupported
1248: */
1249: public Property property(DateTimeFieldType fieldType) {
1250: if (fieldType == null) {
1251: throw new IllegalArgumentException(
1252: "The DateTimeFieldType must not be null");
1253: }
1254: if (isSupported(fieldType) == false) {
1255: throw new IllegalArgumentException("Field '" + fieldType
1256: + "' is not supported");
1257: }
1258: return new Property(this , fieldType.getField(getChronology()));
1259: }
1260:
1261: //-----------------------------------------------------------------------
1262: /**
1263: * Get the era field value.
1264: *
1265: * @return the era
1266: */
1267: public int getEra() {
1268: return getChronology().era().get(getLocalMillis());
1269: }
1270:
1271: /**
1272: * Get the year of era field value.
1273: *
1274: * @return the year of era
1275: */
1276: public int getCenturyOfEra() {
1277: return getChronology().centuryOfEra().get(getLocalMillis());
1278: }
1279:
1280: /**
1281: * Get the year of era field value.
1282: *
1283: * @return the year of era
1284: */
1285: public int getYearOfEra() {
1286: return getChronology().yearOfEra().get(getLocalMillis());
1287: }
1288:
1289: /**
1290: * Get the year of century field value.
1291: *
1292: * @return the year of century
1293: */
1294: public int getYearOfCentury() {
1295: return getChronology().yearOfCentury().get(getLocalMillis());
1296: }
1297:
1298: /**
1299: * Get the year field value.
1300: *
1301: * @return the year
1302: */
1303: public int getYear() {
1304: return getChronology().year().get(getLocalMillis());
1305: }
1306:
1307: /**
1308: * Get the weekyear field value.
1309: * <p>
1310: * The weekyear is the year that matches with the weekOfWeekyear field.
1311: * In the standard ISO8601 week algorithm, the first week of the year
1312: * is that in which at least 4 days are in the year. As a result of this
1313: * definition, day 1 of the first week may be in the previous year.
1314: * The weekyear allows you to query the effective year for that day.
1315: *
1316: * @return the weekyear
1317: */
1318: public int getWeekyear() {
1319: return getChronology().weekyear().get(getLocalMillis());
1320: }
1321:
1322: /**
1323: * Get the month of year field value.
1324: *
1325: * @return the month of year
1326: */
1327: public int getMonthOfYear() {
1328: return getChronology().monthOfYear().get(getLocalMillis());
1329: }
1330:
1331: /**
1332: * Get the week of weekyear field value.
1333: *
1334: * @return the week of a week based year
1335: */
1336: public int getWeekOfWeekyear() {
1337: return getChronology().weekOfWeekyear().get(getLocalMillis());
1338: }
1339:
1340: /**
1341: * Get the day of year field value.
1342: *
1343: * @return the day of year
1344: */
1345: public int getDayOfYear() {
1346: return getChronology().dayOfYear().get(getLocalMillis());
1347: }
1348:
1349: /**
1350: * Get the day of month field value.
1351: * <p>
1352: * The values for the day of month are defined in {@link org.joda.time.DateTimeConstants}.
1353: *
1354: * @return the day of month
1355: */
1356: public int getDayOfMonth() {
1357: return getChronology().dayOfMonth().get(getLocalMillis());
1358: }
1359:
1360: /**
1361: * Get the day of week field value.
1362: * <p>
1363: * The values for the day of week are defined in {@link org.joda.time.DateTimeConstants}.
1364: *
1365: * @return the day of week
1366: */
1367: public int getDayOfWeek() {
1368: return getChronology().dayOfWeek().get(getLocalMillis());
1369: }
1370:
1371: //-----------------------------------------------------------------------
1372: /**
1373: * Returns a copy of this date with the era field updated.
1374: * <p>
1375: * LocalDate is immutable, so there are no set methods.
1376: * Instead, this method returns a new instance with the value of
1377: * era changed.
1378: *
1379: * @param era the era to set
1380: * @return a copy of this object with the field set
1381: * @throws IllegalArgumentException if the value is invalid
1382: */
1383: public LocalDate withEra(int era) {
1384: return withLocalMillis(getChronology().era().set(
1385: getLocalMillis(), era));
1386: }
1387:
1388: /**
1389: * Returns a copy of this date with the century of era field updated.
1390: * <p>
1391: * LocalDate is immutable, so there are no set methods.
1392: * Instead, this method returns a new instance with the value of
1393: * century of era changed.
1394: *
1395: * @param centuryOfEra the centurey of era to set
1396: * @return a copy of this object with the field set
1397: * @throws IllegalArgumentException if the value is invalid
1398: */
1399: public LocalDate withCenturyOfEra(int centuryOfEra) {
1400: return withLocalMillis(getChronology().centuryOfEra().set(
1401: getLocalMillis(), centuryOfEra));
1402: }
1403:
1404: /**
1405: * Returns a copy of this date with the year of era field updated.
1406: * <p>
1407: * LocalDate is immutable, so there are no set methods.
1408: * Instead, this method returns a new instance with the value of
1409: * year of era changed.
1410: *
1411: * @param yearOfEra the year of era to set
1412: * @return a copy of this object with the field set
1413: * @throws IllegalArgumentException if the value is invalid
1414: */
1415: public LocalDate withYearOfEra(int yearOfEra) {
1416: return withLocalMillis(getChronology().yearOfEra().set(
1417: getLocalMillis(), yearOfEra));
1418: }
1419:
1420: /**
1421: * Returns a copy of this date with the year of century field updated.
1422: * <p>
1423: * LocalDate is immutable, so there are no set methods.
1424: * Instead, this method returns a new instance with the value of
1425: * year of century changed.
1426: *
1427: * @param yearOfCentury the year of century to set
1428: * @return a copy of this object with the field set
1429: * @throws IllegalArgumentException if the value is invalid
1430: */
1431: public LocalDate withYearOfCentury(int yearOfCentury) {
1432: return withLocalMillis(getChronology().yearOfCentury().set(
1433: getLocalMillis(), yearOfCentury));
1434: }
1435:
1436: /**
1437: * Returns a copy of this date with the year field updated.
1438: * <p>
1439: * LocalDate is immutable, so there are no set methods.
1440: * Instead, this method returns a new instance with the value of
1441: * year changed.
1442: *
1443: * @param year the year to set
1444: * @return a copy of this object with the field set
1445: * @throws IllegalArgumentException if the value is invalid
1446: */
1447: public LocalDate withYear(int year) {
1448: return withLocalMillis(getChronology().year().set(
1449: getLocalMillis(), year));
1450: }
1451:
1452: /**
1453: * Returns a copy of this date with the weekyear field updated.
1454: * <p>
1455: * LocalDate is immutable, so there are no set methods.
1456: * Instead, this method returns a new instance with the value of
1457: * weekyear changed.
1458: *
1459: * @param weekyear the weekyear to set
1460: * @return a copy of this object with the field set
1461: * @throws IllegalArgumentException if the value is invalid
1462: */
1463: public LocalDate withWeekyear(int weekyear) {
1464: return withLocalMillis(getChronology().weekyear().set(
1465: getLocalMillis(), weekyear));
1466: }
1467:
1468: /**
1469: * Returns a copy of this date with the month of year field updated.
1470: * <p>
1471: * LocalDate is immutable, so there are no set methods.
1472: * Instead, this method returns a new instance with the value of
1473: * month of year changed.
1474: *
1475: * @param monthOfYear the month of year to set
1476: * @return a copy of this object with the field set
1477: * @throws IllegalArgumentException if the value is invalid
1478: */
1479: public LocalDate withMonthOfYear(int monthOfYear) {
1480: return withLocalMillis(getChronology().monthOfYear().set(
1481: getLocalMillis(), monthOfYear));
1482: }
1483:
1484: /**
1485: * Returns a copy of this date with the week of weekyear field updated.
1486: * <p>
1487: * LocalDate is immutable, so there are no set methods.
1488: * Instead, this method returns a new instance with the value of
1489: * week of weekyear changed.
1490: *
1491: * @param weekOfWeekyear the week of weekyear to set
1492: * @return a copy of this object with the field set
1493: * @throws IllegalArgumentException if the value is invalid
1494: */
1495: public LocalDate withWeekOfWeekyear(int weekOfWeekyear) {
1496: return withLocalMillis(getChronology().weekOfWeekyear().set(
1497: getLocalMillis(), weekOfWeekyear));
1498: }
1499:
1500: /**
1501: * Returns a copy of this date with the day of year field updated.
1502: * <p>
1503: * LocalDate is immutable, so there are no set methods.
1504: * Instead, this method returns a new instance with the value of
1505: * day of year changed.
1506: *
1507: * @param dayOfYear the day of year to set
1508: * @return a copy of this object with the field set
1509: * @throws IllegalArgumentException if the value is invalid
1510: */
1511: public LocalDate withDayOfYear(int dayOfYear) {
1512: return withLocalMillis(getChronology().dayOfYear().set(
1513: getLocalMillis(), dayOfYear));
1514: }
1515:
1516: /**
1517: * Returns a copy of this date with the day of month field updated.
1518: * <p>
1519: * LocalDate is immutable, so there are no set methods.
1520: * Instead, this method returns a new instance with the value of
1521: * day of month changed.
1522: *
1523: * @param dayOfMonth the day of month to set
1524: * @return a copy of this object with the field set
1525: * @throws IllegalArgumentException if the value is invalid
1526: */
1527: public LocalDate withDayOfMonth(int dayOfMonth) {
1528: return withLocalMillis(getChronology().dayOfMonth().set(
1529: getLocalMillis(), dayOfMonth));
1530: }
1531:
1532: /**
1533: * Returns a copy of this date with the day of week field updated.
1534: * <p>
1535: * LocalDate is immutable, so there are no set methods.
1536: * Instead, this method returns a new instance with the value of
1537: * day of week changed.
1538: *
1539: * @param dayOfWeek the day of week to set
1540: * @return a copy of this object with the field set
1541: * @throws IllegalArgumentException if the value is invalid
1542: */
1543: public LocalDate withDayOfWeek(int dayOfWeek) {
1544: return withLocalMillis(getChronology().dayOfWeek().set(
1545: getLocalMillis(), dayOfWeek));
1546: }
1547:
1548: //-----------------------------------------------------------------------
1549: /**
1550: * Get the era property which provides access to advanced functionality.
1551: *
1552: * @return the era property
1553: */
1554: public Property era() {
1555: return new Property(this , getChronology().era());
1556: }
1557:
1558: /**
1559: * Get the century of era property which provides access to advanced functionality.
1560: *
1561: * @return the year of era property
1562: */
1563: public Property centuryOfEra() {
1564: return new Property(this , getChronology().centuryOfEra());
1565: }
1566:
1567: /**
1568: * Get the year of century property which provides access to advanced functionality.
1569: *
1570: * @return the year of era property
1571: */
1572: public Property yearOfCentury() {
1573: return new Property(this , getChronology().yearOfCentury());
1574: }
1575:
1576: /**
1577: * Get the year of era property which provides access to advanced functionality.
1578: *
1579: * @return the year of era property
1580: */
1581: public Property yearOfEra() {
1582: return new Property(this , getChronology().yearOfEra());
1583: }
1584:
1585: /**
1586: * Get the year property which provides access to advanced functionality.
1587: *
1588: * @return the year property
1589: */
1590: public Property year() {
1591: return new Property(this , getChronology().year());
1592: }
1593:
1594: /**
1595: * Get the weekyear property which provides access to advanced functionality.
1596: *
1597: * @return the weekyear property
1598: */
1599: public Property weekyear() {
1600: return new Property(this , getChronology().weekyear());
1601: }
1602:
1603: /**
1604: * Get the month of year property which provides access to advanced functionality.
1605: *
1606: * @return the month of year property
1607: */
1608: public Property monthOfYear() {
1609: return new Property(this , getChronology().monthOfYear());
1610: }
1611:
1612: /**
1613: * Get the week of a week based year property which provides access to advanced functionality.
1614: *
1615: * @return the week of a week based year property
1616: */
1617: public Property weekOfWeekyear() {
1618: return new Property(this , getChronology().weekOfWeekyear());
1619: }
1620:
1621: /**
1622: * Get the day of year property which provides access to advanced functionality.
1623: *
1624: * @return the day of year property
1625: */
1626: public Property dayOfYear() {
1627: return new Property(this , getChronology().dayOfYear());
1628: }
1629:
1630: /**
1631: * Get the day of month property which provides access to advanced functionality.
1632: *
1633: * @return the day of month property
1634: */
1635: public Property dayOfMonth() {
1636: return new Property(this , getChronology().dayOfMonth());
1637: }
1638:
1639: /**
1640: * Get the day of week property which provides access to advanced functionality.
1641: *
1642: * @return the day of week property
1643: */
1644: public Property dayOfWeek() {
1645: return new Property(this , getChronology().dayOfWeek());
1646: }
1647:
1648: //-----------------------------------------------------------------------
1649: /**
1650: * Output the date time in ISO8601 format (yyyy-MM-dd).
1651: *
1652: * @return ISO8601 time formatted string.
1653: */
1654: public String toString() {
1655: return ISODateTimeFormat.date().print(this );
1656: }
1657:
1658: /**
1659: * Output the date using the specified format pattern.
1660: *
1661: * @param pattern the pattern specification, null means use <code>toString</code>
1662: * @see org.joda.time.format.DateTimeFormat
1663: */
1664: public String toString(String pattern) {
1665: if (pattern == null) {
1666: return toString();
1667: }
1668: return DateTimeFormat.forPattern(pattern).print(this );
1669: }
1670:
1671: /**
1672: * Output the date using the specified format pattern.
1673: *
1674: * @param pattern the pattern specification, null means use <code>toString</code>
1675: * @param locale Locale to use, null means default
1676: * @see org.joda.time.format.DateTimeFormat
1677: */
1678: public String toString(String pattern, Locale locale)
1679: throws IllegalArgumentException {
1680: if (pattern == null) {
1681: return toString();
1682: }
1683: return DateTimeFormat.forPattern(pattern).withLocale(locale)
1684: .print(this );
1685: }
1686:
1687: //-----------------------------------------------------------------------
1688: /**
1689: * LocalDate.Property binds a LocalDate to a DateTimeField allowing
1690: * powerful datetime functionality to be easily accessed.
1691: * <p>
1692: * The simplest use of this class is as an alternative get method, here used to
1693: * get the year '1972' (as an int) and the month 'December' (as a String).
1694: * <pre>
1695: * LocalDate dt = new LocalDate(1972, 12, 3, 0, 0);
1696: * int year = dt.year().get();
1697: * String monthStr = dt.month().getAsText();
1698: * </pre>
1699: * <p>
1700: * Methods are also provided that allow date modification. These return
1701: * new instances of LocalDate - they do not modify the original. The example
1702: * below yields two independent immutable date objects 20 years apart.
1703: * <pre>
1704: * LocalDate dt = new LocalDate(1972, 12, 3);
1705: * LocalDate dt1920 = dt.year().setCopy(1920);
1706: * </pre>
1707: * <p>
1708: * LocalDate.Property itself is thread-safe and immutable, as well as the
1709: * LocalDate being operated on.
1710: *
1711: * @author Stephen Colebourne
1712: * @author Brian S O'Neill
1713: * @since 1.3
1714: */
1715: public static final class Property extends
1716: AbstractReadableInstantFieldProperty {
1717:
1718: /** Serialization version */
1719: private static final long serialVersionUID = -3193829732634L;
1720:
1721: /** The instant this property is working against */
1722: private transient LocalDate iInstant;
1723: /** The field this property is working against */
1724: private transient DateTimeField iField;
1725:
1726: /**
1727: * Constructor.
1728: *
1729: * @param instant the instant to set
1730: * @param field the field to use
1731: */
1732: Property(LocalDate instant, DateTimeField field) {
1733: super ();
1734: iInstant = instant;
1735: iField = field;
1736: }
1737:
1738: /**
1739: * Writes the property in a safe serialization format.
1740: */
1741: private void writeObject(ObjectOutputStream oos)
1742: throws IOException {
1743: oos.writeObject(iInstant);
1744: oos.writeObject(iField.getType());
1745: }
1746:
1747: /**
1748: * Reads the property from a safe serialization format.
1749: */
1750: private void readObject(ObjectInputStream oos)
1751: throws IOException, ClassNotFoundException {
1752: iInstant = (LocalDate) oos.readObject();
1753: DateTimeFieldType type = (DateTimeFieldType) oos
1754: .readObject();
1755: iField = type.getField(iInstant.getChronology());
1756: }
1757:
1758: //-----------------------------------------------------------------------
1759: /**
1760: * Gets the field being used.
1761: *
1762: * @return the field
1763: */
1764: public DateTimeField getField() {
1765: return iField;
1766: }
1767:
1768: /**
1769: * Gets the milliseconds of the date that this property is linked to.
1770: *
1771: * @return the milliseconds
1772: */
1773: protected long getMillis() {
1774: return iInstant.getLocalMillis();
1775: }
1776:
1777: /**
1778: * Gets the chronology of the datetime that this property is linked to.
1779: *
1780: * @return the chronology
1781: * @since 1.4
1782: */
1783: protected Chronology getChronology() {
1784: return iInstant.getChronology();
1785: }
1786:
1787: /**
1788: * Gets the LocalDate object linked to this property.
1789: *
1790: * @return the linked LocalDate
1791: */
1792: public LocalDate getLocalDate() {
1793: return iInstant;
1794: }
1795:
1796: //-----------------------------------------------------------------------
1797: /**
1798: * Adds to this field in a copy of this LocalDate.
1799: * <p>
1800: * The LocalDate attached to this property is unchanged by this call.
1801: *
1802: * @param value the value to add to the field in the copy
1803: * @return a copy of the LocalDate with the field value changed
1804: * @throws IllegalArgumentException if the value isn't valid
1805: */
1806: public LocalDate addToCopy(int value) {
1807: return iInstant.withLocalMillis(iField.add(iInstant
1808: .getLocalMillis(), value));
1809: }
1810:
1811: /**
1812: * Adds to this field, possibly wrapped, in a copy of this LocalDate.
1813: * A field wrapped operation only changes this field.
1814: * Thus 31st January addWrapField one day goes to the 1st January.
1815: * <p>
1816: * The LocalDate attached to this property is unchanged by this call.
1817: *
1818: * @param value the value to add to the field in the copy
1819: * @return a copy of the LocalDate with the field value changed
1820: * @throws IllegalArgumentException if the value isn't valid
1821: */
1822: public LocalDate addWrapFieldToCopy(int value) {
1823: return iInstant.withLocalMillis(iField.addWrapField(
1824: iInstant.getLocalMillis(), value));
1825: }
1826:
1827: //-----------------------------------------------------------------------
1828: /**
1829: * Sets this field in a copy of the LocalDate.
1830: * <p>
1831: * The LocalDate attached to this property is unchanged by this call.
1832: *
1833: * @param value the value to set the field in the copy to
1834: * @return a copy of the LocalDate with the field value changed
1835: * @throws IllegalArgumentException if the value isn't valid
1836: */
1837: public LocalDate setCopy(int value) {
1838: return iInstant.withLocalMillis(iField.set(iInstant
1839: .getLocalMillis(), value));
1840: }
1841:
1842: /**
1843: * Sets this field in a copy of the LocalDate to a parsed text value.
1844: * <p>
1845: * The LocalDate attached to this property is unchanged by this call.
1846: *
1847: * @param text the text value to set
1848: * @param locale optional locale to use for selecting a text symbol
1849: * @return a copy of the LocalDate with the field value changed
1850: * @throws IllegalArgumentException if the text value isn't valid
1851: */
1852: public LocalDate setCopy(String text, Locale locale) {
1853: return iInstant.withLocalMillis(iField.set(iInstant
1854: .getLocalMillis(), text, locale));
1855: }
1856:
1857: /**
1858: * Sets this field in a copy of the LocalDate to a parsed text value.
1859: * <p>
1860: * The LocalDate attached to this property is unchanged by this call.
1861: *
1862: * @param text the text value to set
1863: * @return a copy of the LocalDate with the field value changed
1864: * @throws IllegalArgumentException if the text value isn't valid
1865: */
1866: public LocalDate setCopy(String text) {
1867: return setCopy(text, null);
1868: }
1869:
1870: //-----------------------------------------------------------------------
1871: /**
1872: * Returns a new LocalDate with this field set to the maximum value
1873: * for this field.
1874: * <p>
1875: * This operation is useful for obtaining a LocalDate on the last day
1876: * of the month, as month lengths vary.
1877: * <pre>
1878: * LocalDate lastDayOfMonth = dt.dayOfMonth().withMaximumValue();
1879: * </pre>
1880: * <p>
1881: * The LocalDate attached to this property is unchanged by this call.
1882: *
1883: * @return a copy of the LocalDate with this field set to its maximum
1884: */
1885: public LocalDate withMaximumValue() {
1886: return setCopy(getMaximumValue());
1887: }
1888:
1889: /**
1890: * Returns a new LocalDate with this field set to the minimum value
1891: * for this field.
1892: * <p>
1893: * The LocalDate attached to this property is unchanged by this call.
1894: *
1895: * @return a copy of the LocalDate with this field set to its minimum
1896: */
1897: public LocalDate withMinimumValue() {
1898: return setCopy(getMinimumValue());
1899: }
1900:
1901: //-----------------------------------------------------------------------
1902: /**
1903: * Rounds to the lowest whole unit of this field on a copy of this
1904: * LocalDate.
1905: * <p>
1906: * For example, rounding floor on the hourOfDay field of a LocalDate
1907: * where the time is 10:30 would result in new LocalDate with the
1908: * time of 10:00.
1909: *
1910: * @return a copy of the LocalDate with the field value changed
1911: */
1912: public LocalDate roundFloorCopy() {
1913: return iInstant.withLocalMillis(iField.roundFloor(iInstant
1914: .getLocalMillis()));
1915: }
1916:
1917: /**
1918: * Rounds to the highest whole unit of this field on a copy of this
1919: * LocalDate.
1920: * <p>
1921: * For example, rounding floor on the hourOfDay field of a LocalDate
1922: * where the time is 10:30 would result in new LocalDate with the
1923: * time of 11:00.
1924: *
1925: * @return a copy of the LocalDate with the field value changed
1926: */
1927: public LocalDate roundCeilingCopy() {
1928: return iInstant.withLocalMillis(iField
1929: .roundCeiling(iInstant.getLocalMillis()));
1930: }
1931:
1932: /**
1933: * Rounds to the nearest whole unit of this field on a copy of this
1934: * LocalDate, favoring the floor if halfway.
1935: *
1936: * @return a copy of the LocalDate with the field value changed
1937: */
1938: public LocalDate roundHalfFloorCopy() {
1939: return iInstant.withLocalMillis(iField
1940: .roundHalfFloor(iInstant.getLocalMillis()));
1941: }
1942:
1943: /**
1944: * Rounds to the nearest whole unit of this field on a copy of this
1945: * LocalDate, favoring the ceiling if halfway.
1946: *
1947: * @return a copy of the LocalDate with the field value changed
1948: */
1949: public LocalDate roundHalfCeilingCopy() {
1950: return iInstant.withLocalMillis(iField
1951: .roundHalfCeiling(iInstant.getLocalMillis()));
1952: }
1953:
1954: /**
1955: * Rounds to the nearest whole unit of this field on a copy of this
1956: * LocalDate. If halfway, the ceiling is favored over the floor
1957: * only if it makes this field's value even.
1958: *
1959: * @return a copy of the LocalDate with the field value changed
1960: */
1961: public LocalDate roundHalfEvenCopy() {
1962: return iInstant.withLocalMillis(iField
1963: .roundHalfEven(iInstant.getLocalMillis()));
1964: }
1965: }
1966:
1967: }
|