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.FieldUnivariateDerivative2;
  26. import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative2Field;
  27. import org.hipparchus.util.FastMath;
  28. import org.orekit.annotation.DefaultDataContext;
  29. import org.orekit.data.DataContext;
  30. import org.orekit.utils.Constants;

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

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

  101.     /** Underlying regular date.
  102.      * @since 13.0
  103.      */
  104.     private final AbsoluteDate date;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

  423.     /** Creates Field date with offset as univariate derivative of second order, with a unit linear coefficient in time.
  424.      * @return univariate derivative 2 date
  425.      * @since 12.2
  426.      */
  427.     public FieldAbsoluteDate<FieldUnivariateDerivative2<T>> toFUD2Field() {
  428.         final FieldUnivariateDerivative2Field<T> fud2Field = FieldUnivariateDerivative2Field.getUnivariateDerivative2Field(fieldOffset.getField());
  429.         final FieldUnivariateDerivative2<T> fud2Shift = new FieldUnivariateDerivative2<>(fieldOffset,
  430.                                                                                          fieldOffset.getField().getOne(),
  431.                                                                                          fieldOffset.getField().getZero());
  432.         return new FieldAbsoluteDate<>(fud2Field, date).shiftedBy(fud2Shift);
  433.     }

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

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

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

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

  572.     /** Build an instance from a CCSDS Calendar Segmented Time Code (CCS).
  573.      * <p>
  574.      * CCSDS Calendar Segmented Time Code is defined in the blue book:
  575.      * CCSDS Time Code Format (CCSDS 301.0-B-4) published in November 2010
  576.      * </p>
  577.      *
  578.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  579.      *
  580.      * @param preambleField field specifying the format, often not transmitted in
  581.      * data interfaces, as it is constant for a given data interface
  582.      * @param timeField byte array containing the time code
  583.      * @return an instance corresponding to the specified date
  584.      * @see #parseCCSDSCalendarSegmentedTimeCode(byte, byte[], TimeScale)
  585.      */
  586.     @DefaultDataContext
  587.     public FieldAbsoluteDate<T> parseCCSDSCalendarSegmentedTimeCode(final byte preambleField, final byte[] timeField) {
  588.         return parseCCSDSCalendarSegmentedTimeCode(preambleField, timeField,
  589.                                                    DataContext.getDefault().getTimeScales().getUTC());
  590.     }

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

  611.     /** Build an instance corresponding to a Julian Day date.
  612.      * @param jd Julian day
  613.      * @param secondsSinceNoon seconds in the Julian day
  614.      * (BEWARE, Julian days start at noon, so 0.0 is noon)
  615.      * @param timeScale time scale in which the seconds in day are defined
  616.      * @return a new instant
  617.      * @param <T> the type of the field elements
  618.      */
  619.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createJDDate(final int jd, final T secondsSinceNoon,
  620.                                                                                         final TimeScale timeScale) {
  621.         return new FieldAbsoluteDate<>(secondsSinceNoon.getField(), new DateComponents(DateComponents.JULIAN_EPOCH, jd),
  622.                         TimeComponents.H12, timeScale).shiftedBy(secondsSinceNoon);
  623.     }

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

  647.         // Compare offsets to TAI of the two time scales
  648.         final T offsetFromTAI = timeScale.offsetFromTAI(dateInPivotTimeScale).
  649.                 subtract(pivotTimeScale.offsetFromTAI(dateInPivotTimeScale));

  650.         // Return date in desired timescale
  651.         return dateInPivotTimeScale.shiftedBy(offsetFromTAI.multiply(-1.));
  652.     }

  653.     /** Build an instance corresponding to a Modified Julian Day date.
  654.      * @param mjd modified Julian day
  655.      * @param secondsInDay seconds in the day
  656.      * @param timeScale time scale in which the seconds in day are defined
  657.      * @return a new instant
  658.      * @param <T> the type of the field elements
  659.      */
  660.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createMJDDate(final int mjd, final T secondsInDay,
  661.                                                                                          final TimeScale timeScale) {
  662.         return new FieldAbsoluteDate<>(secondsInDay.getField(),
  663.                                        new DateComponents(DateComponents.MODIFIED_JULIAN_EPOCH, mjd),
  664.                                        TimeComponents.H00,
  665.                                        timeScale).shiftedBy(secondsInDay);
  666.     }

  667.     /** Create an instance as the median data between two existing instances.
  668.      * @param date1 first instance
  669.      * @param date2 second instance
  670.      * @return median date between first and second instance
  671.      * @param <T> the type of the field elements
  672.      * @since 13.0
  673.      */
  674.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createMedian(final FieldAbsoluteDate<T> date1,
  675.                                                                                         final FieldAbsoluteDate<T> date2) {
  676.         return new FieldAbsoluteDate<>(AbsoluteDate.createMedian(date1.date, date2.date),
  677.                                        date2.fieldOffset.add(date1.fieldOffset).multiply(0.5));
  678.     }

  679.     /** Build an instance corresponding to a GPS date.
  680.      *
  681.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  682.      *
  683.      * <p>GPS dates are provided as a week number starting at
  684.      * {@link #getGPSEpoch(Field) GPS epoch} and as a number of milliseconds
  685.      * since week start.</p>
  686.      * @param weekNumber week number since {@link #getGPSEpoch(Field) GPS epoch}
  687.      * @param milliInWeek number of milliseconds since week start
  688.      * @return a new instant
  689.      * @param <T> the type of the field elements
  690.      * @see #createGPSDate(int, CalculusFieldElement, TimeScale)
  691.      */
  692.     @DefaultDataContext
  693.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createGPSDate(final int weekNumber, final T milliInWeek) {
  694.         return createGPSDate(weekNumber, milliInWeek,
  695.                              DataContext.getDefault().getTimeScales().getGPS());
  696.     }

  697.     /**
  698.      * Build an instance corresponding to a GPS date.
  699.      * <p>GPS dates are provided as a week number starting at
  700.      * {@link #getGPSEpoch(Field) GPS epoch} and as a number of milliseconds since week
  701.      * start.</p>
  702.      *
  703.      * @param <T>         the type of the field elements
  704.      * @param weekNumber  week number since {@link #getGPSEpoch(Field) GPS epoch}
  705.      * @param milliInWeek number of milliseconds since week start
  706.      * @param gps         GPS time scale.
  707.      * @return a new instant
  708.      * @since 10.1
  709.      */
  710.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createGPSDate(
  711.                                                                                          final int weekNumber,
  712.                                                                                          final T milliInWeek,
  713.                                                                                          final TimeScale gps) {

  714.         final int day = (int) FastMath.floor(milliInWeek.getReal() / (1000.0 * Constants.JULIAN_DAY));
  715.         final T secondsInDay = milliInWeek.divide(1000.0).subtract(day * Constants.JULIAN_DAY);
  716.         return new FieldAbsoluteDate<>(milliInWeek.getField(),
  717.                                        new DateComponents(DateComponents.GPS_EPOCH, weekNumber * 7 + day),
  718.                                        TimeComponents.H00, gps).
  719.                shiftedBy(secondsInDay);
  720.     }

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

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

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

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

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

  845.     /** Reference epoch for modified julian dates: 1858-11-17T00:00:00 Terrestrial Time.
  846.      *
  847.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  848.      *
  849.      * @param <T> the type of the field elements
  850.      * @param field field for the components
  851.      * @return the reference epoch for modified julian dates as a FieldAbsoluteDate
  852.      * @see AbsoluteDate#MODIFIED_JULIAN_EPOCH
  853.      * @see TimeScales#getModifiedJulianEpoch()
  854.      */
  855.     @DefaultDataContext
  856.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getModifiedJulianEpoch(final Field<T> field) {
  857.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getModifiedJulianEpoch());
  858.     }

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

  873.     /** Reference epoch for CCSDS Time Code Format (CCSDS 301.0-B-4).
  874.      * <p>
  875.      * This method uses the {@link DataContext#getDefault() default data context}.
  876.      * </p>
  877.      * 1958-01-01T00:00:00 International Atomic Time (<em>not</em> UTC).
  878.      * @param <T> the type of the field elements
  879.      * @param field field for the components
  880.      * @return the reference epoch for CCSDS Time Code Format as a FieldAbsoluteDate
  881.      * @see AbsoluteDate#CCSDS_EPOCH
  882.      * @see TimeScales#getCcsdsEpoch()
  883.      */
  884.     @DefaultDataContext
  885.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getCCSDSEpoch(final Field<T> field) {
  886.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getCcsdsEpoch());
  887.     }

  888.     /** Reference epoch for Galileo System Time: 1999-08-22T00:00:00 UTC.
  889.      *
  890.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  891.      *
  892.      * @param <T> the type of the field elements
  893.      * @param field field for the components
  894.      * @return the reference epoch for Galileo System Time as a FieldAbsoluteDate
  895.      * @see AbsoluteDate#GALILEO_EPOCH
  896.      * @see TimeScales#getGalileoEpoch()
  897.      */
  898.     @DefaultDataContext
  899.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getGalileoEpoch(final Field<T> field) {
  900.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getGalileoEpoch());
  901.     }

  902.     /** Reference epoch for GPS weeks: 1980-01-06T00:00:00 GPS time.
  903.      *
  904.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  905.      *
  906.      * @param <T> the type of the field elements
  907.      * @param field field for the components
  908.      * @return the reference epoch for GPS weeks as a FieldAbsoluteDate
  909.      * @see AbsoluteDate#GPS_EPOCH
  910.      * @see TimeScales#getGpsEpoch()
  911.      */
  912.     @DefaultDataContext
  913.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getGPSEpoch(final Field<T> field) {
  914.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getGpsEpoch());
  915.     }

  916.     /** J2000.0 Reference epoch: 2000-01-01T12:00:00 Terrestrial Time (<em>not</em> UTC).
  917.      *
  918.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  919.      *
  920.      * @param <T> the type of the field elements
  921.      * @param field field for the components
  922.      * @return the J2000.0 reference epoch as a FieldAbsoluteDate
  923.      * @see #createJulianEpoch(CalculusFieldElement)
  924.      * @see AbsoluteDate#J2000_EPOCH
  925.      * @see TimeScales#getJ2000Epoch()
  926.      */
  927.     @DefaultDataContext
  928.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getJ2000Epoch(final Field<T> field) {
  929.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getJ2000Epoch());
  930.     }

  931.     /** Java Reference epoch: 1970-01-01T00:00:00 Universal Time Coordinate.
  932.      *
  933.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  934.      *
  935.      * <p>
  936.      * Between 1968-02-01 and 1972-01-01, UTC-TAI = 4.213 170 0s + (MJD - 39 126) x 0.002 592s.
  937.      * As on 1970-01-01 MJD = 40587, UTC-TAI = 8.000082s
  938.      * </p>
  939.      * @param <T> the type of the field elements
  940.      * @param field field for the components
  941.      * @return the Java reference epoch as a FieldAbsoluteDate
  942.      * @see AbsoluteDate#JAVA_EPOCH
  943.      * @see TimeScales#getJavaEpoch()
  944.      */
  945.     @DefaultDataContext
  946.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getJavaEpoch(final Field<T> field) {
  947.         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getJavaEpoch());
  948.     }

  949.     /** Dummy date at infinity in the past direction.
  950.      * @param <T> the type of the field elements
  951.      * @param field field for the components
  952.      * @return a dummy date at infinity in the past direction as a FieldAbsoluteDate
  953.      * @see AbsoluteDate#PAST_INFINITY
  954.      * @see TimeScales#getPastInfinity()
  955.      */
  956.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getPastInfinity(final Field<T> field) {
  957.         return new FieldAbsoluteDate<>(field, AbsoluteDate.PAST_INFINITY);
  958.     }

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

  969.     /**
  970.      * Get an arbitrary date. Useful when a non-null date is needed but its values does
  971.      * not matter.
  972.      *
  973.      * @param <T>   the type of the field elements
  974.      * @param field field for the components
  975.      * @return an arbitrary date.
  976.      */
  977.     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getArbitraryEpoch(final Field<T> field) {
  978.         return new FieldAbsoluteDate<>(field, AbsoluteDate.ARBITRARY_EPOCH);
  979.     }


  980.     /** Get a time-shifted date.
  981.      * <p>
  982.      * Calling this method is equivalent to call {@code new FieldAbsoluteDate&lt;&gt;(this, dt)}.
  983.      * </p>
  984.      * @param dt time shift in seconds
  985.      * @return a new date, shifted with respect to instance (which is immutable)
  986.      * @see org.orekit.utils.FieldPVCoordinates#shiftedBy(double)
  987.      * @see org.orekit.attitudes.FieldAttitude#shiftedBy(double)
  988.      * @see org.orekit.orbits.FieldOrbit#shiftedBy(double)
  989.      * @see org.orekit.propagation.FieldSpacecraftState#shiftedBy(double)
  990.      */
  991.     @Override
  992.     public FieldAbsoluteDate<T> shiftedBy(final T dt) {
  993.         return new FieldAbsoluteDate<>(this, dt);
  994.     }

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

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

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

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

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

  1113.     /** Compute the offset between two time scales at the current instant.
  1114.      * <p>The offset is defined as <i>l₁-l₂</i>
  1115.      * where <i>l₁</i> is the location of the instant in
  1116.      * the <code>scale1</code> time scale and <i>l₂</i> is the
  1117.      * location of the instant in the <code>scale2</code> time scale.</p>
  1118.      * @param scale1 first time scale
  1119.      * @param scale2 second time scale
  1120.      * @return offset in seconds between the two time scales at the
  1121.      * current instant
  1122.      */
  1123.     public T timeScalesOffset(final TimeScale scale1, final TimeScale scale2) {
  1124.         return scale1.offsetFromTAI(this).subtract(scale2.offsetFromTAI(this));
  1125.     }

  1126.     /** Convert the instance to a Java {@link java.util.Date Date}.
  1127.      * <p>Conversion to the Date class induces a loss of precision because
  1128.      * the Date class does not provide sub-millisecond information. Java Dates
  1129.      * are considered to be locations in some times scales.</p>
  1130.      * @param timeScale time scale to use
  1131.      * @return a {@link java.util.Date Date} instance representing the location
  1132.      * of the instant in the time scale
  1133.      */
  1134.     public Date toDate(final TimeScale timeScale) {
  1135.         return date.toDate(timeScale);
  1136.     }

  1137.     /**
  1138.      * Convert the instance to a Java {@link java.time.Instant Instant}.
  1139.      * Nanosecond precision is preserved during this conversion
  1140.      *
  1141.      * @return a {@link java.time.Instant Instant} instance representing the location
  1142.      * of the instant in the utc time scale
  1143.      * @since 12.1
  1144.      */
  1145.     @DefaultDataContext
  1146.     public Instant toInstant() {
  1147.         return toInstant(TimeScalesFactory.getTimeScales());
  1148.     }

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

  1161.     /** Split the instance into date/time components.
  1162.      * @param timeScale time scale to use
  1163.      * @return date/time components
  1164.      */
  1165.     public DateTimeComponents getComponents(final TimeScale timeScale) {
  1166.         return date.getComponents(timeScale);
  1167.     }

  1168.     /** Split the instance into date/time components for a local time.
  1169.      *
  1170.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  1171.      *
  1172.      * @param minutesFromUTC offset in <em>minutes</em> from UTC (positive Eastwards UTC,
  1173.      * negative Westward UTC)
  1174.      * @return date/time components
  1175.      * @see #getComponents(int, TimeScale)
  1176.      */
  1177.     @DefaultDataContext
  1178.     public DateTimeComponents getComponents(final int minutesFromUTC) {
  1179.         return date.getComponents(minutesFromUTC);
  1180.     }

  1181.     /**
  1182.      * Split the instance into date/time components for a local time.
  1183.      *
  1184.      * @param minutesFromUTC offset in <em>minutes</em> from UTC (positive Eastwards UTC,
  1185.      *                       negative Westward UTC)
  1186.      * @param utc            time scale used to compute date and time components.
  1187.      * @return date/time components
  1188.      * @since 10.1
  1189.      */
  1190.     public DateTimeComponents getComponents(final int minutesFromUTC, final TimeScale utc) {
  1191.         return date.getComponents(minutesFromUTC, utc);
  1192.     }

  1193.     /** {@inheritDoc} */
  1194.     @Override
  1195.     public FieldAbsoluteDate<T> getDate() {
  1196.         return this;
  1197.     }

  1198.     /** Get the field.
  1199.      * @return field instance.
  1200.      */
  1201.     public Field<T> getField() {
  1202.         return fieldOffset.getField();
  1203.     }

  1204.     /** Split the instance into date/time components for a time zone.
  1205.      *
  1206.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  1207.      *
  1208.      * @param timeZone time zone
  1209.      * @return date/time components
  1210.      * @see #getComponents(TimeZone, TimeScale)
  1211.      */
  1212.     @DefaultDataContext
  1213.     public DateTimeComponents getComponents(final TimeZone timeZone) {
  1214.         return date.getComponents(timeZone);
  1215.     }

  1216.     /** Split the instance into date/time components for a time zone.
  1217.      * @param timeZone time zone
  1218.      * @param utc            time scale used to compute date and time components.
  1219.      * @return date/time components
  1220.      * @since 10.1
  1221.      */
  1222.     public DateTimeComponents getComponents(final TimeZone timeZone, final TimeScale utc) {
  1223.         return date.getComponents(timeZone, utc);
  1224.     }

  1225.     /** Compare the instance with another date.
  1226.      * @param other other date to compare the instance to
  1227.      * @return a negative integer, zero, or a positive integer as this date
  1228.      * is before, simultaneous, or after the specified date.
  1229.      */
  1230.     public int compareTo(final FieldAbsoluteDate<T> other) {
  1231.         return date.compareTo(other.date);
  1232.     }


  1233.     /** Check if the instance represents the same time as another instance.
  1234.      * @param other other date
  1235.      * @return true if the instance and the other date refer to the same instant
  1236.      */
  1237.     public boolean equals(final Object other) {

  1238.         if (other == this) {
  1239.             // first fast check
  1240.             return true;
  1241.         }

  1242.         if (other instanceof FieldAbsoluteDate) {
  1243.             final FieldAbsoluteDate<?> otherF = (FieldAbsoluteDate<?>) other;
  1244.             return fieldOffset.getField().equals(otherF.fieldOffset.getField()) &&
  1245.                    date.equals(otherF.date);
  1246.         }

  1247.         return false;

  1248.     }

  1249.     /** Check if the instance represents the same time as another.
  1250.      * @param other the instant to compare this date to
  1251.      * @return true if the instance and the argument refer to the same instant
  1252.      * @see #isCloseTo(FieldTimeStamped, double)
  1253.      * @since 10.1
  1254.      */
  1255.     public boolean isEqualTo(final FieldTimeStamped<T> other) {
  1256.         return this.equals(other.getDate());
  1257.     }

  1258.     /** Check if the instance time is close to another.
  1259.      * @param other the instant to compare this date to
  1260.      * @param tolerance the separation, in seconds, under which the two instants will be considered close to each other
  1261.      * @return true if the duration between the instance and the argument is strictly below the tolerance
  1262.      * @see #isEqualTo(FieldTimeStamped)
  1263.      * @since 10.1
  1264.      */
  1265.     public boolean isCloseTo(final FieldTimeStamped<T> other, final double tolerance) {
  1266.         return date.isCloseTo(other.getDate().date, tolerance);
  1267.     }

  1268.     /** Check if the instance represents a time that is strictly before another.
  1269.      * @param other the instant to compare this date to
  1270.      * @return true if the instance is strictly before the argument when ordering chronologically
  1271.      * @see #isBeforeOrEqualTo(FieldTimeStamped)
  1272.      * @since 10.1
  1273.      */
  1274.     public boolean isBefore(final FieldTimeStamped<T> other) {
  1275.         return date.isBefore(other.getDate().date);
  1276.     }

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

  1286.     /** Check if the instance represents a time that is before or equal to another.
  1287.      * @param other the instant to compare this date to
  1288.      * @return true if the instance is before (or equal to) the argument when ordering chronologically
  1289.      * @see #isBefore(FieldTimeStamped)
  1290.      * @since 10.1
  1291.      */
  1292.     public boolean isBeforeOrEqualTo(final FieldTimeStamped<T> other) {
  1293.         return date.isBeforeOrEqualTo(other.getDate().date);
  1294.     }

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

  1304.     /** Check if the instance represents a time that is strictly between two others representing
  1305.      * the boundaries of a time span. The two boundaries can be provided in any order: in other words,
  1306.      * whether <code>boundary</code> represents a time that is before or after <code>otherBoundary</code> will
  1307.      * not change the result of this method.
  1308.      * @param boundary one end of the time span
  1309.      * @param otherBoundary the other end of the time span
  1310.      * @return true if the instance is strictly between the two arguments when ordering chronologically
  1311.      * @see #isBetweenOrEqualTo(FieldTimeStamped, FieldTimeStamped)
  1312.      * @since 10.1
  1313.      */
  1314.     public boolean isBetween(final FieldTimeStamped<T> boundary, final FieldTimeStamped<T> otherBoundary) {
  1315.         return date.isBetween(boundary.getDate().date, otherBoundary.getDate().date);
  1316.     }

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

  1331.     /** Get a hashcode for this date.
  1332.      * @return hashcode
  1333.      */
  1334.     public int hashCode() {
  1335.         return date.hashCode();
  1336.     }

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

  1359.     /**
  1360.      * Get a String representation of the instant location in ISO-8601 format without the
  1361.      * UTC offset and with up to 16 digits of precision for the seconds value.
  1362.      *
  1363.      * @param timeScale time scale to use
  1364.      * @return a string representation of the instance.
  1365.      * @see DateTimeComponents#toString(int, int)
  1366.      */
  1367.     public String toString(final TimeScale timeScale) {
  1368.         return date.toString(timeScale);
  1369.     }

  1370.     /** Get a String representation of the instant location for a local time.
  1371.      *
  1372.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  1373.      *
  1374.      * @param minutesFromUTC offset in <em>minutes</em> from UTC (positive Eastwards UTC,
  1375.      * negative Westward UTC).
  1376.      * @return string representation of the instance,
  1377.      * in ISO-8601 format with milliseconds accuracy
  1378.      * @see #toString(int, TimeScale)
  1379.      */
  1380.     @DefaultDataContext
  1381.     public String toString(final int minutesFromUTC) {
  1382.         return date.toString(minutesFromUTC);
  1383.     }

  1384.     /**
  1385.      * Get a String representation of the instant location for a local time.
  1386.      *
  1387.      * @param minutesFromUTC offset in <em>minutes</em> from UTC (positive Eastwards UTC,
  1388.      *                       negative Westward UTC).
  1389.      * @param utc            time scale used to compute date and time components.
  1390.      * @return string representation of the instance, in ISO-8601 format with milliseconds
  1391.      * accuracy
  1392.      * @since 10.1
  1393.      */
  1394.     public String toString(final int minutesFromUTC, final TimeScale utc) {
  1395.         return date.toString(minutesFromUTC, utc);
  1396.     }

  1397.     /** Get a String representation of the instant location for a time zone.
  1398.      *
  1399.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  1400.      *
  1401.      * @param timeZone time zone
  1402.      * @return string representation of the instance,
  1403.      * in ISO-8601 format with milliseconds accuracy
  1404.      * @see #toString(TimeZone, TimeScale)
  1405.      */
  1406.     @DefaultDataContext
  1407.     public String toString(final TimeZone timeZone) {
  1408.         return date.toString(timeZone);
  1409.     }

  1410.     /**
  1411.      * Get a String representation of the instant location for a time zone.
  1412.      *
  1413.      * @param timeZone time zone
  1414.      * @param utc      time scale used to compute date and time components.
  1415.      * @return string representation of the instance, in ISO-8601 format with milliseconds
  1416.      * accuracy
  1417.      * @since 10.1
  1418.      */
  1419.     public String toString(final TimeZone timeZone, final TimeScale utc) {
  1420.         return date.toString(timeZone, utc);
  1421.     }

  1422.     /**
  1423.      * Return a string representation of this date-time, rounded to the given precision.
  1424.      *
  1425.      * <p>The format used is ISO8601 without the UTC offset.</p>
  1426.      *
  1427.      *
  1428.      * @param timeScale      to use to compute components.
  1429.      * @param fractionDigits the number of digits to include after the decimal point in
  1430.      *                       the string representation of the seconds. The date and time
  1431.      *                       is first rounded as necessary. {@code fractionDigits} must be
  1432.      *                       greater than or equal to {@code 0}.
  1433.      * @return string representation of this date, time, and UTC offset
  1434.      * @see #toString(TimeScale)
  1435.      * @see DateTimeComponents#toString(int, int)
  1436.      * @see DateTimeComponents#toStringWithoutUtcOffset(int, int)
  1437.      * @since 12.2
  1438.      */
  1439.     public String toStringWithoutUtcOffset(final TimeScale timeScale, final int fractionDigits) {
  1440.         return date.toStringWithoutUtcOffset(timeScale, fractionDigits);
  1441.     }

  1442.     /** Get a time-shifted date.
  1443.      * <p>
  1444.      * Calling this method is equivalent to call <code>new FieldAbsoluteDate(this, dt)</code>.
  1445.      * </p>
  1446.      * @param dt time shift in seconds
  1447.      * @return a new date, shifted with respect to instance (which is immutable)
  1448.      * @see org.orekit.utils.FieldPVCoordinates#shiftedBy(double)
  1449.      * @see org.orekit.attitudes.FieldAttitude#shiftedBy(double)
  1450.      * @see org.orekit.orbits.FieldOrbit#shiftedBy(double)
  1451.      * @see org.orekit.propagation.FieldSpacecraftState#shiftedBy(double)
  1452.      */
  1453.     @Override
  1454.     public FieldAbsoluteDate<T> shiftedBy(final double dt) {
  1455.         return new FieldAbsoluteDate<>(this, dt);
  1456.     }

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

  1473.     /** Get a time-shifted date.
  1474.      * <p>
  1475.      * Calling this method is equivalent to call <code>new FieldAbsoluteDate(this, dt, timeUnit)</code>.
  1476.      * </p>
  1477.      * @param dt time shift in time units
  1478.      * @param timeUnit {@link TimeUnit} for dt
  1479.      * @return a new date, shifted with respect to instance (which is immutable)
  1480.      * @see org.orekit.utils.FieldPVCoordinates#shiftedBy(double)
  1481.      * @see org.orekit.attitudes.FieldAttitude#shiftedBy(double)
  1482.      * @see org.orekit.orbits.FieldOrbit#shiftedBy(double)
  1483.      * @see org.orekit.propagation.FieldSpacecraftState#shiftedBy(double)
  1484.      * @since 12.1
  1485.      */
  1486.     public FieldAbsoluteDate<T> shiftedBy(final long dt, final TimeUnit timeUnit) {
  1487.         return new FieldAbsoluteDate<>(this, dt, timeUnit);
  1488.     }


  1489.     /** Transform the FieldAbsoluteDate in an AbsoluteDate.
  1490.      * @return AbsoluteDate of the FieldObject
  1491.      * */
  1492.     public AbsoluteDate toAbsoluteDate() {
  1493.         return date;
  1494.     }

  1495.     /** Check if the Field is semantically equal to zero.
  1496.      *
  1497.      * <p> Using {@link FieldElement#isZero()}
  1498.      *
  1499.      * @return true the Field is semantically equal to zero
  1500.      * @since 12.0
  1501.      */
  1502.     public boolean hasZeroField() {
  1503.         return fieldOffset.getAddendum().isZero();
  1504.     }

  1505.     /**
  1506.      * Return the given date as a Modified Julian Date <b>expressed in UTC</b>.
  1507.      *
  1508.      * @return double representation of the given date as Modified Julian Date.
  1509.      * @since 12.2
  1510.      */
  1511.     @DefaultDataContext
  1512.     public T getMJD() {
  1513.         return this.getMJD(TimeScalesFactory.getUTC());
  1514.     }

  1515.     /**
  1516.      * Return the given date as a Modified Julian Date expressed in given timescale.
  1517.      *
  1518.      * @param ts time scale
  1519.      * @return double representation of the given date as Modified Julian Date.
  1520.      * @since 12.2
  1521.      */
  1522.     public T getMJD(final TimeScale ts) {
  1523.         final T shift = fieldOffset.divide(Constants.JULIAN_DAY);
  1524.         return shift.add(date.getMJD(ts));
  1525.     }

  1526.     /**
  1527.      * Return the given date as a Julian Date <b>expressed in UTC</b>.
  1528.      *
  1529.      * @return double representation of the given date as Julian Date.
  1530.      * @since 12.2
  1531.      */
  1532.     @DefaultDataContext
  1533.     public T getJD() {
  1534.         return getJD(TimeScalesFactory.getUTC());
  1535.     }

  1536.     /**
  1537.      * Return the given date as a Julian Date expressed in given timescale.
  1538.      *
  1539.      * @param ts time scale
  1540.      * @return double representation of the given date as Julian Date.
  1541.      * @since 12.2
  1542.      */
  1543.     public T getJD(final TimeScale ts) {
  1544.         final T shift = fieldOffset.divide(Constants.JULIAN_DAY);
  1545.         return shift.add(date.getJD(ts));
  1546.     }

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

  1569. }