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

org.threeten.bp.Month.scala Maven / Gradle / Ivy

/*
 * Copyright (c) 2007-present, 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.bp

import java.util.Locale

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.ChronoField.MONTH_OF_YEAR
import org.threeten.bp.temporal.ChronoUnit.MONTHS
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.UnsupportedTemporalTypeException
import org.threeten.bp.temporal.ValueRange

/**
 * A month-of-year, such as 'July'.
 *
 * {@code Month} is an enum representing the 12 months of the year - January, February, March,
 * April, May, June, July, August, September, October, November and December.
 *
 * In addition to the textual enum name, each month-of-year has an {@code int} value. The {@code
 * int} value follows normal usage and the ISO-8601 standard, from 1 (January) to 12 (December). 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 Month}. 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 month-of-year concept defined exactly equivalent
 * to the ISO-8601 calendar system.
 *
 * 

Specification for implementors

This is an immutable and thread-safe enum. */ object Month { /** * The singleton instance for the month of January with 31 days. This has the numeric value of * {@code 1}. */ lazy val JANUARY = new Month("JANUARY", 0) /** * The singleton instance for the month of February with 28 days, or 29 in a leap year. This has * the numeric value of {@code 2}. */ lazy val FEBRUARY = new Month("FEBRUARY", 1) /** * The singleton instance for the month of March with 31 days. This has the numeric value of * {@code 3}. */ lazy val MARCH = new Month("MARCH", 2) /** * The singleton instance for the month of April with 30 days. This has the numeric value of * {@code 4}. */ lazy val APRIL = new Month("APRIL", 3) /** * The singleton instance for the month of May with 31 days. This has the numeric value of {@code * 5}. */ lazy val MAY = new Month("MAY", 4) /** * The singleton instance for the month of June with 30 days. This has the numeric value of {@code * 6}. */ lazy val JUNE = new Month("JUNE", 5) /** * The singleton instance for the month of July with 31 days. This has the numeric value of {@code * 7}. */ lazy val JULY = new Month("JULY", 6) /** * The singleton instance for the month of August with 31 days. This has the numeric value of * {@code 8}. */ lazy val AUGUST = new Month("AUGUST", 7) /** * The singleton instance for the month of September with 30 days. This has the numeric value of * {@code 9}. */ lazy val SEPTEMBER = new Month("SEPTEMBER", 8) /** * The singleton instance for the month of October with 31 days. This has the numeric value of * {@code 10}. */ lazy val OCTOBER = new Month("OCTOBER", 9) /** * The singleton instance for the month of November with 30 days. This has the numeric value of * {@code 11}. */ val NOVEMBER = new Month("NOVEMBER", 10) /** * The singleton instance for the month of December with 31 days. This has the numeric value of * {@code 12}. */ lazy val DECEMBER = new Month("DECEMBER", 11) lazy val values: Array[Month] = Array(JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER ) def valueOf(v: String): Month = values.find(_.name() == v) match { case Some(month) => month case _ => throw new IllegalArgumentException(s"Unrecognized month name: $v") } /** * Private cache of all the constants. */ private lazy val ENUMS: Array[Month] = Month.values /** * Obtains an instance of {@code Month} from an {@code int} value. * * {@code Month} is an enum representing the 12 months of the year. This factory allows the enum * to be obtained from the {@code int} value. The {@code int} value follows the ISO-8601 standard, * from 1 (January) to 12 (December). * * @param month * the month-of-year to represent, from 1 (January) to 12 (December) * @return * the month-of-year, not null * @throws DateTimeException * if the month-of-year is invalid */ def of(month: Int): Month = if (month < 1 || month > 12) throw new DateTimeException(s"Invalid value for MonthOfYear: $month") else ENUMS(month - 1) /** * Obtains an instance of {@code Month} 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 Month}. * * The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} field. The * extraction is only permitted if the temporal object has an ISO chronology, or can be converted * to a {@code LocalDate}. * * This method matches the signature of the functional interface {@link TemporalQuery} allowing it * to be used in queries via method reference, {@code Month::from}. * * @param temporal * the temporal object to convert, not null * @return * the month-of-year, not null * @throws DateTimeException * if unable to convert to a { @code Month} */ def from(temporal: TemporalAccessor): Month = { var _temporal = temporal _temporal match { case month: Month => month case _ => try { if (IsoChronology.INSTANCE != Chronology.from(_temporal)) _temporal = LocalDate.from(_temporal) of(_temporal.get(MONTH_OF_YEAR)) } catch { case ex: DateTimeException => throw new DateTimeException( s"Unable to obtain Month from TemporalAccessor: ${_temporal}, type ${_temporal.getClass.getName}", ex ) } } } } final class Month private (name: String, ordinal: Int) extends Enum[Month](name, ordinal) with TemporalAccessor with TemporalAdjuster { import Month._ /** * Gets the month-of-year {@code int} value. * * The values are numbered following the ISO-8601 standard, from 1 (January) to 12 (December). * * @return * the month-of-year, from 1 (January) to 12 (December) */ def getValue: Int = ordinal + 1 /** * Gets the textual representation, such as 'Jan' or 'December'. * * This returns the textual name used to identify the month-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 month-of-year, not null */ def getDisplayName(style: TextStyle, locale: Locale): String = new DateTimeFormatterBuilder().appendText(MONTH_OF_YEAR, style).toFormatter(locale).format(this) /** * Checks if the specified field is supported. * * This checks if this month-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. * * If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} 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 month-of-year, false if not */ def isSupported(field: TemporalField): Boolean = if (field.isInstanceOf[ChronoField]) field eq MONTH_OF_YEAR else 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 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#MONTH_OF_YEAR MONTH_OF_YEAR} then the range of the * month-of-year, from 1 to 12, 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 def range(field: TemporalField): ValueRange = if (field eq MONTH_OF_YEAR) field.range else if (field.isInstanceOf[ChronoField]) throw new UnsupportedTemporalTypeException(s"Unsupported field: $field") else field.rangeRefinedBy(this) /** * Gets the value of the specified field from this month-of-year as an {@code int}. * * This queries this 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#MONTH_OF_YEAR MONTH_OF_YEAR} then the value of the * month-of-year, from 1 to 12, 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 def get(field: TemporalField): Int = if (field eq MONTH_OF_YEAR) getValue else range(field).checkValidIntValue(getLong(field), field) /** * Gets the value of the specified field from this month-of-year as a {@code long}. * * This queries this 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#MONTH_OF_YEAR MONTH_OF_YEAR} then the value of the * month-of-year, from 1 to 12, 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 */ def getLong(field: TemporalField): Long = if (field eq MONTH_OF_YEAR) getValue.toLong else if (field.isInstanceOf[ChronoField]) throw new UnsupportedTemporalTypeException(s"Unsupported field: $field") else field.getFrom(this) /** * Returns the month-of-year that is the specified number of quarters after this one. * * The calculation rolls around the end of the year from December to January. The specified period * may be negative. * * This instance is immutable and unaffected by this method call. * * @param months * the months to add, positive or negative * @return * the resulting month, not null */ def plus(months: Long): Month = { val amount: Int = (months % 12).toInt Month.ENUMS((ordinal + (amount + 12)) % 12) } /** * Returns the month-of-year that is the specified number of months before this one. * * The calculation rolls around the start of the year from January to December. The specified * period may be negative. * * This instance is immutable and unaffected by this method call. * * @param months * the months to subtract, positive or negative * @return * the resulting month, not null */ def minus(months: Long): Month = plus(-(months % 12)) /** * Gets the length of this month in days. * * This takes a flag to determine whether to return the length for a leap year or not. * * February has 28 days in a standard year and 29 days in a leap year. April, June, September and * November have 30 days. All other months have 31 days. * * @param leapYear * true if the length is required for a leap year * @return * the length of this month in days, from 28 to 31 */ def length(leapYear: Boolean): Int = this match { case FEBRUARY => if (leapYear) 29 else 28 case APRIL | JUNE | SEPTEMBER | NOVEMBER => 30 case _ => 31 } /** * Gets the minimum length of this month in days. * * February has a minimum length of 28 days. April, June, September and November have 30 days. All * other months have 31 days. * * @return * the minimum length of this month in days, from 28 to 31 */ def minLength: Int = this match { case FEBRUARY => 28 case APRIL | JUNE | SEPTEMBER | NOVEMBER => 30 case _ => 31 } /** * Gets the maximum length of this month in days. * * February has a maximum length of 29 days. April, June, September and November have 30 days. All * other months have 31 days. * * @return * the maximum length of this month in days, from 29 to 31 */ def maxLength: Int = this match { case FEBRUARY => 29 case APRIL | JUNE | SEPTEMBER | NOVEMBER => 30 case _ => 31 } /** * Gets the day-of-year corresponding to the first day of this month. * * This returns the day-of-year that this month begins on, using the leap year flag to determine * the length of February. * * @param leapYear * true if the length is required for a leap year * @return * the day of year corresponding to the first day of this month, from 1 to 336 */ def firstDayOfYear(leapYear: Boolean): Int = { val leap: Int = if (leapYear) 1 else 0 this match { case JANUARY => 1 case FEBRUARY => 32 case MARCH => 60 + leap case APRIL => 91 + leap case MAY => 121 + leap case JUNE => 152 + leap case JULY => 182 + leap case AUGUST => 213 + leap case SEPTEMBER => 244 + leap case OCTOBER => 274 + leap case NOVEMBER => 305 + leap case DECEMBER => 335 + leap } } /** * Gets the month corresponding to the first month of this quarter. * * The year can be divided into four quarters. This method returns the first month of the quarter * for the base month. January, February and March return January. April, May and June return * April. July, August and September return July. October, November and December return October. * * @return * the first month of the quarter corresponding to this month, not null */ def firstMonthOfQuarter: Month = Month.ENUMS((ordinal / 3) * 3) /** * Queries this month-of-year using the specified query. * * This queries this month-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. * * @tparam R * the type of the result * @param query * the query to invoke, not null * @return * the query result, null may be returned (defined by the query) * @throws DateTimeException * if unable to query (defined by the query) * @throws ArithmeticException * if numeric overflow occurs (defined by the query) */ override def query[R](query: TemporalQuery[R]): R = if (query eq TemporalQueries.chronology) IsoChronology.INSTANCE.asInstanceOf[R] else if (query eq TemporalQueries.precision) MONTHS.asInstanceOf[R] else if ( (query eq TemporalQueries.localDate) || (query eq TemporalQueries.localTime) || (query eq TemporalQueries.zone) || (query eq TemporalQueries.zoneId) || (query eq TemporalQueries.offset) ) null.asInstanceOf[R] else query.queryFrom(this) /** * Adjusts the specified temporal object to have this month-of-year. * * This returns a temporal object of the same observable type as the input with the month-of-year * changed to be the same as this. * * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} passing {@link * ChronoField#MONTH_OF_YEAR} as the field. If the specified temporal object does not use the ISO * calendar system then a {@code DateTimeException} is thrown. * * In most cases, it is clearer to reverse the calling pattern by using {@link * Temporal#with(TemporalAdjuster)}:
 // these two lines are equivalent, but the second
   * approach is recommended temporal = thisMonth.adjustInto(temporal); temporal =
   * temporal.with(thisMonth); 
* * For example, given a date in May, the following are output:
 dateInMay.with(JANUARY); //
   * four months earlier dateInMay.with(APRIL); // one months earlier dateInMay.with(MAY); // same
   * date dateInMay.with(JUNE); // one month later dateInMay.with(DECEMBER); // seven months later
   * 
* * 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 */ def adjustInto(temporal: Temporal): Temporal = if (Chronology.from(temporal) != IsoChronology.INSTANCE) throw new DateTimeException("Adjustment only supported on ISO date-time") else temporal.`with`(MONTH_OF_YEAR, getValue.toLong) }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy