All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.joda.time.base.BaseSingleFieldPeriod Maven / Gradle / Ivy

The newest version!
/*
 *  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 {@link 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 */ public abstract class BaseSingleFieldPeriod implements ReadablePeriod, Comparable, Serializable { /** Serialization version. */ private static final long serialVersionUID = 9386874258972L; /** The start of 1972. */ private static final long START_1972 = 2L * 365L * 86400L * 1000L; /** The period in the units of this period. */ private volatile int iPeriod; //----------------------------------------------------------------------- /** * 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. * * @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. * * @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. * * @param period the period to represent */ protected BaseSingleFieldPeriod(int period) { super(); iPeriod = period; } //----------------------------------------------------------------------- /** * 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. * * @param value the period value */ protected void setValue(int value) { iPeriod = value; } //----------------------------------------------------------------------- /** * 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. * * @return the period type, not null */ public abstract PeriodType getPeriodType(); //----------------------------------------------------------------------- /** * 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. * * @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. * * @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. * * @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. * * @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(). * * @return a Period 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(). * * @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. * * @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. * * @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. * * @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; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy