/* * ----------------------------------------------------------------------- * Copyright © 2013-2016 Meno Hochschild, <http://www.menodata.de/> * ----------------------------------------------------------------------- * This file (MinguoCalendar.java) is part of project Time4J. * * Time4J is free software: You can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * Time4J is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Time4J. If not, see <http://www.gnu.org/licenses/>. * ----------------------------------------------------------------------- */ package net.time4j.calendar; import net.time4j.CalendarUnit; import net.time4j.GeneralTimestamp; import net.time4j.Moment; import net.time4j.Month; import net.time4j.PlainDate; import net.time4j.PlainTime; import net.time4j.SystemClock; import net.time4j.Weekday; import net.time4j.Weekmodel; import net.time4j.base.GregorianMath; import net.time4j.base.MathUtils; import net.time4j.base.TimeSource; import net.time4j.calendar.service.GenericDatePatterns; import net.time4j.calendar.service.StdEnumDateElement; import net.time4j.calendar.service.StdIntegerDateElement; import net.time4j.calendar.service.StdWeekdayElement; import net.time4j.engine.AttributeQuery; import net.time4j.engine.CalendarEra; import net.time4j.engine.Calendrical; import net.time4j.engine.ChronoElement; import net.time4j.engine.ChronoEntity; import net.time4j.engine.ChronoException; import net.time4j.engine.ChronoMerger; import net.time4j.engine.DisplayStyle; import net.time4j.engine.ElementRule; import net.time4j.engine.EpochDays; import net.time4j.engine.FormattableElement; import net.time4j.engine.StartOfDay; import net.time4j.engine.TimeAxis; import net.time4j.engine.UnitRule; import net.time4j.engine.ValidationElement; import net.time4j.format.Attributes; import net.time4j.format.CalendarType; import net.time4j.format.Leniency; import net.time4j.format.LocalizedPatternSupport; import net.time4j.tz.TZID; import net.time4j.tz.Timezone; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.time.chrono.Chronology; import java.time.chrono.MinguoDate; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalQueries; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; /** * <p>The Minguo calendar used in Taiwan (Republic Of China) uses as only difference to western gregorian * calendar a different year numbering with the Minguo era 1912-01-01. </p> * * <p>See also: <a href="https://en.wikipedia.org/wiki/Minguo_calendar">Wikipedia</a>. </p> * * <p>Following elements which are declared as constants are registered by * this class: </p> * * <ul> * <li>{@link #DAY_OF_WEEK}</li> * <li>{@link #DAY_OF_MONTH}</li> * <li>{@link #DAY_OF_YEAR}</li> * <li>{@link #MONTH_OF_YEAR}</li> * <li>{@link #YEAR_OF_ERA}</li> * <li>{@link #ERA}</li> * </ul> * * <p>Furthermore, all elements defined in {@code EpochDays} and {@link CommonElements} are supported. </p> * * @author Meno Hochschild * @since 3.13/4.10 * @doctags.concurrency {immutable} */ /*[deutsch] * Der Minguo-Kalender wird in Taiwan (Republik von China) verwendet und hat als einzige Differenz * zum gregorianischen Kalender eine andere Jahreszählung, indem als Ausgangspunkt die Minguo-Ära * 1912-01-01 benutzt wird. </p> * * <p>Siehe auch: <a href="https://en.wikipedia.org/wiki/Minguo_calendar">Wikipedia</a>. </p> * * <p>Registriert sind folgende als Konstanten deklarierte Elemente: </p> * * <ul> * <li>{@link #DAY_OF_WEEK}</li> * <li>{@link #DAY_OF_MONTH}</li> * <li>{@link #DAY_OF_YEAR}</li> * <li>{@link #MONTH_OF_YEAR}</li> * <li>{@link #YEAR_OF_ERA}</li> * <li>{@link #ERA}</li> * </ul> * * <p>Au&slig;erdem werden alle Elemente von {@code EpochDays} und {@link CommonElements} unterstützt. </p> * * @author Meno Hochschild * @since 3.13/4.10 * @doctags.concurrency {immutable} */ @CalendarType("roc") public final class MinguoCalendar extends Calendrical<CalendarUnit, MinguoCalendar> implements LocalizedPatternSupport { //~ Statische Felder/Initialisierungen -------------------------------- /** * <p>Represents the Minguo era which cannot be changed. </p> */ /*[deutsch] * <p>Repräsentiert die Minguo-Ära, die nicht geändert werden kann. </p> */ @FormattableElement(format = "G") public static final ChronoElement<MinguoEra> ERA = new StdEnumDateElement<>("ERA", MinguoCalendar.class, MinguoEra.class, 'G'); /** * <p>Represents the Minguo year. </p> */ /*[deutsch] * <p>Repräsentiert das Minguo-Jahr. </p> */ @FormattableElement(format = "y") public static final StdCalendarElement<Integer, MinguoCalendar> YEAR_OF_ERA = new StdIntegerDateElement<>( "YEAR_OF_ERA", MinguoCalendar.class, 1, GregorianMath.MAX_YEAR - 1911, 'y', null, null); /** * <p>Represents the month. </p> */ /*[deutsch] * <p>Repräsentiert den Monat. </p> */ @FormattableElement(format = "M", standalone = "L") public static final StdCalendarElement<Month, MinguoCalendar> MONTH_OF_YEAR = new StdEnumDateElement<>( "MONTH_OF_YEAR", MinguoCalendar.class, Month.class, 'M'); /** * <p>Represents the day of month. </p> */ /*[deutsch] * <p>Repräsentiert den Tag des Monats. </p> */ @FormattableElement(format = "d") public static final StdCalendarElement<Integer, MinguoCalendar> DAY_OF_MONTH = new StdIntegerDateElement<>("DAY_OF_MONTH", MinguoCalendar.class, 1, 31, 'd'); /** * <p>Represents the day of year. </p> */ /*[deutsch] * <p>Repräsentiert den Tag des Jahres. </p> */ @FormattableElement(format = "D") public static final StdCalendarElement<Integer, MinguoCalendar> DAY_OF_YEAR = new StdIntegerDateElement<>("DAY_OF_YEAR", MinguoCalendar.class, 1, 365, 'D'); /** * <p>Represents the day of week. </p> * * <p>If the day-of-week is set to a new value then Time4J handles the calendar week * as starting on Sunday. </p> */ /*[deutsch] * <p>Repräsentiert den Tag der Woche. </p> * * <p>Wenn der Tag der Woche auf einen neuen Wert gesetzt wird, behandelt Time4J die * Kalenderwoche so, daß sie am Sonntag beginnt. </p> */ @FormattableElement(format = "E") public static final StdCalendarElement<Weekday, MinguoCalendar> DAY_OF_WEEK = new StdWeekdayElement<>(MinguoCalendar.class); private static final Map<Object, ChronoElement<?>> CHILDREN; private static final EraYearMonthDaySystem<MinguoCalendar> CALSYS; private static final TimeAxis<CalendarUnit, MinguoCalendar> ENGINE; static { Map<Object, ChronoElement<?>> children = new HashMap<>(); children.put(ERA, YEAR_OF_ERA); children.put(YEAR_OF_ERA, MONTH_OF_YEAR); children.put(MONTH_OF_YEAR, DAY_OF_MONTH); CHILDREN = Collections.unmodifiableMap(children); CALSYS = new Transformer(); TimeAxis.Builder<CalendarUnit, MinguoCalendar> builder = TimeAxis.Builder.setUp( CalendarUnit.class, MinguoCalendar.class, new Merger(), CALSYS) .appendElement( ERA, FieldRule.of(ERA)) .appendElement( YEAR_OF_ERA, FieldRule.of(YEAR_OF_ERA), CalendarUnit.YEARS) .appendElement( MONTH_OF_YEAR, FieldRule.of(MONTH_OF_YEAR), CalendarUnit.MONTHS) .appendElement( CommonElements.RELATED_GREGORIAN_YEAR, new RelatedGregorianYearRule<>(CALSYS, DAY_OF_YEAR)) .appendElement( DAY_OF_MONTH, FieldRule.of(DAY_OF_MONTH), CalendarUnit.DAYS) .appendElement( DAY_OF_YEAR, FieldRule.of(DAY_OF_YEAR), CalendarUnit.DAYS) .appendElement( DAY_OF_WEEK, FieldRule.of(DAY_OF_WEEK), CalendarUnit.DAYS) .appendExtension( new CommonElements.Weekengine( MinguoCalendar.class, DAY_OF_MONTH, DAY_OF_YEAR, getDefaultWeekmodel())); registerUnits(builder); ENGINE = builder.build(); } private static final long serialVersionUID = -6628190121085147706L; //~ Instanzvariablen -------------------------------------------------- private final PlainDate iso; //~ Konstruktoren ----------------------------------------------------- private MinguoCalendar(PlainDate iso) { super(); this.iso = iso; } //~ Methoden ---------------------------------------------------------- /** * <p>Creates a new instance of a Minguo calendar date. </p> * * @param era Minguo era * @param yearOfEra Minguo year of era * @param month gregorian month * @param dayOfMonth day of month * @return new instance of {@code MinguoCalendar} * @throws IllegalArgumentException in case of any inconsistencies * @since 3.13/4.10 */ /*[deutsch] * <p>Erzeugt ein neues Minguo-Kalenderdatum. </p> * * @param era Minguo era * @param yearOfEra Minguo year of era * @param month gregorian month * @param dayOfMonth day of month * @return new instance of {@code MinguoCalendar} * @throws IllegalArgumentException in case of any inconsistencies * @since 3.13/4.10 */ public static MinguoCalendar of( MinguoEra era, int yearOfEra, Month month, int dayOfMonth ) { return MinguoCalendar.of(era, yearOfEra, month.getValue(), dayOfMonth); } /** * <p>Creates a new instance of an Minguo calendar date. </p> * * @param era Minguo era * @param yearOfEra Minguo year of era * @param month gregorian month * @param dayOfMonth day of month * @return new instance of {@code MinguoCalendar} * @throws IllegalArgumentException in case of any inconsistencies * @since 3.13/4.10 */ /*[deutsch] * <p>Erzeugt ein neues Minguo-Kalenderdatum. </p> * * @param era Minguo era * @param yearOfEra Minguo year of era * @param month gregorian month * @param dayOfMonth day of month * @return new instance of {@code MinguoCalendar} * @throws IllegalArgumentException in case of any inconsistencies * @since 3.13/4.10 */ public static MinguoCalendar of( MinguoEra era, int yearOfEra, int month, int dayOfMonth ) { int prolepticYear = toProlepticYear(era, yearOfEra); PlainDate iso = PlainDate.of(prolepticYear, month, dayOfMonth); return new MinguoCalendar(iso); } /** * <p>Obtains the current calendar date in system time. </p> * * <p>Convenient short-cut for: {@code SystemClock.inLocalView().now(MinguoCalendar.axis())}. </p> * * @return current calendar date in system time zone using the system clock * @see SystemClock#inLocalView() * @see net.time4j.ZonalClock#now(net.time4j.engine.Chronology) * @since 3.23/4.19 */ /*[deutsch] * <p>Ermittelt das aktuelle Kalenderdatum in der Systemzeit. </p> * * <p>Bequeme Abkürzung für: {@code SystemClock.inLocalView().now(MinguoCalendar.axis())}. </p> * * @return current calendar date in system time zone using the system clock * @see SystemClock#inLocalView() * @see net.time4j.ZonalClock#now(net.time4j.engine.Chronology) * @since 3.23/4.19 */ public static MinguoCalendar nowInSystemTime() { return SystemClock.inLocalView().now(MinguoCalendar.axis()); } /** * <p>Yields the Minguo era. </p> * * @return enum * @since 3.13/4.10 */ /*[deutsch] * <p>Liefert die Minguo-Ära. </p> * * @return enum * @since 3.13/4.10 */ public MinguoEra getEra() { return ((this.iso.getYear() < 1912) ? MinguoEra.BEFORE_ROC : MinguoEra.ROC); } /** * <p>Yields the Minguo year. </p> * * @return int * @since 3.13/4.10 */ /*[deutsch] * <p>Liefert das Minguo-Jahr. </p> * * @return int * @since 3.13/4.10 */ public int getYear() { MinguoEra era = this.getEra(); return ((era == MinguoEra.ROC) ? this.iso.getYear() - 1911 : 1912 - this.iso.getYear()); } /** * <p>Yields the (gregorian) month. </p> * * @return enum * @since 3.13/4.10 */ /*[deutsch] * <p>Liefert den (gregorianischen) Monat. </p> * * @return enum * @since 3.13/4.10 */ public Month getMonth() { return Month.valueOf(this.iso.getMonth()); } /** * <p>Yields the day of month. </p> * * @return int * @since 3.13/4.10 */ /*[deutsch] * <p>Liefert den Tag des Monats. </p> * * @return int * @since 3.13/4.10 */ public int getDayOfMonth() { return this.iso.getDayOfMonth(); } /** * <p>Determines the day of week. </p> * * @return Weekday * @since 3.13/4.10 */ /*[deutsch] * <p>Ermittelt den Wochentag. </p> * * @return Weekday * @since 3.13/4.10 */ public Weekday getDayOfWeek() { return this.iso.get(PlainDate.DAY_OF_WEEK); } /** * <p>Yields the day of year. </p> * * @return int * @since 3.13/4.10 */ /*[deutsch] * <p>Liefert den Tag des Jahres. </p> * * @return int * @since 3.13/4.10 */ public int getDayOfYear() { return this.iso.get(PlainDate.DAY_OF_YEAR); } /** * <p>Yields the length of current month in days. </p> * * @return int * @since 3.13/4.10 */ /*[deutsch] * <p>Liefert die Länge des aktuellen Monats in Tagen. </p> * * @return int * @since 3.13/4.10 */ public int lengthOfMonth() { return this.iso.lengthOfMonth(); } /** * <p>Yields the length of current year in days. </p> * * @return int * @since 3.13/4.10 */ /*[deutsch] * <p>Liefert die Länge des aktuellen Jahres in Tagen. </p> * * @return int * @since 3.13/4.10 */ public int lengthOfYear() { return this.iso.lengthOfYear(); } /** * <p>Is the year of this date a leap year? </p> * * @return boolean * @since 3.13/4.10 */ /*[deutsch] * <p>Liegt dieses Datum in einem Schaltjahr? </p> * * @return boolean * @since 3.13/4.10 */ public boolean isLeapYear() { return this.iso.isLeapYear(); } /** * <p>Creates a new local timestamp with this date and given wall time. </p> * * <p>If the time {@link PlainTime#midnightAtEndOfDay() T24:00} is used * then the resulting timestamp will automatically be normalized such * that the timestamp will contain the following day instead. </p> * * @param time wall time * @return general timestamp as composition of this date and given time * @since 3.13/4.10 */ /*[deutsch] * <p>Erzeugt einen allgemeinen Zeitstempel mit diesem Datum und der angegebenen Uhrzeit. </p> * * <p>Wenn {@link PlainTime#midnightAtEndOfDay() T24:00} angegeben wird, * dann wird der Zeitstempel automatisch so normalisiert, daß er auf * den nächsten Tag verweist. </p> * * @param time wall time * @return general timestamp as composition of this date and given time * @since 3.13/4.10 */ public GeneralTimestamp<MinguoCalendar> at(PlainTime time) { return GeneralTimestamp.of(this, time); } /** * <p>Is equivalent to {@code at(PlainTime.of(hour, minute))}. </p> * * @param hour hour of day in range (0-24) * @param minute minute of hour in range (0-59) * @return general timestamp as composition of this date and given time * @throws IllegalArgumentException if any argument is out of range * @since 3.13/4.10 */ /*[deutsch] * <p>Entspricht {@code at(PlainTime.of(hour, minute))}. </p> * * @param hour hour of day in range (0-24) * @param minute minute of hour in range (0-59) * @return general timestamp as composition of this date and given time * @throws IllegalArgumentException if any argument is out of range * @since 3.13/4.10 */ public GeneralTimestamp<MinguoCalendar> atTime( int hour, int minute ) { return this.at(PlainTime.of(hour, minute)); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } else if (obj instanceof MinguoCalendar) { MinguoCalendar that = (MinguoCalendar) obj; return this.iso.equals(that.iso); } else { return false; } } @Override public int hashCode() { return this.iso.hashCode(); } @Override public String toString() { StringBuilder sb = new StringBuilder(32); sb.append(this.getEra()); sb.append('-'); sb.append(this.getYear()); sb.append('-'); int m = this.getMonth().getValue(); if (m < 10) { sb.append('0'); } sb.append(m); sb.append('-'); int d = this.getDayOfMonth(); if (d < 10) { sb.append('0'); } sb.append(d); return sb.toString(); } /** * <p>Obtains the standard week model of this calendar. </p> * * <p>The Minguo calendar usually starts on Sunday. </p> * * @return Weekmodel * @since 3.24/4.20 */ /*[deutsch] * <p>Ermittelt das Standardwochenmodell dieses Kalenders. </p> * * <p>Der Minguo-Kalender startet normalerweise am Sonntag. </p> * * @return Weekmodel * @since 3.24/4.20 */ public static Weekmodel getDefaultWeekmodel() { return Weekmodel.of(Weekday.SUNDAY, 1); } /** * <p>Returns the associated time axis. </p> * * @return chronology * @since 3.13/4.10 */ /*[deutsch] * <p>Liefert die zugehörige Zeitachse. </p> * * @return chronology * @since 3.13/4.10 */ public static TimeAxis<CalendarUnit, MinguoCalendar> axis() { return ENGINE; } @Override protected TimeAxis<CalendarUnit, MinguoCalendar> getChronology() { return ENGINE; } @Override protected MinguoCalendar getContext() { return this; } // deserialization PlainDate toISO() { return this.iso; } private static int toProlepticYear( MinguoEra era, int yearOfEra ) { return ( (era == MinguoEra.ROC) ? MathUtils.safeAdd(yearOfEra, 1911) : MathUtils.safeSubtract(1912, yearOfEra)); } private static void registerUnits(TimeAxis.Builder<CalendarUnit, MinguoCalendar> builder) { Set<CalendarUnit> monthly = EnumSet.range(CalendarUnit.MILLENNIA, CalendarUnit.MONTHS); Set<CalendarUnit> daily = EnumSet.range(CalendarUnit.WEEKS, CalendarUnit.DAYS); for (CalendarUnit unit : CalendarUnit.values()) { builder.appendUnit( unit, new MinguoUnitRule(unit), unit.getLength(), (unit.compareTo(CalendarUnit.WEEKS) < 0) ? monthly : daily ); } } /** * @return replacement object in serialization graph * @serialData Uses <a href="../../../serialized-form.html#net.time4j.calendar.SPX"> * a dedicated serialization form</a> as proxy. The first byte contains * the type-ID {@code 6}. Then the associated gregorian date is written. */ private Object writeReplace() { return new SPX(this, SPX.MINGUO); } /** * @param in object input stream * @throws InvalidObjectException (always) * @serialData Blocks because a serialization proxy is required. */ private void readObject(ObjectInputStream in) throws IOException { throw new InvalidObjectException("Serialization proxy required."); } //~ Innere Klassen ---------------------------------------------------- private static class Transformer implements EraYearMonthDaySystem<MinguoCalendar> { //~ Methoden ------------------------------------------------------ @Override public boolean isValid( CalendarEra era, int yearOfEra, int monthOfYear, int dayOfMonth ) { try { if (era instanceof MinguoEra) { int prolepticYear = toProlepticYear(MinguoEra.class.cast(era), yearOfEra); return ( (yearOfEra >= 1) && (prolepticYear <= GregorianMath.MAX_YEAR) && (monthOfYear >= 1) && (monthOfYear <= 12) && (dayOfMonth >= 1) && (dayOfMonth <= GregorianMath.getLengthOfMonth(prolepticYear, monthOfYear)) ); } } catch (ArithmeticException ae) { // okay, we return false anyway } return false; } @Override public int getLengthOfMonth( CalendarEra era, int yearOfEra, int monthOfYear ) { try { int prolepticYear = toProlepticYear(MinguoEra.class.cast(era), yearOfEra); return PlainDate.of(prolepticYear, monthOfYear, 1).lengthOfMonth(); } catch (RuntimeException re) { throw new IllegalArgumentException(re.getMessage(), re); } } @Override public int getLengthOfYear( CalendarEra era, int yearOfEra ) { try { int prolepticYear = toProlepticYear(MinguoEra.class.cast(era), yearOfEra); return PlainDate.of(prolepticYear, Month.JANUARY, 1).lengthOfYear(); } catch (RuntimeException re) { throw new IllegalArgumentException(re.getMessage(), re); } } @Override public MinguoCalendar transform(long utcDays) { return new MinguoCalendar(PlainDate.of(utcDays, EpochDays.UTC)); } @Override public long transform(MinguoCalendar date) { return date.iso.get(EpochDays.UTC); } @Override public long getMinimumSinceUTC() { return PlainDate.axis().getCalendarSystem().getMinimumSinceUTC(); } @Override public long getMaximumSinceUTC() { return PlainDate.axis().getCalendarSystem().getMaximumSinceUTC(); } @Override public List<CalendarEra> getEras() { CalendarEra e0 = MinguoEra.BEFORE_ROC; CalendarEra e1 = MinguoEra.ROC; return Arrays.asList(e0, e1); } } private static class FieldRule<V extends Comparable<V>> implements ElementRule<MinguoCalendar, V> { //~ Instanzvariablen ---------------------------------------------- private final ChronoElement<V> element; //~ Konstruktoren ------------------------------------------------- private FieldRule(ChronoElement<V> element) { super(); this.element = element; } //~ Methoden ------------------------------------------------------ static <V extends Comparable<V>> FieldRule<V> of(ChronoElement<V> element) { return new FieldRule<>(element); } @Override public V getValue(MinguoCalendar context) { Object result; if (this.element == ERA) { result = context.getEra(); } else if (this.element.equals(YEAR_OF_ERA)) { result = context.getYear(); } else if (this.element.equals(MONTH_OF_YEAR)) { result = context.getMonth(); } else if (this.element.equals(DAY_OF_MONTH)) { result = context.getDayOfMonth(); } else if (this.element.equals(DAY_OF_YEAR)) { result = context.getDayOfYear(); } else if (this.element.equals(DAY_OF_WEEK)) { result = context.getDayOfWeek(); } else { throw new ChronoException("Missing rule for: " + this.element.name()); } return this.element.getType().cast(result); } @Override public V getMinimum(MinguoCalendar context) { Object result; if (this.element == ERA) { result = MinguoEra.BEFORE_ROC; } else if (Integer.class.isAssignableFrom(this.element.getType())) { result = Integer.valueOf(1); } else if (this.element.equals(MONTH_OF_YEAR)) { result = Month.JANUARY; } else if (this.element.equals(DAY_OF_WEEK)) { result = Weekday.SUNDAY; } else { throw new ChronoException("Missing rule for: " + this.element.name()); } return this.element.getType().cast(result); } @Override public V getMaximum(MinguoCalendar context) { Object result; if (this.element == ERA) { result = MinguoEra.ROC; } else if (this.element.equals(YEAR_OF_ERA)) { MinguoEra era = context.getEra(); result = ( (era == MinguoEra.ROC) ? Integer.valueOf(GregorianMath.MAX_YEAR - 1911) : Integer.valueOf(1912 - GregorianMath.MIN_YEAR)); } else if (this.element.equals(MONTH_OF_YEAR)) { result = Month.DECEMBER; } else if (this.element.equals(DAY_OF_MONTH)) { result = context.iso.getMaximum(PlainDate.DAY_OF_MONTH); } else if (this.element.equals(DAY_OF_YEAR)) { result = context.iso.getMaximum(PlainDate.DAY_OF_YEAR); } else if (this.element.equals(DAY_OF_WEEK)) { result = Weekday.SATURDAY; } else { throw new ChronoException("Missing rule for: " + this.element.name()); } return this.element.getType().cast(result); } @Override public boolean isValid( MinguoCalendar context, V value ) { if (value == null) { return false; } else if (this.element == ERA) { return value.equals(context.getEra()); } V min = this.getMinimum(context); V max = this.getMaximum(context); return ((min.compareTo(value) <= 0) && (value.compareTo(max) <= 0)); } @Override public MinguoCalendar withValue( MinguoCalendar context, V value, boolean lenient ) { if (!this.isValid(context, value)) { throw new IllegalArgumentException("Out of range: " + value); } if (this.element == ERA) { return context; } else if (this.element.equals(YEAR_OF_ERA)) { MinguoCalendar mc = MinguoCalendar.of(context.getEra(), toNumber(value), context.getMonth(), 1); return mc.with(DAY_OF_MONTH, Math.min(context.getDayOfMonth(), mc.lengthOfMonth())); } else if (this.element.equals(MONTH_OF_YEAR)) { PlainDate date = context.iso.with(PlainDate.MONTH_OF_YEAR, Month.class.cast(value)); return new MinguoCalendar(date); } else if (this.element.equals(DAY_OF_MONTH)) { PlainDate date = context.iso.with(PlainDate.DAY_OF_MONTH, toNumber(value)); return new MinguoCalendar(date); } else if (this.element.equals(DAY_OF_YEAR)) { PlainDate date = context.iso.with(PlainDate.DAY_OF_YEAR, toNumber(value)); return new MinguoCalendar(date); } else if (this.element.equals(DAY_OF_WEEK)) { PlainDate date = context.iso.with(getDefaultWeekmodel().localDayOfWeek(), Weekday.class.cast(value)); return new MinguoCalendar(date); } throw new ChronoException("Missing rule for: " + this.element.name()); } // optional @Override public ChronoElement<?> getChildAtFloor(MinguoCalendar context) { return CHILDREN.get(this.element); } // optional @Override public ChronoElement<?> getChildAtCeiling(MinguoCalendar context) { return CHILDREN.get(this.element); } private static int toNumber(Object value) { return Integer.class.cast(value).intValue(); } } private static class MinguoUnitRule implements UnitRule<MinguoCalendar> { //~ Instanzvariablen ---------------------------------------------- private final CalendarUnit unit; //~ Konstruktoren ------------------------------------------------- MinguoUnitRule(CalendarUnit unit) { super(); this.unit = unit; } //~ Methoden ------------------------------------------------------ @Override public MinguoCalendar addTo( MinguoCalendar date, long amount ) { return new MinguoCalendar(date.iso.plus(amount, this.unit)); } @Override public long between( MinguoCalendar start, MinguoCalendar end ) { return this.unit.between(start.iso, end.iso); } } private static class Merger implements ChronoMerger<MinguoCalendar> { //~ Methoden ------------------------------------------------------ @Override public String getFormatPattern( DisplayStyle style, Locale locale ) { return GenericDatePatterns.get("roc", style, locale); } @Override public MinguoCalendar createFrom( TimeSource<?> clock, AttributeQuery attributes ) { TZID tzid; if (attributes.contains(Attributes.TIMEZONE_ID)) { tzid = attributes.get(Attributes.TIMEZONE_ID); } else if (attributes.get(Attributes.LENIENCY, Leniency.SMART).isLax()) { tzid = Timezone.ofSystem().getID(); } else { return null; } StartOfDay startOfDay = attributes.get(Attributes.START_OF_DAY, this.getDefaultStartOfDay()); return Moment.from(clock.currentTime()).toGeneralTimestamp(ENGINE, tzid, startOfDay).toDate(); } @Override public MinguoCalendar createFrom( TemporalAccessor threeten, AttributeQuery attributes ) { Chronology c = threeten.query(TemporalQueries.chronology()); if (c != null && c.getId().equals("Minguo")) { MinguoDate md = MinguoDate.from(threeten); int era = md.get(ChronoField.ERA); return MinguoCalendar.of( MinguoEra.values()[era], md.get(ChronoField.YEAR_OF_ERA), md.get(ChronoField.MONTH_OF_YEAR), md.get(ChronoField.DAY_OF_MONTH)); } return null; } @Override @Deprecated public MinguoCalendar createFrom( ChronoEntity<?> entity, AttributeQuery attributes, boolean preparsing ) { boolean lenient = attributes.get(Attributes.LENIENCY, Leniency.SMART).isLax(); return this.createFrom(entity, attributes, lenient, preparsing); } @Override public MinguoCalendar createFrom( ChronoEntity<?> entity, AttributeQuery attributes, boolean lenient, boolean preparsing ) { if (entity.contains(PlainDate.COMPONENT)) { return new MinguoCalendar(entity.get(PlainDate.COMPONENT)); } MinguoEra era; if (entity.contains(ERA)) { era = entity.get(ERA); } else if (lenient) { era = MinguoEra.ROC; } else { entity.with(ValidationElement.ERROR_MESSAGE, "Missing Minguo era."); return null; } int yearOfEra = entity.getInt(YEAR_OF_ERA); if (yearOfEra == Integer.MIN_VALUE) { entity.with(ValidationElement.ERROR_MESSAGE, "Missing Minguo year."); return null; } int prolepticYear = toProlepticYear(era, yearOfEra); if (entity.contains(MONTH_OF_YEAR)) { int month = entity.get(MONTH_OF_YEAR).getValue(); int dom = entity.getInt(DAY_OF_MONTH); if (dom != Integer.MIN_VALUE) { if (CALSYS.isValid(era, yearOfEra, month, dom)) { return MinguoCalendar.of(era, yearOfEra, month, dom); } else { entity.with(ValidationElement.ERROR_MESSAGE, "Invalid Minguo date."); } } } else { int doy = entity.getInt(DAY_OF_YEAR); if (doy != Integer.MIN_VALUE) { if (doy > 0) { int month = 1; int daycount = 0; while (month <= 12) { int len = GregorianMath.getLengthOfMonth(prolepticYear, month); if (doy > daycount + len) { month++; daycount += len; } else { int dom = doy - daycount; return MinguoCalendar.of(era, yearOfEra, month, dom); } } } entity.with(ValidationElement.ERROR_MESSAGE, "Invalid Minguo date."); } } return null; } } }