FieldAbsoluteDate.java

  1. /* Copyright 2002-2025 CS GROUP
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.time;

  18. import java.time.Instant;
  19. import java.util.Date;
  20. import java.util.TimeZone;

  21. import java.util.concurrent.TimeUnit;
  22. import org.hipparchus.CalculusFieldElement;
  23. import org.hipparchus.Field;
  24. import org.hipparchus.FieldElement;
  25. import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative1;
  26. import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative1Field;
  27. import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative2;
  28. import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative2Field;
  29. import org.hipparchus.util.FastMath;
  30. import org.orekit.annotation.DefaultDataContext;
  31. import org.orekit.data.DataContext;
  32. import org.orekit.utils.Constants;

  33. /** This class represents a specific instant in time.

  34.  * <p>Instances of this class are considered to be absolute in the sense
  35.  * that each one represent the occurrence of some event and can be compared
  36.  * to other instances or located in <em>any</em> {@link TimeScale time scale}. In
  37.  * other words the different locations of an event with respect to two different
  38.  * time scales (say {@link TAIScale TAI} and {@link UTCScale UTC} for example) are
  39.  * simply different perspective related to a single object. Only one
  40.  * <code>FieldAbsoluteDate&lt;T&gt;</code> instance is needed, both representations being available
  41.  * from this single instance by specifying the time scales as parameter when calling
  42.  * the ad-hoc methods.</p>
  43.  *
  44.  * <p>Since an instance is not bound to a specific time-scale, all methods related
  45.  * to the location of the date within some time scale require to provide the time
  46.  * scale as an argument. It is therefore possible to define a date in one time scale
  47.  * and to use it in another one. An example of such use is to read a date from a file
  48.  * in UTC and write it in another file in TAI. This can be done as follows:</p>
  49.  * <pre>
  50.  *   DateTimeComponents utcComponents = readNextDate();
  51.  *   FieldAbsoluteDate&lt;T&gt; date = new FieldAbsoluteDate&lt;&gt;(utcComponents, TimeScalesFactory.getUTC());
  52.  *   writeNextDate(date.getComponents(TimeScalesFactory.getTAI()));
  53.  * </pre>
  54.  *
  55.  * <p>Two complementary views are available:</p>
  56.  * <ul>
  57.  *   <li><p>location view (mainly for input/output or conversions)</p>
  58.  *   <p>locations represent the coordinate of one event with respect to a
  59.  *   {@link TimeScale time scale}. The related methods are {@link
  60.  *   #FieldAbsoluteDate(Field, DateComponents, TimeComponents, TimeScale)}, {@link
  61.  *   #FieldAbsoluteDate(Field, int, int, int, int, int, double, TimeScale)}, {@link
  62.  *   #FieldAbsoluteDate(Field, int, int, int, TimeScale)}, {@link #FieldAbsoluteDate(Field,
  63.  *   Date, TimeScale)}, {@link #createGPSDate(int, CalculusFieldElement)}, {@link
  64.  *   #parseCCSDSCalendarSegmentedTimeCode(byte, byte[])}, {@link #toDate(TimeScale)},
  65.  *   {@link #toString(TimeScale) toString(timeScale)}, {@link #toString()},
  66.  *   and {@link #timeScalesOffset}.</p>
  67.  *   </li>
  68.  *   <li><p>offset view (mainly for physical computation)</p>
  69.  *   <p>offsets represent either the flow of time between two events
  70.  *   (two instances of the class) or durations. They are counted in seconds,
  71.  *   are continuous and could be measured using only a virtually perfect stopwatch.
  72.  *   The related methods are {@link #FieldAbsoluteDate(FieldAbsoluteDate, double)},
  73.  *   {@link #parseCCSDSUnsegmentedTimeCode(Field, byte, byte, byte[], FieldAbsoluteDate)},
  74.  *   {@link #parseCCSDSDaySegmentedTimeCode(Field, byte, byte[], DateComponents)},
  75.  *   {@link #durationFrom(FieldAbsoluteDate)}, {@link #compareTo(FieldAbsoluteDate)}, {@link #equals(Object)}
  76.  *   and {@link #hashCode()}.</p>
  77.  *   </li>
  78.  * </ul>
  79.  * <p>
  80.  * A few reference epochs which are commonly used in space systems have been defined. These
  81.  * epochs can be used as the basis for offset computation. The supported epochs are:
  82.  * {@link #getJulianEpoch(Field)}, {@link #getModifiedJulianEpoch(Field)}, {@link #getFiftiesEpoch(Field)},
  83.  * {@link #getCCSDSEpoch(Field)}, {@link #getGalileoEpoch(Field)}, {@link #getGPSEpoch(Field)},
  84.  * {@link #getJ2000Epoch(Field)}, {@link #getJavaEpoch(Field)}. There are also two factory methods
  85.  * {@link #createJulianEpoch(CalculusFieldElement)} and {@link #createBesselianEpoch(CalculusFieldElement)}
  86.  * that can be used to compute other reference epochs like J1900.0 or B1950.0.
  87.  * In addition to these reference epochs, two other constants are defined for convenience:
  88.  * {@link #getPastInfinity(Field)} and {@link #getFutureInfinity(Field)}, which can be used either
  89.  * as dummy dates when a date is not yet initialized, or for initialization of loops searching for
  90.  * a min or max date.
  91.  * </p>
  92.  * <p>
  93.  * Instances of the <code>FieldAbsoluteDate&lt;T&gt;</code> class are guaranteed to be immutable.
  94.  * </p>
  95.  * @author Luc Maisonobe
  96.  * @see TimeScale
  97.  * @see TimeStamped
  98.  * @see ChronologicalComparator
  99.  * @param <T> type of the field elements
  100.  */
  101. public class FieldAbsoluteDate<T extends CalculusFieldElement<T>>
  102.         implements FieldTimeStamped<T>, FieldTimeShiftable<FieldAbsoluteDate<T>, T>, Comparable<FieldAbsoluteDate<T>> {

  103.     /** Underlying regular date.
  104.      * @since 13.0
  105.      */
  106.     private final AbsoluteDate date;

  107.     /** Field-specific offset ({@link CalculusFieldElement#getReal() is always 0)}.
  108.      * @since 13.0
  109.      */
  110.     private final T fieldOffset;

  111.     /** Build an instance from an AbsoluteDate.
  112.      * @param field used by default
  113.      * @param date AbsoluteDate to instantiate as a FieldAbsoluteDate
  114.      */
  115.     public FieldAbsoluteDate(final Field<T> field, final AbsoluteDate date) {
  116.         this.date = date;
  117.         this.fieldOffset = field.getZero();
  118.     }

  119.     /** Create an instance with a default value ({@link #getJ2000Epoch(Field)}).
  120.      *
  121.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  122.      *
  123.      * @param field field used by default
  124.      * @see #FieldAbsoluteDate(Field, AbsoluteDate)
  125.      */
  126.     @DefaultDataContext
  127.     public FieldAbsoluteDate(final Field<T> field) {
  128.         this.date        = AbsoluteDate.J2000_EPOCH;
  129.         this.fieldOffset = field.getZero();
  130.     }

  131.     /** Build an instance from an elapsed duration since another instant.
  132.      * <p>It is important to note that the elapsed duration is <em>not</em>
  133.      * the difference between two readings on a time scale. As an example,
  134.      * the duration between the two instants leading to the readings
  135.      * 2005-12-31T23:59:59 and 2006-01-01T00:00:00 in the {@link UTCScale UTC}
  136.      * time scale is <em>not</em> 1 second, but a stop watch would have measured
  137.      * an elapsed duration of 2 seconds between these two instances because a leap
  138.      * second was introduced at the end of 2005 in this time scale.</p>
  139.      * <p>This constructor is the reverse of the {@link #durationFrom(FieldAbsoluteDate)}
  140.      * method.</p>
  141.      * @param since start instant of the measured duration
  142.      * @param elapsedDuration physically elapsed duration from the <code>since</code>
  143.      * instant, as measured in a regular time scale
  144.      * @see #durationFrom(FieldAbsoluteDate)
  145.      */
  146.     public FieldAbsoluteDate(final FieldAbsoluteDate<T> since, final T elapsedDuration) {
  147.         this.date        = since.date.shiftedBy(elapsedDuration.getReal());
  148.         this.fieldOffset = since.fieldOffset.add(elapsedDuration.getAddendum());
  149.     }

  150.     /** Build an instance from a location (parsed from a string) in a {@link TimeScale time scale}.
  151.      * <p>
  152.      * The supported formats for location are mainly the ones defined in ISO-8601 standard,
  153.      * the exact subset is explained in {@link DateTimeComponents#parseDateTime(String)},
  154.      * {@link DateComponents#parseDate(String)} and {@link TimeComponents#parseTime(String)}.
  155.      * </p>
  156.      * <p>
  157.      * As CCSDS ASCII calendar segmented time code is a trimmed down version of ISO-8601,
  158.      * it is also supported by this constructor.
  159.      * </p>
  160.      * @param field field utilized by default
  161.      * @param location location in the time scale, must be in a supported format
  162.      * @param timeScale time scale
  163.      * @exception IllegalArgumentException if location string is not in a supported format
  164.      */
  165.     public FieldAbsoluteDate(final Field<T> field, final String location, final TimeScale timeScale) {
  166.         this(field, DateTimeComponents.parseDateTime(location), timeScale);
  167.     }

  168.     /** Build an instance from a location in a {@link TimeScale time scale}.
  169.      * @param field field utilized by default
  170.      * @param location location in the time scale
  171.      * @param timeScale time scale
  172.      */
  173.     public FieldAbsoluteDate(final Field<T> field, final DateTimeComponents location, final TimeScale timeScale) {
  174.         this(field, location.getDate(), location.getTime(), timeScale);
  175.     }

  176.     /** Build an instance from a location in a {@link TimeScale time scale}.
  177.      * @param field field utilized by default
  178.      * @param date date location in the time scale
  179.      * @param time time location in the time scale
  180.      * @param timeScale time scale
  181.      */
  182.     public FieldAbsoluteDate(final Field<T> field, final DateComponents date, final TimeComponents time,
  183.                              final TimeScale timeScale) {
  184.         this.date        = new AbsoluteDate(date, time, timeScale);
  185.         this.fieldOffset = field.getZero();
  186.     }

  187.     /** Build an instance from a location in a {@link TimeScale time scale}.
  188.      * @param field field utilized by default
  189.      * @param year year number (may be 0 or negative for BC years)
  190.      * @param month month number from 1 to 12
  191.      * @param day day number from 1 to 31
  192.      * @param hour hour number from 0 to 23
  193.      * @param minute minute number from 0 to 59
  194.      * @param second second number from 0.0 to 60.0 (excluded)
  195.      * @param timeScale time scale
  196.      * @exception IllegalArgumentException if inconsistent arguments
  197.      * are given (parameters out of range)
  198.      */
  199.     public FieldAbsoluteDate(final Field<T> field, final int year, final int month, final int day,
  200.                              final int hour, final int minute, final double second,
  201.                              final TimeScale timeScale) throws IllegalArgumentException {
  202.         this(field, year, month, day, hour, minute, new TimeOffset(second), timeScale);
  203.     }

  204.     /** Build an instance from a location in a {@link TimeScale time scale}.
  205.      * @param field field utilized by default
  206.      * @param year year number (may be 0 or negative for BC years)
  207.      * @param month month number from 1 to 12
  208.      * @param day day number from 1 to 31
  209.      * @param hour hour number from 0 to 23
  210.      * @param minute minute number from 0 to 59
  211.      * @param second second number from 0.0 to 60.0 (excluded)
  212.      * @param timeScale time scale
  213.      * @exception IllegalArgumentException if inconsistent arguments
  214.      * are given (parameters out of range)
  215.      * @since 13.0
  216.      */
  217.     public FieldAbsoluteDate(final Field<T> field, final int year, final int month, final int day,
  218.                              final int hour, final int minute, final TimeOffset second,
  219.                              final TimeScale timeScale) throws IllegalArgumentException {
  220.         this(field, new DateComponents(year, month, day), new TimeComponents(hour, minute, second), timeScale);
  221.     }

  222.     /** Build an instance from a location in a {@link TimeScale time scale}.
  223.      * @param field field utilized by default
  224.      * @param year year number (may be 0 or negative for BC years)
  225.      * @param month month enumerate
  226.      * @param day day number from 1 to 31
  227.      * @param hour hour number from 0 to 23
  228.      * @param minute minute number from 0 to 59
  229.      * @param second second number from 0.0 to 60.0 (excluded)
  230.      * @param timeScale time scale
  231.      * @exception IllegalArgumentException if inconsistent arguments
  232.      * are given (parameters out of range)
  233.      */
  234.     public FieldAbsoluteDate(final Field<T> field, final int year, final Month month, final int day,
  235.                              final int hour, final int minute, final double second,
  236.                              final TimeScale timeScale) throws IllegalArgumentException {
  237.         this(field, year, month, day, hour, minute, new TimeOffset(second), timeScale);
  238.     }

  239.     /** Build an instance from a location in a {@link TimeScale time scale}.
  240.      * @param field field utilized by default
  241.      * @param year year number (may be 0 or negative for BC years)
  242.      * @param month month enumerate
  243.      * @param day day number from 1 to 31
  244.      * @param hour hour number from 0 to 23
  245.      * @param minute minute number from 0 to 59
  246.      * @param second second number from 0.0 to 60.0 (excluded)
  247.      * @param timeScale time scale
  248.      * @exception IllegalArgumentException if inconsistent arguments
  249.      * are given (parameters out of range)
  250.      * @since 13.0
  251.      */
  252.     public FieldAbsoluteDate(final Field<T> field, final int year, final Month month, final int day,
  253.                              final int hour, final int minute, final TimeOffset second,
  254.                              final TimeScale timeScale) throws IllegalArgumentException {
  255.         this(field, new DateComponents(year, month, day), new TimeComponents(hour, minute, second), timeScale);
  256.     }

  257.     /** Build an instance from a location in a {@link TimeScale time scale}.
  258.      * <p>The hour is set to 00:00:00.000.</p>
  259.      * @param field field utilized by default
  260.      * @param date date location in the time scale
  261.      * @param timeScale time scale
  262.      * @exception IllegalArgumentException if inconsistent arguments
  263.      * are given (parameters out of range)
  264.      */
  265.     public FieldAbsoluteDate(final Field<T> field, final DateComponents date, final TimeScale timeScale)
  266.                     throws IllegalArgumentException {
  267.         this(field, date, TimeComponents.H00, timeScale);
  268.     }

  269.     /** Build an instance from a location in a {@link TimeScale time scale}.
  270.      * <p>The hour is set to 00:00:00.000.</p>
  271.      * @param field field utilized by default
  272.      * @param year year number (may be 0 or negative for BC years)
  273.      * @param month month number from 1 to 12
  274.      * @param day day number from 1 to 31
  275.      * @param timeScale time scale
  276.      * @exception IllegalArgumentException if inconsistent arguments
  277.      * are given (parameters out of range)
  278.      */
  279.     public FieldAbsoluteDate(final Field<T> field, final int year, final int month, final int day,
  280.                              final TimeScale timeScale) throws IllegalArgumentException {
  281.         this(field, new DateComponents(year, month, day), TimeComponents.H00, timeScale);
  282.     }

  283.     /** Build an instance from a location in a {@link TimeScale time scale}.
  284.      * <p>The hour is set to 00:00:00.000.</p>
  285.      * @param field field utilized by default
  286.      * @param year year number (may be 0 or negative for BC years)
  287.      * @param month month enumerate
  288.      * @param day day number from 1 to 31
  289.      * @param timeScale time scale
  290.      * @exception IllegalArgumentException if inconsistent arguments
  291.      * are given (parameters out of range)
  292.      */
  293.     public FieldAbsoluteDate(final Field<T> field, final int year, final Month month, final int day,
  294.                              final TimeScale timeScale) throws IllegalArgumentException {
  295.         this(field, new DateComponents(year, month, day), TimeComponents.H00, timeScale);
  296.     }

  297.     /** Build an instance from a location in a {@link TimeScale time scale}.
  298.      * @param field field utilized as default
  299.      * @param location location in the time scale
  300.      * @param timeScale time scale
  301.      */
  302.     public FieldAbsoluteDate(final Field<T> field, final Date location, final TimeScale timeScale) {
  303.         this(field,
  304.              new DateComponents(DateComponents.JAVA_EPOCH, (int) (location.getTime() / 86400000L)),
  305.              new TimeComponents(new TimeOffset(location.getTime() % 86400000L, TimeOffset.MILLISECOND)),
  306.              timeScale);
  307.     }

  308.     /** Build an instance from an {@link Instant instant} in a {@link TimeScale time scale}.
  309.      * @param field field utilized as default
  310.      * @param instant instant in the time scale
  311.      * @param timeScale time scale
  312.      * @since 12.0
  313.      */
  314.     public FieldAbsoluteDate(final Field<T> field, final Instant instant, final TimeScale timeScale) {
  315.         this(field,
  316.              new DateComponents(DateComponents.JAVA_EPOCH, (int) (instant.getEpochSecond() / 86400L)),
  317.              new TimeComponents(new TimeOffset(instant.getEpochSecond() % 86400L, TimeOffset.SECOND,
  318.                                                instant.getNano(), TimeOffset.NANOSECOND)),
  319.              timeScale);
  320.     }

  321.     /** Build an instance from an {@link Instant instant} in utc time scale.
  322.      * @param field field utilized as default
  323.      * @param instant instant in the utc timescale
  324.      * @since 12.1
  325.      */
  326.     @DefaultDataContext
  327.     public FieldAbsoluteDate(final Field<T> field, final Instant instant) {
  328.         this(field, instant, TimeScalesFactory.getUTC());
  329.     }

  330.     /** Build an instance from an {@link Instant instant} in the {@link UTCScale time scale}.
  331.      * @param field field utilized as default
  332.      * @param instant instant in the time scale
  333.      * @param utcScale utc time scale
  334.      * @since 12.1
  335.      */
  336.     public FieldAbsoluteDate(final Field<T> field, final Instant instant, final UTCScale utcScale) {
  337.         this(field,
  338.              new DateComponents(DateComponents.JAVA_EPOCH, (int) (instant.getEpochSecond() / 86400L)),
  339.              new TimeComponents(new TimeOffset(instant.getEpochSecond() % 86400L, TimeOffset.SECOND,
  340.                                                instant.getNano(), TimeOffset.NANOSECOND)),
  341.             utcScale);
  342.     }

  343.     /** Build an instance from an elapsed duration since another instant.
  344.      * <p>It is important to note that the elapsed duration is <em>not</em>
  345.      * the difference between two readings on a time scale.
  346.      * @param since start instant of the measured duration
  347.      * @param elapsedDuration physically elapsed duration from the <code>since</code>
  348.      * instant, as measured in a regular time scale
  349.      */
  350.     public FieldAbsoluteDate(final FieldAbsoluteDate<T> since, final double elapsedDuration) {
  351.         this(since, new TimeOffset(elapsedDuration));
  352.     }

  353.     /** Build an instance from an elapsed duration since another instant.
  354.      * <p>It is important to note that the elapsed duration is <em>not</em>
  355.      * the difference between two readings on a time scale.
  356.      * @param since start instant of the measured duration
  357.      * @param elapsedDuration physically elapsed duration from the <code>since</code>
  358.      * instant, as measured in a regular time scale
  359.      * @since 13.0
  360.      */
  361.     public FieldAbsoluteDate(final FieldAbsoluteDate<T> since, final TimeOffset elapsedDuration) {
  362.         this.date        = since.date.shiftedBy(elapsedDuration);
  363.         this.fieldOffset = since.fieldOffset;
  364.     }

  365.     /** Build an instance from an elapsed duration since another instant.
  366.      * <p>It is important to note that the elapsed duration is <em>not</em>
  367.      * the difference between two readings on a time scale.
  368.      * @param since start instant of the measured duration
  369.      * @param elapsedDuration physically elapsed duration from the <code>since</code>
  370.      * instant, as measured in a regular time scale
  371.      * @param timeUnit {@link TimeUnit} of the elapsed duration
  372.      * @since 12.1
  373.      */
  374.     public FieldAbsoluteDate(final FieldAbsoluteDate<T> since, final long elapsedDuration, final TimeUnit timeUnit) {
  375.         this.date        = since.date.shiftedBy(elapsedDuration, timeUnit);
  376.         this.fieldOffset = since.fieldOffset;
  377.     }


  378.     /** Build an instance from an elapsed duration since another instant.
  379.      * <p>It is important to note that the elapsed duration is <em>not</em>
  380.      * the difference between two readings on a time scale.
  381.      * @param since start instant of the measured duration
  382.      * @param elapsedDuration physically elapsed duration from the <code>since</code>
  383.      * instant, as measured in a regular time scale
  384.      */
  385.     public FieldAbsoluteDate(final AbsoluteDate since, final T elapsedDuration) {
  386.         this.date        = since.shiftedBy(elapsedDuration.getReal());
  387.         this.fieldOffset = elapsedDuration.getAddendum();
  388.     }

  389.     /** Build an instance from an elapsed duration since another instant.
  390.      * <p>It is important to note that the elapsed duration is <em>not</em>
  391.      * the difference between two readings on a time scale.
  392.      * @param since start instant of the measured duration
  393.      * @param elapsedDuration physically elapsed duration from the <code>since</code>
  394.      * instant, as measured in a regular time scale
  395.      * @param timeUnit {@link TimeUnit} of the elapsed duration
  396.      * @param field field utilized by default
  397.      * @since 12.1
  398.      */
  399.     public FieldAbsoluteDate(final AbsoluteDate since, final long elapsedDuration, final TimeUnit timeUnit, final Field<T> field) {
  400.         this.date        = since.shiftedBy(elapsedDuration, timeUnit);
  401.         this.fieldOffset = field.getZero();
  402.     }

  403.     /** Build an instance from an apparent clock offset with respect to another
  404.      * instant <em>in the perspective of a specific {@link TimeScale time scale}</em>.
  405.      * <p>It is important to note that the apparent clock offset <em>is</em> the
  406.      * difference between two readings on a time scale and <em>not</em> an elapsed
  407.      * duration. As an example, the apparent clock offset between the two instants
  408.      * leading to the readings 2005-12-31T23:59:59 and 2006-01-01T00:00:00 in the
  409.      * {@link UTCScale UTC} time scale is 1 second, but the elapsed duration is 2
  410.      * seconds because a leap second has been introduced at the end of 2005 in this
  411.      * time scale.</p>
  412.      * <p>This constructor is the reverse of the {@link #offsetFrom(FieldAbsoluteDate,
  413.      * TimeScale)} method.</p>
  414.      * @param reference reference instant
  415.      * @param apparentOffset apparent clock offset from the reference instant
  416.      * (difference between two readings in the specified time scale)
  417.      * @param timeScale time scale with respect to which the offset is defined
  418.      * @see #offsetFrom(FieldAbsoluteDate, TimeScale)
  419.      */
  420.     public FieldAbsoluteDate(final FieldAbsoluteDate<T> reference, final double apparentOffset, final TimeScale timeScale) {
  421.         this(reference.fieldOffset.getField(),
  422.              new DateTimeComponents(reference.getComponents(timeScale), apparentOffset),
  423.              timeScale);
  424.     }

  425.     /** Creates Field date with offset as univariate derivative of first order, with a unit linear coefficient in time.
  426.      * @return univariate derivative 1 date
  427.      * @since 13.1
  428.      */
  429.     public FieldAbsoluteDate<FieldUnivariateDerivative1<T>> toFUD1Field() {
  430.         final FieldUnivariateDerivative1Field<T> fud1Field = FieldUnivariateDerivative1Field.getUnivariateDerivative1Field(fieldOffset.getField());
  431.         final FieldUnivariateDerivative1<T> fud1Shift = new FieldUnivariateDerivative1<>(fieldOffset,
  432.                 fieldOffset.getField().getOne());
  433.         return new FieldAbsoluteDate<>(fud1Field, date).shiftedBy(fud1Shift);
  434.     }

  435.     /** Creates Field date with offset as univariate derivative of second order, with a unit linear coefficient in time.
  436.      * @return univariate derivative 2 date
  437.      * @since 12.2
  438.      */
  439.     public FieldAbsoluteDate<FieldUnivariateDerivative2<T>> toFUD2Field() {
  440.         final FieldUnivariateDerivative2Field<T> fud2Field = FieldUnivariateDerivative2Field.getUnivariateDerivative2Field(fieldOffset.getField());
  441.         final FieldUnivariateDerivative2<T> fud2Shift = new FieldUnivariateDerivative2<>(fieldOffset,
  442.                                                                                          fieldOffset.getField().getOne(),
  443.                                                                                          fieldOffset.getField().getZero());
  444.         return new FieldAbsoluteDate<>(fud2Field, date).shiftedBy(fud2Shift);
  445.     }

  446.     /** Build an instance from a CCSDS Unsegmented Time Code (CUC).
  447.      * <p>
  448.      * CCSDS Unsegmented Time Code is defined in the blue book:
  449.      * CCSDS Time Code Format (CCSDS 301.0-B-4) published in November 2010
  450.      * </p>
  451.      * <p>
  452.      * If the date to be parsed is formatted using version 3 of the standard
  453.      * (CCSDS 301.0-B-3 published in 2002) or if the extension of the preamble
  454.      * field introduced in version 4 of the standard is not used, then the
  455.      * {@code preambleField2} parameter can be set to 0.
  456.      * </p>
  457.      *
  458.      * <p>This method uses the {@link DataContext#getDefault() default data context} if
  459.      * the CCSDS epoch is used.
  460.      *
  461.      * @param field field for the components
  462.      * @param preambleField1 first byte of the field specifying the format, often
  463.      * not transmitted in data interfaces, as it is constant for a given data interface
  464.      * @param preambleField2 second byte of the field specifying the format
  465.      * (added in revision 4 of the CCSDS standard in 2010), often not transmitted in data
  466.      * interfaces, as it is constant for a given data interface (value ignored if presence
  467.      * not signaled in {@code preambleField1})
  468.      * @param timeField byte array containing the time code
  469.      * @param agencyDefinedEpoch reference epoch, ignored if the preamble field
  470.      * specifies the {@link #getCCSDSEpoch(Field) CCSDS reference epoch} is used (and hence
  471.      * may be null in this case)
  472.      * @return an instance corresponding to the specified date
  473.      * @param <T> the type of the field elements
  474.      * @see #parseCCSDSUnsegmentedTimeCode(byte, byte, byte[], FieldAbsoluteDate,
  475.      * FieldAbsoluteDate)
  476.      */
  477.     @DefaultDataContext
  478.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> parseCCSDSUnsegmentedTimeCode(final Field<T> field,
  479.                                                                                                          final byte preambleField1,
  480.                                                                                                          final byte preambleField2,
  481.                                                                                                          final byte[] timeField,
  482.                                                                                                          final FieldAbsoluteDate<T> agencyDefinedEpoch) {
  483.         return parseCCSDSUnsegmentedTimeCode(preambleField1, preambleField2,
  484.                                              timeField, agencyDefinedEpoch,
  485.                                              new FieldAbsoluteDate<>(field,
  486.                                                                      DataContext.getDefault().getTimeScales().getCcsdsEpoch()));
  487.     }

  488.     /**
  489.      * Build an instance from a CCSDS Unsegmented Time Code (CUC).
  490.      * <p>
  491.      * CCSDS Unsegmented Time Code is defined in the blue book: CCSDS Time Code Format
  492.      * (CCSDS 301.0-B-4) published in November 2010
  493.      * </p>
  494.      * <p>
  495.      * If the date to be parsed is formatted using version 3 of the standard (CCSDS
  496.      * 301.0-B-3 published in 2002) or if the extension of the preamble field introduced
  497.      * in version 4 of the standard is not used, then the {@code preambleField2} parameter
  498.      * can be set to 0.
  499.      * </p>
  500.      *
  501.      * @param <T>                the type of the field elements
  502.      * @param preambleField1     first byte of the field specifying the format, often not
  503.      *                           transmitted in data interfaces, as it is constant for a
  504.      *                           given data interface
  505.      * @param preambleField2     second byte of the field specifying the format (added in
  506.      *                           revision 4 of the CCSDS standard in 2010), often not
  507.      *                           transmitted in data interfaces, as it is constant for a
  508.      *                           given data interface (value ignored if presence not
  509.      *                           signaled in {@code preambleField1})
  510.      * @param timeField          byte array containing the time code
  511.      * @param agencyDefinedEpoch reference epoch, ignored if the preamble field specifies
  512.      *                           the {@link DateComponents#CCSDS_EPOCH CCSDS reference epoch} is used
  513.      *                           (and hence may be null in this case, but then {@code ccsdsEpoch} must be non-null)
  514.      * @param ccsdsEpoch         reference epoch, ignored if the preamble field specifies
  515.      *                           the agency epoch is used (and hence may be null in this case,
  516.      *                           but then {@code agencyDefinedEpoch} must be non-null).
  517.      * @return an instance corresponding to the specified date
  518.      * @since 10.1
  519.      */
  520.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> parseCCSDSUnsegmentedTimeCode(final byte preambleField1,
  521.                                                                                                          final byte preambleField2,
  522.                                                                                                          final byte[] timeField,
  523.                                                                                                          final FieldAbsoluteDate<T> agencyDefinedEpoch,
  524.                                                                                                          final FieldAbsoluteDate<T> ccsdsEpoch) {
  525.         final CcsdsUnsegmentedTimeCode<FieldAbsoluteDate<T>> timeCode =
  526.             new CcsdsUnsegmentedTimeCode<>(preambleField1, preambleField2, timeField, agencyDefinedEpoch, ccsdsEpoch);
  527.         return timeCode.getEpoch().shiftedBy(timeCode.getTime());
  528.     }

  529.     /** Build an instance from a CCSDS Day Segmented Time Code (CDS).
  530.      * <p>
  531.      * CCSDS Day Segmented Time Code is defined in the blue book:
  532.      * CCSDS Time Code Format (CCSDS 301.0-B-4) published in November 2010
  533.      * </p>
  534.      *
  535.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  536.      *
  537.      * @param field field for the components
  538.      * @param preambleField field specifying the format, often not transmitted in
  539.      * data interfaces, as it is constant for a given data interface
  540.      * @param timeField byte array containing the time code
  541.      * @param agencyDefinedEpoch reference epoch, ignored if the preamble field
  542.      * specifies the {@link #getCCSDSEpoch(Field) CCSDS reference epoch} is used (and hence
  543.      * may be null in this case)
  544.      * @return an instance corresponding to the specified date
  545.      * @param <T> the type of the field elements
  546.      * @see #parseCCSDSDaySegmentedTimeCode(Field, byte, byte[], DateComponents,
  547.      * TimeScale)
  548.      */
  549.     @DefaultDataContext
  550.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> parseCCSDSDaySegmentedTimeCode(final Field<T> field,
  551.                                                                                                           final byte preambleField, final byte[] timeField,
  552.                                                                                                           final DateComponents agencyDefinedEpoch) {
  553.         return parseCCSDSDaySegmentedTimeCode(field, preambleField, timeField,
  554.                                               agencyDefinedEpoch, DataContext.getDefault().getTimeScales().getUTC());
  555.     }

  556.     /**
  557.      * Build an instance from a CCSDS Day Segmented Time Code (CDS).
  558.      * <p>
  559.      * CCSDS Day Segmented Time Code is defined in the blue book: CCSDS Time Code Format
  560.      * (CCSDS 301.0-B-4) published in November 2010
  561.      * </p>
  562.      *
  563.      * @param <T>                the type of the field elements
  564.      * @param field              field for the components
  565.      * @param preambleField      field specifying the format, often not transmitted in
  566.      *                           data interfaces, as it is constant for a given data
  567.      *                           interface
  568.      * @param timeField          byte array containing the time code
  569.      * @param agencyDefinedEpoch reference epoch, ignored if the preamble field specifies
  570.      *                           the {@link #getCCSDSEpoch(Field) CCSDS reference epoch}
  571.      *                           is used (and hence may be null in this case)
  572.      * @param utc                time scale used to compute date and time components.
  573.      * @return an instance corresponding to the specified date
  574.      * @since 10.1
  575.      */
  576.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> parseCCSDSDaySegmentedTimeCode(final Field<T> field,
  577.                                                                                                           final byte preambleField,
  578.                                                                                                           final byte[] timeField,
  579.                                                                                                           final DateComponents agencyDefinedEpoch,
  580.                                                                                                           final TimeScale utc) {
  581.         final CcsdsSegmentedTimeCode timeCode = new CcsdsSegmentedTimeCode(preambleField, timeField, agencyDefinedEpoch);
  582.         return new FieldAbsoluteDate<>(field, timeCode.getDate(), timeCode.getTime(), utc);
  583.     }

  584.     /** Build an instance from a CCSDS Calendar Segmented Time Code (CCS).
  585.      * <p>
  586.      * CCSDS Calendar Segmented Time Code is defined in the blue book:
  587.      * CCSDS Time Code Format (CCSDS 301.0-B-4) published in November 2010
  588.      * </p>
  589.      *
  590.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  591.      *
  592.      * @param preambleField field specifying the format, often not transmitted in
  593.      * data interfaces, as it is constant for a given data interface
  594.      * @param timeField byte array containing the time code
  595.      * @return an instance corresponding to the specified date
  596.      * @see #parseCCSDSCalendarSegmentedTimeCode(byte, byte[], TimeScale)
  597.      */
  598.     @DefaultDataContext
  599.     public FieldAbsoluteDate<T> parseCCSDSCalendarSegmentedTimeCode(final byte preambleField, final byte[] timeField) {
  600.         return parseCCSDSCalendarSegmentedTimeCode(preambleField, timeField,
  601.                                                    DataContext.getDefault().getTimeScales().getUTC());
  602.     }

  603.     /**
  604.      * Build an instance from a CCSDS Calendar Segmented Time Code (CCS).
  605.      * <p>
  606.      * CCSDS Calendar Segmented Time Code is defined in the blue book: CCSDS Time Code
  607.      * Format (CCSDS 301.0-B-4) published in November 2010
  608.      * </p>
  609.      *
  610.      * @param preambleField field specifying the format, often not transmitted in data
  611.      *                      interfaces, as it is constant for a given data interface
  612.      * @param timeField     byte array containing the time code
  613.      * @param utc           time scale used to compute date and time components.
  614.      * @return an instance corresponding to the specified date
  615.      * @since 10.1
  616.      */
  617.     public FieldAbsoluteDate<T> parseCCSDSCalendarSegmentedTimeCode(final byte preambleField,
  618.                                                                     final byte[] timeField,
  619.                                                                     final TimeScale utc) {
  620.         final CcsdsSegmentedTimeCode timeCode = new CcsdsSegmentedTimeCode(preambleField, timeField);
  621.         return new FieldAbsoluteDate<>(fieldOffset.getField(), timeCode.getDate(), timeCode.getTime(), utc);
  622.     }

  623.     /** Build an instance corresponding to a Julian Day date.
  624.      * @param jd Julian day
  625.      * @param secondsSinceNoon seconds in the Julian day
  626.      * (BEWARE, Julian days start at noon, so 0.0 is noon)
  627.      * @param timeScale time scale in which the seconds in day are defined
  628.      * @return a new instant
  629.      * @param <T> the type of the field elements
  630.      */
  631.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createJDDate(final int jd, final T secondsSinceNoon,
  632.                                                                                         final TimeScale timeScale) {
  633.         return new FieldAbsoluteDate<>(secondsSinceNoon.getField(), new DateComponents(DateComponents.JULIAN_EPOCH, jd),
  634.                         TimeComponents.H12, timeScale).shiftedBy(secondsSinceNoon);
  635.     }

  636.     /** Build an instance corresponding to a Julian Day date.
  637.      * <p>
  638.      * This function should be preferred to {@link #createJDDate(int, CalculusFieldElement, TimeScale)} when the target time scale
  639.      * has a non-constant offset with respect to TAI.
  640.      * <p>
  641.      * The idea is to introduce a pivot time scale that is close to the target time scale but has a constant bias with TAI.
  642.      * <p>
  643.      * For example, to get a date from an MJD in TDB time scale, it's advised to use the TT time scale
  644.      * as a pivot scale. TT is very close to TDB and has constant offset to TAI.
  645.      * </p>
  646.      * @param jd Julian day
  647.      * @param secondsSinceNoon seconds in the Julian day
  648.      * (BEWARE, Julian days start at noon, so 0.0 is noon)
  649.      * @param timeScale time scale in which the seconds in day are defined
  650.      * @param pivotTimeScale pivot timescale used as intermediate timescale
  651.      * @return a new instant
  652.      * @param <T> the type of the field elements
  653.      */
  654.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createJDDate(final int jd, final T secondsSinceNoon,
  655.                                                                                         final TimeScale timeScale,
  656.                                                                                         final TimeScale pivotTimeScale) {
  657.         // Get the date in pivot timescale
  658.         final FieldAbsoluteDate<T> dateInPivotTimeScale = createJDDate(jd, secondsSinceNoon, pivotTimeScale);

  659.         // Compare offsets to TAI of the two time scales
  660.         final T offsetFromTAI = timeScale.offsetFromTAI(dateInPivotTimeScale).
  661.                 subtract(pivotTimeScale.offsetFromTAI(dateInPivotTimeScale));

  662.         // Return date in desired timescale
  663.         return dateInPivotTimeScale.shiftedBy(offsetFromTAI.multiply(-1.));
  664.     }

  665.     /** Build an instance corresponding to a Modified Julian Day date.
  666.      * @param mjd modified Julian day
  667.      * @param secondsInDay seconds in the day
  668.      * @param timeScale time scale in which the seconds in day are defined
  669.      * @return a new instant
  670.      * @param <T> the type of the field elements
  671.      */
  672.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createMJDDate(final int mjd, final T secondsInDay,
  673.                                                                                          final TimeScale timeScale) {
  674.         return new FieldAbsoluteDate<>(secondsInDay.getField(),
  675.                                        new DateComponents(DateComponents.MODIFIED_JULIAN_EPOCH, mjd),
  676.                                        TimeComponents.H00,
  677.                                        timeScale).shiftedBy(secondsInDay);
  678.     }

  679.     /** Create an instance as the median data between two existing instances.
  680.      * @param date1 first instance
  681.      * @param date2 second instance
  682.      * @return median date between first and second instance
  683.      * @param <T> the type of the field elements
  684.      * @since 13.0
  685.      */
  686.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createMedian(final FieldAbsoluteDate<T> date1,
  687.                                                                                         final FieldAbsoluteDate<T> date2) {
  688.         return new FieldAbsoluteDate<>(AbsoluteDate.createMedian(date1.date, date2.date),
  689.                                        date2.fieldOffset.add(date1.fieldOffset).multiply(0.5));
  690.     }

  691.     /** Build an instance corresponding to a GPS date.
  692.      *
  693.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  694.      *
  695.      * <p>GPS dates are provided as a week number starting at
  696.      * {@link #getGPSEpoch(Field) GPS epoch} and as a number of milliseconds
  697.      * since week start.</p>
  698.      * @param weekNumber week number since {@link #getGPSEpoch(Field) GPS epoch}
  699.      * @param milliInWeek number of milliseconds since week start
  700.      * @return a new instant
  701.      * @param <T> the type of the field elements
  702.      * @see #createGPSDate(int, CalculusFieldElement, TimeScale)
  703.      */
  704.     @DefaultDataContext
  705.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createGPSDate(final int weekNumber, final T milliInWeek) {
  706.         return createGPSDate(weekNumber, milliInWeek,
  707.                              DataContext.getDefault().getTimeScales().getGPS());
  708.     }

  709.     /**
  710.      * Build an instance corresponding to a GPS date.
  711.      * <p>GPS dates are provided as a week number starting at
  712.      * {@link #getGPSEpoch(Field) GPS epoch} and as a number of milliseconds since week
  713.      * start.</p>
  714.      *
  715.      * @param <T>         the type of the field elements
  716.      * @param weekNumber  week number since {@link #getGPSEpoch(Field) GPS epoch}
  717.      * @param milliInWeek number of milliseconds since week start
  718.      * @param gps         GPS time scale.
  719.      * @return a new instant
  720.      * @since 10.1
  721.      */
  722.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createGPSDate(
  723.                                                                                          final int weekNumber,
  724.                                                                                          final T milliInWeek,
  725.                                                                                          final TimeScale gps) {

  726.         final int day = (int) FastMath.floor(milliInWeek.getReal() / (1000.0 * Constants.JULIAN_DAY));
  727.         final T secondsInDay = milliInWeek.divide(1000.0).subtract(day * Constants.JULIAN_DAY);
  728.         return new FieldAbsoluteDate<>(milliInWeek.getField(),
  729.                                        new DateComponents(DateComponents.GPS_EPOCH, weekNumber * 7 + day),
  730.                                        TimeComponents.H00, gps).
  731.                shiftedBy(secondsInDay);
  732.     }

  733.     /** Build an instance corresponding to a Julian Epoch (JE).
  734.      * <p>According to Lieske paper: <a
  735.      * href="http://articles.adsabs.harvard.edu/cgi-bin/nph-iarticle_query?1979A%26A....73..282L&amp;defaultprint=YES&amp;filetype=.pdf.">
  736.      * Precession Matrix Based on IAU (1976) System of Astronomical Constants</a>, Astronomy and Astrophysics,
  737.      * vol. 73, no. 3, Mar. 1979, p. 282-284, Julian Epoch is related to Julian Ephemeris Date as:
  738.      * <pre>JE = 2000.0 + (JED - 2451545.0) / 365.25</pre>
  739.      * <p>This method reverts the formula above and computes an {@code FieldAbsoluteDate<T>} from the Julian Epoch.
  740.      *
  741.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  742.      *
  743.      * @param <T> the type of the field elements
  744.      * @param julianEpoch Julian epoch, like 2000.0 for defining the classical reference J2000.0
  745.      * @return a new instant
  746.      * @see #getJ2000Epoch(Field)
  747.      * @see #createBesselianEpoch(CalculusFieldElement)
  748.      * @see #createJulianEpoch(CalculusFieldElement, TimeScales)
  749.      */
  750.     @DefaultDataContext
  751.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createJulianEpoch(final T julianEpoch) {
  752.         return createJulianEpoch(julianEpoch, DataContext.getDefault().getTimeScales());
  753.     }

  754.     /**
  755.      * Build an instance corresponding to a Julian Epoch (JE).
  756.      * <p>According to Lieske paper: <a
  757.      * href="http://articles.adsabs.harvard.edu/cgi-bin/nph-iarticle_query?1979A%26A....73..282L&amp;defaultprint=YES&amp;filetype=.pdf.">
  758.      * Precession Matrix Based on IAU (1976) System of Astronomical Constants</a>,
  759.      * Astronomy and Astrophysics, vol. 73, no. 3, Mar. 1979, p. 282-284, Julian Epoch is
  760.      * related to Julian Ephemeris Date as:
  761.      * <pre>JE = 2000.0 + (JED - 2451545.0) / 365.25</pre>
  762.      * <p>This method reverts the formula above and computes an {@code
  763.      * FieldAbsoluteDate<T>} from the Julian Epoch.
  764.      *
  765.      * @param <T>         the type of the field elements
  766.      * @param julianEpoch Julian epoch, like 2000.0 for defining the classical reference
  767.      *                    J2000.0
  768.      * @param timeScales  used in the computation.
  769.      * @return a new instant
  770.      * @see #getJ2000Epoch(Field)
  771.      * @see #createBesselianEpoch(CalculusFieldElement)
  772.      * @see TimeScales#createJulianEpoch(double)
  773.      * @since 10.1
  774.      */
  775.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createJulianEpoch(
  776.                                                                                              final T julianEpoch,
  777.                                                                                              final TimeScales timeScales) {
  778.         final Field<T> field = julianEpoch.getField();
  779.         return new FieldAbsoluteDate<>(new FieldAbsoluteDate<>(field, timeScales.getJ2000Epoch()),
  780.                                        julianEpoch.subtract(2000.0).multiply(Constants.JULIAN_YEAR));
  781.     }

  782.     /** Build an instance corresponding to a Besselian Epoch (BE).
  783.      * <p>According to Lieske paper: <a
  784.      * href="http://articles.adsabs.harvard.edu/cgi-bin/nph-iarticle_query?1979A%26A....73..282L&amp;defaultprint=YES&amp;filetype=.pdf.">
  785.      * Precession Matrix Based on IAU (1976) System of Astronomical Constants</a>, Astronomy and Astrophysics,
  786.      * vol. 73, no. 3, Mar. 1979, p. 282-284, Besselian Epoch is related to Julian Ephemeris Date as:</p>
  787.      * <pre>
  788.      * BE = 1900.0 + (JED - 2415020.31352) / 365.242198781
  789.      * </pre>
  790.      * <p>
  791.      * This method reverts the formula above and computes an {@code FieldAbsoluteDate<T>} from the Besselian Epoch.
  792.      * </p>
  793.      *
  794.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  795.      *
  796.      * @param <T> the type of the field elements
  797.      * @param besselianEpoch Besselian epoch, like 1950 for defining the classical reference B1950.0
  798.      * @return a new instant
  799.      * @see #createJulianEpoch(CalculusFieldElement)
  800.      * @see #createBesselianEpoch(CalculusFieldElement, TimeScales)
  801.      */
  802.     @DefaultDataContext
  803.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createBesselianEpoch(final T besselianEpoch) {
  804.         return createBesselianEpoch(besselianEpoch, DataContext.getDefault().getTimeScales());
  805.     }

  806.     /**
  807.      * Build an instance corresponding to a Besselian Epoch (BE).
  808.      * <p>According to Lieske paper: <a
  809.      * href="http://articles.adsabs.harvard.edu/cgi-bin/nph-iarticle_query?1979A%26A....73..282L&amp;defaultprint=YES&amp;filetype=.pdf.">
  810.      * Precession Matrix Based on IAU (1976) System of Astronomical Constants</a>,
  811.      * Astronomy and Astrophysics, vol. 73, no. 3, Mar. 1979, p. 282-284, Besselian Epoch
  812.      * is related to Julian Ephemeris Date as:</p>
  813.      * <pre>
  814.      * BE = 1900.0 + (JED - 2415020.31352) / 365.242198781
  815.      * </pre>
  816.      * <p>
  817.      * This method reverts the formula above and computes an {@code FieldAbsoluteDate<T>}
  818.      * from the Besselian Epoch.
  819.      * </p>
  820.      *
  821.      * @param <T>            the type of the field elements
  822.      * @param besselianEpoch Besselian epoch, like 1950 for defining the classical
  823.      *                       reference B1950.0
  824.      * @param timeScales     used in the computation.
  825.      * @return a new instant
  826.      * @see #createJulianEpoch(CalculusFieldElement)
  827.      * @see TimeScales#createBesselianEpoch(double)
  828.      * @since 10.1
  829.      */
  830.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createBesselianEpoch(
  831.                                                                                                 final T besselianEpoch,
  832.                                                                                                 final TimeScales timeScales) {
  833.         final Field<T> field = besselianEpoch.getField();
  834.         return new FieldAbsoluteDate<>(new FieldAbsoluteDate<>(field, timeScales.getJ2000Epoch()),
  835.                                        besselianEpoch.subtract(1900).multiply(Constants.BESSELIAN_YEAR).
  836.                                            add(Constants.JULIAN_DAY * (-36525) + Constants.JULIAN_DAY * 0.31352));
  837.     }

  838.     /** Reference epoch for julian dates: -4712-01-01T12:00:00 Terrestrial Time.
  839.      * <p>Both <code>java.util.Date</code> and {@link DateComponents} classes
  840.      * follow the astronomical conventions and consider a year 0 between
  841.      * years -1 and +1, hence this reference date lies in year -4712 and not
  842.      * in year -4713 as can be seen in other documents or programs that obey
  843.      * a different convention (for example the <code>convcal</code> utility).</p>
  844.      *
  845.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  846.      *
  847.      * @param <T> the type of the field elements
  848.      * @param field field for the components
  849.      * @return the reference epoch for julian dates as a FieldAbsoluteDate
  850.      * @see AbsoluteDate#JULIAN_EPOCH
  851.      * @see TimeScales#getJulianEpoch()
  852.      */
  853.     @DefaultDataContext
  854.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getJulianEpoch(final Field<T> field) {
  855.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getJulianEpoch());
  856.     }

  857.     /** Reference epoch for modified julian dates: 1858-11-17T00:00:00 Terrestrial Time.
  858.      *
  859.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  860.      *
  861.      * @param <T> the type of the field elements
  862.      * @param field field for the components
  863.      * @return the reference epoch for modified julian dates as a FieldAbsoluteDate
  864.      * @see AbsoluteDate#MODIFIED_JULIAN_EPOCH
  865.      * @see TimeScales#getModifiedJulianEpoch()
  866.      */
  867.     @DefaultDataContext
  868.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getModifiedJulianEpoch(final Field<T> field) {
  869.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getModifiedJulianEpoch());
  870.     }

  871.     /** Reference epoch for 1950 dates: 1950-01-01T00:00:00 Terrestrial Time.
  872.      *
  873.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  874.      *
  875.      * @param <T> the type of the field elements
  876.      * @param field field for the components
  877.      * @return the reference epoch for 1950 dates as a FieldAbsoluteDate
  878.      * @see AbsoluteDate#FIFTIES_EPOCH
  879.      * @see TimeScales#getFiftiesEpoch()
  880.      */
  881.     @DefaultDataContext
  882.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getFiftiesEpoch(final Field<T> field) {
  883.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getFiftiesEpoch());
  884.     }

  885.     /** Reference epoch for CCSDS Time Code Format (CCSDS 301.0-B-4).
  886.      * <p>
  887.      * This method uses the {@link DataContext#getDefault() default data context}.
  888.      * </p>
  889.      * 1958-01-01T00:00:00 International Atomic Time (<em>not</em> UTC).
  890.      * @param <T> the type of the field elements
  891.      * @param field field for the components
  892.      * @return the reference epoch for CCSDS Time Code Format as a FieldAbsoluteDate
  893.      * @see AbsoluteDate#CCSDS_EPOCH
  894.      * @see TimeScales#getCcsdsEpoch()
  895.      */
  896.     @DefaultDataContext
  897.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getCCSDSEpoch(final Field<T> field) {
  898.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getCcsdsEpoch());
  899.     }

  900.     /** Reference epoch for Galileo System Time: 1999-08-22T00:00:00 UTC.
  901.      *
  902.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  903.      *
  904.      * @param <T> the type of the field elements
  905.      * @param field field for the components
  906.      * @return the reference epoch for Galileo System Time as a FieldAbsoluteDate
  907.      * @see AbsoluteDate#GALILEO_EPOCH
  908.      * @see TimeScales#getGalileoEpoch()
  909.      */
  910.     @DefaultDataContext
  911.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getGalileoEpoch(final Field<T> field) {
  912.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getGalileoEpoch());
  913.     }

  914.     /** Reference epoch for GPS weeks: 1980-01-06T00:00:00 GPS time.
  915.      *
  916.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  917.      *
  918.      * @param <T> the type of the field elements
  919.      * @param field field for the components
  920.      * @return the reference epoch for GPS weeks as a FieldAbsoluteDate
  921.      * @see AbsoluteDate#GPS_EPOCH
  922.      * @see TimeScales#getGpsEpoch()
  923.      */
  924.     @DefaultDataContext
  925.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getGPSEpoch(final Field<T> field) {
  926.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getGpsEpoch());
  927.     }

  928.     /** J2000.0 Reference epoch: 2000-01-01T12:00:00 Terrestrial Time (<em>not</em> UTC).
  929.      *
  930.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  931.      *
  932.      * @param <T> the type of the field elements
  933.      * @param field field for the components
  934.      * @return the J2000.0 reference epoch as a FieldAbsoluteDate
  935.      * @see #createJulianEpoch(CalculusFieldElement)
  936.      * @see AbsoluteDate#J2000_EPOCH
  937.      * @see TimeScales#getJ2000Epoch()
  938.      */
  939.     @DefaultDataContext
  940.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getJ2000Epoch(final Field<T> field) {
  941.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getJ2000Epoch());
  942.     }

  943.     /** Java Reference epoch: 1970-01-01T00:00:00 Universal Time Coordinate.
  944.      *
  945.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  946.      *
  947.      * <p>
  948.      * Between 1968-02-01 and 1972-01-01, UTC-TAI = 4.213 170 0s + (MJD - 39 126) x 0.002 592s.
  949.      * As on 1970-01-01 MJD = 40587, UTC-TAI = 8.000082s
  950.      * </p>
  951.      * @param <T> the type of the field elements
  952.      * @param field field for the components
  953.      * @return the Java reference epoch as a FieldAbsoluteDate
  954.      * @see AbsoluteDate#JAVA_EPOCH
  955.      * @see TimeScales#getJavaEpoch()
  956.      */
  957.     @DefaultDataContext
  958.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getJavaEpoch(final Field<T> field) {
  959.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getJavaEpoch());
  960.     }

  961.     /** Dummy date at infinity in the past direction.
  962.      * @param <T> the type of the field elements
  963.      * @param field field for the components
  964.      * @return a dummy date at infinity in the past direction as a FieldAbsoluteDate
  965.      * @see AbsoluteDate#PAST_INFINITY
  966.      * @see TimeScales#getPastInfinity()
  967.      */
  968.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getPastInfinity(final Field<T> field) {
  969.         return new FieldAbsoluteDate<>(field, AbsoluteDate.PAST_INFINITY);
  970.     }

  971.     /** Dummy date at infinity in the future direction.
  972.      * @param <T> the type of the field elements
  973.      * @param field field for the components
  974.      * @return a dummy date at infinity in the future direction as a FieldAbsoluteDate
  975.      * @see AbsoluteDate#FUTURE_INFINITY
  976.      * @see TimeScales#getFutureInfinity()
  977.      */
  978.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getFutureInfinity(final Field<T> field) {
  979.         return new FieldAbsoluteDate<>(field, AbsoluteDate.FUTURE_INFINITY);
  980.     }

  981.     /**
  982.      * Get an arbitrary date. Useful when a non-null date is needed but its values does
  983.      * not matter.
  984.      *
  985.      * @param <T>   the type of the field elements
  986.      * @param field field for the components
  987.      * @return an arbitrary date.
  988.      */
  989.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getArbitraryEpoch(final Field<T> field) {
  990.         return new FieldAbsoluteDate<>(field, AbsoluteDate.ARBITRARY_EPOCH);
  991.     }


  992.     /** Get a time-shifted date.
  993.      * <p>
  994.      * Calling this method is equivalent to call {@code new FieldAbsoluteDate&lt;&gt;(this, dt)}.
  995.      * </p>
  996.      * @param dt time shift in seconds
  997.      * @return a new date, shifted with respect to instance (which is immutable)
  998.      * @see org.orekit.utils.FieldPVCoordinates#shiftedBy(double)
  999.      * @see org.orekit.attitudes.FieldAttitude#shiftedBy(double)
  1000.      * @see org.orekit.orbits.FieldOrbit#shiftedBy(double)
  1001.      * @see org.orekit.propagation.FieldSpacecraftState#shiftedBy(double)
  1002.      */
  1003.     @Override
  1004.     public FieldAbsoluteDate<T> shiftedBy(final T dt) {
  1005.         return new FieldAbsoluteDate<>(this, dt);
  1006.     }

  1007.     /** Compute the physically elapsed duration between two instants.
  1008.      * <p>The returned duration is the number of seconds physically
  1009.      * elapsed between the two instants, measured in a regular time
  1010.      * scale with respect to surface of the Earth (i.e either the {@link
  1011.      * TAIScale TAI scale}, the {@link TTScale TT scale} or the {@link
  1012.      * GPSScale GPS scale}). It is the only method that gives a
  1013.      * duration with a physical meaning.</p>
  1014.      * <p>This method gives the same result (with less computation)
  1015.      * as calling {@link #offsetFrom(FieldAbsoluteDate, TimeScale)}
  1016.      * with a second argument set to one of the regular scales cited
  1017.      * above.</p>
  1018.      * <p>This method is the reverse of the {@link #FieldAbsoluteDate(FieldAbsoluteDate,
  1019.      * double)} constructor.</p>
  1020.      * @param instant instant to subtract from the instance
  1021.      * @return offset in seconds between the two instants (positive
  1022.      * if the instance is posterior to the argument)
  1023.      * @see #offsetFrom(FieldAbsoluteDate, TimeScale)
  1024.      * @see #FieldAbsoluteDate(FieldAbsoluteDate, double)
  1025.      */
  1026.     public T durationFrom(final FieldAbsoluteDate<T> instant) {
  1027.         return fieldOffset.subtract(instant.fieldOffset).
  1028.                add(date.durationFrom(instant.date));
  1029.     }

  1030.     /** Compute the physically elapsed duration between two instants.
  1031.      * <p>The returned duration is the number of seconds physically
  1032.      * elapsed between the two instants, measured in a regular time
  1033.      * scale with respect to surface of the Earth (i.e either the {@link
  1034.      * TAIScale TAI scale}, the {@link TTScale TT scale} or the {@link
  1035.      * GPSScale GPS scale}). It is the only method that gives a
  1036.      * duration with a physical meaning.</p>
  1037.      * <p>This method gives the same result (with less computation)
  1038.      * as calling {@link #offsetFrom(FieldAbsoluteDate, TimeScale)}
  1039.      * with a second argument set to one of the regular scales cited
  1040.      * above.</p>
  1041.      * <p>This method is the reverse of the {@link #FieldAbsoluteDate(FieldAbsoluteDate,
  1042.      * double)} constructor.</p>
  1043.      * @param instant instant to subtract from the instance
  1044.      * @param timeUnit {@link TimeUnit} precision for the offset
  1045.      * @return offset in seconds between the two instants (positive
  1046.      * if the instance is posterior to the argument)
  1047.      * @see #offsetFrom(FieldAbsoluteDate, TimeScale)
  1048.      * @see #FieldAbsoluteDate(FieldAbsoluteDate, double)
  1049.      */
  1050.     public T durationFrom(final FieldAbsoluteDate<T> instant, final TimeUnit timeUnit) {
  1051.         return fieldOffset.subtract(instant.fieldOffset).
  1052.                add(date.durationFrom(instant.date, timeUnit));
  1053.     }

  1054.     /** Compute the physically elapsed duration between two instants.
  1055.      * <p>The returned duration is the number of seconds physically
  1056.      * elapsed between the two instants, measured in a regular time
  1057.      * scale with respect to surface of the Earth (i.e either the {@link
  1058.      * TAIScale TAI scale}, the {@link TTScale TT scale} or the {@link
  1059.      * GPSScale GPS scale}). It is the only method that gives a
  1060.      * duration with a physical meaning.</p>
  1061.      * <p>This method gives the same result (with less computation)
  1062.      * as calling {@link #offsetFrom(FieldAbsoluteDate, TimeScale)}
  1063.      * with a second argument set to one of the regular scales cited
  1064.      * above.</p>
  1065.      * <p>This method is the reverse of the {@link #FieldAbsoluteDate(FieldAbsoluteDate,
  1066.      * double)} constructor.</p>
  1067.      * @param instant instant to subtract from the instance
  1068.      * @return offset in seconds between the two instants (positive
  1069.      * if the instance is posterior to the argument)
  1070.      * @see #offsetFrom(FieldAbsoluteDate, TimeScale)
  1071.      * @see #FieldAbsoluteDate(FieldAbsoluteDate, double)
  1072.      */
  1073.     public T durationFrom(final AbsoluteDate instant) {
  1074.         return fieldOffset.add(date.durationFrom(instant));
  1075.     }

  1076.     /** Compute the physically elapsed duration between two instants.
  1077.      * <p>The returned duration is the number of seconds physically
  1078.      * elapsed between the two instants, measured in a regular time
  1079.      * scale with respect to surface of the Earth (i.e either the {@link
  1080.      * TAIScale TAI scale}, the {@link TTScale TT scale} or the {@link
  1081.      * GPSScale GPS scale}). It is the only method that gives a
  1082.      * duration with a physical meaning.</p>
  1083.      * <p>This method gives the same result (with less computation)
  1084.      * as calling {@link #offsetFrom(FieldAbsoluteDate, TimeScale)}
  1085.      * with a second argument set to one of the regular scales cited
  1086.      * above.</p>
  1087.      * <p>This method is the reverse of the {@link #FieldAbsoluteDate(FieldAbsoluteDate,
  1088.      * double)} constructor.</p>
  1089.      * @param instant instant to subtract from the instance
  1090.      * @param timeUnit {@link TimeUnit} precision for the offset
  1091.      * @return offset in the given timeunit between the two instants (positive
  1092.      * if the instance is posterior to the argument), rounded to the nearest integer {@link TimeUnit}
  1093.      * @see #FieldAbsoluteDate(FieldAbsoluteDate, long, TimeUnit)
  1094.      * @since 12.1
  1095.      */
  1096.     public T durationFrom(final AbsoluteDate instant, final TimeUnit timeUnit) {
  1097.         return fieldOffset.add(date.durationFrom(instant, timeUnit));
  1098.     }

  1099.     /** Compute the apparent clock offset between two instant <em>in the
  1100.      * perspective of a specific {@link TimeScale time scale}</em>.
  1101.      * <p>The offset is the number of seconds counted in the given
  1102.      * time scale between the locations of the two instants, with
  1103.      * all time scale irregularities removed (i.e. considering all
  1104.      * days are exactly 86400 seconds long). This method will give
  1105.      * a result that may not have a physical meaning if the time scale
  1106.      * is irregular. For example since a leap second was introduced at
  1107.      * the end of 2005, the apparent offset between 2005-12-31T23:59:59
  1108.      * and 2006-01-01T00:00:00 is 1 second, but the physical duration
  1109.      * of the corresponding time interval as returned by the {@link
  1110.      * #durationFrom(FieldAbsoluteDate)} method is 2 seconds.</p>
  1111.      * <p>This method is the reverse of the {@link #FieldAbsoluteDate(FieldAbsoluteDate,
  1112.      * double, TimeScale)} constructor.</p>
  1113.      * @param instant instant to subtract from the instance
  1114.      * @param timeScale time scale with respect to which the offset should
  1115.      * be computed
  1116.      * @return apparent clock offset in seconds between the two instants
  1117.      * (positive if the instance is posterior to the argument)
  1118.      * @see #durationFrom(FieldAbsoluteDate)
  1119.      * @see #FieldAbsoluteDate(FieldAbsoluteDate, double, TimeScale)
  1120.      */
  1121.     public T offsetFrom(final FieldAbsoluteDate<T> instant, final TimeScale timeScale) {
  1122.         return fieldOffset.subtract(instant.fieldOffset).
  1123.                add(date.offsetFrom(instant.date, timeScale));
  1124.     }

  1125.     /** Compute the offset between two time scales at the current instant.
  1126.      * <p>The offset is defined as <i>l₁-l₂</i>
  1127.      * where <i>l₁</i> is the location of the instant in
  1128.      * the <code>scale1</code> time scale and <i>l₂</i> is the
  1129.      * location of the instant in the <code>scale2</code> time scale.</p>
  1130.      * @param scale1 first time scale
  1131.      * @param scale2 second time scale
  1132.      * @return offset in seconds between the two time scales at the
  1133.      * current instant
  1134.      */
  1135.     public T timeScalesOffset(final TimeScale scale1, final TimeScale scale2) {
  1136.         return scale1.offsetFromTAI(this).subtract(scale2.offsetFromTAI(this));
  1137.     }

  1138.     /** Convert the instance to a Java {@link java.util.Date Date}.
  1139.      * <p>Conversion to the Date class induces a loss of precision because
  1140.      * the Date class does not provide sub-millisecond information. Java Dates
  1141.      * are considered to be locations in some times scales.</p>
  1142.      * @param timeScale time scale to use
  1143.      * @return a {@link java.util.Date Date} instance representing the location
  1144.      * of the instant in the time scale
  1145.      */
  1146.     public Date toDate(final TimeScale timeScale) {
  1147.         return date.toDate(timeScale);
  1148.     }

  1149.     /**
  1150.      * Convert the instance to a Java {@link java.time.Instant Instant}.
  1151.      * Nanosecond precision is preserved during this conversion
  1152.      *
  1153.      * @return a {@link java.time.Instant Instant} instance representing the location
  1154.      * of the instant in the utc time scale
  1155.      * @since 12.1
  1156.      */
  1157.     @DefaultDataContext
  1158.     public Instant toInstant() {
  1159.         return toInstant(TimeScalesFactory.getTimeScales());
  1160.     }

  1161.     /**
  1162.      * Convert the instance to a Java {@link java.time.Instant Instant}.
  1163.      * Nanosecond precision is preserved during this conversion
  1164.      *
  1165.      * @param timeScales the timescales to use
  1166.      * @return a {@link java.time.Instant Instant} instance representing the location
  1167.      * of the instant in the utc time scale
  1168.      * @since 12.1
  1169.      */
  1170.     public Instant toInstant(final TimeScales timeScales) {
  1171.         return date.toInstant(timeScales);
  1172.     }

  1173.     /** Split the instance into date/time components.
  1174.      * @param timeScale time scale to use
  1175.      * @return date/time components
  1176.      */
  1177.     public DateTimeComponents getComponents(final TimeScale timeScale) {
  1178.         return date.getComponents(timeScale);
  1179.     }

  1180.     /** Split the instance into date/time components for a local time.
  1181.      *
  1182.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  1183.      *
  1184.      * @param minutesFromUTC offset in <em>minutes</em> from UTC (positive Eastwards UTC,
  1185.      * negative Westward UTC)
  1186.      * @return date/time components
  1187.      * @see #getComponents(int, TimeScale)
  1188.      */
  1189.     @DefaultDataContext
  1190.     public DateTimeComponents getComponents(final int minutesFromUTC) {
  1191.         return date.getComponents(minutesFromUTC);
  1192.     }

  1193.     /**
  1194.      * Split the instance into date/time components for a local time.
  1195.      *
  1196.      * @param minutesFromUTC offset in <em>minutes</em> from UTC (positive Eastwards UTC,
  1197.      *                       negative Westward UTC)
  1198.      * @param utc            time scale used to compute date and time components.
  1199.      * @return date/time components
  1200.      * @since 10.1
  1201.      */
  1202.     public DateTimeComponents getComponents(final int minutesFromUTC, final TimeScale utc) {
  1203.         return date.getComponents(minutesFromUTC, utc);
  1204.     }

  1205.     /** {@inheritDoc} */
  1206.     @Override
  1207.     public FieldAbsoluteDate<T> getDate() {
  1208.         return this;
  1209.     }

  1210.     /** Get the field.
  1211.      * @return field instance.
  1212.      */
  1213.     public Field<T> getField() {
  1214.         return fieldOffset.getField();
  1215.     }

  1216.     /** Split the instance into date/time components for a time zone.
  1217.      *
  1218.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  1219.      *
  1220.      * @param timeZone time zone
  1221.      * @return date/time components
  1222.      * @see #getComponents(TimeZone, TimeScale)
  1223.      */
  1224.     @DefaultDataContext
  1225.     public DateTimeComponents getComponents(final TimeZone timeZone) {
  1226.         return date.getComponents(timeZone);
  1227.     }

  1228.     /** Split the instance into date/time components for a time zone.
  1229.      * @param timeZone time zone
  1230.      * @param utc            time scale used to compute date and time components.
  1231.      * @return date/time components
  1232.      * @since 10.1
  1233.      */
  1234.     public DateTimeComponents getComponents(final TimeZone timeZone, final TimeScale utc) {
  1235.         return date.getComponents(timeZone, utc);
  1236.     }

  1237.     /** Compare the instance with another date.
  1238.      * @param other other date to compare the instance to
  1239.      * @return a negative integer, zero, or a positive integer as this date
  1240.      * is before, simultaneous, or after the specified date.
  1241.      */
  1242.     public int compareTo(final FieldAbsoluteDate<T> other) {
  1243.         return date.compareTo(other.date);
  1244.     }


  1245.     /** Check if the instance represents the same time as another instance.
  1246.      * @param other other date
  1247.      * @return true if the instance and the other date refer to the same instant with same Field and addendum
  1248.      */
  1249.     public boolean equals(final Object other) {

  1250.         if (other == this) {
  1251.             // first fast check
  1252.             return true;
  1253.         }

  1254.         if (other instanceof FieldAbsoluteDate) {
  1255.             final FieldAbsoluteDate<?> otherF = (FieldAbsoluteDate<?>) other;
  1256.             return fieldOffset.getField().equals(otherF.fieldOffset.getField()) &&
  1257.                    date.equals(otherF.date) && fieldOffset.getAddendum().equals(otherF.fieldOffset.getAddendum());
  1258.         }

  1259.         return false;

  1260.     }

  1261.     /** Check if the instance represents the same time as another.
  1262.      * @param other the instant to compare this date to
  1263.      * @return true if the instance and the argument refer to the same instant
  1264.      * @see #isCloseTo(FieldTimeStamped, double)
  1265.      * @since 10.1
  1266.      */
  1267.     public boolean isEqualTo(final FieldTimeStamped<T> other) {
  1268.         return this.equals(other.getDate());
  1269.     }

  1270.     /** Check if the instance time is close to another.
  1271.      * @param other the instant to compare this date to
  1272.      * @param tolerance the separation, in seconds, under which the two instants will be considered close to each other
  1273.      * @return true if the duration between the instance and the argument is strictly below the tolerance
  1274.      * @see #isEqualTo(FieldTimeStamped)
  1275.      * @since 10.1
  1276.      */
  1277.     public boolean isCloseTo(final FieldTimeStamped<T> other, final double tolerance) {
  1278.         return date.isCloseTo(other.getDate().date, tolerance);
  1279.     }

  1280.     /** Check if the instance represents a time that is strictly before another.
  1281.      * @param other the instant to compare this date to
  1282.      * @return true if the instance is strictly before the argument when ordering chronologically
  1283.      * @see #isBeforeOrEqualTo(FieldTimeStamped)
  1284.      * @since 10.1
  1285.      */
  1286.     public boolean isBefore(final FieldTimeStamped<T> other) {
  1287.         return date.isBefore(other.getDate().date);
  1288.     }

  1289.     /** Check if the instance represents a time that is strictly after another.
  1290.      * @param other the instant to compare this date to
  1291.      * @return true if the instance is strictly after the argument when ordering chronologically
  1292.      * @see #isAfterOrEqualTo(FieldTimeStamped)
  1293.      * @since 10.1
  1294.      */
  1295.     public boolean isAfter(final FieldTimeStamped<T> other) {
  1296.         return date.isAfter(other.getDate().date);
  1297.     }

  1298.     /** Check if the instance represents a time that is before or equal to another.
  1299.      * @param other the instant to compare this date to
  1300.      * @return true if the instance is before (or equal to) the argument when ordering chronologically
  1301.      * @see #isBefore(FieldTimeStamped)
  1302.      * @since 10.1
  1303.      */
  1304.     public boolean isBeforeOrEqualTo(final FieldTimeStamped<T> other) {
  1305.         return date.isBeforeOrEqualTo(other.getDate().date);
  1306.     }

  1307.     /** Check if the instance represents a time that is after or equal to another.
  1308.      * @param other the instant to compare this date to
  1309.      * @return true if the instance is after (or equal to) the argument when ordering chronologically
  1310.      * @see #isAfterOrEqualTo(FieldTimeStamped)
  1311.      * @since 10.1
  1312.      */
  1313.     public boolean isAfterOrEqualTo(final FieldTimeStamped<T> other) {
  1314.         return date.isAfterOrEqualTo(other.getDate().date);
  1315.     }

  1316.     /** Check if the instance represents a time that is strictly between two others representing
  1317.      * the boundaries of a time span. The two boundaries can be provided in any order: in other words,
  1318.      * whether <code>boundary</code> represents a time that is before or after <code>otherBoundary</code> will
  1319.      * not change the result of this method.
  1320.      * @param boundary one end of the time span
  1321.      * @param otherBoundary the other end of the time span
  1322.      * @return true if the instance is strictly between the two arguments when ordering chronologically
  1323.      * @see #isBetweenOrEqualTo(FieldTimeStamped, FieldTimeStamped)
  1324.      * @since 10.1
  1325.      */
  1326.     public boolean isBetween(final FieldTimeStamped<T> boundary, final FieldTimeStamped<T> otherBoundary) {
  1327.         return date.isBetween(boundary.getDate().date, otherBoundary.getDate().date);
  1328.     }

  1329.     /** Check if the instance represents a time that is between two others representing
  1330.      * the boundaries of a time span, or equal to one of them. The two boundaries can be provided in any order:
  1331.      * in other words, whether <code>boundary</code> represents a time that is before or after
  1332.      * <code>otherBoundary</code> will not change the result of this method.
  1333.      * @param boundary one end of the time span
  1334.      * @param otherBoundary the other end of the time span
  1335.      * @return true if the instance is between the two arguments (or equal to at least one of them)
  1336.      * when ordering chronologically
  1337.      * @see #isBetween(FieldTimeStamped, FieldTimeStamped)
  1338.      * @since 10.1
  1339.      */
  1340.     public boolean isBetweenOrEqualTo(final FieldTimeStamped<T> boundary, final FieldTimeStamped<T> otherBoundary) {
  1341.         return date.isBetweenOrEqualTo(boundary.getDate().date, otherBoundary.getDate().date);
  1342.     }

  1343.     /** Get a hashcode for this date.
  1344.      * @return hashcode
  1345.      */
  1346.     public int hashCode() {
  1347.         return date.hashCode() + fieldOffset.getAddendum().hashCode();
  1348.     }

  1349.     /**
  1350.      * Get a String representation of the instant location with up to 16 digits of
  1351.      * precision for the seconds value.
  1352.      *
  1353.      * <p> Since this method is used in exception messages and error handling every
  1354.      * effort is made to return some representation of the instant. If UTC is available
  1355.      * from the default data context then it is used to format the string in UTC. If not
  1356.      * then TAI is used. Finally if the prior attempts fail this method falls back to
  1357.      * converting this class's internal representation to a string.
  1358.      *
  1359.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  1360.      *
  1361.      * @return a string representation of the instance, in ISO-8601 format if UTC is
  1362.      * available from the default data context.
  1363.      * @see AbsoluteDate#toString()
  1364.      * @see #toString(TimeScale)
  1365.      * @see DateTimeComponents#toString(int, int)
  1366.      */
  1367.     @DefaultDataContext
  1368.     public String toString() {
  1369.         return date.toString();
  1370.     }

  1371.     /**
  1372.      * Get a String representation of the instant location in ISO-8601 format without the
  1373.      * UTC offset and with up to 16 digits of precision for the seconds value.
  1374.      *
  1375.      * @param timeScale time scale to use
  1376.      * @return a string representation of the instance.
  1377.      * @see DateTimeComponents#toString(int, int)
  1378.      */
  1379.     public String toString(final TimeScale timeScale) {
  1380.         return date.toString(timeScale);
  1381.     }

  1382.     /** Get a String representation of the instant location for a local time.
  1383.      *
  1384.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  1385.      *
  1386.      * @param minutesFromUTC offset in <em>minutes</em> from UTC (positive Eastwards UTC,
  1387.      * negative Westward UTC).
  1388.      * @return string representation of the instance,
  1389.      * in ISO-8601 format with milliseconds accuracy
  1390.      * @see #toString(int, TimeScale)
  1391.      */
  1392.     @DefaultDataContext
  1393.     public String toString(final int minutesFromUTC) {
  1394.         return date.toString(minutesFromUTC);
  1395.     }

  1396.     /**
  1397.      * Get a String representation of the instant location for a local time.
  1398.      *
  1399.      * @param minutesFromUTC offset in <em>minutes</em> from UTC (positive Eastwards UTC,
  1400.      *                       negative Westward UTC).
  1401.      * @param utc            time scale used to compute date and time components.
  1402.      * @return string representation of the instance, in ISO-8601 format with milliseconds
  1403.      * accuracy
  1404.      * @since 10.1
  1405.      */
  1406.     public String toString(final int minutesFromUTC, final TimeScale utc) {
  1407.         return date.toString(minutesFromUTC, utc);
  1408.     }

  1409.     /** Get a String representation of the instant location for a time zone.
  1410.      *
  1411.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  1412.      *
  1413.      * @param timeZone time zone
  1414.      * @return string representation of the instance,
  1415.      * in ISO-8601 format with milliseconds accuracy
  1416.      * @see #toString(TimeZone, TimeScale)
  1417.      */
  1418.     @DefaultDataContext
  1419.     public String toString(final TimeZone timeZone) {
  1420.         return date.toString(timeZone);
  1421.     }

  1422.     /**
  1423.      * Get a String representation of the instant location for a time zone.
  1424.      *
  1425.      * @param timeZone time zone
  1426.      * @param utc      time scale used to compute date and time components.
  1427.      * @return string representation of the instance, in ISO-8601 format with milliseconds
  1428.      * accuracy
  1429.      * @since 10.1
  1430.      */
  1431.     public String toString(final TimeZone timeZone, final TimeScale utc) {
  1432.         return date.toString(timeZone, utc);
  1433.     }

  1434.     /**
  1435.      * Return a string representation of this date-time, rounded to the given precision.
  1436.      *
  1437.      * <p>The format used is ISO8601 without the UTC offset.</p>
  1438.      *
  1439.      *
  1440.      * @param timeScale      to use to compute components.
  1441.      * @param fractionDigits the number of digits to include after the decimal point in
  1442.      *                       the string representation of the seconds. The date and time
  1443.      *                       is first rounded as necessary. {@code fractionDigits} must be
  1444.      *                       greater than or equal to {@code 0}.
  1445.      * @return string representation of this date, time, and UTC offset
  1446.      * @see #toString(TimeScale)
  1447.      * @see DateTimeComponents#toString(int, int)
  1448.      * @see DateTimeComponents#toStringWithoutUtcOffset(int, int)
  1449.      * @since 12.2
  1450.      */
  1451.     public String toStringWithoutUtcOffset(final TimeScale timeScale, final int fractionDigits) {
  1452.         return date.toStringWithoutUtcOffset(timeScale, fractionDigits);
  1453.     }

  1454.     /** Get a time-shifted date.
  1455.      * <p>
  1456.      * Calling this method is equivalent to call <code>new FieldAbsoluteDate(this, dt)</code>.
  1457.      * </p>
  1458.      * @param dt time shift in seconds
  1459.      * @return a new date, shifted with respect to instance (which is immutable)
  1460.      * @see org.orekit.utils.FieldPVCoordinates#shiftedBy(double)
  1461.      * @see org.orekit.attitudes.FieldAttitude#shiftedBy(double)
  1462.      * @see org.orekit.orbits.FieldOrbit#shiftedBy(double)
  1463.      * @see org.orekit.propagation.FieldSpacecraftState#shiftedBy(double)
  1464.      */
  1465.     @Override
  1466.     public FieldAbsoluteDate<T> shiftedBy(final double dt) {
  1467.         return new FieldAbsoluteDate<>(this, dt);
  1468.     }

  1469.     /** Get a time-shifted date.
  1470.      * <p>
  1471.      * Calling this method is equivalent to call <code>new FieldAbsoluteDate(this, dt)</code>.
  1472.      * </p>
  1473.      * @param dt time shift
  1474.      * @return a new date, shifted with respect to instance (which is immutable)
  1475.      * @see org.orekit.utils.FieldPVCoordinates#shiftedBy(double)
  1476.      * @see org.orekit.attitudes.FieldAttitude#shiftedBy(double)
  1477.      * @see org.orekit.orbits.FieldOrbit#shiftedBy(double)
  1478.      * @see org.orekit.propagation.FieldSpacecraftState#shiftedBy(double)
  1479.      * @since 13.0
  1480.      */
  1481.     @Override
  1482.     public FieldAbsoluteDate<T> shiftedBy(final TimeOffset dt) {
  1483.         return new FieldAbsoluteDate<>(this, dt);
  1484.     }

  1485.     /** Get a time-shifted date.
  1486.      * <p>
  1487.      * Calling this method is equivalent to call <code>new FieldAbsoluteDate(this, dt, timeUnit)</code>.
  1488.      * </p>
  1489.      * @param dt time shift in time units
  1490.      * @param timeUnit {@link TimeUnit} for dt
  1491.      * @return a new date, shifted with respect to instance (which is immutable)
  1492.      * @see org.orekit.utils.FieldPVCoordinates#shiftedBy(double)
  1493.      * @see org.orekit.attitudes.FieldAttitude#shiftedBy(double)
  1494.      * @see org.orekit.orbits.FieldOrbit#shiftedBy(double)
  1495.      * @see org.orekit.propagation.FieldSpacecraftState#shiftedBy(double)
  1496.      * @since 12.1
  1497.      */
  1498.     public FieldAbsoluteDate<T> shiftedBy(final long dt, final TimeUnit timeUnit) {
  1499.         return new FieldAbsoluteDate<>(this, dt, timeUnit);
  1500.     }


  1501.     /** Transform the FieldAbsoluteDate in an AbsoluteDate.
  1502.      * @return AbsoluteDate of the FieldObject
  1503.      * */
  1504.     public AbsoluteDate toAbsoluteDate() {
  1505.         return date;
  1506.     }

  1507.     /** Check if the Field is semantically equal to zero.
  1508.      *
  1509.      * <p> Using {@link FieldElement#isZero()}
  1510.      *
  1511.      * @return true the Field is semantically equal to zero
  1512.      * @since 12.0
  1513.      */
  1514.     public boolean hasZeroField() {
  1515.         return fieldOffset.getAddendum().isZero();
  1516.     }

  1517.     /**
  1518.      * Return the given date as a Modified Julian Date <b>expressed in UTC</b>.
  1519.      *
  1520.      * @return double representation of the given date as Modified Julian Date.
  1521.      * @since 12.2
  1522.      */
  1523.     @DefaultDataContext
  1524.     public T getMJD() {
  1525.         return this.getMJD(TimeScalesFactory.getUTC());
  1526.     }

  1527.     /**
  1528.      * Return the given date as a Modified Julian Date expressed in given timescale.
  1529.      *
  1530.      * @param ts time scale
  1531.      * @return double representation of the given date as Modified Julian Date.
  1532.      * @since 12.2
  1533.      */
  1534.     public T getMJD(final TimeScale ts) {
  1535.         final T shift = fieldOffset.divide(Constants.JULIAN_DAY);
  1536.         return shift.add(date.getMJD(ts));
  1537.     }

  1538.     /**
  1539.      * Return the given date as a Julian Date <b>expressed in UTC</b>.
  1540.      *
  1541.      * @return double representation of the given date as Julian Date.
  1542.      * @since 12.2
  1543.      */
  1544.     @DefaultDataContext
  1545.     public T getJD() {
  1546.         return getJD(TimeScalesFactory.getUTC());
  1547.     }

  1548.     /**
  1549.      * Return the given date as a Julian Date expressed in given timescale.
  1550.      *
  1551.      * @param ts time scale
  1552.      * @return double representation of the given date as Julian Date.
  1553.      * @since 12.2
  1554.      */
  1555.     public T getJD(final TimeScale ts) {
  1556.         final T shift = fieldOffset.divide(Constants.JULIAN_DAY);
  1557.         return shift.add(date.getJD(ts));
  1558.     }

  1559.     /** Get day of year, preserving continuity as much as possible.
  1560.      * <p>
  1561.      * This is a continuous extension of the integer value returned by
  1562.      * {@link #getComponents(TimeZone) getComponents(utc)}{@link DateTimeComponents#getDate() .getDate()}{@link DateComponents#getDayOfYear() .getDayOfYear()}.
  1563.      * In order to have it remain as close as possible to its integer counterpart,
  1564.      * day 1.0 is considered to occur on January 1st at noon.
  1565.      * </p>
  1566.      * <p>
  1567.      * Continuity is preserved from day to day within a year, but of course
  1568.      * there is a discontinuity at year change, where it switches from 365.49999…
  1569.      * (or 366.49999… on leap years) to 0.5
  1570.      * </p>
  1571.      * @param utc time scale to compute date components
  1572.      * @return day of year, with day 1.0 occurring on January first at noon
  1573.      * @since 13.0
  1574.      */
  1575.     public T getDayOfYear(final TimeScale utc) {
  1576.         final int                  year         = date.getComponents(utc).getDate().getYear();
  1577.         final AbsoluteDate         newYearsEveD = new AbsoluteDate(year - 1, 12, 31, 12, 0, 0.0, utc);
  1578.         final FieldAbsoluteDate<T> newYearsEveF = new FieldAbsoluteDate<>(getField(), newYearsEveD);
  1579.         return durationFrom(newYearsEveF).divide(Constants.JULIAN_DAY);
  1580.     }

  1581. }