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

net.time4j.PlainTimestamp Maven / Gradle / Ivy

There is a newer version: 4.38
Show newest version
/*
 * -----------------------------------------------------------------------
 * Copyright © 2013-2016 Meno Hochschild, 
 * -----------------------------------------------------------------------
 * This file (PlainTimestamp.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 .
 * -----------------------------------------------------------------------
 */

package net.time4j;

import net.time4j.base.GregorianDate;
import net.time4j.base.MathUtils;
import net.time4j.base.TimeSource;
import net.time4j.base.UnixTime;
import net.time4j.base.WallTime;
import net.time4j.engine.AttributeQuery;
import net.time4j.engine.ChronoElement;
import net.time4j.engine.ChronoEntity;
import net.time4j.engine.ChronoException;
import net.time4j.engine.ChronoExtension;
import net.time4j.engine.ChronoMerger;
import net.time4j.engine.DisplayStyle;
import net.time4j.engine.ElementRule;
import net.time4j.engine.EpochDays;
import net.time4j.engine.IntElementRule;
import net.time4j.engine.Normalizer;
import net.time4j.engine.Temporal;
import net.time4j.engine.ThreetenAdapter;
import net.time4j.engine.TimeAxis;
import net.time4j.engine.TimeMetric;
import net.time4j.engine.TimePoint;
import net.time4j.engine.TimeSpan;
import net.time4j.engine.UnitRule;
import net.time4j.format.Attributes;
import net.time4j.format.CalendarText;
import net.time4j.format.CalendarType;
import net.time4j.format.ChronoPattern;
import net.time4j.format.DisplayMode;
import net.time4j.format.Leniency;
import net.time4j.format.LocalizedPatternSupport;
import net.time4j.format.TemporalFormatter;
import net.time4j.scale.TimeScale;
import net.time4j.tz.TZID;
import net.time4j.tz.Timezone;
import net.time4j.tz.TransitionStrategy;
import net.time4j.tz.ZonalOffset;

import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAccessor;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import static net.time4j.CalendarUnit.*;
import static net.time4j.ClockUnit.*;
import static net.time4j.PlainDate.*;
import static net.time4j.PlainTime.*;


