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-2015 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.ChronoDisplay;
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.Chronology;
import net.time4j.engine.ElementRule;
import net.time4j.engine.EpochDays;
import net.time4j.engine.Normalizer;
import net.time4j.engine.Temporal;
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.CalendarType;
import net.time4j.format.ChronoPattern;
import net.time4j.format.Leniency;
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.util.Collections;
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.HOURS;
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}
  • *
* *

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 */ /*[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}
  • *
* *

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 */ @CalendarType("iso8601") public final class PlainTimestamp extends TimePoint implements GregorianDate, WallTime, Temporal, Normalizer { //~ 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> CHILDREN; private static final TimeAxis ENGINE; private static final TimeMetric> STD_METRIC; static { 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, FieldRule.of(YEAR), YEARS) .appendElement( YEAR_OF_WEEKDATE, FieldRule.of(YEAR_OF_WEEKDATE), YOWElement.YOWUnit.WEEK_BASED_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, FieldRule.of(MONTH_AS_NUMBER), MONTHS) .appendElement( DAY_OF_MONTH, FieldRule.of(DAY_OF_MONTH), DAYS) .appendElement( DAY_OF_WEEK, FieldRule.of(DAY_OF_WEEK), DAYS) .appendElement( DAY_OF_YEAR, FieldRule.of(DAY_OF_YEAR), DAYS) .appendElement( DAY_OF_QUARTER, FieldRule.of(DAY_OF_QUARTER), DAYS) .appendElement( WEEKDAY_IN_MONTH, FieldRule.of(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, FieldRule.of(CLOCK_HOUR_OF_AMPM), HOURS) .appendElement( CLOCK_HOUR_OF_DAY, FieldRule.of(CLOCK_HOUR_OF_DAY), HOURS) .appendElement( DIGITAL_HOUR_OF_AMPM, FieldRule.of(DIGITAL_HOUR_OF_AMPM), HOURS) .appendElement( DIGITAL_HOUR_OF_DAY, FieldRule.of(DIGITAL_HOUR_OF_DAY), HOURS) .appendElement( ISO_HOUR, FieldRule.of(ISO_HOUR), HOURS) .appendElement( MINUTE_OF_HOUR, FieldRule.of(MINUTE_OF_HOUR), MINUTES) .appendElement( MINUTE_OF_DAY, FieldRule.of(MINUTE_OF_DAY), MINUTES) .appendElement( SECOND_OF_MINUTE, FieldRule.of(SECOND_OF_MINUTE), SECONDS) .appendElement( SECOND_OF_DAY, FieldRule.of(SECOND_OF_DAY), SECONDS) .appendElement( MILLI_OF_SECOND, FieldRule.of(MILLI_OF_SECOND), MILLIS) .appendElement( MICRO_OF_SECOND, FieldRule.of(MICRO_OF_SECOND), MICROS) .appendElement( NANO_OF_SECOND, FieldRule.of(NANO_OF_SECOND), NANOS) .appendElement( MILLI_OF_DAY, FieldRule.of(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)); 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) ); } /** *

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(); } /** *

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); } /** *

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; } /** *

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); } /** * @doctags.exclude */ @Override protected TimeAxis getChronology() { return ENGINE; } /** * @doctags.exclude */ @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, new CompositeUnitRule(unit), unit.getLength(), (unit.compareTo(WEEKS) < 0) ? monthly : daily ); } } private static void registerClockUnits( TimeAxis.Builder builder ) { for (ClockUnit unit : ClockUnit.values()) { builder.appendUnit( unit, new CompositeUnitRule(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 PlainTimestamp createFrom( TimeSource clock, final AttributeQuery attributes ) { Timezone zone; if (attributes.contains(Attributes.TIMEZONE_ID)) { zone = Timezone.of(attributes.get(Attributes.TIMEZONE_ID)); } else { zone = Timezone.ofSystem(); } final UnixTime ut = clock.currentTime(); return PlainTimestamp.from(ut, zone.getOffset(ut)); } @Override public PlainTimestamp createFrom( ChronoEntity entity, AttributeQuery attributes, boolean preparsing ) { Leniency leniency = attributes.get(Attributes.LENIENCY, Leniency.SMART); if (entity instanceof UnixTime) { TZID tzid; if (attributes.contains(Attributes.TIMEZONE_ID)) { tzid = attributes.get(Attributes.TIMEZONE_ID); } else if (leniency.isLax()) { 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.contains(SECOND_OF_MINUTE) && (entity.get(SECOND_OF_MINUTE).intValue() == 60); if (leapsecond) { // temporär, wird später kompensiert entity.with(SECOND_OF_MINUTE, Integer.valueOf(59)); } PlainDate date; PlainTime time; if (entity.contains(CALENDAR_DATE)) { date = entity.get(CALENDAR_DATE); } else { date = PlainDate.axis().createFrom(entity, attributes, false); } if (date == null) { return null; } else if (entity.contains(WALL_TIME)) { time = entity.get(WALL_TIME); } else { time = PlainTime.axis().createFrom(entity, attributes, false); if ( (time == null) && leniency.isLax() ) { 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); } } @Override public ChronoDisplay preformat( PlainTimestamp context, AttributeQuery attributes ) { return context; } @Override public Chronology preparser() { return null; } } private static class FieldRule implements ElementRule { //~ Instanzvariablen ---------------------------------------------- private 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 (this.element.isDateElement()) { return context.date.isValid(this.element, value); } else if (this.element.isTimeElement()) { if (Number.class.isAssignableFrom(this.element.getType())) { if (value == null) { return false; } 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.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 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