/*
 *  Copyright 2001-2013 Stephen Colebourne
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.joda.time.base;

import java.io.Serializable;

import org.joda.time.Chronology;
import org.joda.time.DateTimeUtils;
import org.joda.time.DurationField;
import org.joda.time.DurationFieldType;
import org.joda.time.MutablePeriod;
import org.joda.time.Period;
import org.joda.time.PeriodType;
import org.joda.time.ReadableInstant;
import org.joda.time.ReadablePartial;
import org.joda.time.ReadablePeriod;
import org.joda.time.chrono.ISOChronology;
import org.joda.time.field.FieldUtils;

BaseSingleFieldPeriod is an abstract implementation of ReadablePeriod that manages a single duration field, such as days or minutes.

This class should generally not be used directly by API users. The ReadablePeriod interface should be used when different kinds of period objects are to be referenced.

BaseSingleFieldPeriod subclasses may be mutable and not thread-safe.

Author:Stephen Colebourne
Since:1.4
/** * BaseSingleFieldPeriod is an abstract implementation of ReadablePeriod that * manages a single duration field, such as days or minutes. * <p> * This class should generally not be used directly by API users. * The {@link ReadablePeriod} interface should be used when different * kinds of period objects are to be referenced. * <p> * BaseSingleFieldPeriod subclasses may be mutable and not thread-safe. * * @author Stephen Colebourne * @since 1.4 */
public abstract class BaseSingleFieldPeriod implements ReadablePeriod, Comparable<BaseSingleFieldPeriod>, Serializable {
Serialization version.
/** Serialization version. */
private static final long serialVersionUID = 9386874258972L;
The start of 1972.
/** The start of 1972. */
private static final long START_1972 = 2L * 365L * 86400L * 1000L;
The period in the units of this period.
/** The period in the units of this period. */
private volatile int iPeriod; //-----------------------------------------------------------------------
Calculates the number of whole units between the two specified datetimes.
Params:
  • start – the start instant, validated to not be null
  • end – the end instant, validated to not be null
  • field – the field type to use, must not be null
Throws:
Returns:the period
/** * Calculates the number of whole units between the two specified datetimes. * * @param start the start instant, validated to not be null * @param end the end instant, validated to not be null * @param field the field type to use, must not be null * @return the period * @throws IllegalArgumentException if the instants are null or invalid */
protected static int between(ReadableInstant start, ReadableInstant end, DurationFieldType field) { if (start == null || end == null) { throw new IllegalArgumentException("ReadableInstant objects must not be null"); } Chronology chrono = DateTimeUtils.getInstantChronology(start); int amount = field.getField(chrono).getDifference(end.getMillis(), start.getMillis()); return amount; } //-----------------------------------------------------------------------
Calculates the number of whole units between the two specified partial datetimes.

The two partials must contain the same fields, for example you can specify two LocalDate objects.

Params:
  • start – the start partial date, validated to not be null
  • end – the end partial date, validated to not be null
  • zeroInstance – the zero instance constant, must not be null
Throws:
Returns:the period
/** * Calculates the number of whole units between the two specified partial datetimes. * <p> * The two partials must contain the same fields, for example you can specify * two <code>LocalDate</code> objects. * * @param start the start partial date, validated to not be null * @param end the end partial date, validated to not be null * @param zeroInstance the zero instance constant, must not be null * @return the period * @throws IllegalArgumentException if the partials are null or invalid */
protected static int between(ReadablePartial start, ReadablePartial end, ReadablePeriod zeroInstance) { if (start == null || end == null) { throw new IllegalArgumentException("ReadablePartial objects must not be null"); } if (start.size() != end.size()) { throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields"); } for (int i = 0, isize = start.size(); i < isize; i++) { if (start.getFieldType(i) != end.getFieldType(i)) { throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields"); } } if (DateTimeUtils.isContiguous(start) == false) { throw new IllegalArgumentException("ReadablePartial objects must be contiguous"); } Chronology chrono = DateTimeUtils.getChronology(start.getChronology()).withUTC(); int[] values = chrono.get(zeroInstance, chrono.set(start, START_1972), chrono.set(end, START_1972)); return values[0]; }
Creates a new instance representing the number of complete standard length units in the specified period.

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

  • One week consists of 7 days.
  • One day consists of 24 hours.
  • One hour consists of 60 minutes.
  • One minute consists of 60 seconds.
  • One second consists of 1000 milliseconds.