/**
 * 

Represents a plain composition of calendar date and wall time as defined * in ISO-8601, but without any timezone.

* *

Following elements which are declared as constants are registered by * this class:

* *
    *
  • {@link PlainDate#COMPONENT}
  • *
  • {@link PlainDate#YEAR}
  • *
  • {@link PlainDate#YEAR_OF_WEEKDATE}
  • *
  • {@link PlainDate#QUARTER_OF_YEAR}
  • *
  • {@link PlainDate#MONTH_OF_YEAR}
  • *
  • {@link PlainDate#MONTH_AS_NUMBER}
  • *
  • {@link PlainDate#DAY_OF_MONTH}
  • *
  • {@link PlainDate#DAY_OF_QUARTER}
  • *
  • {@link PlainDate#DAY_OF_WEEK}
  • *
  • {@link PlainDate#DAY_OF_YEAR}
  • *
  • {@link PlainDate#WEEKDAY_IN_MONTH}
  • *
  • {@link PlainTime#COMPONENT}
  • *
  • {@link PlainTime#AM_PM_OF_DAY}
  • *
  • {@link PlainTime#CLOCK_HOUR_OF_AMPM}
  • *
  • {@link PlainTime#CLOCK_HOUR_OF_DAY}
  • *
  • {@link PlainTime#DIGITAL_HOUR_OF_AMPM}
  • *
  • {@link PlainTime#DIGITAL_HOUR_OF_DAY}
  • *
  • {@link PlainTime#ISO_HOUR}
  • *
  • {@link PlainTime#MINUTE_OF_HOUR}
  • *
  • {@link PlainTime#MINUTE_OF_DAY}
  • *
  • {@link PlainTime#SECOND_OF_MINUTE}
  • *
  • {@link PlainTime#SECOND_OF_DAY}
  • *
  • {@link PlainTime#MILLI_OF_SECOND}
  • *
  • {@link PlainTime#MICRO_OF_SECOND}
  • *
  • {@link PlainTime#NANO_OF_SECOND}
  • *
  • {@link PlainTime#MILLI_OF_DAY}
  • *
  • {@link PlainTime#MICRO_OF_DAY}
  • *
  • {@link PlainTime#NANO_OF_DAY}
  • *
  • {@link PlainTime#DECIMAL_HOUR}
  • *
  • {@link PlainTime#DECIMAL_MINUTE}
  • *
  • {@link PlainTime#DECIMAL_SECOND}
  • *
  • {@link PlainTime#PRECISION}
  • *
* *

Furthermore, all elements of class {@link Weekmodel} are supported. As * timestamp units can be used: {@link CalendarUnit} and {@link ClockUnit}.

* *

Note: The special time value 24:00 is only supported in the factory * methods which normalize the resulting timestamp to midnight of the following * day. In element access and manipulations this value is not supported.

* * @author Meno Hochschild * @doctags.concurrency {immutable} */ /*[deutsch] *

Komposition aus Datum und Uhrzeit nach dem ISO-8601-Standard.

* *

Registriert sind folgende als Konstanten deklarierte Elemente:

* *
    *
  • {@link PlainDate#COMPONENT}
  • *
  • {@link PlainDate#YEAR}
  • *
  • {@link PlainDate#YEAR_OF_WEEKDATE}
  • *
  • {@link PlainDate#QUARTER_OF_YEAR}
  • *
  • {@link PlainDate#MONTH_OF_YEAR}
  • *
  • {@link PlainDate#MONTH_AS_NUMBER}
  • *
  • {@link PlainDate#DAY_OF_MONTH}
  • *
  • {@link PlainDate#DAY_OF_QUARTER}
  • *
  • {@link PlainDate#DAY_OF_WEEK}
  • *
  • {@link PlainDate#DAY_OF_YEAR}
  • *
  • {@link PlainDate#WEEKDAY_IN_MONTH}
  • *
  • {@link PlainTime#COMPONENT}
  • *
  • {@link PlainTime#AM_PM_OF_DAY}
  • *
  • {@link PlainTime#CLOCK_HOUR_OF_AMPM}
  • *
  • {@link PlainTime#CLOCK_HOUR_OF_DAY}
  • *
  • {@link PlainTime#DIGITAL_HOUR_OF_AMPM}
  • *
  • {@link PlainTime#DIGITAL_HOUR_OF_DAY}
  • *
  • {@link PlainTime#ISO_HOUR}
  • *
  • {@link PlainTime#MINUTE_OF_HOUR}
  • *
  • {@link PlainTime#MINUTE_OF_DAY}
  • *
  • {@link PlainTime#SECOND_OF_MINUTE}
  • *
  • {@link PlainTime#SECOND_OF_DAY}
  • *
  • {@link PlainTime#MILLI_OF_SECOND}
  • *
  • {@link PlainTime#MICRO_OF_SECOND}
  • *
  • {@link PlainTime#NANO_OF_SECOND}
  • *
  • {@link PlainTime#MILLI_OF_DAY}
  • *
  • {@link PlainTime#MICRO_OF_DAY}
  • *
  • {@link PlainTime#NANO_OF_DAY}
  • *
  • {@link PlainTime#DECIMAL_HOUR}
  • *
  • {@link PlainTime#DECIMAL_MINUTE}
  • *
  • {@link PlainTime#DECIMAL_SECOND}
  • *
  • {@link PlainTime#PRECISION}
  • *
* *

Darüberhinaus sind alle Elemente der Klasse {@link Weekmodel} * nutzbar. Als Zeiteinheiten kommen vor allem {@link CalendarUnit} und * {@link ClockUnit} in Betracht.

* *

Notiz: Unterstützung für den speziellen Zeitwert T24:00 gibt es * nur in den Fabrikmethoden, die dann diesen Wert zum nächsten Tag hin * normalisieren, nicht aber in den Elementen.

* * @author Meno Hochschild * @doctags.concurrency {immutable} */ @CalendarType("iso8601") public final class PlainTimestamp extends TimePoint implements GregorianDate, WallTime, Temporal, ThreetenAdapter, Normalizer, LocalizedPatternSupport { //~ Statische Felder/Initialisierungen -------------------------------- private static final int MRD = 1000000000; private static final PlainTimestamp MIN = new PlainTimestamp(PlainDate.MIN, PlainTime.MIN); private static final PlainTimestamp MAX = new PlainTimestamp(PlainDate.MAX, WALL_TIME.getDefaultMaximum()); private static final Map> CALENDAR_UNIT_RULE_MAP; private static final Map> CLOCK_UNIT_RULE_MAP; private static final Map> CHILDREN; private static final TimeAxis ENGINE; private static final TimeMetric> STD_METRIC; static { Map> m1 = new EnumMap<>(CalendarUnit.class); Map> m2 = new EnumMap<>(ClockUnit.class); for (CalendarUnit unit : CalendarUnit.values()) { m1.put(unit, new CompositeUnitRule(unit)); } for (ClockUnit unit : ClockUnit.values()) { m2.put(unit, new CompositeUnitRule(unit)); } CALENDAR_UNIT_RULE_MAP = m1; CLOCK_UNIT_RULE_MAP = m2; Map> children = new HashMap<>(); children.put(CALENDAR_DATE, WALL_TIME); children.put(YEAR, MONTH_AS_NUMBER); children.put(YEAR_OF_WEEKDATE, Weekmodel.ISO.weekOfYear()); children.put(QUARTER_OF_YEAR, DAY_OF_QUARTER); children.put(MONTH_OF_YEAR, DAY_OF_MONTH); children.put(MONTH_AS_NUMBER, DAY_OF_MONTH); children.put(DAY_OF_MONTH, WALL_TIME); children.put(DAY_OF_WEEK, WALL_TIME); children.put(DAY_OF_YEAR, WALL_TIME); children.put(DAY_OF_QUARTER, WALL_TIME); children.put(WEEKDAY_IN_MONTH, WALL_TIME); children.put(AM_PM_OF_DAY, DIGITAL_HOUR_OF_AMPM); children.put(CLOCK_HOUR_OF_AMPM, MINUTE_OF_HOUR); children.put(CLOCK_HOUR_OF_DAY, MINUTE_OF_HOUR); children.put(DIGITAL_HOUR_OF_AMPM, MINUTE_OF_HOUR); children.put(DIGITAL_HOUR_OF_DAY, MINUTE_OF_HOUR); children.put(ISO_HOUR, MINUTE_OF_HOUR); children.put(MINUTE_OF_HOUR, SECOND_OF_MINUTE); children.put(MINUTE_OF_DAY, SECOND_OF_MINUTE); children.put(SECOND_OF_MINUTE, NANO_OF_SECOND); children.put(SECOND_OF_DAY, NANO_OF_SECOND); CHILDREN = Collections.unmodifiableMap(children); TimeAxis.Builder builder = TimeAxis.Builder .setUp( IsoUnit.class, PlainTimestamp.class, new Merger(), MIN, MAX) .appendElement( CALENDAR_DATE, FieldRule.of(CALENDAR_DATE), DAYS) .appendElement( YEAR, new IntFieldRule(YEAR), YEARS) .appendElement( YEAR_OF_WEEKDATE, new IntFieldRule(YEAR_OF_WEEKDATE), Weekcycle.YEARS) .appendElement( QUARTER_OF_YEAR, FieldRule.of(QUARTER_OF_YEAR), QUARTERS) .appendElement( MONTH_OF_YEAR, FieldRule.of(MONTH_OF_YEAR), MONTHS) .appendElement( MONTH_AS_NUMBER, new IntFieldRule(MONTH_AS_NUMBER), MONTHS) .appendElement( DAY_OF_MONTH, new IntFieldRule(DAY_OF_MONTH), DAYS) .appendElement( DAY_OF_WEEK, FieldRule.of(DAY_OF_WEEK), DAYS) .appendElement( DAY_OF_YEAR, new IntFieldRule(DAY_OF_YEAR), DAYS) .appendElement( DAY_OF_QUARTER, new IntFieldRule(DAY_OF_QUARTER), DAYS) .appendElement( WEEKDAY_IN_MONTH, new IntFieldRule(WEEKDAY_IN_MONTH), WEEKS) .appendElement( WALL_TIME, FieldRule.of(WALL_TIME)) .appendElement( AM_PM_OF_DAY, FieldRule.of(AM_PM_OF_DAY)) .appendElement( CLOCK_HOUR_OF_AMPM, new IntFieldRule(CLOCK_HOUR_OF_AMPM), HOURS) .appendElement( CLOCK_HOUR_OF_DAY, new IntFieldRule(CLOCK_HOUR_OF_DAY), HOURS) .appendElement( DIGITAL_HOUR_OF_AMPM, new IntFieldRule(DIGITAL_HOUR_OF_AMPM), HOURS) .appendElement( DIGITAL_HOUR_OF_DAY, new IntFieldRule(DIGITAL_HOUR_OF_DAY), HOURS) .appendElement( ISO_HOUR, new IntFieldRule(ISO_HOUR), HOURS) .appendElement( MINUTE_OF_HOUR, new IntFieldRule(MINUTE_OF_HOUR), MINUTES) .appendElement( MINUTE_OF_DAY, new IntFieldRule(MINUTE_OF_DAY), MINUTES) .appendElement( SECOND_OF_MINUTE, new IntFieldRule(SECOND_OF_MINUTE), SECONDS) .appendElement( SECOND_OF_DAY, new IntFieldRule(SECOND_OF_DAY), SECONDS) .appendElement( MILLI_OF_SECOND, new IntFieldRule(MILLI_OF_SECOND), MILLIS) .appendElement( MICRO_OF_SECOND, new IntFieldRule(MICRO_OF_SECOND), MICROS) .appendElement( NANO_OF_SECOND, new IntFieldRule(NANO_OF_SECOND), NANOS) .appendElement( MILLI_OF_DAY, new IntFieldRule(MILLI_OF_DAY), MILLIS) .appendElement( MICRO_OF_DAY, FieldRule.of(MICRO_OF_DAY), MICROS) .appendElement( NANO_OF_DAY, FieldRule.of(NANO_OF_DAY), NANOS) .appendElement( DECIMAL_HOUR, new DecimalRule(DECIMAL_HOUR)) .appendElement( DECIMAL_MINUTE, new DecimalRule(DECIMAL_MINUTE)) .appendElement( DECIMAL_SECOND, new DecimalRule(DECIMAL_SECOND)) .appendElement( PRECISION, FieldRule.of(PRECISION)); registerCalendarUnits(builder); registerClockUnits(builder); registerExtensions(builder); ENGINE = builder.build(); IsoUnit[] units = {YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS, NANOS}; STD_METRIC = Duration.in(units); } private static final long serialVersionUID = 7458380065762437714L; //~ Instanzvariablen -------------------------------------------------- private transient final PlainDate date; private transient final PlainTime time; //~ Konstruktoren ----------------------------------------------------- private PlainTimestamp( PlainDate date, PlainTime time ) { super(); if (time.getHour() == 24) { // T24 normalisieren this.date = date.plus(1, DAYS); this.time = PlainTime.MIN; } else if (date == null) { throw new NullPointerException("Missing date."); } else { this.date = date; this.time = time; } } //~ Methoden ---------------------------------------------------------- /** *

Creates a new local timestamp with calendar date and wall time.

* *

The special time value 24:00 will automatically normalized such * that the resulting timestamp is on starting midnight of following * day.

* * @param date calendar date component * @param time wall time component (24:00 will always be normalized) * @return timestamp as composition of date and time * @see #of(int, int, int, int, int) * @see #of(int, int, int, int, int, int) */ /*[deutsch] *

Erzeugt eine neue Instanz mit Datum und Uhrzeit.

* *

Der Spezialwert T24:00 wird automatisch so normalisiert, daß * der resultierende Zeitstempel auf Mitternacht des Folgetags zeigt.

* * @param date calendar date component * @param time wall time component (24:00 will always be normalized) * @return timestamp as composition of date and time * @see #of(int, int, int, int, int) * @see #of(int, int, int, int, int, int) */ public static PlainTimestamp of( PlainDate date, PlainTime time ) { return new PlainTimestamp(date, time); } /** *

Creates a new local timestamp in minute precision.

* *

The special time value 24:00 will automatically normalized such * that the resulting timestamp is on starting midnight of following * day.

* * @param year proleptic iso year [(-999,999,999)-999,999,999] * @param month gregorian month in range (1-12) * @param dayOfMonth day of month in range (1-31) * @param hour hour in the range {@code 0-23} or {@code 24} * if minute and second are equal to {@code 0} * @param minute minute in the range {@code 0-59} * @return timestamp as composition of date and time */ /*[deutsch] *

Erzeugt einen neuen minutengenauen Zeitstempel.

* *

Der Spezialwert T24:00 wird automatisch so normalisiert, daß * der resultierende Zeitstempel auf Mitternacht des Folgetags zeigt.

* * @param year proleptic iso year [(-999,999,999)-999,999,999] * @param month gregorian month in range (1-12) * @param dayOfMonth day of month in range (1-31) * @param hour hour in the range {@code 0-23} or {@code 24} * if minute and second are equal to {@code 0} * @param minute minute in the range {@code 0-59} * @return timestamp as composition of date and time */ public static PlainTimestamp of( int year, int month, int dayOfMonth, int hour, int minute ) { return PlainTimestamp.of(year, month, dayOfMonth, hour, minute, 0); } /** *

Creates a new local timestamp in second precision.

* *

The special time value 24:00 will automatically normalized such * that the resulting timestamp is on starting midnight of following * day.

* * @param year proleptic iso year [(-999,999,999)-999,999,999] * @param month gregorian month in range (1-12) * @param dayOfMonth day of month in range (1-31) * @param hour hour in the range {@code 0-23} or {@code 24} * if minute and second are equal to {@code 0} * @param minute minute in the range {@code 0-59} * @param second second in the range {@code 0-59} * @return timestamp as composition of date and time */ /*[deutsch] *

Erzeugt einen neuen sekundengenauen Zeitstempel.

* *

Der Spezialwert T24:00 wird automatisch so normalisiert, daß * der resultierende Zeitstempel auf Mitternacht des Folgetags zeigt.

* * @param year proleptic iso year [(-999,999,999)-999,999,999] * @param month gregorian month in range (1-12) * @param dayOfMonth day of month in range (1-31) * @param hour hour in the range {@code 0-23} or {@code 24} * if minute and second are equal to {@code 0} * @param minute minute in the range {@code 0-59} * @param second second in the range {@code 0-59} * @return timestamp as composition of date and time */ public static PlainTimestamp of( int year, int month, int dayOfMonth, int hour, int minute, int second ) { return PlainTimestamp.of( PlainDate.of(year, month, dayOfMonth), PlainTime.of(hour, minute, second) ); } /** *

Obtains the current timestamp in system time.

* *

Convenient short-cut for: {@code SystemClock.inLocalView().now()}.

* * @return current timestamp (without zone) in system time zone using the system clock * @see SystemClock#inLocalView() * @see ZonalClock#now() * @since 3.23/4.19 */ /*[deutsch] *

Ermittelt den aktuellen Zeitstempel in der Systemzeit.

* *

Bequeme Abkürzung für: {@code SystemClock.inLocalView().now()}.

* * @return current timestamp (without zone) in system time zone using the system clock * @see SystemClock#inLocalView() * @see ZonalClock#now() * @since 3.23/4.19 */ public static PlainTimestamp nowInSystemTime() { return ZonalClock.ofSystem().now(); } /** *

Short cut for {@code TemporalType.LOCAL_DATE_TIME.translate(ldt)}.

* * @param ldt Threeten-equivalent of this instance * @return PlainTimestamp * @since 4.0 * @see TemporalType#LOCAL_DATE_TIME */ /*[deutsch] *

Abkürzung für {@code TemporalType.LOCAL_DATE_TIME.translate(ldt)}.

* * @param ldt Threeten-equivalent of this instance * @return PlainTimestamp * @since 4.0 * @see TemporalType#LOCAL_DATE_TIME */ public static PlainTimestamp from(LocalDateTime ldt) { return TemporalType.LOCAL_DATE_TIME.translate(ldt); } /** *

Provides the calendar date part.

* * @return calendar date component */ /*[deutsch] *

Liefert die Datumskomponente.

* * @return calendar date component */ public PlainDate getCalendarDate() { return this.date; } /** *

Provides the wall time part.

* * @return wall time component */ /*[deutsch] *

Liefert die Uhrzeitkomponente.

* * @return wall time component */ public PlainTime getWallTime() { return this.time; } @Override public int getYear() { return this.date.getYear(); } @Override public int getMonth() { return this.date.getMonth(); } @Override public int getDayOfMonth() { return this.date.getDayOfMonth(); } @Override public int getHour() { return this.time.getHour(); } @Override public int getMinute() { return this.time.getMinute(); } @Override public int getSecond() { return this.time.getSecond(); } @Override public int getNanosecond() { return this.time.getNanosecond(); } /** *

Adjusts this timestamp by given operator.

* * @param operator element-related operator * @return changed copy of this timestamp * @see ChronoEntity#with(net.time4j.engine.ChronoOperator) */ /*[deutsch] *

Passt diesen Zeitstempel mit Hilfe des angegebenen Operators an.

* * @param operator element-related operator * @return changed copy of this timestamp * @see ChronoEntity#with(net.time4j.engine.ChronoOperator) */ public PlainTimestamp with(ElementOperator operator) { return this.with(operator.onTimestamp()); } /** *

Adjusts the calendar part of this timestamp.

* * @param date new calendar date component * @return changed copy of this timestamp * @see PlainDate#COMPONENT */ /*[deutsch] *

Passt die Datumskomponente an.

* * @param date new calendar date component * @return changed copy of this timestamp * @see PlainDate#COMPONENT */ public PlainTimestamp with(PlainDate date) { return this.with(CALENDAR_DATE, date); } /** *

Adjusts the wall time part of this timestamp.

* * @param time new wall time component * @return changed copy of this timestamp * @see PlainTime#COMPONENT */ /*[deutsch] *

Passt die Uhrzeitkomponente an.

* * @param time new wall time component * @return changed copy of this timestamp * @see PlainTime#COMPONENT */ public PlainTimestamp with(PlainTime time) { return this.with(WALL_TIME, time); } @Override public boolean isBefore(PlainTimestamp timestamp) { return (this.compareTo(timestamp) < 0); } @Override public boolean isAfter(PlainTimestamp timestamp) { return (this.compareTo(timestamp) > 0); } @Override public boolean isSimultaneous(PlainTimestamp timestamp) { return (this.compareTo(timestamp) == 0); } /** *

Defines the temporal order of date and time as natural order.

* *

The comparison is consistent with {@code equals()}.

* * @see #isBefore(PlainTimestamp) * @see #isAfter(PlainTimestamp) */ /*[deutsch] *

Definiert eine natürliche Ordnung, die auf der zeitlichen * Position basiert.

* *

Der Vergleich ist konsistent mit {@code equals()}.

* * @see #isBefore(PlainTimestamp) * @see #isAfter(PlainTimestamp) */ @Override public int compareTo(PlainTimestamp timestamp) { if (this.date.isAfter(timestamp.date)) { return 1; } else if (this.date.isBefore(timestamp.date)) { return -1; } return this.time.compareTo(timestamp.time); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } else if (obj instanceof PlainTimestamp) { PlainTimestamp that = (PlainTimestamp) obj; return (this.date.equals(that.date) && this.time.equals(that.time)); } else { return false; } } @Override public int hashCode() { return 13 * this.date.hashCode() + 37 * this.time.hashCode(); } /** *

Creates a canonical representation of the form * "yyyy-MM-dd'T'HH:mm:ss,fffffffff".

* *

Dependent on the precision (that is last non-zero part of time) * the time representation might be shorter.

* * @return canonical ISO-8601-formatted string * @see PlainTime#toString() */ /*[deutsch] *

Erzeugt eine kanonische Darstellung im Format * "yyyy-MM-dd'T'HH:mm:ss,fffffffff".

* *

Je nach Genauigkeit kann der Uhrzeitanteil auch kürzer sein.

* * @return canonical ISO-8601-formatted string * @see PlainTime#toString() */ @Override public String toString() { return this.date.toString() + this.time.toString(); } /** *

Synonym for {@code getCalendarDate()}.

* * @return calendar date component * @see #getCalendarDate() * @since 3.6/4.4 */ /*[deutsch] *

Synonym für {@code getCalendarDate()}.

* * @return calendar date component * @since 3.6/4.4 */ public PlainDate toDate() { return this.date; } /** *

Synonym for {@code getWallTime()}.

* * @return wall time component * @see #getWallTime() * @since 3.6/4.4 */ /*[deutsch] *

Synonym für {@code getWallTime()}.

* * @return wall time component * @see #getWallTime() * @since 3.6/4.4 */ public PlainTime toTime() { return this.time; } /** *

Creates a new formatter which uses the given pattern in the * default locale for formatting and parsing plain timestamps.

* * @param

generic pattern type * @param formatPattern format definition as pattern * @param patternType pattern dialect * @return format object for formatting {@code PlainTimestamp}-objects * using system locale * @throws IllegalArgumentException if resolving of pattern fails * @since 3.0 */ /*[deutsch] *

Erzeugt ein neues Format-Objekt mit Hilfe des angegebenen Musters * in der Standard-Sprach- und Ländereinstellung.

* * @param

generic pattern type * @param formatPattern format definition as pattern * @param patternType pattern dialect * @return format object for formatting {@code PlainTimestamp}-objects * using system locale * @throws IllegalArgumentException if resolving of pattern fails * @since 3.0 */ public static

