YearQuarter.java

  1. /*
  2.  * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
  3.  *
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions are met:
  8.  *
  9.  *  * Redistributions of source code must retain the above copyright notice,
  10.  *    this list of conditions and the following disclaimer.
  11.  *
  12.  *  * Redistributions in binary form must reproduce the above copyright notice,
  13.  *    this list of conditions and the following disclaimer in the documentation
  14.  *    and/or other materials provided with the distribution.
  15.  *
  16.  *  * Neither the name of JSR-310 nor the names of its contributors
  17.  *    may be used to endorse or promote products derived from this software
  18.  *    without specific prior written permission.
  19.  *
  20.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28.  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31.  */
  32. package org.threeten.extra;

  33. import static java.time.temporal.ChronoField.ERA;
  34. import static java.time.temporal.ChronoField.YEAR;
  35. import static java.time.temporal.ChronoField.YEAR_OF_ERA;
  36. import static java.time.temporal.ChronoUnit.CENTURIES;
  37. import static java.time.temporal.ChronoUnit.DECADES;
  38. import static java.time.temporal.ChronoUnit.ERAS;
  39. import static java.time.temporal.ChronoUnit.MILLENNIA;
  40. import static java.time.temporal.ChronoUnit.YEARS;
  41. import static java.time.temporal.IsoFields.DAY_OF_QUARTER;
  42. import static java.time.temporal.IsoFields.QUARTER_OF_YEAR;
  43. import static java.time.temporal.IsoFields.QUARTER_YEARS;

  44. import java.io.Serializable;
  45. import java.time.Clock;
  46. import java.time.DateTimeException;
  47. import java.time.LocalDate;
  48. import java.time.Month;
  49. import java.time.Period;
  50. import java.time.Year;
  51. import java.time.ZoneId;
  52. import java.time.chrono.Chronology;
  53. import java.time.chrono.IsoChronology;
  54. import java.time.format.DateTimeFormatter;
  55. import java.time.format.DateTimeFormatterBuilder;
  56. import java.time.format.DateTimeParseException;
  57. import java.time.format.SignStyle;
  58. import java.time.temporal.ChronoField;
  59. import java.time.temporal.ChronoUnit;
  60. import java.time.temporal.IsoFields;
  61. import java.time.temporal.Temporal;
  62. import java.time.temporal.TemporalAccessor;
  63. import java.time.temporal.TemporalAdjuster;
  64. import java.time.temporal.TemporalAmount;
  65. import java.time.temporal.TemporalField;
  66. import java.time.temporal.TemporalQueries;
  67. import java.time.temporal.TemporalQuery;
  68. import java.time.temporal.TemporalUnit;
  69. import java.time.temporal.UnsupportedTemporalTypeException;
  70. import java.time.temporal.ValueRange;
  71. import java.util.Objects;
  72. import java.util.stream.LongStream;
  73. import java.util.stream.Stream;

  74. import org.joda.convert.FromString;
  75. import org.joda.convert.ToString;

  76. /**
  77.  * A year-quarter in the ISO-8601 calendar system, such as {@code 2007-Q2}.
  78.  * <p>
  79.  * {@code YearQuarter} is an immutable date-time object that represents the combination
  80.  * of a year and quarter. Any field that can be derived from a year and quarter can be obtained.
  81.  * A quarter is defined by {@link Quarter} and {@link Month#firstMonthOfQuarter()} - Q1, Q2, Q3 and Q4.
  82.  * Q1 is January to March, Q2 is April to June, Q3 is July to September and Q4 is October to December.
  83.  * <p>
  84.  * This class does not store or represent a day, time or time-zone.
  85.  * For example, the value "2nd quarter 2007" can be stored in a {@code YearQuarter}.
  86.  * <p>
  87.  * The ISO-8601 calendar system is the modern civil calendar system used today
  88.  * in most of the world. It is equivalent to the proleptic Gregorian calendar
  89.  * system, in which today's rules for leap years are applied for all time.
  90.  * For most applications written today, the ISO-8601 rules are entirely suitable.
  91.  * However, any application that makes use of historical dates, and requires them
  92.  * to be accurate will find the ISO-8601 approach unsuitable.
  93.  * Note that the ISO-8601 standard does not define or refer to quarters.
  94.  *
  95.  * <h3>Implementation Requirements:</h3>
  96.  * This class is immutable and thread-safe.
  97.  * <p>
  98.  * This class must be treated as a value type. Do not synchronize, rely on the
  99.  * identity hash code or use the distinction between equals() and ==.
  100.  */
  101. public final class YearQuarter
  102.         implements Temporal, TemporalAdjuster, Comparable<YearQuarter>, Serializable {

  103.     /**
  104.      * Serialization version.
  105.      */
  106.     private static final long serialVersionUID = 4183400860270640070L;
  107.     /**
  108.      * Parser.
  109.      */
  110.     private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
  111.             .parseCaseInsensitive()
  112.             .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
  113.             .appendLiteral('-')
  114.             .appendLiteral('Q')
  115.             .appendValue(QUARTER_OF_YEAR, 1)
  116.             .toFormatter();

  117.     /**
  118.      * The year.
  119.      */
  120.     private final int year;
  121.     /**
  122.      * The quarter-of-year, not null.
  123.      */
  124.     private final Quarter quarter;

  125.     //-----------------------------------------------------------------------
  126.     /**
  127.      * Obtains the current year-quarter from the system clock in the default time-zone.
  128.      * <p>
  129.      * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default
  130.      * time-zone to obtain the current year-quarter.
  131.      * The zone and offset will be set based on the time-zone in the clock.
  132.      * <p>
  133.      * Using this method will prevent the ability to use an alternate clock for testing
  134.      * because the clock is hard-coded.
  135.      *
  136.      * @return the current year-quarter using the system clock and default time-zone, not null
  137.      */
  138.     public static YearQuarter now() {
  139.         return now(Clock.systemDefaultZone());
  140.     }

  141.     /**
  142.      * Obtains the current year-quarter from the system clock in the specified time-zone.
  143.      * <p>
  144.      * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current year-quarter.
  145.      * Specifying the time-zone avoids dependence on the default time-zone.
  146.      * <p>
  147.      * Using this method will prevent the ability to use an alternate clock for testing
  148.      * because the clock is hard-coded.
  149.      *
  150.      * @param zone  the zone ID to use, not null
  151.      * @return the current year-quarter using the system clock, not null
  152.      */
  153.     public static YearQuarter now(ZoneId zone) {
  154.         return now(Clock.system(zone));
  155.     }

  156.     /**
  157.      * Obtains the current year-quarter from the specified clock.
  158.      * <p>
  159.      * This will query the specified clock to obtain the current year-quarter.
  160.      * Using this method allows the use of an alternate clock for testing.
  161.      * The alternate clock may be introduced using {@link Clock dependency injection}.
  162.      *
  163.      * @param clock  the clock to use, not null
  164.      * @return the current year-quarter, not null
  165.      */
  166.     public static YearQuarter now(Clock clock) {
  167.         final LocalDate now = LocalDate.now(clock);  // called once
  168.         return YearQuarter.of(now.getYear(), Quarter.from(now.getMonth()));
  169.     }

  170.     //-----------------------------------------------------------------------
  171.     /**
  172.      * Obtains an instance of {@code YearQuarter} from a year and quarter.
  173.      *
  174.      * @param year  the year to represent, not null
  175.      * @param quarter  the quarter-of-year to represent, not null
  176.      * @return the year-quarter, not null
  177.      */
  178.     public static YearQuarter of(Year year, Quarter quarter) {
  179.         return of(year.getValue(), quarter);
  180.     }

  181.     /**
  182.      * Obtains an instance of {@code YearQuarter} from a year and quarter.
  183.      *
  184.      * @param year  the year to represent, not null
  185.      * @param quarter  the quarter-of-year to represent, from 1 to 4
  186.      * @return the year-quarter, not null
  187.      * @throws DateTimeException if the quarter value is invalid
  188.      */
  189.     public static YearQuarter of(Year year, int quarter) {
  190.         return of(year.getValue(), Quarter.of(quarter));
  191.     }

  192.     /**
  193.      * Obtains an instance of {@code YearQuarter} from a year and quarter.
  194.      *
  195.      * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
  196.      * @param quarter  the quarter-of-year to represent, not null
  197.      * @return the year-quarter, not null
  198.      * @throws DateTimeException if the year value is invalid
  199.      */
  200.     public static YearQuarter of(int year, Quarter quarter) {
  201.         YEAR.checkValidValue(year);
  202.         Objects.requireNonNull(quarter, "quarter");
  203.         return new YearQuarter(year, quarter);
  204.     }

  205.     /**
  206.      * Obtains an instance of {@code YearQuarter} from a year and quarter.
  207.      *
  208.      * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
  209.      * @param quarter  the quarter-of-year to represent, from 1 to 4
  210.      * @return the year-quarter, not null
  211.      * @throws DateTimeException if either field value is invalid
  212.      */
  213.     public static YearQuarter of(int year, int quarter) {
  214.         YEAR.checkValidValue(year);
  215.         return new YearQuarter(year, Quarter.of(quarter));
  216.     }

  217.     //-----------------------------------------------------------------------
  218.     /**
  219.      * Obtains an instance of {@code YearQuarter} from a temporal object.
  220.      * <p>
  221.      * This obtains a year-quarter based on the specified temporal.
  222.      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
  223.      * which this factory converts to an instance of {@code YearQuarter}.
  224.      * <p>
  225.      * The conversion extracts the {@link ChronoField#YEAR YEAR} and
  226.      * {@link IsoFields#QUARTER_OF_YEAR QUARTER_OF_YEAR} fields.
  227.      * The extraction is only permitted if the temporal object has an ISO
  228.      * chronology, or can be converted to a {@code LocalDate}.
  229.      * <p>
  230.      * This method matches the signature of the functional interface {@link TemporalQuery}
  231.      * allowing it to be used in queries via method reference, {@code YearQuarter::from}.
  232.      *
  233.      * @param temporal  the temporal object to convert, not null
  234.      * @return the year-quarter, not null
  235.      * @throws DateTimeException if unable to convert to a {@code YearQuarter}
  236.      */
  237.     public static YearQuarter from(TemporalAccessor temporal) {
  238.         if (temporal instanceof YearQuarter) {
  239.             return (YearQuarter) temporal;
  240.         }
  241.         Objects.requireNonNull(temporal, "temporal");
  242.         try {
  243.             TemporalAccessor adjusted =
  244.                     !IsoChronology.INSTANCE.equals(Chronology.from(temporal)) ? LocalDate.from(temporal) : temporal;
  245.             // need to use getLong() as JDK Parsed class get() doesn't work properly
  246.             int year = Math.toIntExact(adjusted.getLong(YEAR));
  247.             int qoy = Math.toIntExact(adjusted.getLong(QUARTER_OF_YEAR));
  248.             return of(year, qoy);
  249.         } catch (DateTimeException ex) {
  250.             throw new DateTimeException("Unable to obtain YearQuarter from TemporalAccessor: " +
  251.                     temporal + " of type " + temporal.getClass().getName(), ex);
  252.         }
  253.     }

  254.     //-----------------------------------------------------------------------
  255.     /**
  256.      * Obtains an instance of {@code YearQuarter} from a text string such as {@code 2007-Q2}.
  257.      * <p>
  258.      * The string must represent a valid year-quarter.
  259.      * The format must be {@code uuuu-'Q'Q} where the 'Q' is case insensitive.
  260.      * Years outside the range 0000 to 9999 must be prefixed by the plus or minus symbol.
  261.      *
  262.      * @param text  the text to parse such as "2007-Q2", not null
  263.      * @return the parsed year-quarter, not null
  264.      * @throws DateTimeParseException if the text cannot be parsed
  265.      */
  266.     @FromString
  267.     public static YearQuarter parse(CharSequence text) {
  268.         return parse(text, PARSER);
  269.     }

  270.     /**
  271.      * Obtains an instance of {@code YearQuarter} from a text string using a specific formatter.
  272.      * <p>
  273.      * The text is parsed using the formatter, returning a year-quarter.
  274.      *
  275.      * @param text  the text to parse, not null
  276.      * @param formatter  the formatter to use, not null
  277.      * @return the parsed year-quarter, not null
  278.      * @throws DateTimeParseException if the text cannot be parsed
  279.      */
  280.     public static YearQuarter parse(CharSequence text, DateTimeFormatter formatter) {
  281.         Objects.requireNonNull(formatter, "formatter");
  282.         return formatter.parse(text, YearQuarter::from);
  283.     }

  284.     //-----------------------------------------------------------------------
  285.     /**
  286.      * Constructor.
  287.      *
  288.      * @param year  the year to represent, validated from MIN_YEAR to MAX_YEAR
  289.      * @param quarter  the quarter-of-year to represent, validated not null
  290.      */
  291.     private YearQuarter(int year, Quarter quarter) {
  292.         this.year = year;
  293.         this.quarter = quarter;
  294.     }

  295.     /**
  296.      * Validates the input.
  297.      *
  298.      * @return the valid object, not null
  299.      */
  300.     private Object readResolve() {
  301.         return of(year, quarter);
  302.     }

  303.     /**
  304.      * Returns a copy of this year-quarter with the new year and quarter, checking
  305.      * to see if a new object is in fact required.
  306.      *
  307.      * @param newYear  the year to represent, validated from MIN_YEAR to MAX_YEAR
  308.      * @param newQuarter  the quarter-of-year to represent, validated not null
  309.      * @return the year-quarter, not null
  310.      */
  311.     private YearQuarter with(int newYear, Quarter newQuarter) {
  312.         if (year == newYear && quarter == newQuarter) {
  313.             return this;
  314.         }
  315.         return new YearQuarter(newYear, newQuarter);
  316.     }

  317.     //-----------------------------------------------------------------------
  318.     /**
  319.      * Checks if the specified field is supported.
  320.      * <p>
  321.      * This checks if this year-quarter can be queried for the specified field.
  322.      * If false, then calling the {@link #range(TemporalField) range},
  323.      * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
  324.      * methods will throw an exception.
  325.      * <p>
  326.      * If the field is a {@link ChronoField} then the query is implemented here.
  327.      * The supported fields are:
  328.      * <ul>
  329.      * <li>{@code QUARTER_OF_YEAR}
  330.      * <li>{@code YEAR_OF_ERA}
  331.      * <li>{@code YEAR}
  332.      * <li>{@code ERA}
  333.      * </ul>
  334.      * All other {@code ChronoField} instances will return false.
  335.      * <p>
  336.      * If the field is not a {@code ChronoField}, then the result of this method
  337.      * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
  338.      * passing {@code this} as the argument.
  339.      * Whether the field is supported is determined by the field.
  340.      *
  341.      * @param field  the field to check, null returns false
  342.      * @return true if the field is supported on this year-quarter, false if not
  343.      */
  344.     @Override
  345.     public boolean isSupported(TemporalField field) {
  346.         if (field == QUARTER_OF_YEAR) {
  347.             return true;
  348.         } else if (field instanceof ChronoField) {
  349.             return field == YEAR || field == YEAR_OF_ERA || field == ERA;
  350.         }
  351.         return field != null && field.isSupportedBy(this);
  352.     }

  353.     /**
  354.      * Checks if the specified unit is supported.
  355.      * <p>
  356.      * This checks if the specified unit can be added to, or subtracted from, this year-quarter.
  357.      * If false, then calling the {@link #plus(long, TemporalUnit)} and
  358.      * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
  359.      * <p>
  360.      * If the unit is a {@link ChronoUnit} then the query is implemented here.
  361.      * The supported units are:
  362.      * <ul>
  363.      * <li>{@code QUARTER_YEARS}
  364.      * <li>{@code YEARS}
  365.      * <li>{@code DECADES}
  366.      * <li>{@code CENTURIES}
  367.      * <li>{@code MILLENNIA}
  368.      * <li>{@code ERAS}
  369.      * </ul>
  370.      * All other {@code ChronoUnit} instances will return false.
  371.      * <p>
  372.      * If the unit is not a {@code ChronoUnit}, then the result of this method
  373.      * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
  374.      * passing {@code this} as the argument.
  375.      * Whether the unit is supported is determined by the unit.
  376.      *
  377.      * @param unit  the unit to check, null returns false
  378.      * @return true if the unit can be added/subtracted, false if not
  379.      */
  380.     @Override
  381.     public boolean isSupported(TemporalUnit unit) {
  382.         if (unit == QUARTER_YEARS) {
  383.             return true;
  384.         } else if (unit instanceof ChronoUnit) {
  385.             return unit == YEARS || unit == DECADES || unit == CENTURIES || unit == MILLENNIA || unit == ERAS;
  386.         }
  387.         return unit != null && unit.isSupportedBy(this);
  388.     }

  389.     //-----------------------------------------------------------------------
  390.     /**
  391.      * Gets the range of valid values for the specified field.
  392.      * <p>
  393.      * The range object expresses the minimum and maximum valid values for a field.
  394.      * This year-quarter is used to enhance the accuracy of the returned range.
  395.      * If it is not possible to return the range, because the field is not supported
  396.      * or for some other reason, an exception is thrown.
  397.      * <p>
  398.      * If the field is a {@link ChronoField} then the query is implemented here.
  399.      * The {@link #isSupported(TemporalField) supported fields} will return
  400.      * appropriate range instances.
  401.      * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
  402.      * <p>
  403.      * If the field is not a {@code ChronoField}, then the result of this method
  404.      * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
  405.      * passing {@code this} as the argument.
  406.      * Whether the range can be obtained is determined by the field.
  407.      *
  408.      * @param field  the field to query the range for, not null
  409.      * @return the range of valid values for the field, not null
  410.      * @throws DateTimeException if the range for the field cannot be obtained
  411.      * @throws UnsupportedTemporalTypeException if the field is not supported
  412.      */
  413.     @Override
  414.     public ValueRange range(TemporalField field) {
  415.         if (field == QUARTER_OF_YEAR) {
  416.             return QUARTER_OF_YEAR.range();
  417.         }
  418.         if (field == YEAR_OF_ERA) {
  419.             return (getYear() <= 0 ? ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE));
  420.         }
  421.         return Temporal.super.range(field);
  422.     }

  423.     /**
  424.      * Gets the value of the specified field from this year-quarter as an {@code int}.
  425.      * <p>
  426.      * This queries this year-quarter for the value for the specified field.
  427.      * The returned value will always be within the valid range of values for the field.
  428.      * If it is not possible to return the value, because the field is not supported
  429.      * or for some other reason, an exception is thrown.
  430.      * <p>
  431.      * If the field is a {@link ChronoField} then the query is implemented here.
  432.      * The {@link #isSupported(TemporalField) supported fields} will return valid
  433.      * values based on this year-quarter,.
  434.      * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
  435.      * <p>
  436.      * If the field is not a {@code ChronoField}, then the result of this method
  437.      * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
  438.      * passing {@code this} as the argument. Whether the value can be obtained,
  439.      * and what the value represents, is determined by the field.
  440.      *
  441.      * @param field  the field to get, not null
  442.      * @return the value for the field
  443.      * @throws DateTimeException if a value for the field cannot be obtained or
  444.      *  the value is outside the range of valid values for the field
  445.      * @throws UnsupportedTemporalTypeException if the field is not supported or
  446.      *  the range of values exceeds an {@code int}
  447.      * @throws ArithmeticException if numeric overflow occurs
  448.      */
  449.     @Override
  450.     public int get(TemporalField field) {
  451.         if (field == QUARTER_OF_YEAR) {
  452.             return quarter.getValue();
  453.         } else if (field instanceof ChronoField) {
  454.             switch ((ChronoField) field) {
  455.                 case YEAR_OF_ERA:
  456.                     return (year < 1 ? 1 - year : year);
  457.                 case YEAR:
  458.                     return year;
  459.                 case ERA:
  460.                     return (year < 1 ? 0 : 1);
  461.                 default:
  462.                     throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
  463.             }
  464.         }
  465.         return Temporal.super.get(field);
  466.     }

  467.     /**
  468.      * Gets the value of the specified field from this year-quarter as a {@code long}.
  469.      * <p>
  470.      * This queries this year-quarter for the value for the specified field.
  471.      * If it is not possible to return the value, because the field is not supported
  472.      * or for some other reason, an exception is thrown.
  473.      * <p>
  474.      * If the field is a {@link ChronoField} then the query is implemented here.
  475.      * The {@link #isSupported(TemporalField) supported fields} will return valid
  476.      * values based on this year-quarter.
  477.      * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
  478.      * <p>
  479.      * If the field is not a {@code ChronoField}, then the result of this method
  480.      * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
  481.      * passing {@code this} as the argument. Whether the value can be obtained,
  482.      * and what the value represents, is determined by the field.
  483.      *
  484.      * @param field  the field to get, not null
  485.      * @return the value for the field
  486.      * @throws DateTimeException if a value for the field cannot be obtained
  487.      * @throws UnsupportedTemporalTypeException if the field is not supported
  488.      * @throws ArithmeticException if numeric overflow occurs
  489.      */
  490.     @Override
  491.     public long getLong(TemporalField field) {
  492.         if (field == QUARTER_OF_YEAR) {
  493.             return quarter.getValue();
  494.         } else if (field instanceof ChronoField) {
  495.             switch ((ChronoField) field) {
  496.                 case YEAR_OF_ERA:
  497.                     return (year < 1 ? 1 - year : year);
  498.                 case YEAR:
  499.                     return year;
  500.                 case ERA:
  501.                     return (year < 1 ? 0 : 1);
  502.                 default:
  503.                     throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
  504.             }
  505.         }
  506.         return field.getFrom(this);
  507.     }

  508.     private long getProlepticQuarter() {
  509.         return year * 4L + (quarter.getValue() - 1);
  510.     }

  511.     //-----------------------------------------------------------------------
  512.     /**
  513.      * Gets the year field.
  514.      * <p>
  515.      * This method returns the primitive {@code int} value for the year.
  516.      * <p>
  517.      * The year returned by this method is proleptic as per {@code get(YEAR)}.
  518.      *
  519.      * @return the year, from MIN_YEAR to MAX_YEAR
  520.      */
  521.     public int getYear() {
  522.         return year;
  523.     }

  524.     /**
  525.      * Gets the quarter-of-year field from 1 to 4.
  526.      * <p>
  527.      * This method returns the quarter as an {@code int} from 1 to 4.
  528.      * Application code is frequently clearer if the enum {@link Quarter}
  529.      * is used by calling {@link #getQuarter()}.
  530.      *
  531.      * @return the quarter-of-year, from 1 to 4
  532.      * @see #getQuarter()
  533.      */
  534.     public int getQuarterValue() {
  535.         return quarter.getValue();
  536.     }

  537.     /**
  538.      * Gets the quarter-of-year field using the {@code Quarter} enum.
  539.      * <p>
  540.      * This method returns the enum {@link Quarter} for the quarter.
  541.      * This avoids confusion as to what {@code int} values mean.
  542.      * If you need access to the primitive {@code int} value then the enum
  543.      * provides the {@link Quarter#getValue() int value}.
  544.      *
  545.      * @return the quarter-of-year, not null
  546.      * @see #getQuarterValue()
  547.      */
  548.     public Quarter getQuarter() {
  549.         return quarter;
  550.     }

  551.     //-----------------------------------------------------------------------
  552.     /**
  553.      * Checks if the year is a leap year, according to the ISO proleptic
  554.      * calendar system rules.
  555.      * <p>
  556.      * This method applies the current rules for leap years across the whole time-line.
  557.      * In general, a year is a leap year if it is divisible by four without
  558.      * remainder. However, years divisible by 100, are not leap years, with
  559.      * the exception of years divisible by 400 which are.
  560.      * <p>
  561.      * For example, 1904 is a leap year it is divisible by 4.
  562.      * 1900 was not a leap year as it is divisible by 100, however 2000 was a
  563.      * leap year as it is divisible by 400.
  564.      * <p>
  565.      * The calculation is proleptic - applying the same rules into the far future and far past.
  566.      * This is historically inaccurate, but is correct for the ISO-8601 standard.
  567.      *
  568.      * @return true if the year is leap, false otherwise
  569.      */
  570.     public boolean isLeapYear() {
  571.         return IsoChronology.INSTANCE.isLeapYear(year);
  572.     }

  573.     /**
  574.      * Checks if the day-of-quarter is valid for this year-quarter.
  575.      * <p>
  576.      * This method checks whether this year and quarter and the input day form
  577.      * a valid date.
  578.      *
  579.      * @param dayOfQuarter  the day-of-quarter to validate, from 1 to 92, invalid value returns false
  580.      * @return true if the day is valid for this year-quarter
  581.      */
  582.     public boolean isValidDay(int dayOfQuarter) {
  583.         return dayOfQuarter >= 1 && dayOfQuarter <= lengthOfQuarter();
  584.     }

  585.     /**
  586.      * Returns the length of the quarter, taking account of the year.
  587.      * <p>
  588.      * This returns the length of the quarter in days.
  589.      *
  590.      * @return the length of the quarter in days, from 90 to 92
  591.      */
  592.     public int lengthOfQuarter() {
  593.         return quarter.length(isLeapYear());
  594.     }

  595.     /**
  596.      * Returns the length of the year.
  597.      * <p>
  598.      * This returns the length of the year in days, either 365 or 366.
  599.      *
  600.      * @return 366 if the year is leap, 365 otherwise
  601.      */
  602.     public int lengthOfYear() {
  603.         return (isLeapYear() ? 366 : 365);
  604.     }

  605.     //-----------------------------------------------------------------------
  606.     /**
  607.      * Returns an adjusted copy of this year-quarter.
  608.      * <p>
  609.      * This returns a {@code YearQuarter} based on this one, with the year-quarter adjusted.
  610.      * The adjustment takes place using the specified adjuster strategy object.
  611.      * Read the documentation of the adjuster to understand what adjustment will be made.
  612.      * <p>
  613.      * A simple adjuster might simply set the one of the fields, such as the year field.
  614.      * A more complex adjuster might set the year-quarter to the next quarter that
  615.      * Halley's comet will pass the Earth.
  616.      * <p>
  617.      * The result of this method is obtained by invoking the
  618.      * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
  619.      * specified adjuster passing {@code this} as the argument.
  620.      * <p>
  621.      * This instance is immutable and unaffected by this method call.
  622.      *
  623.      * @param adjuster the adjuster to use, not null
  624.      * @return a {@code YearQuarter} based on {@code this} with the adjustment made, not null
  625.      * @throws DateTimeException if the adjustment cannot be made
  626.      * @throws ArithmeticException if numeric overflow occurs
  627.      */
  628.     @Override
  629.     public YearQuarter with(TemporalAdjuster adjuster) {
  630.         return (YearQuarter) adjuster.adjustInto(this);
  631.     }

  632.     /**
  633.      * Returns a copy of this year-quarter with the specified field set to a new value.
  634.      * <p>
  635.      * This returns a {@code YearQuarter} based on this one, with the value
  636.      * for the specified field changed.
  637.      * This can be used to change any supported field, such as the year or quarter.
  638.      * If it is not possible to set the value, because the field is not supported or for
  639.      * some other reason, an exception is thrown.
  640.      * <p>
  641.      * If the field is a {@link ChronoField} then the adjustment is implemented here.
  642.      * The supported fields behave as follows:
  643.      * <ul>
  644.      * <li>{@code QUARTER_OF_YEAR} -
  645.      *  Returns a {@code YearQuarter} with the specified quarter-of-year.
  646.      *  The year will be unchanged.
  647.      * <li>{@code YEAR_OF_ERA} -
  648.      *  Returns a {@code YearQuarter} with the specified year-of-era
  649.      *  The quarter and era will be unchanged.
  650.      * <li>{@code YEAR} -
  651.      *  Returns a {@code YearQuarter} with the specified year.
  652.      *  The quarter will be unchanged.
  653.      * <li>{@code ERA} -
  654.      *  Returns a {@code YearQuarter} with the specified era.
  655.      *  The quarter and year-of-era will be unchanged.
  656.      * </ul>
  657.      * <p>
  658.      * In all cases, if the new value is outside the valid range of values for the field
  659.      * then a {@code DateTimeException} will be thrown.
  660.      * <p>
  661.      * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
  662.      * <p>
  663.      * If the field is not a {@code ChronoField}, then the result of this method
  664.      * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
  665.      * passing {@code this} as the argument. In this case, the field determines
  666.      * whether and how to adjust the instant.
  667.      * <p>
  668.      * This instance is immutable and unaffected by this method call.
  669.      *
  670.      * @param field  the field to set in the result, not null
  671.      * @param newValue  the new value of the field in the result
  672.      * @return a {@code YearQuarter} based on {@code this} with the specified field set, not null
  673.      * @throws DateTimeException if the field cannot be set
  674.      * @throws UnsupportedTemporalTypeException if the field is not supported
  675.      * @throws ArithmeticException if numeric overflow occurs
  676.      */
  677.     @Override
  678.     public YearQuarter with(TemporalField field, long newValue) {
  679.         if (field == QUARTER_OF_YEAR) {
  680.             return withQuarter(QUARTER_OF_YEAR.range().checkValidIntValue(newValue, QUARTER_OF_YEAR));
  681.         } else if (field instanceof ChronoField) {
  682.             ChronoField f = (ChronoField) field;
  683.             f.checkValidValue(newValue);
  684.             switch (f) {
  685.                 case YEAR_OF_ERA:
  686.                     return withYear((int) (year < 1 ? 1 - newValue : newValue));
  687.                 case YEAR:
  688.                     return withYear((int) newValue);
  689.                 case ERA:
  690.                     return (getLong(ERA) == newValue ? this : withYear(1 - year));
  691.                 default:
  692.                     throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
  693.             }
  694.         }
  695.         return field.adjustInto(this, newValue);
  696.     }

  697.     //-----------------------------------------------------------------------
  698.     /**
  699.      * Returns a copy of this {@code YearQuarter} with the year altered.
  700.      * <p>
  701.      * This instance is immutable and unaffected by this method call.
  702.      *
  703.      * @param year  the year to set in the returned year-quarter, from MIN_YEAR to MAX_YEAR
  704.      * @return a {@code YearQuarter} based on this year-quarter with the requested year, not null
  705.      * @throws DateTimeException if the year value is invalid
  706.      */
  707.     public YearQuarter withYear(int year) {
  708.         YEAR.checkValidValue(year);
  709.         return with(year, quarter);
  710.     }

  711.     /**
  712.      * Returns a copy of this {@code YearQuarter} with the quarter-of-year altered.
  713.      * <p>
  714.      * This instance is immutable and unaffected by this method call.
  715.      *
  716.      * @param quarter  the quarter-of-year to set in the returned year-quarter, from 1 to 4
  717.      * @return a {@code YearQuarter} based on this year-quarter with the requested quarter, not null
  718.      * @throws DateTimeException if the quarter-of-year value is invalid
  719.      */
  720.     public YearQuarter withQuarter(int quarter) {
  721.         QUARTER_OF_YEAR.range().checkValidValue(quarter, QUARTER_OF_YEAR);
  722.         return with(year, Quarter.of(quarter));
  723.     }

  724.     //-----------------------------------------------------------------------
  725.     /**
  726.      * Returns a copy of this year-quarter with the specified amount added.
  727.      * <p>
  728.      * This returns a {@code YearQuarter} based on this one, with the specified amount added.
  729.      * The amount is typically {@link Period} but may be any other type implementing
  730.      * the {@link TemporalAmount} interface.
  731.      * <p>
  732.      * The calculation is delegated to the amount object by calling
  733.      * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
  734.      * to implement the addition in any way it wishes, however it typically
  735.      * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
  736.      * of the amount implementation to determine if it can be successfully added.
  737.      * <p>
  738.      * This instance is immutable and unaffected by this method call.
  739.      *
  740.      * @param amountToAdd  the amount to add, not null
  741.      * @return a {@code YearQuarter} based on this year-quarter with the addition made, not null
  742.      * @throws DateTimeException if the addition cannot be made
  743.      * @throws ArithmeticException if numeric overflow occurs
  744.      */
  745.     @Override
  746.     public YearQuarter plus(TemporalAmount amountToAdd) {
  747.         return (YearQuarter) amountToAdd.addTo(this);
  748.     }

  749.     /**
  750.      * Returns a copy of this year-quarter with the specified amount added.
  751.      * <p>
  752.      * This returns a {@code YearQuarter} based on this one, with the amount
  753.      * in terms of the unit added. If it is not possible to add the amount, because the
  754.      * unit is not supported or for some other reason, an exception is thrown.
  755.      * <p>
  756.      * If the field is a {@link ChronoUnit} then the addition is implemented here.
  757.      * The supported fields behave as follows:
  758.      * <ul>
  759.      * <li>{@code QUARTER_YEARS} -
  760.      *  Returns a {@code YearQuarter} with the specified number of quarters added.
  761.      *  This is equivalent to {@link #plusQuarters(long)}.
  762.      * <li>{@code YEARS} -
  763.      *  Returns a {@code YearQuarter} with the specified number of years added.
  764.      *  This is equivalent to {@link #plusYears(long)}.
  765.      * <li>{@code DECADES} -
  766.      *  Returns a {@code YearQuarter} with the specified number of decades added.
  767.      *  This is equivalent to calling {@link #plusYears(long)} with the amount
  768.      *  multiplied by 10.
  769.      * <li>{@code CENTURIES} -
  770.      *  Returns a {@code YearQuarter} with the specified number of centuries added.
  771.      *  This is equivalent to calling {@link #plusYears(long)} with the amount
  772.      *  multiplied by 100.
  773.      * <li>{@code MILLENNIA} -
  774.      *  Returns a {@code YearQuarter} with the specified number of millennia added.
  775.      *  This is equivalent to calling {@link #plusYears(long)} with the amount
  776.      *  multiplied by 1,000.
  777.      * <li>{@code ERAS} -
  778.      *  Returns a {@code YearQuarter} with the specified number of eras added.
  779.      *  Only two eras are supported so the amount must be one, zero or minus one.
  780.      *  If the amount is non-zero then the year is changed such that the year-of-era
  781.      *  is unchanged.
  782.      * </ul>
  783.      * <p>
  784.      * All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
  785.      * <p>
  786.      * If the field is not a {@code ChronoUnit}, then the result of this method
  787.      * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
  788.      * passing {@code this} as the argument. In this case, the unit determines
  789.      * whether and how to perform the addition.
  790.      * <p>
  791.      * This instance is immutable and unaffected by this method call.
  792.      *
  793.      * @param amountToAdd  the amount of the unit to add to the result, may be negative
  794.      * @param unit  the unit of the amount to add, not null
  795.      * @return a {@code YearQuarter} based on this year-quarter with the specified amount added, not null
  796.      * @throws DateTimeException if the addition cannot be made
  797.      * @throws UnsupportedTemporalTypeException if the unit is not supported
  798.      * @throws ArithmeticException if numeric overflow occurs
  799.      */
  800.     @Override
  801.     public YearQuarter plus(long amountToAdd, TemporalUnit unit) {
  802.         if (unit == QUARTER_YEARS) {
  803.             return plusQuarters(amountToAdd);
  804.         } else if (unit instanceof ChronoUnit) {
  805.             switch ((ChronoUnit) unit) {
  806.                 case YEARS:
  807.                     return plusYears(amountToAdd);
  808.                 case DECADES:
  809.                     return plusYears(Math.multiplyExact(amountToAdd, 10));
  810.                 case CENTURIES:
  811.                     return plusYears(Math.multiplyExact(amountToAdd, 100));
  812.                 case MILLENNIA:
  813.                     return plusYears(Math.multiplyExact(amountToAdd, 1000));
  814.                 case ERAS:
  815.                     return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
  816.                 default:
  817.                     throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
  818.             }
  819.         }
  820.         return unit.addTo(this, amountToAdd);
  821.     }

  822.     /**
  823.      * Returns a copy of this year-quarter with the specified period in years added.
  824.      * <p>
  825.      * This instance is immutable and unaffected by this method call.
  826.      *
  827.      * @param yearsToAdd  the years to add, may be negative
  828.      * @return a {@code YearQuarter} based on this year-quarter with the years added, not null
  829.      * @throws DateTimeException if the result exceeds the supported range
  830.      */
  831.     public YearQuarter plusYears(long yearsToAdd) {
  832.         if (yearsToAdd == 0) {
  833.             return this;
  834.         }
  835.         int newYear = YEAR.checkValidIntValue(year + yearsToAdd);  // safe overflow
  836.         return with(newYear, quarter);
  837.     }

  838.     /**
  839.      * Returns a copy of this year-quarter with the specified period in quarters added.
  840.      * <p>
  841.      * This instance is immutable and unaffected by this method call.
  842.      *
  843.      * @param quartersToAdd  the quarters to add, may be negative
  844.      * @return a {@code YearQuarter} based on this year-quarter with the quarters added, not null
  845.      * @throws DateTimeException if the result exceeds the supported range
  846.      */
  847.     public YearQuarter plusQuarters(long quartersToAdd) {
  848.         if (quartersToAdd == 0) {
  849.             return this;
  850.         }
  851.         long quarterCount = year * 4L + (quarter.getValue() - 1);
  852.         long calcQuarters = quarterCount + quartersToAdd;  // safe overflow
  853.         int newYear = YEAR.checkValidIntValue(Math.floorDiv(calcQuarters, 4));
  854.         int newQuarter = (int) Math.floorMod(calcQuarters, 4L) + 1;
  855.         return with(newYear, Quarter.of(newQuarter));
  856.     }

  857.     //-----------------------------------------------------------------------
  858.     /**
  859.      * Returns a copy of this year-quarter with the specified amount subtracted.
  860.      * <p>
  861.      * This returns a {@code YearQuarter} based on this one, with the specified amount subtracted.
  862.      * The amount is typically {@link Period} but may be any other type implementing
  863.      * the {@link TemporalAmount} interface.
  864.      * <p>
  865.      * The calculation is delegated to the amount object by calling
  866.      * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
  867.      * to implement the subtraction in any way it wishes, however it typically
  868.      * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
  869.      * of the amount implementation to determine if it can be successfully subtracted.
  870.      * <p>
  871.      * This instance is immutable and unaffected by this method call.
  872.      *
  873.      * @param amountToSubtract  the amount to subtract, not null
  874.      * @return a {@code YearQuarter} based on this year-quarter with the subtraction made, not null
  875.      * @throws DateTimeException if the subtraction cannot be made
  876.      * @throws ArithmeticException if numeric overflow occurs
  877.      */
  878.     @Override
  879.     public YearQuarter minus(TemporalAmount amountToSubtract) {
  880.         return (YearQuarter) amountToSubtract.subtractFrom(this);
  881.     }

  882.     /**
  883.      * Returns a copy of this year-quarter with the specified amount subtracted.
  884.      * <p>
  885.      * This returns a {@code YearQuarter} based on this one, with the amount
  886.      * in terms of the unit subtracted. If it is not possible to subtract the amount,
  887.      * because the unit is not supported or for some other reason, an exception is thrown.
  888.      * <p>
  889.      * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
  890.      * See that method for a full description of how addition, and thus subtraction, works.
  891.      * <p>
  892.      * This instance is immutable and unaffected by this method call.
  893.      *
  894.      * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
  895.      * @param unit  the unit of the amount to subtract, not null
  896.      * @return a {@code YearQuarter} based on this year-quarter with the specified amount subtracted, not null
  897.      * @throws DateTimeException if the subtraction cannot be made
  898.      * @throws UnsupportedTemporalTypeException if the unit is not supported
  899.      * @throws ArithmeticException if numeric overflow occurs
  900.      */
  901.     @Override
  902.     public YearQuarter minus(long amountToSubtract, TemporalUnit unit) {
  903.         return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
  904.     }

  905.     /**
  906.      * Returns a copy of this year-quarter with the specified period in years subtracted.
  907.      * <p>
  908.      * This instance is immutable and unaffected by this method call.
  909.      *
  910.      * @param yearsToSubtract  the years to subtract, may be negative
  911.      * @return a {@code YearQuarter} based on this year-quarter with the years subtracted, not null
  912.      * @throws DateTimeException if the result exceeds the supported range
  913.      */
  914.     public YearQuarter minusYears(long yearsToSubtract) {
  915.         return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
  916.     }

  917.     /**
  918.      * Returns a copy of this year-quarter with the specified period in quarters subtracted.
  919.      * <p>
  920.      * This instance is immutable and unaffected by this method call.
  921.      *
  922.      * @param quartersToSubtract  the quarters to subtract, may be negative
  923.      * @return a {@code YearQuarter} based on this year-quarter with the quarters subtracted, not null
  924.      * @throws DateTimeException if the result exceeds the supported range
  925.      */
  926.     public YearQuarter minusQuarters(long quartersToSubtract) {
  927.         return (quartersToSubtract == Long.MIN_VALUE ? plusQuarters(Long.MAX_VALUE).plusQuarters(1) : plusQuarters(-quartersToSubtract));
  928.     }

  929.     //-----------------------------------------------------------------------
  930.     /**
  931.      * Queries this year-quarter using the specified query.
  932.      * <p>
  933.      * This queries this year-quarter using the specified query strategy object.
  934.      * The {@code TemporalQuery} object defines the logic to be used to
  935.      * obtain the result. Read the documentation of the query to understand
  936.      * what the result of this method will be.
  937.      * <p>
  938.      * The result of this method is obtained by invoking the
  939.      * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
  940.      * specified query passing {@code this} as the argument.
  941.      *
  942.      * @param <R> the type of the result
  943.      * @param query  the query to invoke, not null
  944.      * @return the query result, null may be returned (defined by the query)
  945.      * @throws DateTimeException if unable to query (defined by the query)
  946.      * @throws ArithmeticException if numeric overflow occurs (defined by the query)
  947.      */
  948.     @SuppressWarnings("unchecked")
  949.     @Override
  950.     public <R> R query(TemporalQuery<R> query) {
  951.         if (query == TemporalQueries.chronology()) {
  952.             return (R) IsoChronology.INSTANCE;
  953.         } else if (query == TemporalQueries.precision()) {
  954.             return (R) QUARTER_YEARS;
  955.         }
  956.         return Temporal.super.query(query);
  957.     }

  958.     /**
  959.      * Adjusts the specified temporal object to have this year-quarter.
  960.      * <p>
  961.      * This returns a temporal object of the same observable type as the input
  962.      * with the year and quarter changed to be the same as this.
  963.      * <p>
  964.      * The adjustment is equivalent to using {@link Temporal#plus(long, TemporalUnit)}
  965.      * passing the number of quarters to adjust by.
  966.      * If the specified temporal object does not use the ISO calendar system then
  967.      * a {@code DateTimeException} is thrown.
  968.      * <p>
  969.      * In most cases, it is clearer to reverse the calling pattern by using
  970.      * {@link Temporal#with(TemporalAdjuster)}:
  971.      * <pre>
  972.      *   // these two lines are equivalent, but the second approach is recommended
  973.      *   temporal = thisYearQuarter.adjustInto(temporal);
  974.      *   temporal = temporal.with(thisYearQuarter);
  975.      * </pre>
  976.      * <p>
  977.      * This instance is immutable and unaffected by this method call.
  978.      *
  979.      * @param temporal  the target object to be adjusted, not null
  980.      * @return the adjusted object, not null
  981.      * @throws DateTimeException if unable to make the adjustment
  982.      * @throws ArithmeticException if numeric overflow occurs
  983.      */
  984.     @Override
  985.     public Temporal adjustInto(Temporal temporal) {
  986.         if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) {
  987.             throw new DateTimeException("Adjustment only supported on ISO date-time");
  988.         }
  989.         long newProlepticQuarter = getProlepticQuarter();
  990.         long oldProlepticQuarter = temporal.get(YEAR) * 4L + (temporal.get(QUARTER_OF_YEAR) - 1);
  991.         return temporal.plus(newProlepticQuarter - oldProlepticQuarter, QUARTER_YEARS);
  992.     }

  993.     /**
  994.      * Calculates the amount of time until another year-quarter in terms of the specified unit.
  995.      * <p>
  996.      * This calculates the amount of time between two {@code YearQuarter}
  997.      * objects in terms of a single {@code TemporalUnit}.
  998.      * The start and end points are {@code this} and the specified year-quarter.
  999.      * The result will be negative if the end is before the start.
  1000.      * The {@code Temporal} passed to this method is converted to a
  1001.      * {@code YearQuarter} using {@link #from(TemporalAccessor)}.
  1002.      * For example, the period in years between two year-quarters can be calculated
  1003.      * using {@code startYearQuarter.until(endYearQuarter, YEARS)}.
  1004.      * <p>
  1005.      * The calculation returns a whole number, representing the number of
  1006.      * complete units between the two year-quarters.
  1007.      * For example, the period in decades between 2012-Q3 and 2032-Q2
  1008.      * will only be one decade as it is one quarter short of two decades.
  1009.      * <p>
  1010.      * There are two equivalent ways of using this method.
  1011.      * The first is to invoke this method.
  1012.      * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
  1013.      * <pre>
  1014.      *   // these two lines are equivalent
  1015.      *   amount = start.until(end, QUARTER_YEARS);
  1016.      *   amount = QUARTER_YEARS.between(start, end);
  1017.      * </pre>
  1018.      * The choice should be made based on which makes the code more readable.
  1019.      * <p>
  1020.      * The calculation is implemented in this method for {@link ChronoUnit}.
  1021.      * The units {@code QUARTER_YEARS}, {@code YEARS}, {@code DECADES},
  1022.      * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
  1023.      * Other {@code ChronoUnit} values will throw an exception.
  1024.      * <p>
  1025.      * If the unit is not a {@code ChronoUnit}, then the result of this method
  1026.      * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
  1027.      * passing {@code this} as the first argument and the converted input temporal
  1028.      * as the second argument.
  1029.      * <p>
  1030.      * This instance is immutable and unaffected by this method call.
  1031.      *
  1032.      * @param endExclusive  the end date, exclusive, which is converted to a {@code YearQuarter}, not null
  1033.      * @param unit  the unit to measure the amount in, not null
  1034.      * @return the amount of time between this year-quarter and the end year-quarter
  1035.      * @throws DateTimeException if the amount cannot be calculated, or the end
  1036.      *  temporal cannot be converted to a {@code YearQuarter}
  1037.      * @throws UnsupportedTemporalTypeException if the unit is not supported
  1038.      * @throws ArithmeticException if numeric overflow occurs
  1039.      */
  1040.     @Override
  1041.     public long until(Temporal endExclusive, TemporalUnit unit) {
  1042.         YearQuarter end = YearQuarter.from(endExclusive);
  1043.         long quartersUntil = end.getProlepticQuarter() - getProlepticQuarter();  // no overflow
  1044.         if (unit == QUARTER_YEARS) {
  1045.             return quartersUntil;
  1046.         } else if (unit instanceof ChronoUnit) {
  1047.             switch ((ChronoUnit) unit) {
  1048.                 case YEARS:
  1049.                     return quartersUntil / 4;
  1050.                 case DECADES:
  1051.                     return quartersUntil / 40;
  1052.                 case CENTURIES:
  1053.                     return quartersUntil / 400;
  1054.                 case MILLENNIA:
  1055.                     return quartersUntil / 4000;
  1056.                 case ERAS:
  1057.                     return end.getLong(ERA) - getLong(ERA);
  1058.                 default:
  1059.                     throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
  1060.             }
  1061.         }
  1062.         return unit.between(this, end);
  1063.     }

  1064.     /**
  1065.      * Returns a sequential ordered stream of year-quarter. The returned stream starts from this year-quarter
  1066.      * (inclusive) and goes to {@code endExclusive} (exclusive) by an incremental step of 1 {@code QUARTER_YEARS}.
  1067.      * <p>
  1068.      * This instance is immutable and unaffected by this method call.
  1069.      *
  1070.      * @param endExclusive  the end year-quarter, exclusive, not null
  1071.      * @return a sequential {@code Stream} for the range of {@code YearQuarter} values
  1072.      * @throws IllegalArgumentException if end year-quarter is before this year-quarter
  1073.      */
  1074.     public Stream<YearQuarter> quartersUntil(YearQuarter endExclusive) {
  1075.         if (endExclusive.isBefore(this)) {
  1076.             throw new IllegalArgumentException(endExclusive + " < " + this);
  1077.         }
  1078.         long intervalLength = until(endExclusive, QUARTER_YEARS);
  1079.         return LongStream.range(0, intervalLength).mapToObj(n -> plusQuarters(n));
  1080.     }

  1081.     /**
  1082.      * Formats this year-quarter using the specified formatter.
  1083.      * <p>
  1084.      * This year-quarter will be passed to the formatter to produce a string.
  1085.      *
  1086.      * @param formatter  the formatter to use, not null
  1087.      * @return the formatted year-quarter string, not null
  1088.      * @throws DateTimeException if an error occurs during printing
  1089.      */
  1090.     public String format(DateTimeFormatter formatter) {
  1091.         Objects.requireNonNull(formatter, "formatter");
  1092.         return formatter.format(this);
  1093.     }

  1094.     //-----------------------------------------------------------------------
  1095.     /**
  1096.      * Combines this year-quarter with a day-of-quarter to create a {@code LocalDate}.
  1097.      * <p>
  1098.      * This returns a {@code LocalDate} formed from this year-quarter and the specified day-of-quarter.
  1099.      * <p>
  1100.      * The day-of-quarter value must be valid for the year-quarter.
  1101.      * <p>
  1102.      * This method can be used as part of a chain to produce a date:
  1103.      * <pre>
  1104.      *  LocalDate date = yearQuarter.atDay(day);
  1105.      * </pre>
  1106.      *
  1107.      * @param dayOfQuarter  the day-of-quarter to use, from 1 to 92
  1108.      * @return the date formed from this year-quarter and the specified day, not null
  1109.      * @throws DateTimeException if the day is invalid for the year-quarter
  1110.      * @see #isValidDay(int)
  1111.      */
  1112.     public LocalDate atDay(int dayOfQuarter) {
  1113.         ValueRange.of(1, lengthOfQuarter()).checkValidValue(dayOfQuarter, DAY_OF_QUARTER);
  1114.         boolean leap = Year.isLeap(year);
  1115.         Month month = quarter.firstMonth();
  1116.         int dom = dayOfQuarter;
  1117.         while (dom > month.length(leap)) {
  1118.             dom -= month.length(leap);
  1119.             month = month.plus(1);
  1120.         }
  1121.         return LocalDate.of(year, month, dom);
  1122.     }

  1123.     /**
  1124.      * Returns a {@code LocalDate} at the end of the quarter.
  1125.      * <p>
  1126.      * This returns a {@code LocalDate} based on this year-quarter.
  1127.      * The day-of-quarter is set to the last valid day of the quarter, taking
  1128.      * into account leap years.
  1129.      * <p>
  1130.      * This method can be used as part of a chain to produce a date:
  1131.      * <pre>
  1132.      *  LocalDate date = year.atQuarter(quarter).atEndOfQuarter();
  1133.      * </pre>
  1134.      *
  1135.      * @return the last valid date of this year-quarter, not null
  1136.      */
  1137.     public LocalDate atEndOfQuarter() {
  1138.         Month month = quarter.firstMonth().plus(2);
  1139.         return LocalDate.of(year, month, month.maxLength());
  1140.     }

  1141.     //-----------------------------------------------------------------------
  1142.     /**
  1143.      * Compares this year-quarter to another
  1144.      * <p>
  1145.      * The comparison is based first on the value of the year, then on the value of the quarter.
  1146.      * It is "consistent with equals", as defined by {@link Comparable}.
  1147.      *
  1148.      * @param other  the other year-quarter to compare to, not null
  1149.      * @return the comparator value, negative if less, positive if greater
  1150.      */
  1151.     @Override
  1152.     public int compareTo(YearQuarter other) {
  1153.         int cmp = (year - other.year);
  1154.         if (cmp == 0) {
  1155.             cmp = quarter.compareTo(other.quarter);
  1156.         }
  1157.         return cmp;
  1158.     }

  1159.     /**
  1160.      * Is this year-quarter after the specified year-quarter.
  1161.      *
  1162.      * @param other  the other year-quarter to compare to, not null
  1163.      * @return true if this is after the specified year-quarter
  1164.      */
  1165.     public boolean isAfter(YearQuarter other) {
  1166.         return compareTo(other) > 0;
  1167.     }

  1168.     /**
  1169.      * Is this year-quarter before the specified year-quarter.
  1170.      *
  1171.      * @param other  the other year-quarter to compare to, not null
  1172.      * @return true if this point is before the specified year-quarter
  1173.      */
  1174.     public boolean isBefore(YearQuarter other) {
  1175.         return compareTo(other) < 0;
  1176.     }

  1177.     //-----------------------------------------------------------------------
  1178.     /**
  1179.      * Checks if this year-quarter is equal to another year-quarter.
  1180.      * <p>
  1181.      * The comparison is based on the time-line position of the year-quarters.
  1182.      *
  1183.      * @param obj  the object to check, null returns false
  1184.      * @return true if this is equal to the other year-quarter
  1185.      */
  1186.     @Override
  1187.     public boolean equals(Object obj) {
  1188.         if (this == obj) {
  1189.             return true;
  1190.         }
  1191.         if (obj instanceof YearQuarter) {
  1192.             YearQuarter other = (YearQuarter) obj;
  1193.             return year == other.year && quarter == other.quarter;
  1194.         }
  1195.         return false;
  1196.     }

  1197.     /**
  1198.      * A hash code for this year-quarter.
  1199.      *
  1200.      * @return a suitable hash code
  1201.      */
  1202.     @Override
  1203.     public int hashCode() {
  1204.         return year ^ (quarter.getValue() << 27);
  1205.     }

  1206.     //-----------------------------------------------------------------------
  1207.     /**
  1208.      * Outputs this year-quarter as a {@code String}, such as {@code 2007-Q2}.
  1209.      * <p>
  1210.      * The output will be in the format {@code uuuu-'Q'Q}:
  1211.      *
  1212.      * @return a string representation of this year-quarter, not null
  1213.      */
  1214.     @Override
  1215.     @ToString
  1216.     public String toString() {
  1217.         int absYear = Math.abs(year);
  1218.         StringBuilder buf = new StringBuilder(10);
  1219.         if (absYear < 1000) {
  1220.             if (year < 0) {
  1221.                 buf.append(year - 10000).deleteCharAt(1);
  1222.             } else {
  1223.                 buf.append(year + 10000).deleteCharAt(0);
  1224.             }
  1225.         } else {
  1226.             if (year > 9999) {
  1227.                 buf.append('+');
  1228.             }
  1229.             buf.append(year);
  1230.         }
  1231.         return buf.append('-').append(quarter).toString();
  1232.     }

  1233. }