Months and Years are imprecise and periods containing these values cannot be converted.
Params:
  • period – the period to get the number of hours from, must not be null
  • millisPerUnit – the number of milliseconds in one standard unit of this period
Throws:
/** * Creates a new instance representing the number of complete standard length units * in the specified period. * <p> * This factory method converts all fields from the period to hours using standardised * durations for each field. Only those fields which have a precise duration in * the ISO UTC chronology can be converted. * <ul> * <li>One week consists of 7 days. * <li>One day consists of 24 hours. * <li>One hour consists of 60 minutes. * <li>One minute consists of 60 seconds. * <li>One second consists of 1000 milliseconds. * </ul> * Months and Years are imprecise and periods containing these values cannot be converted. * * @param period the period to get the number of hours from, must not be null * @param millisPerUnit the number of milliseconds in one standard unit of this period * @throws IllegalArgumentException if the period contains imprecise duration values */
protected static int standardPeriodIn(ReadablePeriod period, long millisPerUnit) { if (period == null) { return 0; } Chronology iso = ISOChronology.getInstanceUTC(); long duration = 0L; for (int i = 0; i < period.size(); i++) { int value = period.getValue(i); if (value != 0) { DurationField field = period.getFieldType(i).getField(iso); if (field.isPrecise() == false) { throw new IllegalArgumentException( "Cannot convert period to duration as " + field.getName() + " is not precise in the period " + period); } duration = FieldUtils.safeAdd(duration, FieldUtils.safeMultiply(field.getUnitMillis(), value)); } } return FieldUtils.safeToInt(duration / millisPerUnit); } //-----------------------------------------------------------------------
Creates a new instance representing the specified period.
Params:
  • period – the period to represent
/** * Creates a new instance representing the specified period. * * @param period the period to represent */
protected BaseSingleFieldPeriod(int period) { super(); iPeriod = period; } //-----------------------------------------------------------------------
Gets the amount of this period.
Returns:the period value
/** * Gets the amount of this period. * * @return the period value */
protected int getValue() { return iPeriod; }
Sets the amount of this period. To make a subclass immutable you must declare it final, or block this method.
Params:
  • value – the period value
/** * Sets the amount of this period. * To make a subclass immutable you must declare it final, or block this method. * * @param value the period value */
protected void setValue(int value) { iPeriod = value; } //-----------------------------------------------------------------------
Gets the single duration field type.
Returns:the duration field type, not null
/** * Gets the single duration field type. * * @return the duration field type, not null */
public abstract DurationFieldType getFieldType();
Gets the period type which matches the duration field type.
Returns:the period type, not null
/** * Gets the period type which matches the duration field type. * * @return the period type, not null */
public abstract PeriodType getPeriodType(); //-----------------------------------------------------------------------
Gets the number of fields that this period supports, which is one.
Returns:the number of fields supported, which is one
/** * Gets the number of fields that this period supports, which is one. * * @return the number of fields supported, which is one */
public int size() { return 1; }
Gets the field type at the specified index.

The only index supported by this period is zero which returns the field type of this class.

Params:
  • index – the index to retrieve, which must be zero
Throws:
Returns:the field at the specified index
/** * Gets the field type at the specified index. * <p> * The only index supported by this period is zero which returns the * field type of this class. * * @param index the index to retrieve, which must be zero * @return the field at the specified index * @throws IndexOutOfBoundsException if the index is invalid */
public DurationFieldType getFieldType(int index) { if (index != 0) { throw new IndexOutOfBoundsException(String.valueOf(index)); } return getFieldType(); }
Gets the value at the specified index.

The only index supported by this period is zero.