> TemporalFormatter localFormatter( String formatPattern, P patternType ) { return FormatSupport.createFormatter(PlainTimestamp.class, formatPattern, patternType, Locale.getDefault()); } /** *

Creates a new formatter which uses the given pattern and locale * for formatting and parsing plain timestamps.

* * @param

generic pattern type * @param formatPattern format definition as pattern * @param patternType pattern dialect * @param locale locale setting * @return format object for formatting {@code PlainTimestamp}-objects using given locale * @throws IllegalArgumentException if resolving of pattern fails * @since 3.0 * @see #localFormatter(String,ChronoPattern) */ /*[deutsch] *

Erzeugt ein neues Format-Objekt mit Hilfe des angegebenen Musters * in der angegebenen Sprach- und Ländereinstellung.

* * @param

generic pattern type * @param formatPattern format definition as pattern * @param patternType pattern dialect * @param locale locale setting * @return format object for formatting {@code PlainTimestamp}-objects using given locale * @throws IllegalArgumentException if resolving of pattern fails * @since 3.0 * @see #localFormatter(String,ChronoPattern) */ public static

> TemporalFormatter formatter( String formatPattern, P patternType, Locale locale ) { return FormatSupport.createFormatter(PlainTimestamp.class, formatPattern, patternType, locale); } @Override public LocalDateTime toTemporalAccessor() { return TemporalType.LOCAL_DATE_TIME.from(this); } /** *

Provides a static access to the associated time axis respective * chronology which contains the chronological rules.

* * @return chronological system as time axis (never {@code null}) */ /*[deutsch] *

Liefert die zugehörige Zeitachse, die alle notwendigen * chronologischen Regeln enthält.

* * @return chronological system as time axis (never {@code null}) */ public static TimeAxis axis() { return ENGINE; } /** *

Combines this local timestamp with the timezone offset UTC+00:00 * to a global UTC-moment.

* * @return global UTC-moment based on this local timestamp interpreted * at offset UTC+00:00 * @see #at(ZonalOffset) */ /*[deutsch] *

Kombiniert diesen lokalen Zeitstempel mit UTC+00:00 zu * einem globalen UTC-Moment.

* * @return global UTC-moment based on this local timestamp interpreted * at offset UTC+00:00 * @see #at(ZonalOffset) */ public Moment atUTC() { return this.at(ZonalOffset.UTC); } /** *

Combines this local timestamp with the given timezone offset * to a global UTC-moment.

* * @param offset timezone offset * @return global UTC-moment based on this local timestamp interpreted * at given offset * @since 1.2 * @see #atUTC() * @see #in(Timezone) */ /*[deutsch] *

Kombiniert diesen lokalen Zeitstempel mit dem angegebenen * Zeitzonen-Offset zu einem globalen UTC-Moment.

* * @param offset timezone offset * @return global UTC-moment based on this local timestamp interpreted * at given offset * @since 1.2 * @see #atUTC() * @see #in(Timezone) */ public Moment at(ZonalOffset offset) { long localSeconds = MathUtils.safeMultiply( this.date.getDaysSinceUTC() + 2 * 365, 86400); localSeconds += (this.time.getHour() * 3600); localSeconds += (this.time.getMinute() * 60); localSeconds += this.time.getSecond(); int localNanos = this.time.getNanosecond(); long posixTime = localSeconds - offset.getIntegralAmount(); int posixNanos = localNanos - offset.getFractionalAmount(); if (posixNanos < 0) { posixNanos += MRD; posixTime--; } else if (posixNanos >= MRD) { posixNanos -= MRD; posixTime++; } return Moment.of(posixTime, posixNanos, TimeScale.POSIX); } /** *

Combines this local timestamp with the system timezone to a global * UTC-moment.

* * @return global UTC-moment based on this local timestamp interpreted * in system timezone * @since 1.2 * @see Timezone#ofSystem() * @see #inTimezone(TZID) */ /*[deutsch] *

Kombiniert diesen lokalen Zeitstempel mit der System-Zeitzone * zu einem UTC-Moment.

* * @return global UTC-moment based on this local timestamp interpreted * in system timezone * @since 1.2 * @see Timezone#ofSystem() * @see #inTimezone(TZID) */ public Moment inStdTimezone() { return this.in(Timezone.ofSystem()); } /** *

Combines this local timestamp with given timezone to a global * UTC-moment.

* * @param tzid timezone id * @return global UTC-moment based on this local timestamp interpreted * in given timezone * @throws IllegalArgumentException if given timezone cannot be loaded * @since 1.2 * @see Timezone#of(TZID) * @see #inStdTimezone() */ /*[deutsch] *

Kombiniert diesen lokalen Zeitstempel mit der angegebenen Zeitzone * zu einem UTC-Moment.

* * @param tzid timezone id * @return global UTC-moment based on this local timestamp interpreted * in given timezone * @throws IllegalArgumentException if given timezone cannot be loaded * @since 1.2 * @see Timezone#of(TZID) * @see #inStdTimezone() */ public Moment inTimezone(TZID tzid) { return this.in(Timezone.of(tzid)); } /** *

Combines this local timestamp with given timezone to a global * UTC-moment.

* * @param tz timezone * @return global UTC-moment based on this local timestamp interpreted * in given timezone * @since 1.2 * @see Timezone#of(String) */ /*[deutsch] *

Kombiniert diesen lokalen Zeitstempel mit der angegebenen Zeitzone * zu einem UTC-Moment.

* * @param tz timezone * @return global UTC-moment based on this local timestamp interpreted * in given timezone * @since 1.2 * @see Timezone#of(String) */ public Moment in(Timezone tz) { if (tz.isFixed()) { // optimization return this.at(tz.getOffset(this.date, this.time)); } TransitionStrategy strategy = tz.getStrategy(); long posixTime = strategy.resolve(this.date, this.time, tz); Moment moment = Moment.of(posixTime, this.time.getNanosecond(), TimeScale.POSIX); if (strategy == Timezone.STRICT_MODE) { Moment.checkNegativeLS(posixTime, this); } return moment; } /** *

Equivalent to {@link #inZonalView(Timezone) inZonalView(Timezone.ofSystem()}.

* * @return ZonalDateTime * @since 3.16/4.13 */ /*[deutsch] *

Äquivalent zu {@link #inZonalView(Timezone) inZonalView(Timezone.ofSystem()}.

* * @return ZonalDateTime * @since 3.16/4.13 */ public ZonalDateTime inLocalView() { return this.inZonalView(Timezone.ofSystem()); } /** *

Converts this instance to a combination of UTC-moment, given timezone and its zonal timestamp.

* *

Attention: Due to winter/summer-time-changes the resulting zonal timestamp * ({@link ZonalDateTime#toTimestamp()}) can deviate from this plain timestamp.

* * @param tz timezone * @return ZonalDateTime * @since 3.16/4.13 */ /*[deutsch] *

Converts this instance to a combination of UTC-moment, given timezone and its zonal timestamp.

* *

Achtung: Wegen Winter-/Sommerzeitumstellungen kann der resultierende zonale * Zeitstempel ({@link ZonalDateTime#toTimestamp()}) von diesem Zeitstempel abweichen.

* * @param tz timezone * @return ZonalDateTime * @since 3.16/4.13 */ public ZonalDateTime inZonalView(Timezone tz) { Moment m = this.in(tz); return ZonalDateTime.of(m, tz); } /** *

Does this local timestamp exist in given timezone?

* * @param tzid timezone id (optional) * @return {@code true} if this timestamp is valid in given timezone * @throws IllegalArgumentException if given timezone cannot be loaded */ /*[deutsch] *

Existiert dieser Zeitstempel in der angegebenen Zeitzone?

* * @param tzid timezone id (optional) * @return {@code true} if this timestamp is valid in given timezone * @throws IllegalArgumentException if given timezone cannot be loaded */ public boolean isValid(TZID tzid) { if (tzid == null) { return false; } return !Timezone.of(tzid).isInvalid(this.date, this.time); } /** *

Normalized given timespan using years, months, days and * all clock units.

* *

This normalizer can also convert from days to months. Example:

* *
     *  Duration<CalendarUnit> dur = Duration.of(30, CalendarUnit.DAYS);
     *  Duration<IsoUnit> result =
     *      PlainTimestamp.of(2012, 2, 28, 0, 0).normalize(dur);
     *  System.out.println(result); // output: P1M1D (leap year!)
     * 
* * @param timespan to be normalized * @return normalized duration * @since 2.0 */ /*[deutsch] *

Normalisiert die angegebene Zeitspanne, indem Jahre, Monate, Tage * und alle Uhrzeiteinheiten verwendet werden.

* *

Dieser Normalisierer kann auch von Tagen zu Monaten konvertieren. * Beispiel:

* *
     *  Duration<CalendarUnit> dur = Duration.of(30, CalendarUnit.DAYS);
     *  Duration<IsoUnit> result =
     *      PlainTimestamp.of(2012, 2, 28, 0, 0).normalize(dur);
     *  System.out.println(result); // Ausgabe: P1M1D (Schaltjahr!)
     * 
* * @param timespan to be normalized * @return normalized duration * @since 2.0 */ @Override public Duration normalize(TimeSpan timespan) { return this.until(this.plus(timespan), STD_METRIC); } /** *

Adds given amount in units to this timestamp and yields the result of addition.

* *

Covers the most important calendar units and is overloaded for performance reasons.

* * @param amount the amount of units to be added to this timestamp (maybe negative) * @param unit the unit to be used in addition * @return result of addition as changed copy while this instance remains unaffected * @throws ArithmeticException in case of numerical overflow * @see #plus(long, Object) plus(long, IsoUnit) * @since 4.19 */ /*[deutsch] *

Addiert den angegebenen Betrag der entsprechenden Zeiteinheit * zu diesem Zeitstempel und liefert das Additionsergebnis zurück.

* *

Deckt die wichtigsten kalendarischen Zeiteinheiten ab, die mit diesem Typ verwendet werden * können und ist aus Performance-Gründen überladen.

* * @param amount the amount of units to be added to this timestamp (maybe negative) * @param unit the unit to be used in addition * @return result of addition as changed copy while this instance remains unaffected * @throws ArithmeticException in case of numerical overflow * @see #plus(long, Object) plus(long, IsoUnit) * @since 4.19 */ public PlainTimestamp plus( long amount, CalendarUnit unit ) { if (unit == null) { throw new NullPointerException("Missing unit."); } else if (amount == 0) { return this; } try { return CALENDAR_UNIT_RULE_MAP.get(unit).addTo(this, amount); } catch (IllegalArgumentException iae) { ArithmeticException ex = new ArithmeticException("Result beyond boundaries of time axis."); ex.initCause(iae); throw ex; } } /** *

Adds given amount in units to this timestamp and yields the result of addition.

* *

Covers the most important clock units and is overloaded for performance reasons.

* * @param amount the amount of units to be added to this timestamp (maybe negative) * @param unit the unit to be used in addition * @return result of addition as changed copy while this instance remains unaffected * @throws ArithmeticException in case of numerical overflow * @see #plus(long, Object) plus(long, IsoUnit) * @since 4.19 */ /*[deutsch] *

Addiert den angegebenen Betrag der entsprechenden Zeiteinheit * zu diesem Zeitstempel und liefert das Additionsergebnis zurück.

* *

Deckt die wichtigsten Uhrzeiteinheiten ab, die mit diesem Typ verwendet werden * können und ist aus Performance-Gründen überladen.

* * @param amount the amount of units to be added to this timestamp (maybe negative) * @param unit the unit to be used in addition * @return result of addition as changed copy while this instance remains unaffected * @throws ArithmeticException in case of numerical overflow * @see #plus(long, Object) plus(long, IsoUnit) * @since 4.19 */ public PlainTimestamp plus( long amount, ClockUnit unit ) { if (unit == null) { throw new NullPointerException("Missing unit."); } else if (amount == 0) { return this; } try { return CLOCK_UNIT_RULE_MAP.get(unit).addTo(this, amount); } catch (IllegalArgumentException iae) { ArithmeticException ex = new ArithmeticException("Result beyond boundaries of time axis."); ex.initCause(iae); throw ex; } } /** *

Subtracts given amount in units from this timestamp and yields the result of subtraction.

* *

Covers the most important calendar units and is overloaded for performance reasons.

* * @param amount the amount of units to be subtracted from this timestamp (maybe negative) * @param unit the unit to be used in subtraction * @return result of subtraction as changed copy while this instance remains unaffected * @throws ArithmeticException in case of numerical overflow * @see #minus(long, Object) minus(long, IsoUnit) * @since 4.19 */ /*[deutsch] *

Subtrahiert den angegebenen Betrag der entsprechenden Zeiteinheit * von diesem Zeitstempel und liefert das Subtraktionsergebnis zurück.

* *

Deckt die wichtigsten kalendarischen Zeiteinheiten ab, die mit diesem Typ verwendet werden * können und ist aus Performance-Gründen überladen.

* * @param amount the amount of units to be subtracted from this timestamp (maybe negative) * @param unit the unit to be used in subtraction * @return result of subtraction as changed copy while this instance remains unaffected * @throws ArithmeticException in case of numerical overflow * @see #minus(long, Object) minus(long, IsoUnit) * @since 4.19 */ public PlainTimestamp minus( long amount, CalendarUnit unit ) { return this.plus(Math.negateExact(amount), unit); } /** *

Subtracts given amount in units from this timestamp and yields the result of subtraction.

* *

Covers the most important clock units and is overloaded for performance reasons.

* * @param amount the amount of units to be subtracted from this timestamp (maybe negative) * @param unit the unit to be used in subtraction * @return result of subtraction as changed copy while this instance remains unaffected * @throws ArithmeticException in case of numerical overflow * @see #minus(long, Object) minus(long, IsoUnit) * @since 4.19 */ /*[deutsch] *

Subtrahiert den angegebenen Betrag der entsprechenden Zeiteinheit * von diesem Zeitstempel und liefert das Subtraktionsergebnis zurück.

* *

Deckt die wichtigsten Uhrzeiteinheiten ab, die mit diesem Typ verwendet werden * können und ist aus Performance-Gründen überladen.

* * @param amount the amount of units to be subtracted from this timestamp (maybe negative) * @param unit the unit to be used in subtraction * @return result of subtraction as changed copy while this instance remains unaffected * @throws ArithmeticException in case of numerical overflow * @see #minus(long, Object) minus(long, IsoUnit) * @since 4.19 */ public PlainTimestamp minus( long amount, ClockUnit unit ) { return this.plus(Math.negateExact(amount), unit); } @Override protected TimeAxis getChronology() { return ENGINE; } @Override protected PlainTimestamp getContext() { return this; } /** *

Erzeugt eine neue Uhrzeit passend zur angegebenen absoluten Zeit.

* * @param ut unix time in seconds * @param offset shift of local timestamp relative to UTC * @return new or cached local timestamp */ static PlainTimestamp from( UnixTime ut, ZonalOffset offset ) { long localSeconds = ut.getPosixTime() + offset.getIntegralAmount(); int localNanos = ut.getNanosecond() + offset.getFractionalAmount(); if (localNanos < 0) { localNanos += MRD; localSeconds--; } else if (localNanos >= MRD) { localNanos -= MRD; localSeconds++; } PlainDate date = PlainDate.of( MathUtils.floorDivide(localSeconds, 86400), EpochDays.UNIX); int secondsOfDay = MathUtils.floorModulo(localSeconds, 86400); int second = secondsOfDay % 60; int minutesOfDay = secondsOfDay / 60; int minute = minutesOfDay % 60; int hour = minutesOfDay / 60; PlainTime time = PlainTime.of( hour, minute, second, localNanos ); return PlainTimestamp.of(date, time); } private static void registerCalendarUnits( TimeAxis.Builder builder ) { Set monthly = EnumSet.range(MILLENNIA, MONTHS); Set daily = EnumSet.range(WEEKS, DAYS); for (CalendarUnit unit : CalendarUnit.values()) { builder.appendUnit( unit, CALENDAR_UNIT_RULE_MAP.get(unit), unit.getLength(), (unit.compareTo(WEEKS) < 0) ? monthly : daily ); } } private static void registerClockUnits( TimeAxis.Builder builder ) { for (ClockUnit unit : ClockUnit.values()) { builder.appendUnit( unit, CLOCK_UNIT_RULE_MAP.get(unit), unit.getLength(), EnumSet.allOf(ClockUnit.class) ); } } private static void registerExtensions( TimeAxis.Builder builder ) { for (ChronoExtension extension : PlainDate.axis().getExtensions()) { builder.appendExtension(extension); } for (ChronoExtension extension : PlainTime.axis().getExtensions()) { builder.appendExtension(extension); } } /** * @serialData Uses * a dedicated serialization form as proxy. The layout * is bit-compressed. The first byte contains within the * four most significant bits the type id {@code 8}. Then * the data bytes for date and time component follow. * * Schematic algorithm: * *
       int range;

       if (year >= 1850 && year <= 2100) {
           range = 1;
       } else if (Math.abs(year) < 10000) {
           range = 2;
       } else {
           range = 3;
       }

       int header = 8; // type-id
       header <<= 4;
       header |= month;
       out.writeByte(header);

       int header2 = range;
       header2 <<= 5;
       header2 |= dayOfMonth;
       out.writeByte(header2);

       if (range == 1) {
           out.writeByte(year - 1850 - 128);
       } else if (range == 2) {
           out.writeShort(year);
       } else {
           out.writeInt(year);
       }

       if (time.nano == 0) {
           if (time.second == 0) {
               if (time.minute == 0) {
                   out.writeByte(~time.hour);
               } else {
                   out.writeByte(time.hour);
                   out.writeByte(~time.minute);
               }
           } else {
               out.writeByte(time.hour);
               out.writeByte(time.minute);
               out.writeByte(~time.second);
           }
       } else {
           out.writeByte(time.hour);
           out.writeByte(time.minute);
           out.writeByte(time.second);
           out.writeInt(time.nano);
       }
      
* * @return replacement object in serialization graph */ private Object writeReplace() { return new SPX(this, SPX.TIMESTAMP_TYPE); } /** * @serialData Blocks because a serialization proxy is required. * @param in object input stream * @throws InvalidObjectException (always) */ private void readObject(ObjectInputStream in) throws IOException { throw new InvalidObjectException("Serialization proxy required."); } //~ Innere Klassen ---------------------------------------------------- private static class Merger implements ChronoMerger { //~ Methoden ------------------------------------------------------ @Override public String getFormatPattern( DisplayStyle style, Locale locale ) { DisplayMode mode = DisplayMode.ofStyle(style.getStyleValue()); return CalendarText.patternForTimestamp(mode, mode, locale); } @Override public PlainTimestamp createFrom( TimeSource clock, final AttributeQuery attributes ) { Timezone zone; if (attributes.contains(Attributes.TIMEZONE_ID)) { zone = Timezone.of(attributes.get(Attributes.TIMEZONE_ID)); } else if (attributes.get(Attributes.LENIENCY, Leniency.SMART).isLax()) { zone = Timezone.ofSystem(); } else { return null; } final UnixTime ut = clock.currentTime(); return PlainTimestamp.from(ut, zone.getOffset(ut)); } @Override public PlainTimestamp createFrom( TemporalAccessor threeten, AttributeQuery attributes ) { PlainDate date = PlainDate.axis().createFrom(threeten, attributes); PlainTime time = PlainTime.axis().createFrom(threeten, attributes); if ((date != null) && (time != null)) { return PlainTimestamp.of(date, time); } return null; } @Override @Deprecated public PlainTimestamp 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 PlainTimestamp createFrom( ChronoEntity entity, AttributeQuery attributes, boolean lenient, boolean preparsing ) { if (entity instanceof UnixTime) { TZID tzid; if (attributes.contains(Attributes.TIMEZONE_ID)) { tzid = attributes.get(Attributes.TIMEZONE_ID); } else if (lenient) { tzid = ZonalOffset.UTC; } else { throw new IllegalArgumentException( "Missing timezone attribute for type conversion."); } Moment ut = Moment.from(UnixTime.class.cast(entity)); return ut.toZonalTimestamp(tzid); } boolean leapsecond = (preparsing && (entity.getInt(SECOND_OF_MINUTE) == 60)); if (leapsecond) { // temporär, wird später kompensiert entity.with(SECOND_OF_MINUTE, 59); } PlainDate date; PlainTime time; if (entity.contains(CALENDAR_DATE)) { date = entity.get(CALENDAR_DATE); } else { date = PlainDate.axis().createFrom(entity, attributes, lenient, false); } if (date == null) { return null; } else if (entity.contains(WALL_TIME)) { time = entity.get(WALL_TIME); } else { time = PlainTime.axis().createFrom(entity, attributes, lenient, false); if ((time == null) && lenient) { time = PlainTime.MIN; } } if (time == null) { return null; } else { if (entity.contains(LongElement.DAY_OVERFLOW)) { date = date.plus( entity.get(LongElement.DAY_OVERFLOW).longValue(), DAYS); } if ( leapsecond && entity.isValid(LeapsecondElement.INSTANCE, Boolean.TRUE) ) { entity.with( LeapsecondElement.INSTANCE, Boolean.TRUE); } return PlainTimestamp.of(date, time); } } } private static class FieldRule implements ElementRule { //~ Instanzvariablen ---------------------------------------------- final ChronoElement element; //~ Konstruktoren ------------------------------------------------- private FieldRule(ChronoElement element) { super(); this.element = element; } //~ Methoden ------------------------------------------------------ static FieldRule of(ChronoElement element) { return new FieldRule<>(element); } @Override public V getValue(PlainTimestamp context) { if (this.element.isDateElement()) { return context.date.get(this.element); } else if (this.element.isTimeElement()) { return context.time.get(this.element); } throw new ChronoException( "Missing rule for: " + this.element.name()); } @Override public V getMinimum(PlainTimestamp context) { if (this.element.isDateElement()) { return context.date.getMinimum(this.element); } else if (this.element.isTimeElement()) { return this.element.getDefaultMinimum(); } throw new ChronoException( "Missing rule for: " + this.element.name()); } @Override public V getMaximum(PlainTimestamp context) { if (this.element.isDateElement()) { return context.date.getMaximum(this.element); } else if (this.element.isTimeElement()) { return this.element.getDefaultMaximum(); } throw new ChronoException( "Missing rule for: " + this.element.name()); } @Override public boolean isValid( PlainTimestamp context, V value ) { if (value == null) { return false; } if (this.element.isDateElement()) { return context.date.isValid(this.element, value); } else if (this.element.isTimeElement()) { if (Number.class.isAssignableFrom(this.element.getType())) { long min = this.toNumber(this.element.getDefaultMinimum()); long max = this.toNumber(this.element.getDefaultMaximum()); long val = this.toNumber(value); return ((min <= val) && (max >= val)); } else if ( this.element.equals(WALL_TIME) && PlainTime.MAX.equals(value) ) { return false; } else { return context.time.isValid(this.element, value); } } throw new ChronoException( "Missing rule for: " + this.element.name()); } @Override public PlainTimestamp withValue( PlainTimestamp context, V value, boolean lenient ) { if (value == null) { throw new IllegalArgumentException("Missing element value."); } if (value.equals(this.getValue(context))) { return context; } else if (lenient) { // nur auf numerischen Elementen definiert IsoUnit unit = ENGINE.getBaseUnit(this.element); long oldValue = this.toNumber(this.getValue(context)); long newValue = this.toNumber(value); long amount = MathUtils.safeSubtract(newValue, oldValue); return context.plus(amount, unit); } else if (this.element.isDateElement()) { PlainDate date = context.date.with(this.element, value); return PlainTimestamp.of(date, context.time); } else if (this.element.isTimeElement()) { if (Number.class.isAssignableFrom(this.element.getType())) { long min = this.toNumber(this.element.getDefaultMinimum()); long max = this.toNumber(this.element.getDefaultMaximum()); long val = this.toNumber(value); if ((min > val) || (max < val)) { throw new IllegalArgumentException("Out of range: " + value); } } else if ( this.element.equals(WALL_TIME) && value.equals(PlainTime.MAX) ) { throw new IllegalArgumentException("Out of range: " + value); } PlainTime time = context.time.with(this.element, value); return PlainTimestamp.of(context.date, time); } throw new ChronoException( "Missing rule for: " + this.element.name()); } // optional @Override public ChronoElement getChildAtFloor(PlainTimestamp context) { return CHILDREN.get(this.element); } // optional @Override public ChronoElement getChildAtCeiling(PlainTimestamp context) { return CHILDREN.get(this.element); } private long toNumber(V value) { return Number.class.cast(value).longValue(); } } private static class IntFieldRule extends FieldRule implements IntElementRule { //~ Konstruktoren ------------------------------------------------- private IntFieldRule(ChronoElement element) { super(element); } //~ Methoden ------------------------------------------------------ @Override public int getInt(PlainTimestamp context) { if (this.element.isDateElement()) { return context.date.getInt(this.element); } else if (this.element.isTimeElement()) { return context.time.getInt(this.element); } throw new ChronoException( "Missing rule for: " + this.element.name()); } @Override public boolean isValid( PlainTimestamp context, int value ) { if (this.element.isDateElement()) { return context.date.isValid(this.element, value); } else if (this.element.isTimeElement()) { int min = this.element.getDefaultMinimum().intValue(); int max = this.element.getDefaultMaximum().intValue(); return ((min <= value) && (max >= value)); } throw new ChronoException( "Missing rule for: " + this.element.name()); } @Override public PlainTimestamp withValue( PlainTimestamp context, int value, boolean lenient ) { if (value == this.getInt(context)) { return context; } else if (lenient) { // nur auf numerischen Elementen definiert IsoUnit unit = ENGINE.getBaseUnit(this.element); long amount = MathUtils.safeSubtract((long) value, this.getInt(context)); return context.plus(amount, unit); } else if (this.element.isDateElement()) { PlainDate date = context.date.with(this.element, value); return PlainTimestamp.of(date, context.time); } else if (this.element.isTimeElement()) { int min = this.element.getDefaultMinimum().intValue(); int max = this.element.getDefaultMaximum().intValue(); if ((min > value) || (max < value)) { throw new IllegalArgumentException("Out of range: " + value); } PlainTime time = context.time.with(this.element, value); return PlainTimestamp.of(context.date, time); } throw new ChronoException( "Missing rule for: " + this.element.name()); } } private static class DecimalRule extends FieldRule { //~ Konstruktoren ------------------------------------------------- DecimalRule(ChronoElement element) { super(element); } //~ Methoden ------------------------------------------------------ @Override public boolean isValid( PlainTimestamp context, BigDecimal value ) { if (value == null) { return false; } BigDecimal min = super.element.getDefaultMinimum(); BigDecimal max = super.element.getDefaultMaximum(); return ( (min.compareTo(value) <= 0) && (value.compareTo(max) <= 0) ); } @Override public PlainTimestamp withValue( PlainTimestamp context, BigDecimal value, boolean lenient ) { if (!this.isValid(context, value)) { throw new IllegalArgumentException("Out of range: " + value); } PlainTime time = context.time.with(super.element, value); return PlainTimestamp.of(context.date, time); } } private static class CompositeUnitRule implements UnitRule { //~ Instanzvariablen ---------------------------------------------- private final CalendarUnit calendarUnit; private final ClockUnit clockUnit; //~ Konstruktoren ------------------------------------------------- CompositeUnitRule(CalendarUnit unit) { super(); this.calendarUnit = unit; this.clockUnit = null; } CompositeUnitRule(ClockUnit unit) { super(); this.calendarUnit = null; this.clockUnit = unit; } //~ Methoden ------------------------------------------------------ @Override public PlainTimestamp addTo( PlainTimestamp timepoint, long amount ) { PlainDate d; PlainTime t; if (this.calendarUnit != null) { d = timepoint.date.plus(amount, this.calendarUnit); t = timepoint.time; } else { DayCycles cycles = timepoint.time.roll(amount, this.clockUnit); d = timepoint.date.plus(cycles.getDayOverflow(), DAYS); t = cycles.getWallTime(); } return PlainTimestamp.of(d, t); } @Override public long between( PlainTimestamp start, PlainTimestamp end ) { long delta; if (this.calendarUnit != null) { delta = this.calendarUnit.between(start.date, end.date); if (delta != 0) { boolean needsTimeCorrection; if (this.calendarUnit == DAYS) { needsTimeCorrection = true; } else { PlainDate d = start.date.plus(delta, this.calendarUnit); needsTimeCorrection = (d.compareByTime(end.date) == 0); } if (needsTimeCorrection) { PlainTime t1 = start.time; PlainTime t2 = end.time; if ((delta > 0) && t1.isAfter(t2)) { delta--; } else if ((delta < 0) && t1.isBefore(t2)) { delta++; } } } } else if (start.date.isAfter(end.date)) { delta = -between(end, start); } else { long days = start.date.until(end.date, DAYS); if (days == 0) { return this.clockUnit.between(start.time, end.time); } else if (this.clockUnit.compareTo(SECONDS) <= 0) { // HOURS, MINUTES, SECONDS delta = MathUtils.safeAdd( MathUtils.safeMultiply(days, 86400), MathUtils.safeSubtract( end.time.get(SECOND_OF_DAY).longValue(), start.time.get(SECOND_OF_DAY).longValue() ) ); if (start.time.getNanosecond() > end.time.getNanosecond()) { delta--; } } else { // MILLIS, MICROS, NANOS delta = MathUtils.safeAdd( MathUtils.safeMultiply(days, 86400L * MRD), MathUtils.safeSubtract( end.time.get(NANO_OF_DAY).longValue(), start.time.get(NANO_OF_DAY).longValue() ) ); } switch (this.clockUnit) { case HOURS: delta = delta / 3600; break; case MINUTES: delta = delta / 60; break; case SECONDS: break; case MILLIS: delta = delta / 1000000; break; case MICROS: delta = delta / 1000; break; case NANOS: break; default: throw new UnsupportedOperationException(this.clockUnit.name()); } } return delta; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy