diff --git a/src/main/java/org/threeten/extra/AbstractSimpleAmount.java b/src/main/java/org/threeten/extra/AbstractSimpleAmount.java new file mode 100644 index 0000000..866c174 --- /dev/null +++ b/src/main/java/org/threeten/extra/AbstractSimpleAmount.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import org.threeten.bp.jdk8.Jdk8Methods; +import org.threeten.bp.temporal.TemporalUnit; + +/** + * An abstract amount of time measured in terms of a single field, + * such as days or seconds. + *
+ * This class exists to share code between the public implementations. + * + *
+ * This instance is immutable and unaffected by this method call. + * + * @param amount the amount of time to add, may be negative + * @return the new amount plus the specified amount of time, not null + * @throws ArithmeticException if the result overflows an {@code int} + */ + public T plus(int amount) { + if (amount == 0) { + @SuppressWarnings("unchecked") + T result = (T) this; + return result; + } + return withAmount(Jdk8Methods.safeAdd(getAmount(), amount)); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the specified amount of time subtracted. + *
+ * This instance is immutable and unaffected by this method call. + * + * @param amount the amount of time to take away, may be negative + * @return the new amount minus the specified amount of time, not null + * @throws ArithmeticException if the result overflows an {@code int} + */ + public T minus(int amount) { + return (amount == Integer.MIN_VALUE ? plus(Integer.MAX_VALUE).plus(1) : plus(-amount)); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the amount multiplied by the specified scalar. + *
+ * This instance is immutable and unaffected by this method call. + * + * @param scalar the amount to multiply by, may be negative + * @return the new amount multiplied by the specified scalar, not null + * @throws ArithmeticException if the result overflows an {@code int} + */ + public T multipliedBy(int scalar) { + return withAmount(Jdk8Methods.safeMultiply(getAmount(), scalar)); + } + + /** + * Returns a new instance with the amount divided by the specified divisor. + * The calculation uses integer division, thus 3 divided by 2 is 1. + *
+ * This instance is immutable and unaffected by this method call. + * + * @param divisor the amount to divide by, may be negative + * @return the new amount divided by the specified divisor, not null + * @throws ArithmeticException if the divisor is zero + */ + public T dividedBy(int divisor) { + if (divisor == 1) { + @SuppressWarnings("unchecked") + T result = (T) this; + return result; + } + return withAmount(getAmount() / divisor); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with the amount negated. + * + * @return the new amount with a negated amount, not null + * @throws ArithmeticException if the result overflows an {@code int} + */ + public T negated() { + return withAmount(safeNegate(getAmount())); + } + + /** + * Negates the input value, throwing an exception if an overflow occurs. + * + * @param value the value to negate + * @return the negated value + * @throws ArithmeticException if the value is MIN_VALUE and cannot be negated + */ + private static int safeNegate(int value) { + if (value == Integer.MIN_VALUE) { + throw new ArithmeticException("Integer.MIN_VALUE cannot be negated"); + } + return -value; + } + + //----------------------------------------------------------------------- + /** + * Compares the amount of time in this instance to another instance. + * + * @param other the other amount, not null + * @return the comparator value, negative if less, positive if greater + * @throws NullPointerException if the other amount is null + */ + @Override + public int compareTo(T other) { + int thisValue = this.getAmount(); + int otherValue = other.getAmount(); + return (thisValue < otherValue ? -1 : (thisValue == otherValue ? 0 : 1)); + } + + /** + * Checks if the amount of time in this instance greater than that in another instance. + * + * @param other the other amount, not null + * @return true if this amount is greater + * @throws NullPointerException if the other amount is null + */ + public boolean isGreaterThan(T other) { + return compareTo(other) > 0; + } + + /** + * Checks if the amount of time in this instance less than that in another instance. + * + * @param other the other amount, not null + * @return true if this amount is less + * @throws NullPointerException if the other amount is null + */ + public boolean isLessThan(T other) { + return compareTo(other) < 0; + } + + //----------------------------------------------------------------------- + /** + * Is this instance equal to that specified. + * + * @param obj the other amount of time, null returns false + * @return true if this amount of time is the same as that specified + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof AbstractSimpleAmount>) { + AbstractSimpleAmount> other = (AbstractSimpleAmount>) obj; + return getAmount() == other.getAmount() && getUnit().equals(other.getUnit()); + } + return false; + } + + /** + * Returns the hash code for this amount. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return getUnit().hashCode() ^ getAmount(); + } + + //----------------------------------------------------------------------- + /** + * Returns a string representation of the amount of time. + * + * @return the amount of time in ISO8601 string format + */ + @Override + public abstract String toString(); + +} diff --git a/src/main/java/org/threeten/extra/AmPm.java b/src/main/java/org/threeten/extra/AmPm.java new file mode 100644 index 0000000..e7789b7 --- /dev/null +++ b/src/main/java/org/threeten/extra/AmPm.java @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static org.threeten.bp.temporal.ChronoField.AMPM_OF_DAY; +import static org.threeten.bp.temporal.ChronoField.HOUR_OF_DAY; +import static org.threeten.bp.temporal.ChronoUnit.HALF_DAYS; + +import java.util.Calendar; +import java.util.Locale; + +import org.threeten.bp.DateTimeException; +import org.threeten.bp.format.DateTimeFormatterBuilder; +import org.threeten.bp.format.TextStyle; +import org.threeten.bp.temporal.ChronoField; +import org.threeten.bp.temporal.Temporal; +import org.threeten.bp.temporal.TemporalAccessor; +import org.threeten.bp.temporal.TemporalAdjuster; +import org.threeten.bp.temporal.TemporalField; +import org.threeten.bp.temporal.TemporalQueries; +import org.threeten.bp.temporal.TemporalQuery; +import org.threeten.bp.temporal.ValueRange; + +/** + * A half-day before or after midday, with the values 'AM' and 'PM'. + *
+ * {@code AmPm} is an enum representing the half-day concepts of AM and PM. + * AM is defined as from 00:00 to 11:59, while PM is defined from 12:00 to 23:59. + *
+ * All date-time fields have an {@code int} value. + * The {@code int} value follows {@link Calendar}, assigning 0 to AM and 1 to PM. + * It is recommended that applications use the enum rather than the {@code int} value + * to ensure code clarity. + *
+ * Do not use {@code ordinal()} to obtain the numeric representation of {@code AmPm}. + * Use {@code getValue()} instead. + *
+ * This enum represents a common concept that is found in many calendar systems. + * As such, this enum may be used by any calendar system that has the AM/PM + * concept defined exactly equivalent to the ISO calendar system. + * + *
+ * {@code AmPm} is an enum representing before and after midday. + * This factory allows the enum to be obtained from the {@code int} value. + * The {@code int} value follows {@link Calendar}, assigning 0 to AM and 1 to PM. + * + * @param amPmValue the AM/PM value to represent, from 0 (AM) to 1 (PM) + * @return the AM/PM, not null + * @throws DateTimeException if the value is invalid + */ + public static AmPm of(int amPmValue) { + switch (amPmValue) { + case 0: return AM; + case 1: return PM; + default: throw new DateTimeException("Invalid value for AM/PM: " + amPmValue); + } + } + + /** + * Obtains an instance of {@code AmPm} from an hour-of-day. + *
+ * {@code AmPm} is an enum representing before and after midday. + * This factory allows the enum to be obtained from the hour-of-day value, from 0 to 23. + * + * @param hourOfDay the hour-of-day to extract from, from 0 to 23 + * @return the AM/PM, not null + * @throws DateTimeException if the hour-of-day is invalid + */ + public static AmPm ofHour(int hourOfDay) { + HOUR_OF_DAY.checkValidValue(hourOfDay); + return hourOfDay < 12 ? AM : PM; + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code AmPm} from a temporal object. + *
+ * A {@code TemporalAccessor} represents some form of date and time information. + * This factory converts the arbitrary temporal object to an instance of {@code DayOfWeek}. + *
+ * The conversion extracts the {@link ChronoField#AMPM_OF_DAY AMPM_OF_DAY} field. + *
+ * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used as a query via method reference, {@code AmPm::from}. + * + * @param temporal the temporal object to convert, not null + * @return the AM/PM, not null + * @throws DateTimeException if unable to convert to a {@code AmPm} + */ + public static AmPm from(TemporalAccessor temporal) { + if (temporal instanceof AmPm) { + return (AmPm) temporal; + } + return of(temporal.get(AMPM_OF_DAY)); + } + + //----------------------------------------------------------------------- + /** + * Gets the AM/PM {@code int} value. + *
+ * The values are numbered following {@link Calendar}, assigning 0 to AM and 1 to PM. + * + * @return the AM/PM value, from 0 (AM) to 1 (PM) + */ + public int getValue() { + return ordinal(); + } + + //----------------------------------------------------------------------- + /** + * Gets the textual representation, such as 'AM' or 'PM'. + *
+ * This returns the textual name used to identify the AM/PM. + * The parameters control the length of the returned text and the locale. + *
+ * If no textual mapping is found then the {@link #getValue() numeric value} is returned. + * + * @param style the length of the text required, not null + * @param locale the locale to use, not null + * @return the text value of the AM/PM, not null + */ + public String getDisplayName(TextStyle style, Locale locale) { + return new DateTimeFormatterBuilder().appendText(AMPM_OF_DAY, style).toFormatter(locale).format(this); + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *
+ * This checks if this AM/PM can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and + * {@link #get(TemporalField) get} methods will throw an exception. + *
+ * If the field is {@link ChronoField#AMPM_OF_DAY AMPM_OF_DAY} then + * this method returns true. + * All other {@code ChronoField} instances will return false. + *
+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this AM/PM, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + if (field instanceof ChronoField) { + return field == AMPM_OF_DAY; + } + return field != null && field.isSupportedBy(this); + } + + /** + * Gets the range of valid values for the specified field. + *
+ * The range object expresses the minimum and maximum valid values for a field. + * This AM/PM is used to enhance the accuracy of the returned range. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + *
+ * If the field is {@link ChronoField#AMPM_OF_DAY AMPM_OF_DAY} then the + * range of the AM/PM, from 0 to 1, will be returned. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *
+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the range can be obtained is determined by the field. + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + */ + @Override + public ValueRange range(TemporalField field) { + if (field == AMPM_OF_DAY) { + return field.range(); + } else if (field instanceof ChronoField) { + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.rangeRefinedBy(this); + } + + /** + * Gets the value of the specified field from this AM/PM as an {@code int}. + *
+ * This queries this AM/PM for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *
+ * If the field is {@link ChronoField#AMPM_OF_DAY AMPM_OF_DAY} then the + * value of the AM/PM, from 0 to 1, will be returned. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *
+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field, within the valid range of values + * @throws DateTimeException if a value for the field cannot be obtained + * @throws DateTimeException if the range of valid values for the field exceeds an {@code int} + * @throws DateTimeException if the value is outside the range of valid values for the field + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public int get(TemporalField field) { + if (field == AMPM_OF_DAY) { + return getValue(); + } + return range(field).checkValidIntValue(getLong(field), field); + } + + /** + * Gets the value of the specified field from this AM/PM as a {@code long}. + *
+ * This queries this AM/PM for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *
+ * If the field is {@link ChronoField#AMPM_OF_DAY AMPM_OF_DAY} then the + * value of the AM/PM, from 0 to 1, will be returned. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *
+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long getLong(TemporalField field) { + if (field == AMPM_OF_DAY) { + return getValue(); + } else if (field instanceof ChronoField) { + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.getFrom(this); + } + + //----------------------------------------------------------------------- + /** + * Queries this AM/PM using the specified query. + *
+ * This queries this AM/PM using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *
+ * The result of this method is obtained by invoking the
+ * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+ * specified query passing {@code this} as the argument.
+ *
+ * @param
+ * This returns a temporal object of the same observable type as the input
+ * with the AM/PM changed to be the same as this.
+ *
+ * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+ * passing {@link ChronoField#AMPM_OF_DAY} as the field.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#with(TemporalAdjuster)}:
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param temporal the target object to be adjusted, not null
+ * @return the adjusted object, not null
+ * @throws DateTimeException if unable to make the adjustment
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public Temporal adjustInto(Temporal temporal) {
+ return temporal.with(AMPM_OF_DAY, getValue());
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/ChronoAdjusters.java b/src/main/java/org/threeten/extra/ChronoAdjusters.java
new file mode 100644
index 0000000..0bb4759
--- /dev/null
+++ b/src/main/java/org/threeten/extra/ChronoAdjusters.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra;
+
+import org.threeten.bp.chrono.ChronoLocalDate;
+import org.threeten.bp.chrono.HijrahChronology;
+import org.threeten.bp.chrono.JapaneseChronology;
+import org.threeten.bp.chrono.MinguoChronology;
+import org.threeten.bp.chrono.ThaiBuddhistChronology;
+import org.threeten.bp.temporal.Temporal;
+import org.threeten.bp.temporal.TemporalAdjuster;
+
+/**
+ * Adjusters that allow dates to be adjusted in terms of a calendar system.
+ */
+public final class ChronoAdjusters {
+
+ /**
+ * Restricted constructor.
+ */
+ private ChronoAdjusters() {
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Convenience wrapper allowing a date to be easily adjusted in the Minguo calendar system.
+ *
+ * This allows the specified adjuster to be run in terms of a Minguo date.
+ * This would be used as follows:
+ *
+ * This allows the specified adjuster to be run in terms of a Hijrah date.
+ * This would be used as follows:
+ *
+ * This allows the specified adjuster to be run in terms of a Japanese date.
+ * This would be used as follows:
+ *
+ * This allows the specified adjuster to be run in terms of a ThaiBuddhist date.
+ * This would be used as follows:
+ *
+ * {@code DayOfMonth} allows the day-of-month to be represented in a type-safe way.
+ * The value can range from 1 to 31, as there is no month or year to validate against.
+ *
+ *
+ * A day-of-month object represents one of the 31 days of the month, from 1 to 31.
+ *
+ * @param dayOfMonth the day-of-month to represent, from 1 to 31
+ * @return the day-of-month, not null
+ * @throws DateTimeException if the day-of-month is invalid
+ */
+ public static DayOfMonth of(int dayOfMonth) {
+ try {
+ DayOfMonth result = CACHE.get(--dayOfMonth);
+ if (result == null) {
+ DayOfMonth temp = new DayOfMonth(dayOfMonth + 1);
+ CACHE.compareAndSet(dayOfMonth, null, temp);
+ result = CACHE.get(dayOfMonth);
+ }
+ return result;
+ } catch (IndexOutOfBoundsException ex) {
+ throw new DateTimeException("Invalid value for DayOfMonth: " + ++dayOfMonth);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code DayOfMonth} from a temporal object.
+ *
+ * A {@code TemporalAccessor} represents some form of date and time information.
+ * This factory converts the arbitrary temporal object to an instance of {@code DayOfWeek}.
+ *
+ * The conversion extracts the {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} field.
+ *
+ * This method matches the signature of the functional interface {@link TemporalQuery}
+ * allowing it to be used as a query via method reference, {@code DayOfMonth::from}.
+ *
+ * @param temporal the temporal object to convert, not null
+ * @return the day-of-month, not null
+ * @throws DateTimeException if unable to convert to a {@code DayOfMonth}
+ */
+ public static DayOfMonth from(TemporalAccessor temporal) {
+ if (temporal instanceof DayOfMonth) {
+ return (DayOfMonth) temporal;
+ }
+ return of(temporal.get(DAY_OF_MONTH));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Constructs an instance with the specified day-of-month.
+ *
+ * @param dayOfMonth the day-of-month to represent
+ */
+ private DayOfMonth(int dayOfMonth) {
+ this.dayOfMonth = dayOfMonth;
+ }
+
+ /**
+ * Resolve the singleton.
+ *
+ * @return the singleton, not null
+ */
+ private Object readResolve() {
+ return of(dayOfMonth);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the field that defines how the day-of-month field operates.
+ *
+ * The field provides access to the minimum and maximum values, and a
+ * generic way to access values within a date-time.
+ *
+ * @return the day-of-month field, not null
+ */
+ public TemporalField getField() {
+ return DAY_OF_MONTH;
+ }
+
+ /**
+ * Gets the day-of-month value.
+ *
+ * @return the day-of-month, from 1 to 31
+ */
+ public int getValue() {
+ return dayOfMonth;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if the specified field is supported.
+ *
+ * This checks if this day-of-month can be queried for the specified field.
+ * If false, then calling the {@link #range(TemporalField) range} and
+ * {@link #get(TemporalField) get} methods will throw an exception.
+ *
+ * If the field is {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} then
+ * this method returns true.
+ * All other {@code ChronoField} instances will return false.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the field is supported is determined by the field.
+ *
+ * @param field the field to check, null returns false
+ * @return true if the field is supported on this day-of-month, false if not
+ */
+ @Override
+ public boolean isSupported(TemporalField field) {
+ if (field instanceof ChronoField) {
+ return field == DAY_OF_MONTH;
+ }
+ return field != null && field.isSupportedBy(this);
+ }
+
+ /**
+ * Gets the range of valid values for the specified field.
+ *
+ * The range object expresses the minimum and maximum valid values for a field.
+ * This day-of-month is used to enhance the accuracy of the returned range.
+ * If it is not possible to return the range, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} then the
+ * range of the day-of-month, from 1 to 31, will be returned.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the range can be obtained is determined by the field.
+ *
+ * @param field the field to query the range for, not null
+ * @return the range of valid values for the field, not null
+ * @throws DateTimeException if the range for the field cannot be obtained
+ */
+ @Override
+ public ValueRange range(TemporalField field) {
+ if (field == DAY_OF_MONTH) {
+ return field.range();
+ } else if (field instanceof ChronoField) {
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+ return field.rangeRefinedBy(this);
+ }
+
+ /**
+ * Gets the value of the specified field from this day-of-month as an {@code int}.
+ *
+ * This queries this day-of-month for the value for the specified field.
+ * The returned value will always be within the valid range of values for the field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} then the
+ * value of the day-of-month, from 1 to 31, will be returned.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field, within the valid range of values
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws DateTimeException if the range of valid values for the field exceeds an {@code int}
+ * @throws DateTimeException if the value is outside the range of valid values for the field
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public int get(TemporalField field) {
+ if (field == DAY_OF_MONTH) {
+ return getValue();
+ }
+ return range(field).checkValidIntValue(getLong(field), field);
+ }
+
+ /**
+ * Gets the value of the specified field from this day-of-month as a {@code long}.
+ *
+ * This queries this day-of-month for the value for the specified field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} then the
+ * value of the day-of-month, from 1 to 31, will be returned.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public long getLong(TemporalField field) {
+ if (field == DAY_OF_MONTH) {
+ return getValue();
+ } else if (field instanceof ChronoField) {
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+ return field.getFrom(this);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Queries this day-of-month using the specified query.
+ *
+ * This queries this day-of-month using the specified query strategy object.
+ * The {@code TemporalQuery} object defines the logic to be used to
+ * obtain the result. Read the documentation of the query to understand
+ * what the result of this method will be.
+ *
+ * The result of this method is obtained by invoking the
+ * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+ * specified query passing {@code this} as the argument.
+ *
+ * @param
+ * This returns a temporal object of the same observable type as the input
+ * with the day-of-month changed to be the same as this.
+ *
+ * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+ * passing {@link ChronoField#DAY_OF_MONTH} as the field.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#with(TemporalAdjuster)}:
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param temporal the target object to be adjusted, not null
+ * @return the adjusted object, not null
+ * @throws DateTimeException if unable to make the adjustment
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public Temporal adjustInto(Temporal temporal) {
+ return temporal.with(DAY_OF_MONTH, getValue());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Combines this day with a month to create a {@code MonthDay}.
+ *
+ * This returns a {@code MonthDay} formed from this day and the specified month.
+ *
+ * @param month the month to use, from 1 to 12
+ * @return the date formed from this day and the specified month, not null
+ * @throws DateTimeException if the month is invalid
+ */
+ public MonthDay atMonth(int month) {
+ return MonthDay.of(month, dayOfMonth);
+ }
+
+ /**
+ * Combines this day with a month to create a {@code MonthDay}.
+ *
+ * This returns a {@code MonthDay} formed from this day and the specified month.
+ *
+ * @param month the month to use, not null
+ * @return the date formed from this day and the specified month, not null
+ */
+ public MonthDay atMonth(Month month) {
+ return MonthDay.of(month, dayOfMonth);
+ }
+
+ /**
+ * Combines this day with a year-month to create a {@code LocalDate}.
+ *
+ * This returns a {@code LocalDate} formed from this day-of-month and the specified year-month.
+ *
+ * If the day-of-month value if not valid for the year-month, it is adjusted
+ * to the last valid day-of-month.
+ *
+ * @param yearMonth the year-month to use, not null
+ * @return the date formed from this day and the specified year-month, not null
+ */
+ public LocalDate atYearMonth(YearMonth yearMonth) {
+ int day = Math.min(dayOfMonth, yearMonth.lengthOfMonth());
+ return yearMonth.atDay(day);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Compares this day-of-month instance to another.
+ *
+ * @param otherDayOfMonth the other day-of-month instance, not null
+ * @return the comparator value, negative if less, positive if greater
+ */
+ @Override
+ public int compareTo(DayOfMonth otherDayOfMonth) {
+ return Integer.compare(dayOfMonth, otherDayOfMonth.dayOfMonth);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Is this instance equal to that specified, evaluating the day-of-month.
+ *
+ * @param otherDayOfMonth the other day-of-month instance, null returns false
+ * @return true if the day-of-month is the same
+ */
+ @Override
+ public boolean equals(Object otherDayOfMonth) {
+ return this == otherDayOfMonth;
+ }
+
+ /**
+ * A hash code for the day-of-month object.
+ *
+ * @return a suitable hash code
+ */
+ @Override
+ public int hashCode() {
+ return dayOfMonth;
+ }
+
+ /**
+ * A string describing the day-of-month object.
+ *
+ * @return a string describing this object
+ */
+ @Override
+ public String toString() {
+ return "DayOfMonth=" + getValue();
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/Days.java b/src/main/java/org/threeten/extra/Days.java
new file mode 100644
index 0000000..c1e9236
--- /dev/null
+++ b/src/main/java/org/threeten/extra/Days.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra;
+
+import static org.threeten.bp.temporal.ChronoUnit.DAYS;
+
+import java.io.Serializable;
+
+import org.threeten.bp.temporal.TemporalUnit;
+
+/**
+ * An amount of time measured in days, such as '6 Days'.
+ *
+ * This class stores an amount of time in terms of the days unit of time.
+ *
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount plus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Days plus(Days amount) {
+ return plus(amount.getAmount());
+ }
+
+ /**
+ * Returns a new instance with the specified amount of time subtracted.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount minus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Days minus(Days amount) {
+ return minus(amount.getAmount());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a string representation of the number of days.
+ * This will be in the format 'PnD' where n is the number of days.
+ *
+ * @return the number of days in ISO8601 string format
+ */
+ @Override
+ public String toString() {
+ return "P" + days + "D";
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/Hours.java b/src/main/java/org/threeten/extra/Hours.java
new file mode 100644
index 0000000..346d55f
--- /dev/null
+++ b/src/main/java/org/threeten/extra/Hours.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra;
+
+import static org.threeten.bp.temporal.ChronoUnit.HOURS;
+
+import java.io.Serializable;
+
+import org.threeten.bp.temporal.TemporalUnit;
+
+/**
+ * An amount of time measured in hours, such as '6 Hours'.
+ *
+ * This class stores an amount of time in terms of the hours unit of time.
+ *
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount plus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Hours plus(Hours amount) {
+ return plus(amount.getAmount());
+ }
+
+ /**
+ * Returns a new instance with the specified amount of time subtracted.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount minus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Hours minus(Hours amount) {
+ return minus(amount.getAmount());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a string representation of the number of hours.
+ * This will be in the format 'PTnH' where n is the number of hours.
+ *
+ * @return the number of hours in ISO8601 string format
+ */
+ @Override
+ public String toString() {
+ return "PT" + hours + "H";
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/Minutes.java b/src/main/java/org/threeten/extra/Minutes.java
new file mode 100644
index 0000000..77683c8
--- /dev/null
+++ b/src/main/java/org/threeten/extra/Minutes.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra;
+
+import static org.threeten.bp.temporal.ChronoUnit.MINUTES;
+
+import java.io.Serializable;
+
+import org.threeten.bp.temporal.TemporalUnit;
+
+/**
+ * An amount of time measured in minutes, such as '6 Minutes'.
+ *
+ * This class stores an amount of time in terms of the minutes unit of time.
+ *
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount plus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Minutes plus(Minutes amount) {
+ return plus(amount.getAmount());
+ }
+
+ /**
+ * Returns a new instance with the specified amount of time subtracted.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount minus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Minutes minus(Minutes amount) {
+ return minus(amount.getAmount());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a string representation of the number of minutes.
+ * This will be in the format 'PTnM' where n is the number of minutes.
+ *
+ * @return the number of minutes in ISO8601 string format
+ */
+ @Override
+ public String toString() {
+ return "PT" + minutes + "M";
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/Months.java b/src/main/java/org/threeten/extra/Months.java
new file mode 100644
index 0000000..7ff1564
--- /dev/null
+++ b/src/main/java/org/threeten/extra/Months.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra;
+
+import static org.threeten.bp.temporal.ChronoUnit.MONTHS;
+
+import java.io.Serializable;
+
+import org.threeten.bp.temporal.TemporalUnit;
+
+/**
+ * An amount of time measured in months, such as '6 Months'.
+ *
+ * This class stores an amount of time in terms of the months unit of time.
+ *
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount plus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Months plus(Months amount) {
+ return plus(amount.getAmount());
+ }
+
+ /**
+ * Returns a new instance with the specified amount of time subtracted.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount minus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Months minus(Months amount) {
+ return minus(amount.getAmount());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a string representation of the number of months.
+ * This will be in the format 'PnM' where n is the number of months.
+ *
+ * @return the number of months in ISO8601 string format
+ */
+ @Override
+ public String toString() {
+ return "P" + months + "M";
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/QuarterOfYear.java b/src/main/java/org/threeten/extra/QuarterOfYear.java
new file mode 100644
index 0000000..0a2a937
--- /dev/null
+++ b/src/main/java/org/threeten/extra/QuarterOfYear.java
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra;
+
+import static org.threeten.bp.temporal.IsoFields.QUARTER_OF_YEAR;
+import static org.threeten.bp.temporal.IsoFields.QUARTER_YEARS;
+
+import java.util.Locale;
+import java.util.Objects;
+
+import org.threeten.bp.DateTimeException;
+import org.threeten.bp.Month;
+import org.threeten.bp.chrono.Chronology;
+import org.threeten.bp.chrono.IsoChronology;
+import org.threeten.bp.format.DateTimeFormatterBuilder;
+import org.threeten.bp.format.TextStyle;
+import org.threeten.bp.temporal.ChronoField;
+import org.threeten.bp.temporal.IsoFields;
+import org.threeten.bp.temporal.Temporal;
+import org.threeten.bp.temporal.TemporalAccessor;
+import org.threeten.bp.temporal.TemporalAdjuster;
+import org.threeten.bp.temporal.TemporalField;
+import org.threeten.bp.temporal.TemporalQueries;
+import org.threeten.bp.temporal.TemporalQuery;
+import org.threeten.bp.temporal.ValueRange;
+
+/**
+ * A quarter-of-year, such as 'Q2'.
+ *
+ * {@code QuarterOfYear} is an enum representing the 4 quarters of the year -
+ * Q1, Q2, Q3 and Q4. These are defined as January to March, April to June,
+ * July to September and October to December.
+ *
+ * The {@code int} value follows the quarter, from 1 (Q1) to 4 (Q4).
+ * It is recommended that applications use the enum rather than the {@code int} value
+ * to ensure code clarity.
+ *
+ * Do not use {@code ordinal()} to obtain the numeric representation of {@code QuarterOfYear}.
+ * Use {@code getValue()} instead.
+ *
+ * This enum represents a common concept that is found in many calendar systems.
+ * As such, this enum may be used by any calendar system that has the quarter-of-year
+ * concept defined exactly equivalent to the ISO calendar system.
+ *
+ *
+ * {@code QuarterOfYear} is an enum representing the 4 quarters of the year.
+ * This factory allows the enum to be obtained from the {@code int} value.
+ * The {@code int} value follows the quarter, from 1 (Q1) to 4 (Q4).
+ *
+ * @param quarterOfYear the quarter-of-year to represent, from 1 (Q1) to 4 (Q4)
+ * @return the QuarterOfYear singleton, not null
+ * @throws DateTimeException if the value is invalid
+ */
+ public static QuarterOfYear of(int quarterOfYear) {
+ switch (quarterOfYear) {
+ case 1: return Q1;
+ case 2: return Q2;
+ case 3: return Q3;
+ case 4: return Q4;
+ default: throw new DateTimeException("Invalid value for QuarterOfYear: " + quarterOfYear);
+ }
+ }
+
+ /**
+ * Obtains an instance of {@code QuarterOfYear} from a month-of-year.
+ *
+ * {@code QuarterOfYear} is an enum representing the 4 quarters of the year.
+ * This factory allows the enum to be obtained from the {@code Month} value.
+ *
+ * January to March are Q1, April to June are Q2, July to September are Q3
+ * and October to December are Q4.
+ *
+ * @param month the month-of-year to convert from, from 1 to 12
+ * @return the QuarterOfYear singleton, not null
+ */
+ public static QuarterOfYear ofMonth(Month month) {
+ Objects.requireNonNull(month, "month");
+ return of(month.ordinal() / 3 + 1);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code QuarterOfYear} from a temporal object.
+ *
+ * A {@code TemporalAccessor} represents some form of date and time information.
+ * This factory converts the arbitrary temporal object to an instance of {@code DayOfWeek}.
+ *
+ * The conversion extracts the {@link IsoFields#QUARTER_OF_YEAR QUARTER_OF_YEAR} field.
+ *
+ * This method matches the signature of the functional interface {@link TemporalQuery}
+ * allowing it to be used as a query via method reference, {@code QuarterOfYear::from}.
+ *
+ * @param temporal the temporal object to convert, not null
+ * @return the quarter-of-year, not null
+ * @throws DateTimeException if unable to convert to a {@code QuarterOfYear}
+ */
+ public static QuarterOfYear from(TemporalAccessor temporal) {
+ if (temporal instanceof QuarterOfYear) {
+ return (QuarterOfYear) temporal;
+ }
+ return of(temporal.get(QUARTER_OF_YEAR));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the quarter-of-year {@code int} value.
+ *
+ * The values are numbered following the ISO-8601 standard,
+ * from 1 (Q1) to 4 (Q4).
+ *
+ * @return the quarter-of-year, from 1 (Q1) to 4 (Q4)
+ */
+ public int getValue() {
+ return ordinal() + 1;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the textual representation, such as 'Q1' or '4th quarter'.
+ *
+ * This returns the textual name used to identify the quarter-of-year.
+ * The parameters control the length of the returned text and the locale.
+ *
+ * If no textual mapping is found then the {@link #getValue() numeric value} is returned.
+ *
+ * @param style the length of the text required, not null
+ * @param locale the locale to use, not null
+ * @return the text value of the quarter-of-year, not null
+ */
+ public String getDisplayName(TextStyle style, Locale locale) {
+ return new DateTimeFormatterBuilder().appendText(QUARTER_OF_YEAR, style).toFormatter(locale).format(this);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if the specified field is supported.
+ *
+ * This checks if this quarter-of-year can be queried for the specified field.
+ * If false, then calling the {@link #range(TemporalField) range} and
+ * {@link #get(TemporalField) get} methods will throw an exception.
+ *
+ * All {@code ChronoField} instances will return false.
+ *
+ * If the field is {@link IsoFields#QUARTER_OF_YEAR QUARTER_OF_YEAR} then this
+ * method returns true.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the field is supported is determined by the field.
+ *
+ * @param field the field to check, null returns false
+ * @return true if the field is supported on this quarter-of-year, false if not
+ */
+ @Override
+ public boolean isSupported(TemporalField field) {
+ if (field == QUARTER_OF_YEAR) {
+ return true;
+ } else if (field instanceof ChronoField) {
+ return false;
+ }
+ return field != null && field.isSupportedBy(this);
+ }
+
+ /**
+ * Gets the range of valid values for the specified field.
+ *
+ * The range object expresses the minimum and maximum valid values for a field.
+ * This quarter-of-year is used to enhance the accuracy of the returned range.
+ * If it is not possible to return the range, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is {@link IsoFields#QUARTER_OF_YEAR QUARTER_OF_YEAR} then this
+ * method returns the range of the quarter-of-year, from 1 to 4.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the range can be obtained is determined by the field.
+ *
+ * @param field the field to query the range for, not null
+ * @return the range of valid values for the field, not null
+ * @throws DateTimeException if the range for the field cannot be obtained
+ */
+ @Override
+ public ValueRange range(TemporalField field) {
+ if (field == QUARTER_OF_YEAR) {
+ return QUARTER_OF_YEAR.range();
+ } else if (field instanceof ChronoField) {
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+ return field.rangeRefinedBy(this);
+ }
+
+ /**
+ * Gets the value of the specified field from this quarter-of-year as an {@code int}.
+ *
+ * This queries this quarter-of-year for the value for the specified field.
+ * The returned value will always be within the valid range of values for the field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * All {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is {@link IsoFields#QUARTER_OF_YEAR QUARTER_OF_YEAR} then the
+ * value of the quarter-of-year, from 0 to 1, will be returned.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field, within the valid range of values
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws DateTimeException if the range of valid values for the field exceeds an {@code int}
+ * @throws DateTimeException if the value is outside the range of valid values for the field
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public int get(TemporalField field) {
+ if (field == QUARTER_OF_YEAR) {
+ return getValue();
+ }
+ return range(field).checkValidIntValue(getLong(field), field);
+ }
+
+ /**
+ * Gets the value of the specified field from this quarter-of-year as a {@code long}.
+ *
+ * This queries this quarter-of-year for the value for the specified field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * All {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is {@link IsoFields#QUARTER_OF_YEAR QUARTER_OF_YEAR} then the
+ * value of the quarter-of-year, from 0 to 1, will be returned.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public long getLong(TemporalField field) {
+ if (field == QUARTER_OF_YEAR) {
+ return getValue();
+ } else if (field instanceof ChronoField) {
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+ return field.getFrom(this);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns the quarter that is the specified number of quarters after this one.
+ *
+ * The calculation rolls around the end of the year from Q4 to Q1.
+ * The specified period may be negative.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param quarters the quarters to add, positive or negative
+ * @return the resulting quarter, not null
+ */
+ public QuarterOfYear plus(long quarters) {
+ int amount = (int) quarters % 4;
+ return values()[(ordinal() + (amount + 4)) % 4];
+ }
+
+ /**
+ * Returns the quarter that is the specified number of quarters before this one.
+ *
+ * The calculation rolls around the start of the year from Q1 to Q4.
+ * The specified period may be negative.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param quarters the quarters to subtract, positive or negative
+ * @return the resulting quarter, not null
+ */
+ public QuarterOfYear minus(long quarters) {
+ return plus(-(quarters % 4));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the first of the three months that this quarter refers to.
+ *
+ * Q1 will return January.
+ * To obtain the other two months of the quarter, simply use {@link Month#plus(long)}
+ * on the returned month.
+ *
+ * @return the first month in the quarter, not null
+ */
+ public Month firstMonth() {
+ switch (this) {
+ case Q1: return Month.JANUARY;
+ case Q2: return Month.APRIL;
+ case Q3: return Month.JULY;
+ case Q4: return Month.OCTOBER;
+ default: throw new IllegalStateException("Unreachable");
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Queries this quarter-of-year using the specified query.
+ *
+ * This queries this quarter-of-year using the specified query strategy object.
+ * The {@code TemporalQuery} object defines the logic to be used to
+ * obtain the result. Read the documentation of the query to understand
+ * what the result of this method will be.
+ *
+ * The result of this method is obtained by invoking the
+ * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+ * specified query passing {@code this} as the argument.
+ *
+ * @param
+ * This returns a temporal object of the same observable type as the input
+ * with the quarter-of-year changed to be the same as this.
+ *
+ * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+ * passing {@link IsoFields#QUARTER_OF_YEAR} as the field.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#with(TemporalAdjuster)}:
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param temporal the target object to be adjusted, not null
+ * @return the adjusted object, not null
+ * @throws DateTimeException if unable to make the adjustment
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public Temporal adjustInto(Temporal temporal) {
+ if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) {
+ throw new DateTimeException("Adjustment only supported on ISO date-time");
+ }
+ return temporal.with(QUARTER_OF_YEAR, getValue());
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/Seconds.java b/src/main/java/org/threeten/extra/Seconds.java
new file mode 100644
index 0000000..06df9cc
--- /dev/null
+++ b/src/main/java/org/threeten/extra/Seconds.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra;
+
+import static org.threeten.bp.temporal.ChronoUnit.SECONDS;
+
+import java.io.Serializable;
+
+import org.threeten.bp.temporal.TemporalUnit;
+
+/**
+ * An amount of time measured in seconds, such as '6 Seconds'.
+ *
+ * This class stores an amount of time in terms of the seconds unit of time.
+ *
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount plus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Seconds plus(Seconds amount) {
+ return plus(amount.getAmount());
+ }
+
+ /**
+ * Returns a new instance with the specified amount of time subtracted.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount minus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Seconds minus(Seconds amount) {
+ return minus(amount.getAmount());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a string representation of the number of seconds.
+ * This will be in the format 'PTnS' where n is the number of seconds.
+ *
+ * @return the number of seconds in ISO8601 string format
+ */
+ @Override
+ public String toString() {
+ return "PT" + seconds + "S";
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/WeekendRules.java b/src/main/java/org/threeten/extra/WeekendRules.java
new file mode 100644
index 0000000..f3f1c41
--- /dev/null
+++ b/src/main/java/org/threeten/extra/WeekendRules.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra;
+
+import static org.threeten.bp.temporal.ChronoField.DAY_OF_WEEK;
+import static org.threeten.bp.temporal.ChronoUnit.DAYS;
+
+import org.threeten.bp.temporal.Temporal;
+import org.threeten.bp.temporal.TemporalAdjuster;
+
+/**
+ * A helper class for rules around weekends.
+ *
+ *
+ * Some territories have weekends that do not consist of Saturday and Sunday.
+ * No implementation is supplied to support this, however an adjuster
+ * can be easily written to do so.
+ *
+ * @return the next working day adjuster, not null
+ */
+ public static TemporalAdjuster nextNonWeekendDay() {
+ return Adjuster.NEXT_NON_WEEKEND;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Enum implementing the adjusters.
+ */
+ private static enum Adjuster implements TemporalAdjuster {
+ /** Next non weekend day adjuster. */
+ NEXT_NON_WEEKEND {
+ @Override
+ public Temporal adjustInto(Temporal dateTime) {
+ int dow = dateTime.get(DAY_OF_WEEK);
+ switch (dow) {
+ case 6: // Saturday
+ return dateTime.plus(2, DAYS);
+ case 5: // Friday
+ return dateTime.plus(3, DAYS);
+ default:
+ return dateTime.plus(1, DAYS);
+ }
+ }
+ },
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/Weeks.java b/src/main/java/org/threeten/extra/Weeks.java
new file mode 100644
index 0000000..caf6da0
--- /dev/null
+++ b/src/main/java/org/threeten/extra/Weeks.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra;
+
+import static org.threeten.bp.temporal.ChronoUnit.WEEKS;
+
+import java.io.Serializable;
+
+import org.threeten.bp.temporal.TemporalUnit;
+
+/**
+ * An amount of time measured in weeks, such as '6 Weeks'.
+ *
+ * This class stores an amount of time in terms of the weeks unit of time.
+ *
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount plus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Weeks plus(Weeks amount) {
+ return plus(amount.getAmount());
+ }
+
+ /**
+ * Returns a new instance with the specified amount of time subtracted.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount minus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Weeks minus(Weeks amount) {
+ return minus(amount.getAmount());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a string representation of the number of weeks.
+ * This will be in the format 'PnW' where n is the number of weeks.
+ *
+ * @return the number of weeks in ISO8601 string format
+ */
+ @Override
+ public String toString() {
+ return "P" + weeks + "W";
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/Years.java b/src/main/java/org/threeten/extra/Years.java
new file mode 100644
index 0000000..497dfeb
--- /dev/null
+++ b/src/main/java/org/threeten/extra/Years.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra;
+
+import static org.threeten.bp.temporal.ChronoUnit.YEARS;
+
+import java.io.Serializable;
+
+import org.threeten.bp.temporal.TemporalUnit;
+
+/**
+ * An amount of time measured in years, such as '6 Years'.
+ *
+ * This class stores an amount of time in terms of the years unit of time.
+ *
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount plus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Years plus(Years amount) {
+ return plus(amount.getAmount());
+ }
+
+ /**
+ * Returns a new instance with the specified amount of time subtracted.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount of time to add, may be negative
+ * @return the new amount minus the specified amount of time, not null
+ * @throws ArithmeticException if the result overflows an {@code int}
+ */
+ public Years minus(Years amount) {
+ return minus(amount.getAmount());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a string representation of the number of years.
+ * This will be in the format 'PnY' where n is the number of years.
+ *
+ * @return the number of years in ISO8601 string format
+ */
+ @Override
+ public String toString() {
+ return "P" + years + "Y";
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/chrono/CopticChronology.java b/src/main/java/org/threeten/extra/chrono/CopticChronology.java
new file mode 100644
index 0000000..c73c33d
--- /dev/null
+++ b/src/main/java/org/threeten/extra/chrono/CopticChronology.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra.chrono;
+
+import static org.threeten.bp.temporal.ChronoField.EPOCH_DAY;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+
+import org.threeten.bp.Clock;
+import org.threeten.bp.DateTimeException;
+import org.threeten.bp.Instant;
+import org.threeten.bp.ZoneId;
+import org.threeten.bp.chrono.ChronoLocalDateTime;
+import org.threeten.bp.chrono.ChronoZonedDateTime;
+import org.threeten.bp.chrono.Chronology;
+import org.threeten.bp.chrono.Era;
+import org.threeten.bp.jdk8.Jdk8Methods;
+import org.threeten.bp.temporal.ChronoField;
+import org.threeten.bp.temporal.TemporalAccessor;
+import org.threeten.bp.temporal.ValueRange;
+
+/**
+ * The Coptic calendar system.
+ *
+ * This chronology defines the rules of the Coptic calendar system.
+ * This calendar system is primarily used in Christian Egypt.
+ * Dates are aligned such that {@code 0001AM-01-01 (Coptic)} is {@code 0284-08-29 (ISO)}.
+ *
+ * The fields are defined as follows:
+ *
+ *
+ *
+ * The ID uniquely identifies the {@code Chrono}.
+ * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+ *
+ * @return the chronology ID - 'Coptic'
+ * @see #getCalendarType()
+ */
+ @Override
+ public String getId() {
+ return "Coptic";
+ }
+
+ /**
+ * Gets the calendar type of the underlying calendar system - 'coptic'.
+ *
+ * The calendar type is an identifier defined by the
+ * Unicode Locale Data Markup Language (LDML) specification.
+ * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+ * It can also be used as part of a locale, accessible via
+ * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+ *
+ * @return the calendar system type - 'coptic'
+ * @see #getId()
+ */
+ @Override
+ public String getCalendarType() {
+ return "coptic";
+ }
+
+ //-----------------------------------------------------------------------
+ @Override // override with covariant return type
+ public CopticDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
+ return (CopticDate) super.date(era, yearOfEra, month, dayOfMonth);
+ }
+
+ @Override // override with covariant return type
+ public CopticDate date(int prolepticYear, int month, int dayOfMonth) {
+ return new CopticDate(prolepticYear, month, dayOfMonth);
+ }
+
+ @Override // override with covariant return type
+ public CopticDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
+ return (CopticDate) super.dateYearDay(era, yearOfEra, dayOfYear);
+ }
+
+ @Override // override with covariant return type
+ public CopticDate dateYearDay(int prolepticYear, int dayOfYear) {
+ return new CopticDate(prolepticYear, (dayOfYear - 1) / 30 + 1, (dayOfYear - 1) % 30 + 1);
+ }
+
+ //-----------------------------------------------------------------------
+ @Override // override with covariant return type
+ public CopticDate date(TemporalAccessor temporal) {
+ if (temporal instanceof CopticDate) {
+ return (CopticDate) temporal;
+ }
+ return CopticDate.ofEpochDay(temporal.getLong(EPOCH_DAY));
+ }
+
+ @Override // override with covariant return type
+ public ChronoLocalDateTime
+ * A Coptic proleptic-year is leap if the remainder after division by four equals three.
+ * This method does not validate the year passed in, and only has a
+ * well-defined result for years in the supported range.
+ *
+ * @param prolepticYear the proleptic-year to check, not validated for range
+ * @return true if the year is a leap year
+ */
+ @Override
+ public boolean isLeapYear(long prolepticYear) {
+ return Jdk8Methods.floorMod(prolepticYear, 4) == 3;
+ }
+
+ @Override
+ public int prolepticYear(Era era, int yearOfEra) {
+ if (era instanceof CopticEra == false) {
+ throw new DateTimeException("Era must be CopticEra");
+ }
+ return (era == CopticEra.AM ? yearOfEra : 1 - yearOfEra);
+ }
+
+ @Override
+ public Era eraOf(int eraValue) {
+ return CopticEra.of(eraValue);
+ }
+
+ @Override
+ public List
+ * This implements {@code ChronoLocalDate} for the {@link CopticChronology Coptic calendar}.
+ *
+ *
+ * The Coptic calendar system uses the 'Era of the Martyrs'.
+ * The start of the Coptic epoch {@code 0001-01-01 (Coptic)} is {@code 0284-08-29 (ISO)}.
+ *
+ * Do not use {@code ordinal()} to obtain the numeric representation of {@code CopticEra}.
+ * Use {@code getValue()} instead.
+ *
+ *
+ * {@code CopticEra} is an enum representing the Coptic eras of BEFORE_AM/AM.
+ * This factory allows the enum to be obtained from the {@code int} value.
+ *
+ * @param era the BEFORE_AM/AM value to represent, from 0 (BEFORE_AM) to 1 (AM)
+ * @return the era singleton, not null
+ * @throws DateTimeException if the value is invalid
+ */
+ public static CopticEra of(int era) {
+ switch (era) {
+ case 0:
+ return BEFORE_AM;
+ case 1:
+ return AM;
+ default:
+ throw new DateTimeException("Invalid era: " + era);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the numeric era {@code int} value.
+ *
+ * The era BEFORE_AM has the value 0, while the era AM has the value 1.
+ *
+ * @return the era value, from 0 (BEFORE_AM) to 1 (AM)
+ */
+ @Override
+ public int getValue() {
+ return ordinal();
+ }
+
+ @Override
+ public CopticChronology getChronology() {
+ return CopticChronology.INSTANCE;
+ }
+
+ // JDK8 default methods:
+ //-----------------------------------------------------------------------
+ @Override
+ public CopticDate date(int year, int month, int day) {
+ return (CopticDate) getChronology().date(this, year, month, day);
+ }
+
+ @Override
+ public CopticDate dateYearDay(int year, int dayOfYear) {
+ return (CopticDate) getChronology().dateYearDay(this, year, dayOfYear);
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public boolean isSupported(TemporalField field) {
+ if (field instanceof ChronoField) {
+ return field == ERA;
+ }
+ return field != null && field.isSupportedBy(this);
+ }
+
+ @Override
+ public ValueRange range(TemporalField field) {
+ if (field == ERA) {
+ return field.range();
+ } else if (field instanceof ChronoField) {
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+ return field.rangeRefinedBy(this);
+ }
+
+ @Override
+ public int get(TemporalField field) {
+ if (field == ERA) {
+ return getValue();
+ }
+ return range(field).checkValidIntValue(getLong(field), field);
+ }
+
+ @Override
+ public long getLong(TemporalField field) {
+ if (field == ERA) {
+ return getValue();
+ } else if (field instanceof ChronoField) {
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+ return field.getFrom(this);
+ }
+
+ //-------------------------------------------------------------------------
+ @Override
+ public Temporal adjustInto(Temporal temporal) {
+ return temporal.with(ERA, getValue());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public
+ * Most of the Time Framework for Java works on the assumption that the time-line is
+ * simple, there are no leap-seconds and there are always 24 * 60 * 60 seconds in a day.
+ * However, the Earth's rotation is not straightforward, and a solar day does not match
+ * this definition.
+ *
+ * This class is an alternative representation based on the TAI time-scale.
+ * TAI is a single incrementing count of SI seconds.
+ * There are no leap seconds or other discontinuities.
+ *
+ * As a result of the simple definition, this time-scale would make an excellent timestamp.
+ * However, there are, at the time of writing, few easy ways to obtain an accurate TAI instant,
+ * but it is relatively easy to obtain a GPS instant.
+ * GPS and TAI differ by the fixed amount of 19 seconds.
+ *
+ * The duration between two points on the TAI time-scale is calculated solely using this class.
+ * Do not use the {@code between} method on {@code Duration} as that will lose information.
+ * Instead use {@link #durationUntil(TAIInstant)} on this class.
+ *
+ * It is intended that most applications will use the {@code Instant} class
+ * which uses the UTC-SLS mapping from UTC to guarantee 86400 seconds per day.
+ * Specialist applications with access to an accurate time-source may find this class useful.
+ *
+ *
+ * The TAI time-scale is a very simple well-regarded representation of time.
+ * The scale is defined using atomic clocks counting SI seconds.
+ * It has proceeded in a continuous uninterrupted manner since the defined
+ * epoch of {@code 1958-01-01T00:00:00(TAI)}.
+ * There are no leap seconds or other discontinuities.
+ *
+ * This class may be used for instants in the far past and far future.
+ * Since some instants will be prior to 1958, it is not strictly an implementation of TAI.
+ * Instead, it is a proleptic time-scale based on TAI and equivalent to it since 1958.
+ *
+ *
+ *
+ * This method allows an arbitrary number of nanoseconds to be passed in.
+ * The factory will alter the values of the second and nanosecond in order
+ * to ensure that the stored nanosecond is in the range 0 to 999,999,999.
+ * For example, the following will result in the exactly the same instant:
+ *
+ * Converting a UTC-SLS instant to a TAI instant requires leap second rules.
+ * This method uses the latest available system rules.
+ * The conversion first maps from UTC-SLS to UTC, then converts to TAI.
+ *
+ * Conversion from an {@code Instant} will not be completely accurate near
+ * a leap second in accordance with UTC-SLS.
+ *
+ * @param instant the instant to convert, not null
+ * @return the TAI instant, not null
+ * @throws ArithmeticException if the calculation exceeds the supported range
+ */
+ public static TAIInstant of(Instant instant) {
+ return UTCInstant.of(instant).toTAIInstant();
+ }
+
+ /**
+ * Obtains an instance of {@code TAIInstant} from a {@code UTCInstant}.
+ *
+ * Converting a UTC instant to a TAI instant requires leap second rules.
+ * This method uses the rules held in within the UTC instant.
+ *
+ * Conversion from a {@code UTCInstant} will be entirely accurate.
+ * The resulting TAI instant will not reference the leap second rules, so
+ * converting back to a UTC instant may result in a different UTC instant.
+ *
+ * @param instant the instant to convert, not null
+ * @return the TAI instant, not null
+ * @throws ArithmeticException if the calculation exceeds the supported range
+ */
+ public static TAIInstant of(UTCInstant instant) {
+ return instant.toTAIInstant();
+ }
+
+ /**
+ * Obtains an instance of {@code TAIInstant} from a text string.
+ *
+ * The following format is accepted:
+ *
+ * The accepted format is strict.
+ * The seconds part must contain only numbers and a possible leading negative sign.
+ * The nanoseconds part must contain exactly nine digits.
+ * The trailing literal must be exactly specified.
+ * This format parses the {@code toString} format.
+ *
+ * @param text the text to parse such as "12345.123456789s(TAI)", not null
+ * @return the parsed instant, not null
+ * @throws DateTimeException if the text cannot be parsed
+ */
+ public static TAIInstant parse(CharSequence text) {
+ Objects.requireNonNull(text, "text");
+ Matcher matcher = PARSER.matcher(text);
+ if (matcher.matches()) {
+ try {
+ long seconds = Long.parseLong(matcher.group(1));
+ long nanos = Long.parseLong(matcher.group(2));
+ return TAIInstant.ofTAISeconds(seconds, nanos);
+ } catch (NumberFormatException ex) {
+ throw new DateTimeParseException("The text could not be parsed", text, 0, ex);
+ }
+ }
+ throw new DateTimeParseException("The text could not be parsed", text, 0);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Constructs an instance.
+ *
+ * @param taiSeconds the number of TAI seconds from the epoch
+ * @param nanoOfSecond the nanoseconds within the second, from 0 to 999,999,999
+ */
+ private TAIInstant(long taiSeconds, int nanoOfSecond) {
+ super();
+ this.seconds = taiSeconds;
+ this.nanos = nanoOfSecond;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the number of seconds from the TAI epoch of 1958-01-01T00:00:00(TAI).
+ *
+ * The TAI second count is a simple incrementing count of seconds where
+ * second 0 is 1958-01-01T00:00:00(TAI).
+ * The nanosecond part of the day is returned by {@code getNanosOfSecond}.
+ *
+ * @return the seconds from the epoch of 1958-01-01T00:00:00(TAI)
+ */
+ public long getTAISeconds() {
+ return seconds;
+ }
+
+ /**
+ * Returns a copy of this {@code TAIInstant} with the number of seconds
+ * from the TAI epoch of 1958-01-01T00:00:00(TAI).
+ *
+ * The TAI second count is a simple incrementing count of seconds where
+ * second 0 is 1958-01-01T00:00:00(TAI).
+ * The nanosecond part of the day is returned by {@code getNanosOfSecond}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param taiSeconds the number of seconds from the epoch of 1958-01-01T00:00:00(TAI)
+ * @return a {@code TAIInstant} based on this instant with the requested second, not null
+ */
+ public TAIInstant withTAISeconds(long taiSeconds) {
+ return ofTAISeconds(taiSeconds, nanos);
+ }
+
+ /**
+ * Gets the number of nanoseconds, later along the time-line, from the start
+ * of the second.
+ *
+ * The nanosecond-of-second value measures the total number of nanoseconds from
+ * the second returned by {@code getTAISeconds}.
+ *
+ * @return the nanoseconds within the second, from 0 to 999,999,999
+ */
+ public int getNano() {
+ return nanos;
+ }
+
+ /**
+ * Returns a copy of this {@code TAIInstant} with the nano-of-second value changed.
+ *
+ * The nanosecond-of-second value measures the total number of nanoseconds from
+ * the second returned by {@code getTAISeconds}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param nanoOfSecond the nano-of-second, from 0 to 999,999,999
+ * @return a {@code TAIInstant} based on this instant with the requested nano-of-second, not null
+ * @throws IllegalArgumentException if nanoOfSecond is out of range
+ */
+ public TAIInstant withNano(int nanoOfSecond) {
+ if (nanoOfSecond < 0 || nanoOfSecond >= NANOS_PER_SECOND) {
+ throw new IllegalArgumentException("NanoOfSecond must be from 0 to 999,999,999");
+ }
+ return ofTAISeconds(seconds, nanoOfSecond);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this instant with the specified duration added.
+ *
+ * The duration is added using simple addition of the seconds and nanoseconds
+ * in the duration to the seconds and nanoseconds of this instant.
+ * As a result, the duration is treated as being measured in TAI compatible seconds
+ * for the purpose of this method.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param duration the duration to add, not null
+ * @return a {@code TAIInstant} based on this instant with the duration added, not null
+ * @throws ArithmeticException if the calculation exceeds the supported range
+ */
+ public TAIInstant plus(Duration duration) {
+ long secsToAdd = duration.getSeconds();
+ int nanosToAdd = duration.getNano();
+ if ((secsToAdd | nanosToAdd) == 0) {
+ return this;
+ }
+ long secs = Jdk8Methods.safeAdd(seconds, secsToAdd);
+ long nanoAdjustment = ((long) nanos) + nanosToAdd; // safe int+int
+ return ofTAISeconds(secs, nanoAdjustment);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this instant with the specified duration subtracted.
+ *
+ * The duration is subtracted using simple subtraction of the seconds and nanoseconds
+ * in the duration from the seconds and nanoseconds of this instant.
+ * As a result, the duration is treated as being measured in TAI compatible seconds
+ * for the purpose of this method.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param duration the duration to subtract, not null
+ * @return a {@code TAIInstant} based on this instant with the duration subtracted, not null
+ * @throws ArithmeticException if the calculation exceeds the supported range
+ */
+ public TAIInstant minus(Duration duration) {
+ long secsToSubtract = duration.getSeconds();
+ int nanosToSubtract = duration.getNano();
+ if ((secsToSubtract | nanosToSubtract) == 0) {
+ return this;
+ }
+ long secs = Jdk8Methods.safeSubtract(seconds, secsToSubtract);
+ long nanoAdjustment = ((long) nanos) - nanosToSubtract; // safe int+int
+ return ofTAISeconds(secs, nanoAdjustment);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns the duration between this instant and the specified instant.
+ *
+ * This calculates the duration between this instant and another based on
+ * the TAI time-scale. Adding the duration to this instant using {@link #plus}
+ * will always result in an instant equal to the specified instant.
+ *
+ * @param taiInstant the instant to calculate the duration until, not null
+ * @return the duration until the specified instant, may be negative, not null
+ * @throws ArithmeticException if the calculation exceeds the supported range
+ */
+ public Duration durationUntil(TAIInstant taiInstant) {
+ long durSecs = Jdk8Methods.safeSubtract(taiInstant.seconds, seconds);
+ long durNanos = taiInstant.nanos - nanos;
+ return Duration.ofSeconds(durSecs, durNanos);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Converts this instant to a {@code UTCInstant} using the system default
+ * leap second rules.
+ *
+ * This method converts this instant from the TAI to the UTC time-scale using the
+ * system default leap-second rules. This conversion does not lose information
+ * and the UTC instant may safely be converted back to a {@code TAIInstant}.
+ *
+ * @return a {@code UTCInstant} representing the same instant using the system leap second rules, not null
+ */
+ public UTCInstant toUTCInstant() {
+ return UTCInstant.of(this, UTCRules.system());
+ }
+
+ /**
+ * Converts this instant to an {@code Instant} using the system default
+ * leap second rules.
+ *
+ * This method converts this instant from the TAI to the UTC-SLS time-scale using the
+ * system default leap-second rules to convert to UTC.
+ * This conversion will lose information around a leap second in accordance with UTC-SLS.
+ * Converting back to a {@code TAIInstant} may result in a slightly different instant.
+ *
+ * @return an {@code Instant} representing the best approximation of this instant, not null
+ */
+ public Instant toInstant() {
+ return toUTCInstant().toInstant();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Compares this instant to another based on the time-line.
+ *
+ * @param otherInstant the other instant to compare to, not null
+ * @return the comparator value, negative if less, positive if greater
+ */
+ public int compareTo(TAIInstant otherInstant) {
+ int cmp = Long.compare(seconds, otherInstant.seconds);
+ if (cmp != 0) {
+ return cmp;
+ }
+ return nanos - otherInstant.nanos;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if this instant is equal to the specified {@code TAIInstant}.
+ *
+ * @param otherInstant the other instant, null returns false
+ * @return true if the other instant is equal to this one
+ */
+ @Override
+ public boolean equals(Object otherInstant) {
+ if (this == otherInstant) {
+ return true;
+ }
+ if (otherInstant instanceof TAIInstant) {
+ TAIInstant other = (TAIInstant) otherInstant;
+ return this.seconds == other.seconds &&
+ this.nanos == other.nanos;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a hash code for this instant.
+ *
+ * @return a suitable hash code
+ */
+ @Override
+ public int hashCode() {
+ // TODO: Evaluate hash code
+ return ((int) (seconds ^ (seconds >>> 32))) + 51 * nanos;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * A string representation of this instant.
+ *
+ * The string is formatted as {@code {seconds).(nanosOfSecond}s(TAI)}.
+ * At least one second digit will be present.
+ * The nanoseconds will always be nine digits.
+ *
+ * @return a representation of this instant, not null
+ */
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+ buf.append(seconds);
+ int pos = buf.length();
+ buf.append(nanos + NANOS_PER_SECOND);
+ buf.setCharAt(pos, '.');
+ buf.append("s(TAI)");
+ return buf.toString();
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/scale/TimeSource.java b/src/main/java/org/threeten/extra/scale/TimeSource.java
new file mode 100644
index 0000000..367d4ff
--- /dev/null
+++ b/src/main/java/org/threeten/extra/scale/TimeSource.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra.scale;
+
+import org.threeten.bp.Clock;
+import org.threeten.bp.Instant;
+
+/**
+ * A clock that provides the current UTC or TAI instant.
+ *
+ * This clock differs from {@link Clock} in providing access to the current instant
+ * in the UTC and TAI time-scales. However, there is currently no implementation that
+ * provides accurate UTC or TAI.
+ *
+ *
+ * The principal methods are defined to allow the throwing of an exception.
+ * In normal use, no exceptions will be thrown, however one possible implementation would be to
+ * obtain the time from a central time server across the network. Obviously, in this case the
+ * lookup could fail, and so the method is permitted to throw an exception.
+ *
+ * Subclass implementations should implement {@code Serializable} wherever possible.
+ * They should also be immutable and thread-safe, implementing {@code equals()},
+ * {@code hashCode()} and {@code toString()} based on their state.
+ */
+public interface TimeSource {
+
+ /**
+ * Gets the current {@code Instant}.
+ *
+ * The instant returned by this method will vary according to the implementation.
+ * For example, the time-source returned by {@link #system()} will return
+ * an instant based on {@link System#currentTimeMillis()}.
+ *
+ * @return the current {@code Instant} from this time-source, not null
+ * @throws RuntimeException if the instant cannot be obtained, not thrown by most implementations
+ */
+ public abstract Instant instant();
+
+ /**
+ * Gets the current {@code UTCInstant}.
+ *
+ * The UTC time-scale is the current world civil time and includes leap seconds.
+ * An accurate implementation of this interface will return the correct UTC instant.
+ *
+ * @return the current {@code UTCInstant} from this time-source, not null
+ * @throws RuntimeException if the instant cannot be obtained, not thrown by most implementations
+ */
+ public abstract UTCInstant utcInstant();
+
+ /**
+ * Gets the current {@code TAIInstant}.
+ *
+ * The TAI time-scale is a simple incrementing number of seconds from the TAI epoch of 1958-01-01(TAI).
+ * It ignores all human concepts of time such as days.
+ * An accurate implementation of this interface will return the correct TAI instant.
+ *
+ * @return the current {@code TAIInstant} from this time-source, not null
+ * @throws RuntimeException if the instant cannot be obtained, not thrown by most implementations
+ */
+ public abstract TAIInstant taiInstant();
+
+}
diff --git a/src/main/java/org/threeten/extra/scale/UTCInstant.java b/src/main/java/org/threeten/extra/scale/UTCInstant.java
new file mode 100644
index 0000000..7602390
--- /dev/null
+++ b/src/main/java/org/threeten/extra/scale/UTCInstant.java
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra.scale;
+
+import java.io.Serializable;
+
+import org.threeten.bp.Duration;
+import org.threeten.bp.Instant;
+import org.threeten.bp.LocalDate;
+import org.threeten.bp.temporal.JulianFields;
+
+/**
+ * An instantaneous point on the time-line measured in the UTC time-scale
+ * with leap seconds.
+ *
+ * Most of the Java time classes work on the assumption that the time-line is simple,
+ * there are no leap-seconds and there are always 24 * 60 * 60 seconds in a day.
+ * However, the Earth's rotation is not straightforward, and a solar day does not match
+ * this definition.
+ *
+ * This class is an alternative representation based on the UTC time-scale which
+ * includes leap-seconds. Leap-seconds are additional seconds that are inserted into the
+ * year-month-day-hour-minute-second time-line in order to keep UTC in line with the solar day.
+ * When a leap second occurs, an accurate clock will show the time {@code 23:59:60} just before midnight.
+ *
+ * Leap-seconds are announced in advance, typically at least six months.
+ * The {@link UTCRules} class models which dates have leap-seconds.
+ * Alternative implementations of the rules may be supplied.
+ *
+ * The default rules implementation fixes the start point of UTC as 1972.
+ * This date was chosen as UTC was more complex before 1972.
+ *
+ * The duration between two points on the UTC time-scale is calculated solely using this class.
+ * Do not use the {@code between} method on {@code Duration} as that will lose information.
+ * Instead use {@link #durationUntil(UTCInstant)} on this class.
+ *
+ * It is intended that most applications will use the {@code Instant} class
+ * which uses the UTC-SLS mapping from UTC to guarantee 86400 seconds per day.
+ * Specialist applications with access to an accurate time-source may find this class useful.
+ *
+ *
+ * The length of the solar day is the standard way that humans measure time.
+ * As the Earth's rotation changes, the length of the day varies.
+ * In general, a solar day is slightly longer than 86400 SI seconds.
+ * The actual length is not predictable and can only be determined by measurement.
+ * The UT1 time-scale captures these measurements.
+ *
+ * The UTC time-scale is a standard approach to bundle up all the additional fractions
+ * of a second from UT1 into whole seconds, known as leap-seconds.
+ * A leap-second may be added or removed depending on the Earth's rotational changes.
+ * If it is removed, then the relevant date will have no time of {@code 23:59:59}.
+ * If it is added, then the relevant date will have an extra second of {@code 23:59:60}.
+ *
+ * The modern UTC time-scale was introduced in 1972, introducing the concept of whole leap-seconds.
+ * Between 1958 and 1972, the definition of UTC was complex, with minor sub-second leaps and
+ * alterations to the length of the notional second.
+ *
+ * This class may be used for instants in the far past and far future.
+ * Since some instants will be prior to 1972, it is not strictly an implementation of UTC.
+ * Instead, it is a proleptic time-scale based on UTC and equivalent to it since 1972.
+ * Prior to 1972, the default rules fix the UTC-TAI offset at 10 seconds.
+ * While not historically accurate, it is a simple, easy definition, suitable for this library.
+ *
+ * The standard Java epoch of {@code 1970-01-01} is prior to the introduction of whole leap-seconds into UTC in 1972.
+ * As such, the Time Framework for Java needs to define what the 1970 epoch actually means.
+ * The chosen definition follows the UTC definition given above, such that {@code 1970-01-01} is 10 seconds
+ * offset from TAI.
+ *
+ *
+ * This factory creates an instance of a UTC instant.
+ * The nanosecond of day value includes any leap second and has a valid range from
+ * {@code 0} to {@code 86,400,000,000,000 - 1} on days other than leap-second-days
+ * and other lengths on leap-second-days.
+ *
+ * The nanosecond value must be positive even for negative values of Modified
+ * Julian Days. One nanosecond before Modified Julian Day zero will be
+ * {@code -1} days and the maximum nanosecond value.
+ *
+ * @param mjDay the date as a Modified Julian Day (number of days from the epoch of 1858-11-17)
+ * @param nanoOfDay the nanoseconds within the day, including leap seconds
+ * @return the UTC instant, not null
+ * @throws IllegalArgumentException if nanoOfDay is out of range
+ */
+ public static UTCInstant ofModifiedJulianDay(long mjDay, long nanoOfDay) {
+ return ofModifiedJulianDay(mjDay, nanoOfDay, UTCRules.system());
+ }
+
+ /**
+ * Obtains an instance of {@code UTCInstant} from a Modified Julian Day with
+ * a nanosecond fraction of second using the specified leap second rules.
+ *
+ * This factory creates an instance of a UTC instant.
+ * The nanosecond of day value includes any leap second and has a valid range from
+ * {@code 0} to {@code 86,400,000,000,000 - 1} on days other than leap-second-days
+ * and other lengths on leap-second-days.
+ *
+ * The nanosecond value must be positive even for negative values of Modified
+ * Julian Days. One nanosecond before Modified Julian Day zero will be
+ * {@code -1} days and the maximum nanosecond value.
+ *
+ * @param mjDay the date as a Modified Julian Day (number of days from the epoch of 1858-11-17)
+ * @param nanoOfDay the nanoseconds within the day, including leap seconds
+ * @return the UTC instant, not null
+ * @throws IllegalArgumentException if nanoOfDay is out of range
+ */
+ public static UTCInstant ofModifiedJulianDay(long mjDay, long nanoOfDay, UTCRules rules) {
+ long leapSecs = rules.getLeapSecondAdjustment(mjDay);
+ long maxNanos = (SECS_PER_DAY + leapSecs) * NANOS_PER_SECOND;
+ if (nanoOfDay < 0 || nanoOfDay >= maxNanos) {
+ throw new IllegalArgumentException("Nanosecond-of-day must be between 0 and " + maxNanos + " on date " + mjDay);
+ }
+ return new UTCInstant(mjDay, nanoOfDay, rules);
+ }
+
+ /**
+ * Obtains an instance of {@code UTCInstant} from a provider of instants
+ * using the system default leap second rules.
+ *
+ * This method converts from the UTC-SLS to the UTC time-scale using the
+ * system default leap-second rules. This conversion will lose information
+ * around a leap second in accordance with UTC-SLS.
+ * Converting back to an {@code Instant} may result in a slightly different instant.
+ *
+ * @param instant the instant to convert, not null
+ * @return the UTC instant, not null
+ */
+ public static UTCInstant of(Instant instant) {
+ return of(instant, UTCRules.system());
+ }
+
+ /**
+ * Obtains an instance of {@code UTCInstant} from a provider of instants
+ * using the specified leap second rules.
+ *
+ * This method converts from the UTC-SLS to the UTC time-scale using the
+ * specified leap-second rules. This conversion will lose information
+ * around a leap second in accordance with UTC-SLS.
+ * Converting back to an {@code Instant} may result in a slightly different instant.
+ *
+ * @param instant the instant to convert, not null
+ * @param rules the leap second rules, not null
+ * @return the UTC instant, not null
+ */
+ public static UTCInstant of(Instant instant, UTCRules rules) {
+ return rules.convertToUTC(instant);
+ }
+
+ /**
+ * Obtains an instance of {@code UTCInstant} from a TAI instant
+ * using the system default leap second rules.
+ *
+ * This method converts from the TAI to the UTC time-scale using the
+ * system default leap-second rules. This conversion does not lose information
+ * and the UTC instant may safely be converted back to a {@code TAIInstant}.
+ *
+ * @param taiInstant the TAI instant to convert, not null
+ * @return the UTC instant, not null
+ */
+ public static UTCInstant of(TAIInstant taiInstant) {
+ return of(taiInstant, UTCRules.system());
+ }
+
+ /**
+ * Obtains an instance of {@code UTCInstant} from a TAI instant
+ * using the specified leap second rules.
+ *
+ * This method converts from the TAI to the UTC time-scale using the
+ * specified leap-second rules. This conversion does not lose information
+ * and the UTC instant may safely be converted back to a {@code TAIInstant}.
+ *
+ * @param taiInstant the TAI instant to convert, not null
+ * @param rules the leap second rules, not null
+ * @return the UTC instant, not null
+ */
+ public static UTCInstant of(TAIInstant taiInstant, UTCRules rules) {
+ return rules.convertToUTC(taiInstant);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Constructs an instance.
+ *
+ * @param mjDay the date as a Modified Julian Day (number of days from the epoch of 1858-11-17)
+ * @param nanoOfDay the nanoseconds within the day, including leap seconds
+ * @param rules the leap second rules, not null
+ */
+ private UTCInstant(long mjDay, long nanoOfDay, UTCRules rules) {
+ super();
+ this.mjDay = mjDay;
+ this.nanoOfDay = nanoOfDay;
+ this.rules = rules;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the leap second rules defining when leap seconds occur.
+ *
+ * @return the leap seconds rules
+ */
+ public UTCRules getRules() {
+ return rules;
+ }
+
+ /**
+ * Gets the Modified Julian Day (MJD).
+ *
+ * The Modified Julian Day count is a simple incrementing count of days
+ * where day 0 is 1858-11-17.
+ * The nanosecond part of the day is returned by {@code getNanosOfDay}.
+ * The day varies in length, being one second longer on a leap day.
+ *
+ * @return the Modified Julian Day based on the epoch 1858-11-17
+ */
+ public long getModifiedJulianDay() {
+ return mjDay;
+ }
+
+ /**
+ * Returns a copy of this {@code UTCInstant} with the Modified Julian Day (MJD) altered.
+ *
+ * The Modified Julian Day count is a simple incrementing count of days
+ * where day 0 is 1858-11-17.
+ * The nanosecond part of the day is returned by {@code getNanosOfDay}.
+ * The day varies in length, being one second longer on a leap day.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param mjDay the date as a Modified Julian Day (number of days from the epoch of 1858-11-17)
+ * @return a {@code UTCInstant} based on this instant with the requested day, not null
+ * @throws IllegalArgumentException if nanoOfDay becomes invalid
+ */
+ public UTCInstant withModifiedJulianDay(long mjDay) {
+ return ofModifiedJulianDay(mjDay, nanoOfDay, rules);
+ }
+
+ /**
+ * Gets the number of nanoseconds, later along the time-line, from the start
+ * of the Modified Julian Day.
+ *
+ * The nanosecond-of-day value measures the total number of nanoseconds within
+ * the day from the start of the day returned by {@code getModifiedJulianDay}.
+ * This value will include any additional leap seconds.
+ *
+ * @return the nanoseconds within the day, including leap seconds
+ */
+ public long getNanoOfDay() {
+ return nanoOfDay;
+ }
+
+ /**
+ * Returns a copy of this {@code UTCInstant} with the nano-of-day altered.
+ *
+ * The nanosecond-of-day value measures the total number of nanoseconds within
+ * the day from the start of the day returned by {@code getModifiedJulianDay}.
+ * This value will include any additional leap seconds.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param nanoOfDay the nanoseconds within the day, including leap seconds
+ * @return a {@code UTCInstant} based on this instant with the requested nano-of-day, not null
+ * @throws IllegalArgumentException if the nanoOfDay value is invalid
+ */
+ public UTCInstant withNanoOfDay(long nanoOfDay) {
+ return ofModifiedJulianDay(mjDay, nanoOfDay, rules);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if the instant is within a leap second.
+ *
+ * This method returns true when an accurate clock would return a seconds
+ * field of 60.
+ *
+ * @return true if this instant is within a leap second
+ */
+ public boolean isLeapSecond() {
+ return nanoOfDay > SECS_PER_DAY * NANOS_PER_SECOND;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this instant with the specified duration added.
+ *
+ * The duration is added using simple addition of the seconds and nanoseconds
+ * in the duration to the seconds and nanoseconds of this instant.
+ * As a result, the duration is treated as being measured in TAI compatible seconds
+ * for the purpose of this method.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param duration the duration to add, not null
+ * @return a {@code UTCInstant} with the duration added, not null
+ * @throws ArithmeticException if the calculation exceeds the supported range
+ */
+ public UTCInstant plus(Duration duration) {
+ return UTCInstant.of(toTAIInstant().plus(duration), rules);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this instant with the specified duration subtracted.
+ *
+ * The duration is subtracted using simple subtraction of the seconds and nanoseconds
+ * in the duration from the seconds and nanoseconds of this instant.
+ * As a result, the duration is treated as being measured in TAI compatible seconds
+ * for the purpose of this method.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param duration the duration to subtract, not null
+ * @return a {@code UTCInstant} with the duration subtracted, not null
+ * @throws ArithmeticException if the calculation exceeds the supported range
+ */
+ public UTCInstant minus(Duration duration) {
+ return UTCInstant.of(toTAIInstant().minus(duration), rules);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns the duration between this instant and the specified instant.
+ *
+ * This calculates the duration between this instant and another based on
+ * the UTC time-scale. Any leap seconds that occur will be included in the duration.
+ * Adding the duration to this instant using {@link #plus} will always result
+ * in an instant equal to the specified instant.
+ *
+ * @param utcInstant the instant to calculate the duration until, not null
+ * @return the duration until the specified instant, may be negative, not null
+ * @throws ArithmeticException if the calculation exceeds the supported range
+ */
+ public Duration durationUntil(UTCInstant utcInstant) {
+ TAIInstant thisTAI = toTAIInstant();
+ TAIInstant otherTAI = utcInstant.toTAIInstant();
+ return thisTAI.durationUntil(otherTAI);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Converts this instant to a {@code TAIInstant} using the stored
+ * leap second rules.
+ *
+ * This method converts from the UTC to the TAI time-scale using the stored leap-second rules.
+ * Conversion to a {@code TAIInstant} retains the same point on the time-line
+ * but loses the stored rules. If the TAI instant is converted back to a UTC instant
+ * with different or updated rules then the calculated UTC instant may be different.
+ *
+ * @return a {@code TAIInstant} representing the same instant, not null
+ * @throws ArithmeticException if the calculation exceeds the supported range
+ */
+ public TAIInstant toTAIInstant() {
+ return rules.convertToTAI(this);
+ }
+
+ /**
+ * Converts this instant to an {@code Instant} using the system default
+ * leap second rules.
+ *
+ * This method converts this instant from the UTC to the UTC-SLS time-scale using the
+ * stored leap-second rules.
+ * This conversion will lose information around a leap second in accordance with UTC-SLS.
+ * Converting back to a {@code UTCInstant} may result in a slightly different instant.
+ *
+ * @return an {@code Instant} representing the best approximation of this instant, not null
+ * @throws ArithmeticException if the calculation exceeds the supported range
+ */
+ public Instant toInstant() {
+ return rules.convertToInstant(this);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Compares this instant to another based on the time-line, ignoring the rules.
+ *
+ * The comparison is based on the positions on the time-line.
+ * Ignoring the rules makes this comparison inconsistent with equals.
+ *
+ * @param otherInstant the other instant to compare to, not null
+ * @return the comparator value, negative if less, positive if greater
+ */
+ public int compareTo(UTCInstant otherInstant) {
+ int cmp = Long.compare(mjDay, otherInstant.mjDay);
+ if (cmp != 0) {
+ return cmp;
+ }
+ return Long.compare(nanoOfDay, otherInstant.nanoOfDay);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if this instant is equal to the specified {@code UTCInstant}.
+ *
+ * The comparison is based on the positions on the time-line and the rules.
+ * This definition means that two instants representing the same instant on
+ * the time-line will differ if the rules differ. To compare the time-line
+ * instant, convert both instants to a {@code TAIInstant}.
+ *
+ * @param otherInstant the other instant, null returns false
+ * @return true if the other instant is equal to this one
+ */
+ @Override
+ public boolean equals(Object otherInstant) {
+ if (this == otherInstant) {
+ return true;
+ }
+ if (otherInstant instanceof UTCInstant) {
+ UTCInstant other = (UTCInstant) otherInstant;
+ return this.mjDay == other.mjDay &&
+ this.nanoOfDay == other.nanoOfDay &&
+ this.rules.equals(other.rules);
+ }
+ return false;
+ }
+
+ /**
+ * Returns a hash code for this instant.
+ *
+ * @return a suitable hash code
+ */
+ @Override
+ public int hashCode() {
+ // TODO: Evaluate hash code
+ return ((int) (mjDay ^ (mjDay >>> 32))) + 51 * ((int) (nanoOfDay ^ (nanoOfDay >>> 32))) +
+ rules.hashCode();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * A string representation of this instant.
+ *
+ * The string is formatted using ISO-8601.
+ *
+ * @return a representation of this instant, not null
+ */
+ @Override
+ public String toString() {
+ LocalDate date = LocalDate.MAX.with(JulianFields.MODIFIED_JULIAN_DAY, mjDay); // TODO: capacity/import issues
+ StringBuilder buf = new StringBuilder(18);
+ int sod = (int) (nanoOfDay / NANOS_PER_SECOND);
+ int hourValue = sod / (60 * 60);
+ int minuteValue = (sod / 60) % 60;
+ int secondValue = sod % 60;
+ if (hourValue == 24) {
+ hourValue = 23;
+ minuteValue = 59;
+ secondValue += 60;
+ }
+ int nanoValue = (int) (nanoOfDay % NANOS_PER_SECOND);
+ buf.append(date).append('T')
+ .append(hourValue < 10 ? "0" : "").append(hourValue)
+ .append(minuteValue < 10 ? ":0" : ":").append(minuteValue)
+ .append(secondValue < 10 ? ":0" : ":").append(secondValue);
+ int pos = buf.length();
+ buf.append(nanoValue + NANOS_PER_SECOND);
+ buf.setCharAt(pos, '.');
+ buf.append("(UTC)");
+ return buf.toString();
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/scale/UTCRules.java b/src/main/java/org/threeten/extra/scale/UTCRules.java
new file mode 100644
index 0000000..8e6a107
--- /dev/null
+++ b/src/main/java/org/threeten/extra/scale/UTCRules.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra.scale;
+
+import java.util.ConcurrentModificationException;
+
+import org.threeten.bp.Instant;
+import org.threeten.bp.jdk8.Jdk8Methods;
+
+/**
+ * Rules defining the UTC time-scale, notably when leap seconds occur.
+ *
+ * This class defines the UTC time-scale including when leap seconds occur.
+ * Subclasses obtain the data from a suitable source, such as TZDB or GPS.
+ *
+ * The static methods on this class provide access to the system leap second rules.
+ * These are used by default.
+ *
+ *
+ * The system default rules are serializable, immutable and thread-safe.
+ * They will remain up to date as new leap seconds are added.
+ *
+ * @return the system rules, not null
+ */
+ public static UTCRules system() {
+ return SystemUTCRules.INSTANCE;
+ }
+
+ /**
+ * Adds a new leap second to the system default leap second rules.
+ *
+ * This method registers a new leap second with the system leap second rules.
+ * Once registered, there is no way to deregister the leap second.
+ *
+ * Calling this method is thread-safe.
+ * Its effects are immediately visible in all threads.
+ * Where possible, only call this method from a single thread to avoid the possibility of
+ * a {@code ConcurrentModificationException}.
+ *
+ * If the leap second being added matches a previous definition, then the method returns normally.
+ * If the date is before the last registered date and doesn't match, then an exception is thrown.
+ *
+ * @param mjDay the modified julian date that the leap second occurs at the end of
+ * @param leapAdjustment the leap seconds to add/remove at the end of the day, either -1 or 1
+ * @throws IllegalArgumentException if the leap adjustment is invalid
+ * @throws IllegalArgumentException if the day is before or equal the last known leap second day
+ * and the definition does not match a previously registered leap
+ * @throws ConcurrentModificationException if another thread updates the rules at the same time
+ */
+ public static void registerSystemLeapSecond(long mjDay, int leapAdjustment) {
+ SystemUTCRules.INSTANCE.registerLeapSecond(mjDay, leapAdjustment);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Creates an instance of the rules.
+ */
+ protected UTCRules() {
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * The name of these rules.
+ *
+ * @return the name, not null
+ */
+ public abstract String getName();
+
+ /**
+ * Gets the leap second adjustment on the specified date.
+ *
+ * The UTC standard restricts the adjustment to a day to {@code -1} or {@code 1}.
+ *
+ * Any leap seconds are added to, or removed from, the end of the specified date.
+ *
+ * NOTE: If the UTC specification is altered to allow multiple leap seconds at once,
+ * then the result of this method would change.
+ *
+ * @param mjDay the date as a Modified Julian Day (number of days from the epoch of 1858-11-17)
+ * @return the number of seconds added, or removed, from the date, either -1 or 1
+ */
+ public abstract int getLeapSecondAdjustment(long mjDay);
+
+ /**
+ * Gets the offset to TAI on the specified date.
+ *
+ * The TAI offset starts at 10 in 1972 and varies from then on based on the
+ * dates of leap seconds.
+ * The offset will apply for the whole of the date.
+ *
+ * @param mjDay the date as a Modified Julian Day (number of days from the epoch of 1858-11-17)
+ * @return the TAI offset in seconds
+ */
+ public abstract int getTAIOffset(long mjDay);
+
+ /**
+ * Gets all known leap second dates.
+ *
+ * The dates are returned as Modified Julian Day values.
+ * The leap second is added to, or removed from, the end of the specified dates.
+ * The dates will be sorted from earliest to latest.
+ *
+ * @return an array of leap second dates expressed as Modified Julian Day values, not null
+ */
+ public abstract long[] getLeapSecondDates();
+
+ //-----------------------------------------------------------------------
+ /**
+ * Converts a {@code UTCInstant} to a {@code TAIInstant}.
+ *
+ * This method converts from the UTC to the TAI time-scale using the
+ * leap-second rules of the implementation.
+ *
+ * The standard implementation uses {@code getTAIOffset}.
+ *
+ * @param utcInstant the UTC instant to convert, not null
+ * @return the converted TAI instant, not null
+ * @throws ArithmeticException if the capacity is exceeded
+ */
+ protected TAIInstant convertToTAI(UTCInstant utcInstant) {
+ long mjd = utcInstant.getModifiedJulianDay();
+ long nod = utcInstant.getNanoOfDay();
+ long taiUtcDaySeconds = Jdk8Methods.safeMultiply(mjd - OFFSET_MJD_TAI, SECS_PER_DAY);
+ long taiSecs = Jdk8Methods.safeAdd(taiUtcDaySeconds, nod / NANOS_PER_SECOND + getTAIOffset(mjd));
+ int nos = (int) (nod % NANOS_PER_SECOND);
+ return TAIInstant.ofTAISeconds(taiSecs, nos);
+ }
+
+ /**
+ * Converts a {@code TAIInstant} to a {@code UTCInstant}.
+ *
+ * This method converts from the TAI to the UTC time-scale using the
+ * leap-second rules of the implementation.
+ *
+ * @param taiInstant the TAI instant to convert, not null
+ * @return the converted UTC instant, not null
+ * @throws ArithmeticException if the capacity is exceeded
+ */
+ protected abstract UTCInstant convertToUTC(TAIInstant taiInstant);
+
+ //-----------------------------------------------------------------------
+ /**
+ * Converts a {@code UTCInstant} to an {@code Instant}.
+ *
+ * This method converts from the UTC time-scale to one with 86400 seconds per day
+ * using the leap-second rules of the implementation.
+ *
+ * The standard implementation uses the UTC-SLS algorithm.
+ * Overriding this algorithm is possible, however doing so will conflict other parts
+ * of the specification.
+ *
+ * The algorithm calculates the UTC-SLS nanos-of-day {@code US} from the UTC nanos-of day {@code U}.
+ * This method converts from an instant with 86400 seconds per day to the UTC
+ * time-scale using the leap-second rules of the implementation.
+ *
+ * The standard implementation uses the UTC-SLS algorithm.
+ * Overriding this algorithm is possible, however doing so will conflict other parts
+ * of the specification.
+ *
+ * The algorithm calculates the UTC nanos-of-day {@code U} from the UTC-SLS nanos-of day {@code US}.
+ * // these two lines are equivalent, but the second approach is recommended
+ * temporal = thisDayOfWeek.adjustInto(temporal);
+ * temporal = temporal.with(thisDayOfWeek);
+ *
+ *
+ * date = date.with(minguo(temporal -> temporal.plus(1, MONTHS)));
+ *
+ * or in JDK 1.7:
+ *
+ * date = date.with(minguo(new TemporalAdjuster() {
+ * @Override
+ * public Temporal adjustInto(Temporal temporal) {
+ * return temporal.plus(1, MONTHS);
+ * }
+ * }));
+ *
+ *
+ * @param adjuster the adjuster to run in the Minguo calendar system
+ * @return the adjuster, not null
+ */
+ public static TemporalAdjuster minguo(final TemporalAdjuster adjuster) {
+ return new TemporalAdjuster() {
+ @Override
+ public Temporal adjustInto(Temporal temporal) {
+ ChronoLocalDate> baseDate = MinguoChronology.INSTANCE.date(temporal);
+ ChronoLocalDate> adjustedDate = (ChronoLocalDate>) adjuster.adjustInto(baseDate);
+ return temporal.with(adjustedDate);
+ }
+ };
+ }
+
+ /**
+ * Convenience wrapper allowing a date to be easily adjusted in the Hijrah calendar system.
+ *
+ * date = date.with(hijrah(temporal -> temporal.plus(1, MONTHS)));
+ *
+ * or in JDK 1.7:
+ *
+ * date = date.with(hijrah(new TemporalAdjuster() {
+ * @Override
+ * public Temporal adjustInto(Temporal temporal) {
+ * return temporal.plus(1, MONTHS);
+ * }
+ * }));
+ *
+ *
+ * @param adjuster the adjuster to run in the Hijrah calendar system
+ * @return the adjuster, not null
+ */
+ public static TemporalAdjuster hijrah(final TemporalAdjuster adjuster) {
+ return new TemporalAdjuster() {
+ @Override
+ public Temporal adjustInto(Temporal temporal) {
+ ChronoLocalDate> baseDate = HijrahChronology.INSTANCE.date(temporal);
+ ChronoLocalDate> adjustedDate = (ChronoLocalDate>) adjuster.adjustInto(baseDate);
+ return temporal.with(adjustedDate);
+ }
+ };
+ }
+
+ /**
+ * Convenience wrapper allowing a date to be easily adjusted in the Japanese calendar system.
+ *
+ * date = date.with(japanese(temporal -> temporal.plus(1, MONTHS)));
+ *
+ * or in JDK 1.7:
+ *
+ * date = date.with(japanese(new TemporalAdjuster() {
+ * @Override
+ * public Temporal adjustInto(Temporal temporal) {
+ * return temporal.plus(1, MONTHS);
+ * }
+ * }));
+ *
+ *
+ * @param adjuster the adjuster to run in the Japanese calendar system
+ * @return the adjuster, not null
+ */
+ public static TemporalAdjuster japanese(final TemporalAdjuster adjuster) {
+ return new TemporalAdjuster() {
+ @Override
+ public Temporal adjustInto(Temporal temporal) {
+ ChronoLocalDate> baseDate = JapaneseChronology.INSTANCE.date(temporal);
+ ChronoLocalDate> adjustedDate = (ChronoLocalDate>) adjuster.adjustInto(baseDate);
+ return temporal.with(adjustedDate);
+ }
+ };
+ }
+
+ /**
+ * Convenience wrapper allowing a date to be easily adjusted in the ThaiBuddhist calendar system.
+ *
+ * date = date.with(thaiBuddhist(temporal -> temporal.plus(1, MONTHS)));
+ *
+ * or in JDK 1.7:
+ *
+ * date = date.with(thaiBuddhist(new TemporalAdjuster() {
+ * @Override
+ * public Temporal adjustInto(Temporal temporal) {
+ * return temporal.plus(1, MONTHS);
+ * }
+ * }));
+ *
+ *
+ * @param adjuster the adjuster to run in the ThaiBuddhist calendar system
+ * @return the adjuster, not null
+ */
+ public static TemporalAdjuster thaiBuddhist(final TemporalAdjuster adjuster) {
+ return new TemporalAdjuster() {
+ @Override
+ public Temporal adjustInto(Temporal temporal) {
+ ChronoLocalDate> baseDate = ThaiBuddhistChronology.INSTANCE.date(temporal);
+ ChronoLocalDate> adjustedDate = (ChronoLocalDate>) adjuster.adjustInto(baseDate);
+ return temporal.with(adjustedDate);
+ }
+ };
+ }
+
+}
diff --git a/src/main/java/org/threeten/extra/DayOfMonth.java b/src/main/java/org/threeten/extra/DayOfMonth.java
new file mode 100644
index 0000000..270df39
--- /dev/null
+++ b/src/main/java/org/threeten/extra/DayOfMonth.java
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra;
+
+import static org.threeten.bp.temporal.ChronoField.DAY_OF_MONTH;
+import static org.threeten.bp.temporal.ChronoUnit.DAYS;
+
+import java.io.Serializable;
+import java.util.concurrent.atomic.AtomicReferenceArray;
+
+import org.threeten.bp.DateTimeException;
+import org.threeten.bp.LocalDate;
+import org.threeten.bp.Month;
+import org.threeten.bp.MonthDay;
+import org.threeten.bp.YearMonth;
+import org.threeten.bp.temporal.ChronoField;
+import org.threeten.bp.temporal.Temporal;
+import org.threeten.bp.temporal.TemporalAccessor;
+import org.threeten.bp.temporal.TemporalAdjuster;
+import org.threeten.bp.temporal.TemporalField;
+import org.threeten.bp.temporal.TemporalQueries;
+import org.threeten.bp.temporal.TemporalQuery;
+import org.threeten.bp.temporal.ValueRange;
+
+/**
+ * A representation of a day-of-month in the ISO-8601 calendar system.
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ */
+public final class DayOfMonth
+ implements Comparable
+ * // these two lines are equivalent, but the second approach is recommended
+ * temporal = thisDayOfWeek.adjustInto(temporal);
+ * temporal = temporal.with(thisDayOfWeek);
+ *
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ */
+public final class Days extends AbstractSimpleAmountSpecification for implementors
+ * This class is immutable and thread-safe.
+ */
+public final class Hours extends AbstractSimpleAmountSpecification for implementors
+ * This class is immutable and thread-safe.
+ */
+public final class Minutes extends AbstractSimpleAmountSpecification for implementors
+ * This class is immutable and thread-safe.
+ */
+public final class Months extends AbstractSimpleAmountSpecification for implementors
+ * This is an immutable and thread-safe enum.
+ */
+public enum QuarterOfYear implements TemporalAccessor, TemporalAdjuster {
+
+ /**
+ * The singleton instance for the first quarter-of-year, from January to March.
+ * This has the numeric value of {@code 1}.
+ */
+ Q1,
+ /**
+ * The singleton instance for the second quarter-of-year, from April to June.
+ * This has the numeric value of {@code 2}.
+ */
+ Q2,
+ /**
+ * The singleton instance for the third quarter-of-year, from July to September.
+ * This has the numeric value of {@code 3}.
+ */
+ Q3,
+ /**
+ * The singleton instance for the fourth quarter-of-year, from October to December.
+ * This has the numeric value of {@code 4}.
+ */
+ Q4;
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code QuarterOfYear} from an {@code int} value.
+ *
+ * Q2 will return April.
+ * Q3 will return July.
+ * Q4 will return October.
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * temporal = thisDayOfWeek.adjustInto(temporal);
+ * temporal = temporal.with(thisDayOfWeek);
+ *
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ */
+public final class Seconds extends AbstractSimpleAmountSpecification for implementors
+ * This is a thread-safe utility class.
+ * All returned classes are immutable and thread-safe.
+ */
+public final class WeekendRules {
+
+ /**
+ * Restricted constructor.
+ */
+ private WeekendRules() {
+ }
+
+ /**
+ * Returns the next non weekend day adjuster, which adjusts the date one day
+ * forward skipping Saturday and Sunday.
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ */
+public final class Weeks extends AbstractSimpleAmountSpecification for implementors
+ * This class is immutable and thread-safe.
+ */
+public final class Years extends AbstractSimpleAmount
+ *
Specification for implementors
+ * This class is immutable and thread-safe.
+ */
+public final class CopticChronology extends Chronology implements Serializable {
+
+ /**
+ * Singleton instance of the Coptic chronology.
+ */
+ public static final CopticChronology INSTANCE = new CopticChronology();
+
+ /**
+ * Serialization version.
+ */
+ private static final long serialVersionUID = 7291205177830286973L;
+ /**
+ * Range of months.
+ */
+ static final ValueRange MOY_RANGE = ValueRange.of(1, 13);
+ /**
+ * Range of days.
+ */
+ static final ValueRange DOM_RANGE = ValueRange.of(1, 5, 30);
+ /**
+ * Range of days.
+ */
+ static final ValueRange DOM_RANGE_NONLEAP = ValueRange.of(1, 5);
+ /**
+ * Range of days.
+ */
+ static final ValueRange DOM_RANGE_LEAP = ValueRange.of(1, 6);
+
+ /**
+ * Restricted constructor.
+ */
+ private CopticChronology() {
+ }
+
+ /**
+ * Resolve singleton.
+ *
+ * @return the singleton instance, not null
+ */
+ private Object readResolve() {
+ return INSTANCE;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the ID of the chronology - 'Coptic'.
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ */
+public final class CopticDate
+ extends DefaultInterfaceChronoLocalDateSpecification for implementors
+ * This is an immutable and thread-safe enum.
+ */
+public enum CopticEra implements Era {
+
+ /**
+ * The singleton instance for the era BEFORE_AM, 'Before Era of the Martyrs'.
+ * This has the numeric value of {@code 0}.
+ */
+ BEFORE_AM,
+ /**
+ * The singleton instance for the era AM, 'Era of the Martyrs'.
+ * This has the numeric value of {@code 1}.
+ */
+ AM;
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code CopticEra} from an {@code int} value.
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ */
+final class SystemUTCRules extends UTCRules implements Serializable {
+
+ /**
+ * Singleton.
+ */
+ static final SystemUTCRules INSTANCE = new SystemUTCRules();
+ /**
+ * Serialization version.
+ */
+ private static final long serialVersionUID = 7594178360693417218L;
+
+ /**
+ * The table of leap second dates.
+ */
+ private AtomicReference dataRef = new AtomicReference(loadLeapSeconds());
+
+ /** Data holder. */
+ private static final class Data implements Serializable {
+ /** Serialization version. */
+ private static final long serialVersionUID = -3655687912882817265L;
+ /** Constructor. */
+ private Data(long[] dates, int[] offsets, long[] taiSeconds) {
+ super();
+ this.dates = dates;
+ this.offsets = offsets;
+ this.taiSeconds = taiSeconds;
+ }
+ /** The table of leap second date when the leap second occurs. */
+ final long[] dates;
+ /** The table of TAI offset after the leap second. */
+ final int[] offsets;
+ /** The table of TAI second when the new offset starts. */
+ final long[] taiSeconds;
+
+ /**
+ * @return The modified Julian Date of the newest leap second
+ */
+ public long getNewestDate() {
+ return dates[dates.length - 1];
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Restricted constructor.
+ */
+ private SystemUTCRules() {
+ }
+
+ /**
+ * Resolves singleton.
+ *
+ * @return the resolved instance, not null
+ */
+ private Object readResolve() {
+ return INSTANCE;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Adds a new leap second to these rules.
+ *
+ * @param mjDay the modified julian date that the leap second occurs at the end of
+ * @param leapAdjustment the leap seconds to add/remove at the end of the day, either -1 or 1
+ * @throws IllegalArgumentException if the leap adjustment is invalid
+ * @throws IllegalArgumentException if the day is before or equal the last known leap second day
+ * and the definition does not match a previously registered leap
+ * @throws ConcurrentModificationException if another thread updates the rules at the same time
+ */
+ void registerLeapSecond(long mjDay, int leapAdjustment) {
+ if (leapAdjustment != -1 && leapAdjustment != 1) {
+ throw new IllegalArgumentException("Leap adjustment must be -1 or 1");
+ }
+ Data data = dataRef.get();
+ int pos = Arrays.binarySearch(data.dates, mjDay);
+ int currentAdj = pos > 0 ? data.offsets[pos] - data.offsets[pos - 1] : 0;
+ if (currentAdj == leapAdjustment) {
+ return; // matches previous definition
+ }
+ if (mjDay <= data.dates[data.dates.length - 1]) {
+ throw new IllegalArgumentException("Date must be after the last configured leap second date");
+ }
+ long[] dates = Arrays.copyOf(data.dates, data.dates.length + 1);
+ int[] offsets = Arrays.copyOf(data.offsets, data.offsets.length + 1);
+ long[] taiSeconds = Arrays.copyOf(data.taiSeconds, data.taiSeconds.length + 1);
+ int offset = offsets[offsets.length - 2] + leapAdjustment;
+ dates[dates.length - 1] = mjDay;
+ offsets[offsets.length - 1] = offset;
+ taiSeconds[taiSeconds.length - 1] = tai(mjDay, offset);
+ Data newData = new Data(dates, offsets, taiSeconds);
+ if (dataRef.compareAndSet(data, newData) == false) {
+ throw new ConcurrentModificationException("Unable to update leap second rules as they have already been updated");
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public String getName() {
+ return "System";
+ }
+
+ @Override
+ public int getLeapSecondAdjustment(long mjDay) {
+ Data data = dataRef.get();
+ int pos = Arrays.binarySearch(data.dates, mjDay);
+ return pos > 0 ? data.offsets[pos] - data.offsets[pos - 1] : 0;
+ }
+
+ @Override
+ public int getTAIOffset(long mjDay) {
+ Data data = dataRef.get();
+ int pos = Arrays.binarySearch(data.dates, mjDay);
+ pos = (pos < 0 ? ~pos : pos);
+ return pos > 0 ? data.offsets[pos - 1] : 10;
+ }
+
+ @Override
+ public long[] getLeapSecondDates() {
+ Data data = dataRef.get();
+ return data.dates.clone();
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ protected UTCInstant convertToUTC(TAIInstant taiInstant) {
+ Data data = dataRef.get();
+ long[] mjds = data.dates;
+ long[] tais = data.taiSeconds;
+ int pos = Arrays.binarySearch(tais, taiInstant.getTAISeconds());
+ pos = (pos >= 0 ? pos : ~pos - 1);
+ int taiOffset = (pos >= 0 ? data.offsets[pos] : 10);
+ long adjustedTaiSecs = taiInstant.getTAISeconds() - taiOffset;
+ long mjd = Jdk8Methods.floorDiv(adjustedTaiSecs, SECS_PER_DAY) + OFFSET_MJD_TAI;
+ long nod = Jdk8Methods.floorMod(adjustedTaiSecs, SECS_PER_DAY) * NANOS_PER_SECOND + taiInstant.getNano();
+ long mjdNextRegionStart = (pos + 1 < mjds.length ? mjds[pos + 1] + 1 : Long.MAX_VALUE);
+ if (mjd == mjdNextRegionStart) { // in leap second
+ mjd--;
+ nod = SECS_PER_DAY * NANOS_PER_SECOND + (nod / NANOS_PER_SECOND) * NANOS_PER_SECOND + nod % NANOS_PER_SECOND;
+ }
+ return UTCInstant.ofModifiedJulianDay(mjd, nod, this);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Loads the rules from files in the class loader, often jar files.
+ *
+ * @return the list of loaded rules, not null
+ * @throws Exception if an error occurs
+ */
+ private static Data loadLeapSeconds() {
+ Data bestData = null;
+ URL url = null;
+ try {
+ EnumerationTime-scale
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ */
+public final class TAIInstant
+ implements Comparable
+ * TAIInstant.ofSeconds(3, 1);
+ * TAIInstant.ofSeconds(4, -999999999);
+ * TAIInstant.ofSeconds(2, 1000000001);
+ *
+ *
+ * @param taiSeconds the number of seconds from the epoch of 1958-01-01T00:00:00(TAI)
+ * @param nanoAdjustment the nanosecond adjustment to the number of seconds, positive or negative
+ * @return the TAI instant, not null
+ */
+ public static TAIInstant ofTAISeconds(long taiSeconds, long nanoAdjustment) {
+ long secs = Jdk8Methods.safeAdd(taiSeconds, Jdk8Methods.floorDiv(nanoAdjustment, NANOS_PER_SECOND));
+ int nos = Jdk8Methods.floorMod(nanoAdjustment, NANOS_PER_SECOND);
+ return new TAIInstant(secs, nos);
+ }
+
+ /**
+ * Obtains an instance of {@code TAIInstant} from an {@code Instant}
+ * using the system default leap second rules.
+ *
+ *
Specification for implementors
+ * This abstract class must be implemented with care to ensure other classes in
+ * the framework operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Time-scale
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ */
+public final class UTCInstant
+ implements ComparableSpecification for implementors
+ * This is an abstract class and must be implemented with care
+ * to ensure other classes in the framework operate correctly.
+ * All implementations must be final, immutable and thread-safe.
+ * Subclasses should be {@code Serializable} wherever possible.
+ */
+public abstract class UTCRules {
+
+ /**
+ * Constant for the offset from MJD day 0 to the Java Epoch of 1970-01-01: 40587.
+ */
+ static final int OFFSET_MJD_EPOCH = 40587;
+ /**
+ * Constant for the offset from MJD day 0 to TAI day 0 of 1958-01-01: 36204.
+ */
+ static final int OFFSET_MJD_TAI = 36204;
+ /**
+ * Constant for number of seconds per standard day: 86,400.
+ */
+ static final long SECS_PER_DAY = 24L * 60L * 60L;
+ /**
+ * Constant for nanos per standard second: 1,000,000,000.
+ */
+ static final long NANOS_PER_SECOND = 1000000000L;
+
+ /**
+ * Gets the system default leap second rules.
+ *
+ * Let {@code L = getLeapAdjustment(mjd)}.
+ * Let {@code B = 86400 + L - 1000}.
+ * Let {@code US = U - L * (U - B) / 1000}.
+ * Where the algorithm is applied while {@code U >= B}.
+ *
+ * @param utcInstant the UTC instant to convert, not null
+ * @return the converted instant, not null
+ * @throws ArithmeticException if the capacity is exceeded
+ */
+ protected Instant convertToInstant(UTCInstant utcInstant) {
+ long mjd = utcInstant.getModifiedJulianDay();
+ long utcNanos = utcInstant.getNanoOfDay();
+ long epochDay = Jdk8Methods.safeSubtract(mjd, OFFSET_MJD_EPOCH);
+ long epochSec = Jdk8Methods.safeMultiply(epochDay, SECS_PER_DAY);
+ int leapAdj = getLeapSecondAdjustment(mjd);
+ long startSlsNanos = (SECS_PER_DAY + leapAdj - 1000) * NANOS_PER_SECOND;
+ long slsNanos = utcNanos;
+ if (leapAdj != 0 && utcNanos >= startSlsNanos) {
+ slsNanos = utcNanos - leapAdj * (utcNanos - startSlsNanos) / 1000; // apply UTC-SLS mapping
+ }
+ return Instant.ofEpochSecond(epochSec + slsNanos / NANOS_PER_SECOND, slsNanos % NANOS_PER_SECOND);
+ }
+
+ /**
+ * Converts an {@code Instant} to a {@code UTCInstant}.
+ *
+ * Let {@code L = getLeapAdjustment(mjd)}.
+ * Let {@code B = 86400 + L - 1000}.
+ * Let {@code U = B + ((US - B) * 1000) / (1000 - L)}.
+ * Where the algorithm is applied while {@code US >= B}.
+ * (This algorithm has been tuned for integer arithmetic from the UTC-SLS specification.)
+ *
+ * @param instant the instant to convert, not null
+ * @return the converted UTC instant, not null
+ * @throws ArithmeticException if the capacity is exceeded
+ */
+ protected UTCInstant convertToUTC(Instant instant) {
+ long epochDay = Jdk8Methods.floorDiv(instant.getEpochSecond(), SECS_PER_DAY);
+ long mjd = epochDay + OFFSET_MJD_EPOCH;
+ long slsNanos = Jdk8Methods.floorMod(instant.getEpochSecond(), SECS_PER_DAY) * NANOS_PER_SECOND + instant.getNano();
+ int leapAdj = getLeapSecondAdjustment(mjd);
+ long startSlsNanos = (SECS_PER_DAY + leapAdj - 1000) * NANOS_PER_SECOND;
+ long utcNanos = slsNanos;
+ if (leapAdj != 0 && slsNanos >= startSlsNanos) {
+ utcNanos = startSlsNanos + ((slsNanos - startSlsNanos) * 1000) / (1000 - leapAdj); // apply UTC-SLS mapping
+ }
+ return UTCInstant.ofModifiedJulianDay(mjd, utcNanos, this);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * A string representation of these rules.
+ *
+ * @return the string representation, not null
+ */
+ @Override
+ public String toString() {
+ return "UTCRules[" + getName() + ']';
+ }
+
+}
diff --git a/src/test/java/org/threeten/extra/MockFieldNoValue.java b/src/test/java/org/threeten/extra/MockFieldNoValue.java
new file mode 100644
index 0000000..e0b0d0d
--- /dev/null
+++ b/src/test/java/org/threeten/extra/MockFieldNoValue.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.threeten.extra;
+
+import static org.threeten.bp.temporal.ChronoUnit.MONTHS;
+import static org.threeten.bp.temporal.ChronoUnit.WEEKS;
+
+import java.util.Map;
+
+import org.threeten.bp.DateTimeException;
+import org.threeten.bp.temporal.Temporal;
+import org.threeten.bp.temporal.TemporalAccessor;
+import org.threeten.bp.temporal.TemporalField;
+import org.threeten.bp.temporal.TemporalUnit;
+import org.threeten.bp.temporal.ValueRange;
+
+/**
+ * Mock DateTimeField that returns null.
+ */
+public enum MockFieldNoValue implements TemporalField {
+
+ INSTANCE;
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public TemporalUnit getBaseUnit() {
+ return WEEKS;
+ }
+
+ @Override
+ public TemporalUnit getRangeUnit() {
+ return MONTHS;
+ }
+
+ @Override
+ public ValueRange range() {
+ return ValueRange.of(1, 20);
+ }
+
+ @Override
+ public int compare(TemporalAccessor dateTime1, TemporalAccessor dateTime2) {
+ return Long.compare(getFrom(dateTime1), getFrom(dateTime2));
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public boolean isSupportedBy(TemporalAccessor dateTime) {
+ return true;
+ }
+
+ @Override
+ public ValueRange rangeRefinedBy(TemporalAccessor dateTime) {
+ return ValueRange.of(1, 20);
+ }
+
+ @Override
+ public long getFrom(TemporalAccessor dateTime) {
+ throw new DateTimeException("Mock");
+ }
+
+ @Override
+ public