Params:
  • index – the index to retrieve, which must be zero
Throws:
Returns:the value of the field at the specified index
/** * Gets the value at the specified index. * <p> * The only index supported by this period is zero. * * @param index the index to retrieve, which must be zero * @return the value of the field at the specified index * @throws IndexOutOfBoundsException if the index is invalid */
public int getValue(int index) { if (index != 0) { throw new IndexOutOfBoundsException(String.valueOf(index)); } return getValue(); }
Gets the value of a duration field represented by this period.

If the field type specified does not match the type used by this class then zero is returned.

Params:
  • type – the field type to query, null returns zero
Returns:the value of that field, zero if field not supported
/** * Gets the value of a duration field represented by this period. * <p> * If the field type specified does not match the type used by this class * then zero is returned. * * @param type the field type to query, null returns zero * @return the value of that field, zero if field not supported */
public int get(DurationFieldType type) { if (type == getFieldType()) { return getValue(); } return 0; }
Checks whether the duration field specified is supported by this period.
Params:
  • type – the type to check, may be null which returns false
Returns:true if the field is supported
/** * Checks whether the duration field specified is supported by this period. * * @param type the type to check, may be null which returns false * @return true if the field is supported */
public boolean isSupported(DurationFieldType type) { return (type == getFieldType()); } //-----------------------------------------------------------------------
Get this period as an immutable Period object. The period will use PeriodType.standard().
Returns:a Period representing the same number of days
/** * Get this period as an immutable <code>Period</code> object. * The period will use <code>PeriodType.standard()</code>. * * @return a <code>Period</code> representing the same number of days */
public Period toPeriod() { return Period.ZERO.withFields(this); }
Get this object as a MutablePeriod.

This will always return a new MutablePeriod with the same fields. The period will use PeriodType.standard().

Returns:a MutablePeriod using the same field set and values
/** * Get this object as a <code>MutablePeriod</code>. * <p> * This will always return a new <code>MutablePeriod</code> with the same fields. * The period will use <code>PeriodType.standard()</code>. * * @return a MutablePeriod using the same field set and values */
public MutablePeriod toMutablePeriod() { MutablePeriod period = new MutablePeriod(); period.add(this); return period; } //-----------------------------------------------------------------------
Compares this object with the specified object for equality based on the value of each field. All ReadablePeriod instances are accepted, but only those with a matching PeriodType can return true.
Params:
  • period – a readable period to check against
Returns:true if all the field values are equal, false if not or the period is null or of an incorrect type
/** * Compares this object with the specified object for equality based on the * value of each field. All ReadablePeriod instances are accepted, but only * those with a matching <code>PeriodType</code> can return true. * * @param period a readable period to check against * @return true if all the field values are equal, false if * not or the period is null or of an incorrect type */
public boolean equals(Object period) { if (this == period) { return true; } if (period instanceof ReadablePeriod == false) { return false; } ReadablePeriod other = (ReadablePeriod) period; return (other.getPeriodType() == getPeriodType() && other.getValue(0) == getValue()); }
Gets a hash code for the period as defined by ReadablePeriod.
Returns:a hash code
/** * Gets a hash code for the period as defined by ReadablePeriod. * * @return a hash code */
public int hashCode() { int total = 17; total = 27 * total + getValue(); total = 27 * total + getFieldType().hashCode(); return total; }
Compares this period to another object of the same class.
Params:
  • other – the other period, must not be null
Throws:
Returns:zero if equal, positive if greater, negative if less
/** * Compares this period to another object of the same class. * * @param other the other period, must not be null * @return zero if equal, positive if greater, negative if less * @throws NullPointerException if the other period is null * @throws ClassCastException if the other period is of a different type */
public int compareTo(BaseSingleFieldPeriod other) { if (other.getClass() != getClass()) { throw new ClassCastException(getClass() + " cannot be compared to " + other.getClass()); } int otherValue = other.getValue(); int thisValue = getValue(); if (thisValue > otherValue) { return 1; } if (thisValue < otherValue) { return -1; } return 0; } }