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  
19  import java.time.Instant;
20  import java.util.Date;
21  import java.util.TimeZone;
22  
23  import java.util.concurrent.TimeUnit;
24  import org.hipparchus.CalculusFieldElement;
25  import org.hipparchus.Field;
26  import org.hipparchus.FieldElement;
27  import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative1;
28  import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative1Field;
29  import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative2;
30  import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative2Field;
31  import org.hipparchus.util.FastMath;
32  import org.orekit.annotation.DefaultDataContext;
33  import org.orekit.data.DataContext;
34  import org.orekit.utils.Constants;
35  
36  /** This class represents a specific instant in time.
37  
38   * <p>Instances of this class are considered to be absolute in the sense
39   * that each one represent the occurrence of some event and can be compared
40   * to other instances or located in <em>any</em> {@link TimeScale time scale}. In
41   * other words the different locations of an event with respect to two different
42   * time scales (say {@link TAIScale TAI} and {@link UTCScale UTC} for example) are
43   * simply different perspective related to a single object. Only one
44   * <code>FieldAbsoluteDate&lt;T&gt;</code> instance is needed, both representations being available
45   * from this single instance by specifying the time scales as parameter when calling
46   * the ad-hoc methods.</p>
47   *
48   * <p>Since an instance is not bound to a specific time-scale, all methods related
49   * to the location of the date within some time scale require to provide the time
50   * scale as an argument. It is therefore possible to define a date in one time scale
51   * and to use it in another one. An example of such use is to read a date from a file
52   * in UTC and write it in another file in TAI. This can be done as follows:</p>
53   * <pre>
54   *   DateTimeComponents utcComponents = readNextDate();
55   *   FieldAbsoluteDate&lt;T&gt; date = new FieldAbsoluteDate&lt;&gt;(utcComponents, TimeScalesFactory.getUTC());
56   *   writeNextDate(date.getComponents(TimeScalesFactory.getTAI()));
57   * </pre>
58   *
59   * <p>Two complementary views are available:</p>
60   * <ul>
61   *   <li><p>location view (mainly for input/output or conversions)</p>
62   *   <p>locations represent the coordinate of one event with respect to a
63   *   {@link TimeScale time scale}. The related methods are {@link
64   *   #FieldAbsoluteDate(Field, DateComponents, TimeComponents, TimeScale)}, {@link
65   *   #FieldAbsoluteDate(Field, int, int, int, int, int, double, TimeScale)}, {@link
66   *   #FieldAbsoluteDate(Field, int, int, int, TimeScale)}, {@link #FieldAbsoluteDate(Field,
67   *   Date, TimeScale)}, {@link #createGPSDate(int, CalculusFieldElement)}, {@link
68   *   #parseCCSDSCalendarSegmentedTimeCode(byte, byte[])}, {@link #toDate(TimeScale)},
69   *   {@link #toString(TimeScale) toString(timeScale)}, {@link #toString()},
70   *   and {@link #timeScalesOffset}.</p>
71   *   </li>
72   *   <li><p>offset view (mainly for physical computation)</p>
73   *   <p>offsets represent either the flow of time between two events
74   *   (two instances of the class) or durations. They are counted in seconds,
75   *   are continuous and could be measured using only a virtually perfect stopwatch.
76   *   The related methods are {@link #FieldAbsoluteDate(FieldAbsoluteDate, double)},
77   *   {@link #parseCCSDSUnsegmentedTimeCode(Field, byte, byte, byte[], FieldAbsoluteDate)},
78   *   {@link #parseCCSDSDaySegmentedTimeCode(Field, byte, byte[], DateComponents)},
79   *   {@link #durationFrom(FieldAbsoluteDate)}, {@link #compareTo(FieldAbsoluteDate)}, {@link #equals(Object)}
80   *   and {@link #hashCode()}.</p>
81   *   </li>
82   * </ul>
83   * <p>
84   * A few reference epochs which are commonly used in space systems have been defined. These
85   * epochs can be used as the basis for offset computation. The supported epochs are:
86   * {@link #getJulianEpoch(Field)}, {@link #getModifiedJulianEpoch(Field)}, {@link #getFiftiesEpoch(Field)},
87   * {@link #getCCSDSEpoch(Field)}, {@link #getGalileoEpoch(Field)}, {@link #getGPSEpoch(Field)},
88   * {@link #getJ2000Epoch(Field)}, {@link #getJavaEpoch(Field)}. There are also two factory methods
89   * {@link #createJulianEpoch(CalculusFieldElement)} and {@link #createBesselianEpoch(CalculusFieldElement)}
90   * that can be used to compute other reference epochs like J1900.0 or B1950.0.
91   * In addition to these reference epochs, two other constants are defined for convenience:
92   * {@link #getPastInfinity(Field)} and {@link #getFutureInfinity(Field)}, which can be used either
93   * as dummy dates when a date is not yet initialized, or for initialization of loops searching for
94   * a min or max date.
95   * </p>
96   * <p>
97   * Instances of the <code>FieldAbsoluteDate&lt;T&gt;</code> class are guaranteed to be immutable.
98   * </p>
99   * @author Luc Maisonobe
100  * @see TimeScale
101  * @see TimeStamped
102  * @see ChronologicalComparator
103  * @param <T> type of the field elements
104  */
105 public class FieldAbsoluteDate<T extends CalculusFieldElement<T>>
106         implements FieldTimeStamped<T>, FieldTimeShiftable<FieldAbsoluteDate<T>, T>, Comparable<FieldAbsoluteDate<T>> {
107 
108     /** Underlying regular date.
109      * @since 13.0
110      */
111     private final AbsoluteDate date;
112 
113     /** Field-specific offset ({@link CalculusFieldElement#getReal() is always 0)}.
114      * @since 13.0
115      */
116     private final T fieldOffset;
117 
118     /** Build an instance from an AbsoluteDate.
119      * @param field used by default
120      * @param date AbsoluteDate to instantiate as a FieldAbsoluteDate
121      */
122     public FieldAbsoluteDate(final Field<T> field, final AbsoluteDate date) {
123         this.date = date;
124         this.fieldOffset = field.getZero();
125     }
126 
127     /** Create an instance with a default value ({@link #getJ2000Epoch(Field)}).
128      *
129      * <p>This method uses the {@link DataContext#getDefault() default data context}.
130      *
131      * @param field field used by default
132      * @see #FieldAbsoluteDate(Field, AbsoluteDate)
133      */
134     @DefaultDataContext
135     public FieldAbsoluteDate(final Field<T> field) {
136         this.date        = AbsoluteDate.J2000_EPOCH;
137         this.fieldOffset = field.getZero();
138     }
139 
140     /** Build an instance from an elapsed duration since another instant.
141      * <p>It is important to note that the elapsed duration is <em>not</em>
142      * the difference between two readings on a time scale. As an example,
143      * the duration between the two instants leading to the readings
144      * 2005-12-31T23:59:59 and 2006-01-01T00:00:00 in the {@link UTCScale UTC}
145      * time scale is <em>not</em> 1 second, but a stop watch would have measured
146      * an elapsed duration of 2 seconds between these two instances because a leap
147      * second was introduced at the end of 2005 in this time scale.</p>
148      * <p>This constructor is the reverse of the {@link #durationFrom(FieldAbsoluteDate)}
149      * method.</p>
150      * @param since start instant of the measured duration
151      * @param elapsedDuration physically elapsed duration from the <code>since</code>
152      * instant, as measured in a regular time scale
153      * @see #durationFrom(FieldAbsoluteDate)
154      */
155     public FieldAbsoluteDate(final FieldAbsoluteDate<T> since, final T elapsedDuration) {
156         this.date        = since.date.shiftedBy(elapsedDuration.getReal());
157         this.fieldOffset = since.fieldOffset.add(elapsedDuration.getAddendum());
158     }
159 
160     /** Build an instance from a location (parsed from a string) in a {@link TimeScale time scale}.
161      * <p>
162      * The supported formats for location are mainly the ones defined in ISO-8601 standard,
163      * the exact subset is explained in {@link DateTimeComponents#parseDateTime(String)},
164      * {@link DateComponents#parseDate(String)} and {@link TimeComponents#parseTime(String)}.
165      * </p>
166      * <p>
167      * As CCSDS ASCII calendar segmented time code is a trimmed down version of ISO-8601,
168      * it is also supported by this constructor.
169      * </p>
170      * @param field field utilized by default
171      * @param location location in the time scale, must be in a supported format
172      * @param timeScale time scale
173      * @exception IllegalArgumentException if location string is not in a supported format
174      */
175     public FieldAbsoluteDate(final Field<T> field, final String location, final TimeScale timeScale) {
176         this(field, DateTimeComponents.parseDateTime(location), timeScale);
177     }
178 
179     /** Build an instance from a location in a {@link TimeScale time scale}.
180      * @param field field utilized by default
181      * @param location location in the time scale
182      * @param timeScale time scale
183      */
184     public FieldAbsoluteDate(final Field<T> field, final DateTimeComponents location, final TimeScale timeScale) {
185         this(field, location.getDate(), location.getTime(), timeScale);
186     }
187 
188     /** Build an instance from a location in a {@link TimeScale time scale}.
189      * @param field field utilized by default
190      * @param date date location in the time scale
191      * @param time time location in the time scale
192      * @param timeScale time scale
193      */
194     public FieldAbsoluteDate(final Field<T> field, final DateComponents date, final TimeComponents time,
195                              final TimeScale timeScale) {
196         this.date        = new AbsoluteDate(date, time, timeScale);
197         this.fieldOffset = field.getZero();
198     }
199 
200     /** Build an instance from a location in a {@link TimeScale time scale}.
201      * @param field field utilized by default
202      * @param year year number (may be 0 or negative for BC years)
203      * @param month month number from 1 to 12
204      * @param day day number from 1 to 31
205      * @param hour hour number from 0 to 23
206      * @param minute minute number from 0 to 59
207      * @param second second number from 0.0 to 60.0 (excluded)
208      * @param timeScale time scale
209      * @exception IllegalArgumentException if inconsistent arguments
210      * are given (parameters out of range)
211      */
212     public FieldAbsoluteDate(final Field<T> field, final int year, final int month, final int day,
213                              final int hour, final int minute, final double second,
214                              final TimeScale timeScale) throws IllegalArgumentException {
215         this(field, year, month, day, hour, minute, new TimeOffset(second), timeScale);
216     }
217 
218     /** Build an instance from a location in a {@link TimeScale time scale}.
219      * @param field field utilized by default
220      * @param year year number (may be 0 or negative for BC years)
221      * @param month month number from 1 to 12
222      * @param day day number from 1 to 31
223      * @param hour hour number from 0 to 23
224      * @param minute minute number from 0 to 59
225      * @param second second number from 0.0 to 60.0 (excluded)
226      * @param timeScale time scale
227      * @exception IllegalArgumentException if inconsistent arguments
228      * are given (parameters out of range)
229      * @since 13.0
230      */
231     public FieldAbsoluteDate(final Field<T> field, final int year, final int month, final int day,
232                              final int hour, final int minute, final TimeOffset second,
233                              final TimeScale timeScale) throws IllegalArgumentException {
234         this(field, new DateComponents(year, month, day), new TimeComponents(hour, minute, second), timeScale);
235     }
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      */
249     public FieldAbsoluteDate(final Field<T> field, final int year, final Month month, final int day,
250                              final int hour, final int minute, final double second,
251                              final TimeScale timeScale) throws IllegalArgumentException {
252         this(field, year, month, day, hour, minute, new TimeOffset(second), timeScale);
253     }
254 
255     /** Build an instance from a location in a {@link TimeScale time scale}.
256      * @param field field utilized by default
257      * @param year year number (may be 0 or negative for BC years)
258      * @param month month enumerate
259      * @param day day number from 1 to 31
260      * @param hour hour number from 0 to 23
261      * @param minute minute number from 0 to 59
262      * @param second second number from 0.0 to 60.0 (excluded)
263      * @param timeScale time scale
264      * @exception IllegalArgumentException if inconsistent arguments
265      * are given (parameters out of range)
266      * @since 13.0
267      */
268     public FieldAbsoluteDate(final Field<T> field, final int year, final Month month, final int day,
269                              final int hour, final int minute, final TimeOffset second,
270                              final TimeScale timeScale) throws IllegalArgumentException {
271         this(field, new DateComponents(year, month, day), new TimeComponents(hour, minute, second), timeScale);
272     }
273 
274     /** Build an instance from a location in a {@link TimeScale time scale}.
275      * <p>The hour is set to 00:00:00.000.</p>
276      * @param field field utilized by default
277      * @param date date location in the time scale
278      * @param timeScale time scale
279      * @exception IllegalArgumentException if inconsistent arguments
280      * are given (parameters out of range)
281      */
282     public FieldAbsoluteDate(final Field<T> field, final DateComponents date, final TimeScale timeScale)
283                     throws IllegalArgumentException {
284         this(field, date, TimeComponents.H00, timeScale);
285     }
286 
287     /** Build an instance from a location in a {@link TimeScale time scale}.
288      * <p>The hour is set to 00:00:00.000.</p>
289      * @param field field utilized by default
290      * @param year year number (may be 0 or negative for BC years)
291      * @param month month number from 1 to 12
292      * @param day day number from 1 to 31
293      * @param timeScale time scale
294      * @exception IllegalArgumentException if inconsistent arguments
295      * are given (parameters out of range)
296      */
297     public FieldAbsoluteDate(final Field<T> field, final int year, final int month, final int day,
298                              final TimeScale timeScale) throws IllegalArgumentException {
299         this(field, new DateComponents(year, month, day), TimeComponents.H00, timeScale);
300     }
301 
302     /** Build an instance from a location in a {@link TimeScale time scale}.
303      * <p>The hour is set to 00:00:00.000.</p>
304      * @param field field utilized by default
305      * @param year year number (may be 0 or negative for BC years)
306      * @param month month enumerate
307      * @param day day number from 1 to 31
308      * @param timeScale time scale
309      * @exception IllegalArgumentException if inconsistent arguments
310      * are given (parameters out of range)
311      */
312     public FieldAbsoluteDate(final Field<T> field, final int year, final Month month, final int day,
313                              final TimeScale timeScale) throws IllegalArgumentException {
314         this(field, new DateComponents(year, month, day), TimeComponents.H00, timeScale);
315     }
316 
317     /** Build an instance from a location in a {@link TimeScale time scale}.
318      * @param field field utilized as default
319      * @param location location in the time scale
320      * @param timeScale time scale
321      */
322     public FieldAbsoluteDate(final Field<T> field, final Date location, final TimeScale timeScale) {
323         this(field,
324              new DateComponents(DateComponents.JAVA_EPOCH, (int) (location.getTime() / 86400000L)),
325              new TimeComponents(new TimeOffset(location.getTime() % 86400000L, TimeOffset.MILLISECOND)),
326              timeScale);
327     }
328 
329     /** Build an instance from an {@link Instant instant} in a {@link TimeScale time scale}.
330      * @param field field utilized as default
331      * @param instant instant in the time scale
332      * @param timeScale time scale
333      * @since 12.0
334      */
335     public FieldAbsoluteDate(final Field<T> field, final Instant instant, final TimeScale timeScale) {
336         this(field,
337              new DateComponents(DateComponents.JAVA_EPOCH, (int) (instant.getEpochSecond() / 86400L)),
338              new TimeComponents(new TimeOffset(instant.getEpochSecond() % 86400L, TimeOffset.SECOND,
339                                                instant.getNano(), TimeOffset.NANOSECOND)),
340              timeScale);
341     }
342 
343     /** Build an instance from an {@link Instant instant} in utc time scale.
344      * @param field field utilized as default
345      * @param instant instant in the utc timescale
346      * @since 12.1
347      */
348     @DefaultDataContext
349     public FieldAbsoluteDate(final Field<T> field, final Instant instant) {
350         this(field, instant, TimeScalesFactory.getUTC());
351     }
352 
353     /** Build an instance from an {@link Instant instant} in the {@link UTCScale time scale}.
354      * @param field field utilized as default
355      * @param instant instant in the time scale
356      * @param utcScale utc time scale
357      * @since 12.1
358      */
359     public FieldAbsoluteDate(final Field<T> field, final Instant instant, final UTCScale utcScale) {
360         this(field,
361              new DateComponents(DateComponents.JAVA_EPOCH, (int) (instant.getEpochSecond() / 86400L)),
362              new TimeComponents(new TimeOffset(instant.getEpochSecond() % 86400L, TimeOffset.SECOND,
363                                                instant.getNano(), TimeOffset.NANOSECOND)),
364             utcScale);
365     }
366 
367     /** Build an instance from an elapsed duration since another instant.
368      * <p>It is important to note that the elapsed duration is <em>not</em>
369      * the difference between two readings on a time scale.
370      * @param since start instant of the measured duration
371      * @param elapsedDuration physically elapsed duration from the <code>since</code>
372      * instant, as measured in a regular time scale
373      */
374     public FieldAbsoluteDate(final FieldAbsoluteDate<T> since, final double elapsedDuration) {
375         this(since, new TimeOffset(elapsedDuration));
376     }
377 
378     /** Build an instance from an elapsed duration since another instant.
379      * <p>It is important to note that the elapsed duration is <em>not</em>
380      * the difference between two readings on a time scale.
381      * @param since start instant of the measured duration
382      * @param elapsedDuration physically elapsed duration from the <code>since</code>
383      * instant, as measured in a regular time scale
384      * @since 13.0
385      */
386     public FieldAbsoluteDate(final FieldAbsoluteDate<T> since, final TimeOffset elapsedDuration) {
387         this.date        = since.date.shiftedBy(elapsedDuration);
388         this.fieldOffset = since.fieldOffset;
389     }
390 
391     /** Build an instance from an elapsed duration since another instant.
392      * <p>It is important to note that the elapsed duration is <em>not</em>
393      * the difference between two readings on a time scale.
394      * @param since start instant of the measured duration
395      * @param elapsedDuration physically elapsed duration from the <code>since</code>
396      * instant, as measured in a regular time scale
397      * @param timeUnit {@link TimeUnit} of the elapsed duration
398      * @since 12.1
399      */
400     public FieldAbsoluteDate(final FieldAbsoluteDate<T> since, final long elapsedDuration, final TimeUnit timeUnit) {
401         this.date        = since.date.shiftedBy(elapsedDuration, timeUnit);
402         this.fieldOffset = since.fieldOffset;
403     }
404 
405 
406     /** Build an instance from an elapsed duration since another instant.
407      * <p>It is important to note that the elapsed duration is <em>not</em>
408      * the difference between two readings on a time scale.
409      * @param since start instant of the measured duration
410      * @param elapsedDuration physically elapsed duration from the <code>since</code>
411      * instant, as measured in a regular time scale
412      */
413     public FieldAbsoluteDate(final AbsoluteDate since, final T elapsedDuration) {
414         this.date        = since.shiftedBy(elapsedDuration.getReal());
415         this.fieldOffset = elapsedDuration.getAddendum();
416     }
417 
418     /** Build an instance from an elapsed duration since another instant.
419      * <p>It is important to note that the elapsed duration is <em>not</em>
420      * the difference between two readings on a time scale.
421      * @param since start instant of the measured duration
422      * @param elapsedDuration physically elapsed duration from the <code>since</code>
423      * instant, as measured in a regular time scale
424      * @param timeUnit {@link TimeUnit} of the elapsed duration
425      * @param field field utilized by default
426      * @since 12.1
427      */
428     public FieldAbsoluteDate(final AbsoluteDate since, final long elapsedDuration, final TimeUnit timeUnit, final Field<T> field) {
429         this.date        = since.shiftedBy(elapsedDuration, timeUnit);
430         this.fieldOffset = field.getZero();
431     }
432 
433     /** Build an instance from an apparent clock offset with respect to another
434      * instant <em>in the perspective of a specific {@link TimeScale time scale}</em>.
435      * <p>It is important to note that the apparent clock offset <em>is</em> the
436      * difference between two readings on a time scale and <em>not</em> an elapsed
437      * duration. As an example, the apparent clock offset between the two instants
438      * leading to the readings 2005-12-31T23:59:59 and 2006-01-01T00:00:00 in the
439      * {@link UTCScale UTC} time scale is 1 second, but the elapsed duration is 2
440      * seconds because a leap second has been introduced at the end of 2005 in this
441      * time scale.</p>
442      * <p>This constructor is the reverse of the {@link #offsetFrom(FieldAbsoluteDate,
443      * TimeScale)} method.</p>
444      * @param reference reference instant
445      * @param apparentOffset apparent clock offset from the reference instant
446      * (difference between two readings in the specified time scale)
447      * @param timeScale time scale with respect to which the offset is defined
448      * @see #offsetFrom(FieldAbsoluteDate, TimeScale)
449      */
450     public FieldAbsoluteDate(final FieldAbsoluteDate<T> reference, final double apparentOffset, final TimeScale timeScale) {
451         this(reference.fieldOffset.getField(),
452              new DateTimeComponents(reference.getComponents(timeScale), apparentOffset),
453              timeScale);
454     }
455 
456     /** Creates Field date with offset as univariate derivative of first order, with a unit linear coefficient in time.
457      * @return univariate derivative 1 date
458      * @since 13.1
459      */
460     public FieldAbsoluteDate<FieldUnivariateDerivative1<T>> toFUD1Field() {
461         final FieldUnivariateDerivative1Field<T> fud1Field = FieldUnivariateDerivative1Field.getUnivariateDerivative1Field(fieldOffset.getField());
462         final FieldUnivariateDerivative1<T> fud1Shift = new FieldUnivariateDerivative1<>(fieldOffset,
463                 fieldOffset.getField().getOne());
464         return new FieldAbsoluteDate<>(fud1Field, date).shiftedBy(fud1Shift);
465     }
466 
467     /** Creates Field date with offset as univariate derivative of second order, with a unit linear coefficient in time.
468      * @return univariate derivative 2 date
469      * @since 12.2
470      */
471     public FieldAbsoluteDate<FieldUnivariateDerivative2<T>> toFUD2Field() {
472         final FieldUnivariateDerivative2Field<T> fud2Field = FieldUnivariateDerivative2Field.getUnivariateDerivative2Field(fieldOffset.getField());
473         final FieldUnivariateDerivative2<T> fud2Shift = new FieldUnivariateDerivative2<>(fieldOffset,
474                                                                                          fieldOffset.getField().getOne(),
475                                                                                          fieldOffset.getField().getZero());
476         return new FieldAbsoluteDate<>(fud2Field, date).shiftedBy(fud2Shift);
477     }
478 
479     /** Build an instance from a CCSDS Unsegmented Time Code (CUC).
480      * <p>
481      * CCSDS Unsegmented Time Code is defined in the blue book:
482      * CCSDS Time Code Format (CCSDS 301.0-B-4) published in November 2010
483      * </p>
484      * <p>
485      * If the date to be parsed is formatted using version 3 of the standard
486      * (CCSDS 301.0-B-3 published in 2002) or if the extension of the preamble
487      * field introduced in version 4 of the standard is not used, then the
488      * {@code preambleField2} parameter can be set to 0.
489      * </p>
490      *
491      * <p>This method uses the {@link DataContext#getDefault() default data context} if
492      * the CCSDS epoch is used.
493      *
494      * @param field field for the components
495      * @param preambleField1 first byte of the field specifying the format, often
496      * not transmitted in data interfaces, as it is constant for a given data interface
497      * @param preambleField2 second byte of the field specifying the format
498      * (added in revision 4 of the CCSDS standard in 2010), often not transmitted in data
499      * interfaces, as it is constant for a given data interface (value ignored if presence
500      * not signaled in {@code preambleField1})
501      * @param timeField byte array containing the time code
502      * @param agencyDefinedEpoch reference epoch, ignored if the preamble field
503      * specifies the {@link #getCCSDSEpoch(Field) CCSDS reference epoch} is used (and hence
504      * may be null in this case)
505      * @return an instance corresponding to the specified date
506      * @param <T> the type of the field elements
507      * @see #parseCCSDSUnsegmentedTimeCode(byte, byte, byte[], FieldAbsoluteDate,
508      * FieldAbsoluteDate)
509      */
510     @DefaultDataContext
511     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> parseCCSDSUnsegmentedTimeCode(final Field<T> field,
512                                                                                                          final byte preambleField1,
513                                                                                                          final byte preambleField2,
514                                                                                                          final byte[] timeField,
515                                                                                                          final FieldAbsoluteDate<T> agencyDefinedEpoch) {
516         return parseCCSDSUnsegmentedTimeCode(preambleField1, preambleField2,
517                                              timeField, agencyDefinedEpoch,
518                                              new FieldAbsoluteDate<>(field,
519                                                                      DataContext.getDefault().getTimeScales().getCcsdsEpoch()));
520     }
521 
522     /**
523      * Build an instance from a CCSDS Unsegmented Time Code (CUC).
524      * <p>
525      * CCSDS Unsegmented Time Code is defined in the blue book: CCSDS Time Code Format
526      * (CCSDS 301.0-B-4) published in November 2010
527      * </p>
528      * <p>
529      * If the date to be parsed is formatted using version 3 of the standard (CCSDS
530      * 301.0-B-3 published in 2002) or if the extension of the preamble field introduced
531      * in version 4 of the standard is not used, then the {@code preambleField2} parameter
532      * can be set to 0.
533      * </p>
534      *
535      * @param <T>                the type of the field elements
536      * @param preambleField1     first byte of the field specifying the format, often not
537      *                           transmitted in data interfaces, as it is constant for a
538      *                           given data interface
539      * @param preambleField2     second byte of the field specifying the format (added in
540      *                           revision 4 of the CCSDS standard in 2010), often not
541      *                           transmitted in data interfaces, as it is constant for a
542      *                           given data interface (value ignored if presence not
543      *                           signaled in {@code preambleField1})
544      * @param timeField          byte array containing the time code
545      * @param agencyDefinedEpoch reference epoch, ignored if the preamble field specifies
546      *                           the {@link DateComponents#CCSDS_EPOCH CCSDS reference epoch} is used
547      *                           (and hence may be null in this case, but then {@code ccsdsEpoch} must be non-null)
548      * @param ccsdsEpoch         reference epoch, ignored if the preamble field specifies
549      *                           the agency epoch is used (and hence may be null in this case,
550      *                           but then {@code agencyDefinedEpoch} must be non-null).
551      * @return an instance corresponding to the specified date
552      * @since 10.1
553      */
554     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> parseCCSDSUnsegmentedTimeCode(final byte preambleField1,
555                                                                                                          final byte preambleField2,
556                                                                                                          final byte[] timeField,
557                                                                                                          final FieldAbsoluteDate<T> agencyDefinedEpoch,
558                                                                                                          final FieldAbsoluteDate<T> ccsdsEpoch) {
559         final CcsdsUnsegmentedTimeCode<FieldAbsoluteDate<T>> timeCode =
560             new CcsdsUnsegmentedTimeCode<>(preambleField1, preambleField2, timeField, agencyDefinedEpoch, ccsdsEpoch);
561         return timeCode.getEpoch().shiftedBy(timeCode.getTime());
562     }
563 
564     /** Build an instance from a CCSDS Day Segmented Time Code (CDS).
565      * <p>
566      * CCSDS Day Segmented Time Code is defined in the blue book:
567      * CCSDS Time Code Format (CCSDS 301.0-B-4) published in November 2010
568      * </p>
569      *
570      * <p>This method uses the {@link DataContext#getDefault() default data context}.
571      *
572      * @param field field for the components
573      * @param preambleField field specifying the format, often not transmitted in
574      * data interfaces, as it is constant for a given data interface
575      * @param timeField byte array containing the time code
576      * @param agencyDefinedEpoch reference epoch, ignored if the preamble field
577      * specifies the {@link #getCCSDSEpoch(Field) CCSDS reference epoch} is used (and hence
578      * may be null in this case)
579      * @return an instance corresponding to the specified date
580      * @param <T> the type of the field elements
581      * @see #parseCCSDSDaySegmentedTimeCode(Field, byte, byte[], DateComponents,
582      * TimeScale)
583      */
584     @DefaultDataContext
585     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> parseCCSDSDaySegmentedTimeCode(final Field<T> field,
586                                                                                                           final byte preambleField, final byte[] timeField,
587                                                                                                           final DateComponents agencyDefinedEpoch) {
588         return parseCCSDSDaySegmentedTimeCode(field, preambleField, timeField,
589                                               agencyDefinedEpoch, DataContext.getDefault().getTimeScales().getUTC());
590     }
591 
592     /**
593      * Build an instance from a CCSDS Day Segmented Time Code (CDS).
594      * <p>
595      * CCSDS Day Segmented Time Code is defined in the blue book: CCSDS Time Code Format
596      * (CCSDS 301.0-B-4) published in November 2010
597      * </p>
598      *
599      * @param <T>                the type of the field elements
600      * @param field              field for the components
601      * @param preambleField      field specifying the format, often not transmitted in
602      *                           data interfaces, as it is constant for a given data
603      *                           interface
604      * @param timeField          byte array containing the time code
605      * @param agencyDefinedEpoch reference epoch, ignored if the preamble field specifies
606      *                           the {@link #getCCSDSEpoch(Field) CCSDS reference epoch}
607      *                           is used (and hence may be null in this case)
608      * @param utc                time scale used to compute date and time components.
609      * @return an instance corresponding to the specified date
610      * @since 10.1
611      */
612     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> parseCCSDSDaySegmentedTimeCode(final Field<T> field,
613                                                                                                           final byte preambleField,
614                                                                                                           final byte[] timeField,
615                                                                                                           final DateComponents agencyDefinedEpoch,
616                                                                                                           final TimeScale utc) {
617         final CcsdsSegmentedTimeCode timeCode = new CcsdsSegmentedTimeCode(preambleField, timeField, agencyDefinedEpoch);
618         return new FieldAbsoluteDate<>(field, timeCode.getDate(), timeCode.getTime(), utc);
619     }
620 
621     /** Build an instance from a CCSDS Calendar Segmented Time Code (CCS).
622      * <p>
623      * CCSDS Calendar Segmented Time Code is defined in the blue book:
624      * CCSDS Time Code Format (CCSDS 301.0-B-4) published in November 2010
625      * </p>
626      *
627      * <p>This method uses the {@link DataContext#getDefault() default data context}.
628      *
629      * @param preambleField field specifying the format, often not transmitted in
630      * data interfaces, as it is constant for a given data interface
631      * @param timeField byte array containing the time code
632      * @return an instance corresponding to the specified date
633      * @see #parseCCSDSCalendarSegmentedTimeCode(byte, byte[], TimeScale)
634      */
635     @DefaultDataContext
636     public FieldAbsoluteDate<T> parseCCSDSCalendarSegmentedTimeCode(final byte preambleField, final byte[] timeField) {
637         return parseCCSDSCalendarSegmentedTimeCode(preambleField, timeField,
638                                                    DataContext.getDefault().getTimeScales().getUTC());
639     }
640 
641     /**
642      * Build an instance from a CCSDS Calendar Segmented Time Code (CCS).
643      * <p>
644      * CCSDS Calendar Segmented Time Code is defined in the blue book: CCSDS Time Code
645      * Format (CCSDS 301.0-B-4) published in November 2010
646      * </p>
647      *
648      * @param preambleField field specifying the format, often not transmitted in data
649      *                      interfaces, as it is constant for a given data interface
650      * @param timeField     byte array containing the time code
651      * @param utc           time scale used to compute date and time components.
652      * @return an instance corresponding to the specified date
653      * @since 10.1
654      */
655     public FieldAbsoluteDate<T> parseCCSDSCalendarSegmentedTimeCode(final byte preambleField,
656                                                                     final byte[] timeField,
657                                                                     final TimeScale utc) {
658         final CcsdsSegmentedTimeCode timeCode = new CcsdsSegmentedTimeCode(preambleField, timeField);
659         return new FieldAbsoluteDate<>(fieldOffset.getField(), timeCode.getDate(), timeCode.getTime(), utc);
660     }
661 
662     /** Build an instance corresponding to a Julian Day date.
663      * @param jd Julian day
664      * @param secondsSinceNoon seconds in the Julian day
665      * (BEWARE, Julian days start at noon, so 0.0 is noon)
666      * @param timeScale time scale in which the seconds in day are defined
667      * @return a new instant
668      * @param <T> the type of the field elements
669      */
670     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createJDDate(final int jd, final T secondsSinceNoon,
671                                                                                         final TimeScale timeScale) {
672         return new FieldAbsoluteDate<>(secondsSinceNoon.getField(), new DateComponents(DateComponents.JULIAN_EPOCH, jd),
673                         TimeComponents.H12, timeScale).shiftedBy(secondsSinceNoon);
674     }
675 
676     /** Build an instance corresponding to a Julian Day date.
677      * <p>
678      * This function should be preferred to {@link #createJDDate(int, CalculusFieldElement, TimeScale)} when the target time scale
679      * has a non-constant offset with respect to TAI.
680      * <p>
681      * The idea is to introduce a pivot time scale that is close to the target time scale but has a constant bias with TAI.
682      * <p>
683      * For example, to get a date from an MJD in TDB time scale, it's advised to use the TT time scale
684      * as a pivot scale. TT is very close to TDB and has constant offset to TAI.
685      * </p>
686      * @param jd Julian day
687      * @param secondsSinceNoon seconds in the Julian day
688      * (BEWARE, Julian days start at noon, so 0.0 is noon)
689      * @param timeScale time scale in which the seconds in day are defined
690      * @param pivotTimeScale pivot timescale used as intermediate timescale
691      * @return a new instant
692      * @param <T> the type of the field elements
693      */
694     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createJDDate(final int jd, final T secondsSinceNoon,
695                                                                                         final TimeScale timeScale,
696                                                                                         final TimeScale pivotTimeScale) {
697         // Get the date in pivot timescale
698         final FieldAbsoluteDate<T> dateInPivotTimeScale = createJDDate(jd, secondsSinceNoon, pivotTimeScale);
699 
700         // Compare offsets to TAI of the two time scales
701         final T offsetFromTAI = timeScale.offsetFromTAI(dateInPivotTimeScale).
702                 subtract(pivotTimeScale.offsetFromTAI(dateInPivotTimeScale));
703 
704         // Return date in desired timescale
705         return dateInPivotTimeScale.shiftedBy(offsetFromTAI.multiply(-1.));
706     }
707 
708     /** Build an instance corresponding to a Modified Julian Day date.
709      * @param mjd modified Julian day
710      * @param secondsInDay seconds in the day
711      * @param timeScale time scale in which the seconds in day are defined
712      * @return a new instant
713      * @param <T> the type of the field elements
714      */
715     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createMJDDate(final int mjd, final T secondsInDay,
716                                                                                          final TimeScale timeScale) {
717         return new FieldAbsoluteDate<>(secondsInDay.getField(),
718                                        new DateComponents(DateComponents.MODIFIED_JULIAN_EPOCH, mjd),
719                                        TimeComponents.H00,
720                                        timeScale).shiftedBy(secondsInDay);
721     }
722 
723     /** Create an instance as the median data between two existing instances.
724      * @param date1 first instance
725      * @param date2 second instance
726      * @return median date between first and second instance
727      * @param <T> the type of the field elements
728      * @since 13.0
729      */
730     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createMedian(final FieldAbsoluteDate<T> date1,
731                                                                                         final FieldAbsoluteDate<T> date2) {
732         return new FieldAbsoluteDate<>(AbsoluteDate.createMedian(date1.date, date2.date),
733                                        date2.fieldOffset.add(date1.fieldOffset).multiply(0.5));
734     }
735 
736     /** Build an instance corresponding to a GPS date.
737      *
738      * <p>This method uses the {@link DataContext#getDefault() default data context}.
739      *
740      * <p>GPS dates are provided as a week number starting at
741      * {@link #getGPSEpoch(Field) GPS epoch} and as a number of milliseconds
742      * since week start.</p>
743      * @param weekNumber week number since {@link #getGPSEpoch(Field) GPS epoch}
744      * @param milliInWeek number of milliseconds since week start
745      * @return a new instant
746      * @param <T> the type of the field elements
747      * @see #createGPSDate(int, CalculusFieldElement, TimeScale)
748      */
749     @DefaultDataContext
750     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createGPSDate(final int weekNumber, final T milliInWeek) {
751         return createGPSDate(weekNumber, milliInWeek,
752                              DataContext.getDefault().getTimeScales().getGPS());
753     }
754 
755     /**
756      * Build an instance corresponding to a GPS date.
757      * <p>GPS dates are provided as a week number starting at
758      * {@link #getGPSEpoch(Field) GPS epoch} and as a number of milliseconds since week
759      * start.</p>
760      *
761      * @param <T>         the type of the field elements
762      * @param weekNumber  week number since {@link #getGPSEpoch(Field) GPS epoch}
763      * @param milliInWeek number of milliseconds since week start
764      * @param gps         GPS time scale.
765      * @return a new instant
766      * @since 10.1
767      */
768     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createGPSDate(
769                                                                                          final int weekNumber,
770                                                                                          final T milliInWeek,
771                                                                                          final TimeScale gps) {
772 
773         final int day = (int) FastMath.floor(milliInWeek.getReal() / (1000.0 * Constants.JULIAN_DAY));
774         final T secondsInDay = milliInWeek.divide(1000.0).subtract(day * Constants.JULIAN_DAY);
775         return new FieldAbsoluteDate<>(milliInWeek.getField(),
776                                        new DateComponents(DateComponents.GPS_EPOCH, weekNumber * 7 + day),
777                                        TimeComponents.H00, gps).
778                shiftedBy(secondsInDay);
779     }
780 
781     /** Build an instance corresponding to a Julian Epoch (JE).
782      * <p>According to Lieske paper: <a
783      * href="http://articles.adsabs.harvard.edu/cgi-bin/nph-iarticle_query?1979A%26A....73..282L&amp;defaultprint=YES&amp;filetype=.pdf.">
784      * Precession Matrix Based on IAU (1976) System of Astronomical Constants</a>, Astronomy and Astrophysics,
785      * vol. 73, no. 3, Mar. 1979, p. 282-284, Julian Epoch is related to Julian Ephemeris Date as:
786      * <pre>JE = 2000.0 + (JED - 2451545.0) / 365.25</pre>
787      * <p>This method reverts the formula above and computes an {@code FieldAbsoluteDate<T>} from the Julian Epoch.
788      *
789      * <p>This method uses the {@link DataContext#getDefault() default data context}.
790      *
791      * @param <T> the type of the field elements
792      * @param julianEpoch Julian epoch, like 2000.0 for defining the classical reference J2000.0
793      * @return a new instant
794      * @see #getJ2000Epoch(Field)
795      * @see #createBesselianEpoch(CalculusFieldElement)
796      * @see #createJulianEpoch(CalculusFieldElement, TimeScales)
797      */
798     @DefaultDataContext
799     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createJulianEpoch(final T julianEpoch) {
800         return createJulianEpoch(julianEpoch, DataContext.getDefault().getTimeScales());
801     }
802 
803     /**
804      * Build an instance corresponding to a Julian Epoch (JE).
805      * <p>According to Lieske paper: <a
806      * href="http://articles.adsabs.harvard.edu/cgi-bin/nph-iarticle_query?1979A%26A....73..282L&amp;defaultprint=YES&amp;filetype=.pdf.">
807      * Precession Matrix Based on IAU (1976) System of Astronomical Constants</a>,
808      * Astronomy and Astrophysics, vol. 73, no. 3, Mar. 1979, p. 282-284, Julian Epoch is
809      * related to Julian Ephemeris Date as:
810      * <pre>JE = 2000.0 + (JED - 2451545.0) / 365.25</pre>
811      * <p>This method reverts the formula above and computes an {@code
812      * FieldAbsoluteDate<T>} from the Julian Epoch.
813      *
814      * @param <T>         the type of the field elements
815      * @param julianEpoch Julian epoch, like 2000.0 for defining the classical reference
816      *                    J2000.0
817      * @param timeScales  used in the computation.
818      * @return a new instant
819      * @see #getJ2000Epoch(Field)
820      * @see #createBesselianEpoch(CalculusFieldElement)
821      * @see TimeScales#createJulianEpoch(double)
822      * @since 10.1
823      */
824     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createJulianEpoch(
825                                                                                              final T julianEpoch,
826                                                                                              final TimeScales timeScales) {
827         final Field<T> field = julianEpoch.getField();
828         return new FieldAbsoluteDate<>(new FieldAbsoluteDate<>(field, timeScales.getJ2000Epoch()),
829                                        julianEpoch.subtract(2000.0).multiply(Constants.JULIAN_YEAR));
830     }
831 
832     /** Build an instance corresponding to a Besselian Epoch (BE).
833      * <p>According to Lieske paper: <a
834      * href="http://articles.adsabs.harvard.edu/cgi-bin/nph-iarticle_query?1979A%26A....73..282L&amp;defaultprint=YES&amp;filetype=.pdf.">
835      * Precession Matrix Based on IAU (1976) System of Astronomical Constants</a>, Astronomy and Astrophysics,
836      * vol. 73, no. 3, Mar. 1979, p. 282-284, Besselian Epoch is related to Julian Ephemeris Date as:</p>
837      * <pre>
838      * BE = 1900.0 + (JED - 2415020.31352) / 365.242198781
839      * </pre>
840      * <p>
841      * This method reverts the formula above and computes an {@code FieldAbsoluteDate<T>} from the Besselian Epoch.
842      * </p>
843      *
844      * <p>This method uses the {@link DataContext#getDefault() default data context}.
845      *
846      * @param <T> the type of the field elements
847      * @param besselianEpoch Besselian epoch, like 1950 for defining the classical reference B1950.0
848      * @return a new instant
849      * @see #createJulianEpoch(CalculusFieldElement)
850      * @see #createBesselianEpoch(CalculusFieldElement, TimeScales)
851      */
852     @DefaultDataContext
853     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createBesselianEpoch(final T besselianEpoch) {
854         return createBesselianEpoch(besselianEpoch, DataContext.getDefault().getTimeScales());
855     }
856 
857     /**
858      * Build an instance corresponding to a Besselian Epoch (BE).
859      * <p>According to Lieske paper: <a
860      * href="http://articles.adsabs.harvard.edu/cgi-bin/nph-iarticle_query?1979A%26A....73..282L&amp;defaultprint=YES&amp;filetype=.pdf.">
861      * Precession Matrix Based on IAU (1976) System of Astronomical Constants</a>,
862      * Astronomy and Astrophysics, vol. 73, no. 3, Mar. 1979, p. 282-284, Besselian Epoch
863      * is related to Julian Ephemeris Date as:</p>
864      * <pre>
865      * BE = 1900.0 + (JED - 2415020.31352) / 365.242198781
866      * </pre>
867      * <p>
868      * This method reverts the formula above and computes an {@code FieldAbsoluteDate<T>}
869      * from the Besselian Epoch.
870      * </p>
871      *
872      * @param <T>            the type of the field elements
873      * @param besselianEpoch Besselian epoch, like 1950 for defining the classical
874      *                       reference B1950.0
875      * @param timeScales     used in the computation.
876      * @return a new instant
877      * @see #createJulianEpoch(CalculusFieldElement)
878      * @see TimeScales#createBesselianEpoch(double)
879      * @since 10.1
880      */
881     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> createBesselianEpoch(
882                                                                                                 final T besselianEpoch,
883                                                                                                 final TimeScales timeScales) {
884         final Field<T> field = besselianEpoch.getField();
885         return new FieldAbsoluteDate<>(new FieldAbsoluteDate<>(field, timeScales.getJ2000Epoch()),
886                                        besselianEpoch.subtract(1900).multiply(Constants.BESSELIAN_YEAR).
887                                            add(Constants.JULIAN_DAY * (-36525) + Constants.JULIAN_DAY * 0.31352));
888     }
889 
890     /** Reference epoch for julian dates: -4712-01-01T12:00:00 Terrestrial Time.
891      * <p>Both <code>java.util.Date</code> and {@link DateComponents} classes
892      * follow the astronomical conventions and consider a year 0 between
893      * years -1 and +1, hence this reference date lies in year -4712 and not
894      * in year -4713 as can be seen in other documents or programs that obey
895      * a different convention (for example the <code>convcal</code> utility).</p>
896      *
897      * <p>This method uses the {@link DataContext#getDefault() default data context}.
898      *
899      * @param <T> the type of the field elements
900      * @param field field for the components
901      * @return the reference epoch for julian dates as a FieldAbsoluteDate
902      * @see AbsoluteDate#JULIAN_EPOCH
903      * @see TimeScales#getJulianEpoch()
904      */
905     @DefaultDataContext
906     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getJulianEpoch(final Field<T> field) {
907         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getJulianEpoch());
908     }
909 
910     /** Reference epoch for modified julian dates: 1858-11-17T00:00:00 Terrestrial Time.
911      *
912      * <p>This method uses the {@link DataContext#getDefault() default data context}.
913      *
914      * @param <T> the type of the field elements
915      * @param field field for the components
916      * @return the reference epoch for modified julian dates as a FieldAbsoluteDate
917      * @see AbsoluteDate#MODIFIED_JULIAN_EPOCH
918      * @see TimeScales#getModifiedJulianEpoch()
919      */
920     @DefaultDataContext
921     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getModifiedJulianEpoch(final Field<T> field) {
922         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getModifiedJulianEpoch());
923     }
924 
925     /** Reference epoch for 1950 dates: 1950-01-01T00:00:00 Terrestrial Time.
926      *
927      * <p>This method uses the {@link DataContext#getDefault() default data context}.
928      *
929      * @param <T> the type of the field elements
930      * @param field field for the components
931      * @return the reference epoch for 1950 dates as a FieldAbsoluteDate
932      * @see AbsoluteDate#FIFTIES_EPOCH
933      * @see TimeScales#getFiftiesEpoch()
934      */
935     @DefaultDataContext
936     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getFiftiesEpoch(final Field<T> field) {
937         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getFiftiesEpoch());
938     }
939 
940     /** Reference epoch for CCSDS Time Code Format (CCSDS 301.0-B-4).
941      * <p>
942      * This method uses the {@link DataContext#getDefault() default data context}.
943      * </p>
944      * 1958-01-01T00:00:00 International Atomic Time (<em>not</em> UTC).
945      * @param <T> the type of the field elements
946      * @param field field for the components
947      * @return the reference epoch for CCSDS Time Code Format as a FieldAbsoluteDate
948      * @see AbsoluteDate#CCSDS_EPOCH
949      * @see TimeScales#getCcsdsEpoch()
950      */
951     @DefaultDataContext
952     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getCCSDSEpoch(final Field<T> field) {
953         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getCcsdsEpoch());
954     }
955 
956     /** Reference epoch for Galileo System Time: 1999-08-22T00:00:00 UTC.
957      *
958      * <p>This method uses the {@link DataContext#getDefault() default data context}.
959      *
960      * @param <T> the type of the field elements
961      * @param field field for the components
962      * @return the reference epoch for Galileo System Time as a FieldAbsoluteDate
963      * @see AbsoluteDate#GALILEO_EPOCH
964      * @see TimeScales#getGalileoEpoch()
965      */
966     @DefaultDataContext
967     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getGalileoEpoch(final Field<T> field) {
968         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getGalileoEpoch());
969     }
970 
971     /** Reference epoch for GPS weeks: 1980-01-06T00:00:00 GPS time.
972      *
973      * <p>This method uses the {@link DataContext#getDefault() default data context}.
974      *
975      * @param <T> the type of the field elements
976      * @param field field for the components
977      * @return the reference epoch for GPS weeks as a FieldAbsoluteDate
978      * @see AbsoluteDate#GPS_EPOCH
979      * @see TimeScales#getGpsEpoch()
980      */
981     @DefaultDataContext
982     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getGPSEpoch(final Field<T> field) {
983         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getGpsEpoch());
984     }
985 
986     /** J2000.0 Reference epoch: 2000-01-01T12:00:00 Terrestrial Time (<em>not</em> UTC).
987      *
988      * <p>This method uses the {@link DataContext#getDefault() default data context}.
989      *
990      * @param <T> the type of the field elements
991      * @param field field for the components
992      * @return the J2000.0 reference epoch as a FieldAbsoluteDate
993      * @see #createJulianEpoch(CalculusFieldElement)
994      * @see AbsoluteDate#J2000_EPOCH
995      * @see TimeScales#getJ2000Epoch()
996      */
997     @DefaultDataContext
998     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getJ2000Epoch(final Field<T> field) {
999         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getJ2000Epoch());
1000     }
1001 
1002     /** Java Reference epoch: 1970-01-01T00:00:00 Universal Time Coordinate.
1003      *
1004      * <p>This method uses the {@link DataContext#getDefault() default data context}.
1005      *
1006      * <p>
1007      * Between 1968-02-01 and 1972-01-01, UTC-TAI = 4.213 170 0s + (MJD - 39 126) x 0.002 592s.
1008      * As on 1970-01-01 MJD = 40587, UTC-TAI = 8.000082s
1009      * </p>
1010      * @param <T> the type of the field elements
1011      * @param field field for the components
1012      * @return the Java reference epoch as a FieldAbsoluteDate
1013      * @see AbsoluteDate#JAVA_EPOCH
1014      * @see TimeScales#getJavaEpoch()
1015      */
1016     @DefaultDataContext
1017     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getJavaEpoch(final Field<T> field) {
1018         return new FieldAbsoluteDate<>(field, DataContext.getDefault().getTimeScales().getJavaEpoch());
1019     }
1020 
1021     /** Dummy date at infinity in the past direction.
1022      * @param <T> the type of the field elements
1023      * @param field field for the components
1024      * @return a dummy date at infinity in the past direction as a FieldAbsoluteDate
1025      * @see AbsoluteDate#PAST_INFINITY
1026      * @see TimeScales#getPastInfinity()
1027      */
1028     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getPastInfinity(final Field<T> field) {
1029         return new FieldAbsoluteDate<>(field, AbsoluteDate.PAST_INFINITY);
1030     }
1031 
1032     /** Dummy date at infinity in the future direction.
1033      * @param <T> the type of the field elements
1034      * @param field field for the components
1035      * @return a dummy date at infinity in the future direction as a FieldAbsoluteDate
1036      * @see AbsoluteDate#FUTURE_INFINITY
1037      * @see TimeScales#getFutureInfinity()
1038      */
1039     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getFutureInfinity(final Field<T> field) {
1040         return new FieldAbsoluteDate<>(field, AbsoluteDate.FUTURE_INFINITY);
1041     }
1042 
1043     /**
1044      * Get an arbitrary date. Useful when a non-null date is needed but its values does
1045      * not matter.
1046      *
1047      * @param <T>   the type of the field elements
1048      * @param field field for the components
1049      * @return an arbitrary date.
1050      */
1051     public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getArbitraryEpoch(final Field<T> field) {
1052         return new FieldAbsoluteDate<>(field, AbsoluteDate.ARBITRARY_EPOCH);
1053     }
1054 
1055 
1056     /** Get a time-shifted date.
1057      * <p>
1058      * Calling this method is equivalent to call {@code new FieldAbsoluteDate&lt;&gt;(this, dt)}.
1059      * </p>
1060      * @param dt time shift in seconds
1061      * @return a new date, shifted with respect to instance (which is immutable)
1062      * @see org.orekit.utils.FieldPVCoordinates#shiftedBy(double)
1063      * @see org.orekit.attitudes.FieldAttitude#shiftedBy(double)
1064      * @see org.orekit.orbits.FieldOrbit#shiftedBy(double)
1065      * @see org.orekit.propagation.FieldSpacecraftState#shiftedBy(double)
1066      */
1067     @Override
1068     public FieldAbsoluteDate<T> shiftedBy(final T dt) {
1069         return new FieldAbsoluteDate<>(this, dt);
1070     }
1071 
1072     /** Compute the physically elapsed duration between two instants.
1073      * <p>The returned duration is the number of seconds physically
1074      * elapsed between the two instants, measured in a regular time
1075      * scale with respect to surface of the Earth (i.e either the {@link
1076      * TAIScale TAI scale}, the {@link TTScale TT scale} or the {@link
1077      * GPSScale GPS scale}). It is the only method that gives a
1078      * duration with a physical meaning.</p>
1079      * <p>This method gives the same result (with less computation)
1080      * as calling {@link #offsetFrom(FieldAbsoluteDate, TimeScale)}
1081      * with a second argument set to one of the regular scales cited
1082      * above.</p>
1083      * <p>This method is the reverse of the {@link #FieldAbsoluteDate(FieldAbsoluteDate,
1084      * double)} constructor.</p>
1085      * @param instant instant to subtract from the instance
1086      * @return offset in seconds between the two instants (positive
1087      * if the instance is posterior to the argument)
1088      * @see #offsetFrom(FieldAbsoluteDate, TimeScale)
1089      * @see #FieldAbsoluteDate(FieldAbsoluteDate, double)
1090      */
1091     public T durationFrom(final FieldAbsoluteDate<T> instant) {
1092         return fieldOffset.subtract(instant.fieldOffset).
1093                add(date.durationFrom(instant.date));
1094     }
1095 
1096     /** Compute the physically elapsed duration between two instants.
1097      * <p>The returned duration is the number of seconds physically
1098      * elapsed between the two instants, measured in a regular time
1099      * scale with respect to surface of the Earth (i.e either the {@link
1100      * TAIScale TAI scale}, the {@link TTScale TT scale} or the {@link
1101      * GPSScale GPS scale}). It is the only method that gives a
1102      * duration with a physical meaning.</p>
1103      * <p>This method gives the same result (with less computation)
1104      * as calling {@link #offsetFrom(FieldAbsoluteDate, TimeScale)}
1105      * with a second argument set to one of the regular scales cited
1106      * above.</p>
1107      * <p>This method is the reverse of the {@link #FieldAbsoluteDate(FieldAbsoluteDate,
1108      * double)} constructor.</p>
1109      * @param instant instant to subtract from the instance
1110      * @param timeUnit {@link TimeUnit} precision for the offset
1111      * @return offset in seconds between the two instants (positive
1112      * if the instance is posterior to the argument)
1113      * @see #offsetFrom(FieldAbsoluteDate, TimeScale)
1114      * @see #FieldAbsoluteDate(FieldAbsoluteDate, double)
1115      */
1116     public T durationFrom(final FieldAbsoluteDate<T> instant, final TimeUnit timeUnit) {
1117         return fieldOffset.subtract(instant.fieldOffset).
1118                add(date.durationFrom(instant.date, timeUnit));
1119     }
1120 
1121     /** Compute the physically elapsed duration between two instants.
1122      * <p>The returned duration is the number of seconds physically
1123      * elapsed between the two instants, measured in a regular time
1124      * scale with respect to surface of the Earth (i.e either the {@link
1125      * TAIScale TAI scale}, the {@link TTScale TT scale} or the {@link
1126      * GPSScale GPS scale}). It is the only method that gives a
1127      * duration with a physical meaning.</p>
1128      * <p>This method gives the same result (with less computation)
1129      * as calling {@link #offsetFrom(FieldAbsoluteDate, TimeScale)}
1130      * with a second argument set to one of the regular scales cited
1131      * above.</p>
1132      * <p>This method is the reverse of the {@link #FieldAbsoluteDate(FieldAbsoluteDate,
1133      * double)} constructor.</p>
1134      * @param instant instant to subtract from the instance
1135      * @return offset in seconds between the two instants (positive
1136      * if the instance is posterior to the argument)
1137      * @see #offsetFrom(FieldAbsoluteDate, TimeScale)
1138      * @see #FieldAbsoluteDate(FieldAbsoluteDate, double)
1139      */
1140     public T durationFrom(final AbsoluteDate instant) {
1141         return fieldOffset.add(date.durationFrom(instant));
1142     }
1143 
1144     /** Compute the physically elapsed duration between two instants.
1145      * <p>The returned duration is the number of seconds physically
1146      * elapsed between the two instants, measured in a regular time
1147      * scale with respect to surface of the Earth (i.e either the {@link
1148      * TAIScale TAI scale}, the {@link TTScale TT scale} or the {@link
1149      * GPSScale GPS scale}). It is the only method that gives a
1150      * duration with a physical meaning.</p>
1151      * <p>This method gives the same result (with less computation)
1152      * as calling {@link #offsetFrom(FieldAbsoluteDate, TimeScale)}
1153      * with a second argument set to one of the regular scales cited
1154      * above.</p>
1155      * <p>This method is the reverse of the {@link #FieldAbsoluteDate(FieldAbsoluteDate,
1156      * double)} constructor.</p>
1157      * @param instant instant to subtract from the instance
1158      * @param timeUnit {@link TimeUnit} precision for the offset
1159      * @return offset in the given timeunit between the two instants (positive
1160      * if the instance is posterior to the argument), rounded to the nearest integer {@link TimeUnit}
1161      * @see #FieldAbsoluteDate(FieldAbsoluteDate, long, TimeUnit)
1162      * @since 12.1
1163      */
1164     public T durationFrom(final AbsoluteDate instant, final TimeUnit timeUnit) {
1165         return fieldOffset.add(date.durationFrom(instant, timeUnit));
1166     }
1167 
1168     /** Compute the apparent clock offset between two instant <em>in the
1169      * perspective of a specific {@link TimeScale time scale}</em>.
1170      * <p>The offset is the number of seconds counted in the given
1171      * time scale between the locations of the two instants, with
1172      * all time scale irregularities removed (i.e. considering all
1173      * days are exactly 86400 seconds long). This method will give
1174      * a result that may not have a physical meaning if the time scale
1175      * is irregular. For example since a leap second was introduced at
1176      * the end of 2005, the apparent offset between 2005-12-31T23:59:59
1177      * and 2006-01-01T00:00:00 is 1 second, but the physical duration
1178      * of the corresponding time interval as returned by the {@link
1179      * #durationFrom(FieldAbsoluteDate)} method is 2 seconds.</p>
1180      * <p>This method is the reverse of the {@link #FieldAbsoluteDate(FieldAbsoluteDate,
1181      * double, TimeScale)} constructor.</p>
1182      * @param instant instant to subtract from the instance
1183      * @param timeScale time scale with respect to which the offset should
1184      * be computed
1185      * @return apparent clock offset in seconds between the two instants
1186      * (positive if the instance is posterior to the argument)
1187      * @see #durationFrom(FieldAbsoluteDate)
1188      * @see #FieldAbsoluteDate(FieldAbsoluteDate, double, TimeScale)
1189      */
1190     public T offsetFrom(final FieldAbsoluteDate<T> instant, final TimeScale timeScale) {
1191         return fieldOffset.subtract(instant.fieldOffset).
1192                add(date.offsetFrom(instant.date, timeScale));
1193     }
1194 
1195     /** Compute the offset between two time scales at the current instant.
1196      * <p>The offset is defined as <i>l₁-l₂</i>
1197      * where <i>l₁</i> is the location of the instant in
1198      * the <code>scale1</code> time scale and <i>l₂</i> is the
1199      * location of the instant in the <code>scale2</code> time scale.</p>
1200      * @param scale1 first time scale
1201      * @param scale2 second time scale
1202      * @return offset in seconds between the two time scales at the
1203      * current instant
1204      */
1205     public T timeScalesOffset(final TimeScale scale1, final TimeScale scale2) {
1206         return scale1.offsetFromTAI(this).subtract(scale2.offsetFromTAI(this));
1207     }
1208 
1209     /** Convert the instance to a Java {@link java.util.Date Date}.
1210      * <p>Conversion to the Date class induces a loss of precision because
1211      * the Date class does not provide sub-millisecond information. Java Dates
1212      * are considered to be locations in some times scales.</p>
1213      * @param timeScale time scale to use
1214      * @return a {@link java.util.Date Date} instance representing the location
1215      * of the instant in the time scale
1216      */
1217     public Date toDate(final TimeScale timeScale) {
1218         return date.toDate(timeScale);
1219     }
1220 
1221     /**
1222      * Convert the instance to a Java {@link java.time.Instant Instant}.
1223      * Nanosecond precision is preserved during this conversion
1224      *
1225      * @return a {@link java.time.Instant Instant} instance representing the location
1226      * of the instant in the utc time scale
1227      * @since 12.1
1228      */
1229     @DefaultDataContext
1230     public Instant toInstant() {
1231         return toInstant(TimeScalesFactory.getTimeScales());
1232     }
1233 
1234     /**
1235      * Convert the instance to a Java {@link java.time.Instant Instant}.
1236      * Nanosecond precision is preserved during this conversion
1237      *
1238      * @param timeScales the timescales to use
1239      * @return a {@link java.time.Instant Instant} instance representing the location
1240      * of the instant in the utc time scale
1241      * @since 12.1
1242      */
1243     public Instant toInstant(final TimeScales timeScales) {
1244         return date.toInstant(timeScales);
1245     }
1246 
1247     /** Split the instance into date/time components.
1248      * @param timeScale time scale to use
1249      * @return date/time components
1250      */
1251     public DateTimeComponents getComponents(final TimeScale timeScale) {
1252         return date.getComponents(timeScale);
1253     }
1254 
1255     /** Split the instance into date/time components for a local time.
1256      *
1257      * <p>This method uses the {@link DataContext#getDefault() default data context}.
1258      *
1259      * @param minutesFromUTC offset in <em>minutes</em> from UTC (positive Eastwards UTC,
1260      * negative Westward UTC)
1261      * @return date/time components
1262      * @see #getComponents(int, TimeScale)
1263      */
1264     @DefaultDataContext
1265     public DateTimeComponents getComponents(final int minutesFromUTC) {
1266         return date.getComponents(minutesFromUTC);
1267     }
1268 
1269     /**
1270      * Split the instance into date/time components for a local time.
1271      *
1272      * @param minutesFromUTC offset in <em>minutes</em> from UTC (positive Eastwards UTC,
1273      *                       negative Westward UTC)
1274      * @param utc            time scale used to compute date and time components.
1275      * @return date/time components
1276      * @since 10.1
1277      */
1278     public DateTimeComponents getComponents(final int minutesFromUTC, final TimeScale utc) {
1279         return date.getComponents(minutesFromUTC, utc);
1280     }
1281 
1282     /** {@inheritDoc} */
1283     @Override
1284     public FieldAbsoluteDate<T> getDate() {
1285         return this;
1286     }
1287 
1288     /** Get the field.
1289      * @return field instance.
1290      */
1291     public Field<T> getField() {
1292         return fieldOffset.getField();
1293     }
1294 
1295     /** Split the instance into date/time components for a time zone.
1296      *
1297      * <p>This method uses the {@link DataContext#getDefault() default data context}.
1298      *
1299      * @param timeZone time zone
1300      * @return date/time components
1301      * @see #getComponents(TimeZone, TimeScale)
1302      */
1303     @DefaultDataContext
1304     public DateTimeComponents getComponents(final TimeZone timeZone) {
1305         return date.getComponents(timeZone);
1306     }
1307 
1308     /** Split the instance into date/time components for a time zone.
1309      * @param timeZone time zone
1310      * @param utc            time scale used to compute date and time components.
1311      * @return date/time components
1312      * @since 10.1
1313      */
1314     public DateTimeComponents getComponents(final TimeZone timeZone, final TimeScale utc) {
1315         return date.getComponents(timeZone, utc);
1316     }
1317 
1318     /** Compare the instance with another date.
1319      * @param other other date to compare the instance to
1320      * @return a negative integer, zero, or a positive integer as this date
1321      * is before, simultaneous, or after the specified date.
1322      */
1323     public int compareTo(final FieldAbsoluteDate<T> other) {
1324         return date.compareTo(other.date);
1325     }
1326 
1327 
1328     /** Check if the instance represents the same time as another instance.
1329      * @param other other date
1330      * @return true if the instance and the other date refer to the same instant with same Field and addendum
1331      */
1332     public boolean equals(final Object other) {
1333 
1334         if (other == this) {
1335             // first fast check
1336             return true;
1337         }
1338 
1339         if (other instanceof FieldAbsoluteDate) {
1340             final FieldAbsoluteDate<?> otherF = (FieldAbsoluteDate<?>) other;
1341             return fieldOffset.getField().equals(otherF.fieldOffset.getField()) &&
1342                    date.equals(otherF.date) && fieldOffset.getAddendum().equals(otherF.fieldOffset.getAddendum());
1343         }
1344 
1345         return false;
1346 
1347     }
1348 
1349     /** Check if the instance represents the same time as another.
1350      * @param other the instant to compare this date to
1351      * @return true if the instance and the argument refer to the same instant
1352      * @see #isCloseTo(FieldTimeStamped, double)
1353      * @since 10.1
1354      */
1355     public boolean isEqualTo(final FieldTimeStamped<T> other) {
1356         return this.equals(other.getDate());
1357     }
1358 
1359     /** Check if the instance time is close to another.
1360      * @param other the instant to compare this date to
1361      * @param tolerance the separation, in seconds, under which the two instants will be considered close to each other
1362      * @return true if the duration between the instance and the argument is strictly below the tolerance
1363      * @see #isEqualTo(FieldTimeStamped)
1364      * @since 10.1
1365      */
1366     public boolean isCloseTo(final FieldTimeStamped<T> other, final double tolerance) {
1367         return date.isCloseTo(other.getDate().date, tolerance);
1368     }
1369 
1370     /** Check if the instance represents a time that is strictly before another.
1371      * @param other the instant to compare this date to
1372      * @return true if the instance is strictly before the argument when ordering chronologically
1373      * @see #isBeforeOrEqualTo(FieldTimeStamped)
1374      * @since 10.1
1375      */
1376     public boolean isBefore(final FieldTimeStamped<T> other) {
1377         return date.isBefore(other.getDate().date);
1378     }
1379 
1380     /** Check if the instance represents a time that is strictly after another.
1381      * @param other the instant to compare this date to
1382      * @return true if the instance is strictly after the argument when ordering chronologically
1383      * @see #isAfterOrEqualTo(FieldTimeStamped)
1384      * @since 10.1
1385      */
1386     public boolean isAfter(final FieldTimeStamped<T> other) {
1387         return date.isAfter(other.getDate().date);
1388     }
1389 
1390     /** Check if the instance represents a time that is before or equal to another.
1391      * @param other the instant to compare this date to
1392      * @return true if the instance is before (or equal to) the argument when ordering chronologically
1393      * @see #isBefore(FieldTimeStamped)
1394      * @since 10.1
1395      */
1396     public boolean isBeforeOrEqualTo(final FieldTimeStamped<T> other) {
1397         return date.isBeforeOrEqualTo(other.getDate().date);
1398     }
1399 
1400     /** Check if the instance represents a time that is after or equal to another.
1401      * @param other the instant to compare this date to
1402      * @return true if the instance is after (or equal to) the argument when ordering chronologically
1403      * @see #isAfterOrEqualTo(FieldTimeStamped)
1404      * @since 10.1
1405      */
1406     public boolean isAfterOrEqualTo(final FieldTimeStamped<T> other) {
1407         return date.isAfterOrEqualTo(other.getDate().date);
1408     }
1409 
1410     /** Check if the instance represents a time that is strictly between two others representing
1411      * the boundaries of a time span. The two boundaries can be provided in any order: in other words,
1412      * whether <code>boundary</code> represents a time that is before or after <code>otherBoundary</code> will
1413      * not change the result of this method.
1414      * @param boundary one end of the time span
1415      * @param otherBoundary the other end of the time span
1416      * @return true if the instance is strictly between the two arguments when ordering chronologically
1417      * @see #isBetweenOrEqualTo(FieldTimeStamped, FieldTimeStamped)
1418      * @since 10.1
1419      */
1420     public boolean isBetween(final FieldTimeStamped<T> boundary, final FieldTimeStamped<T> otherBoundary) {
1421         return date.isBetween(boundary.getDate().date, otherBoundary.getDate().date);
1422     }
1423 
1424     /** Check if the instance represents a time that is between two others representing
1425      * the boundaries of a time span, or equal to one of them. The two boundaries can be provided in any order:
1426      * in other words, whether <code>boundary</code> represents a time that is before or after
1427      * <code>otherBoundary</code> will not change the result of this method.
1428      * @param boundary one end of the time span
1429      * @param otherBoundary the other end of the time span
1430      * @return true if the instance is between the two arguments (or equal to at least one of them)
1431      * when ordering chronologically
1432      * @see #isBetween(FieldTimeStamped, FieldTimeStamped)
1433      * @since 10.1
1434      */
1435     public boolean isBetweenOrEqualTo(final FieldTimeStamped<T> boundary, final FieldTimeStamped<T> otherBoundary) {
1436         return date.isBetweenOrEqualTo(boundary.getDate().date, otherBoundary.getDate().date);
1437     }
1438 
1439     /** Get a hashcode for this date.
1440      * @return hashcode
1441      */
1442     public int hashCode() {
1443         return date.hashCode() + fieldOffset.getAddendum().hashCode();
1444     }
1445 
1446     /**
1447      * Get a String representation of the instant location with up to 16 digits of
1448      * precision for the seconds value.
1449      *
1450      * <p> Since this method is used in exception messages and error handling every
1451      * effort is made to return some representation of the instant. If UTC is available
1452      * from the default data context then it is used to format the string in UTC. If not
1453      * then TAI is used. Finally if the prior attempts fail this method falls back to
1454      * converting this class's internal representation to a string.
1455      *
1456      * <p>This method uses the {@link DataContext#getDefault() default data context}.
1457      *
1458      * @return a string representation of the instance, in ISO-8601 format if UTC is
1459      * available from the default data context.
1460      * @see AbsoluteDate#toString()
1461      * @see #toString(TimeScale)
1462      * @see DateTimeComponents#toString(int, int)
1463      */
1464     @DefaultDataContext
1465     public String toString() {
1466         return date.toString();
1467     }
1468 
1469     /**
1470      * Get a String representation of the instant location in ISO-8601 format without the
1471      * UTC offset and with up to 16 digits of precision for the seconds value.
1472      *
1473      * @param timeScale time scale to use
1474      * @return a string representation of the instance.
1475      * @see DateTimeComponents#toString(int, int)
1476      */
1477     public String toString(final TimeScale timeScale) {
1478         return date.toString(timeScale);
1479     }
1480 
1481     /** Get a String representation of the instant location for a local time.
1482      *
1483      * <p>This method uses the {@link DataContext#getDefault() default data context}.
1484      *
1485      * @param minutesFromUTC offset in <em>minutes</em> from UTC (positive Eastwards UTC,
1486      * negative Westward UTC).
1487      * @return string representation of the instance,
1488      * in ISO-8601 format with milliseconds accuracy
1489      * @see #toString(int, TimeScale)
1490      */
1491     @DefaultDataContext
1492     public String toString(final int minutesFromUTC) {
1493         return date.toString(minutesFromUTC);
1494     }
1495 
1496     /**
1497      * Get a String representation of the instant location for a local time.
1498      *
1499      * @param minutesFromUTC offset in <em>minutes</em> from UTC (positive Eastwards UTC,
1500      *                       negative Westward UTC).
1501      * @param utc            time scale used to compute date and time components.
1502      * @return string representation of the instance, in ISO-8601 format with milliseconds
1503      * accuracy
1504      * @since 10.1
1505      */
1506     public String toString(final int minutesFromUTC, final TimeScale utc) {
1507         return date.toString(minutesFromUTC, utc);
1508     }
1509 
1510     /** Get a String representation of the instant location for a time zone.
1511      *
1512      * <p>This method uses the {@link DataContext#getDefault() default data context}.
1513      *
1514      * @param timeZone time zone
1515      * @return string representation of the instance,
1516      * in ISO-8601 format with milliseconds accuracy
1517      * @see #toString(TimeZone, TimeScale)
1518      */
1519     @DefaultDataContext
1520     public String toString(final TimeZone timeZone) {
1521         return date.toString(timeZone);
1522     }
1523 
1524     /**
1525      * Get a String representation of the instant location for a time zone.
1526      *
1527      * @param timeZone time zone
1528      * @param utc      time scale used to compute date and time components.
1529      * @return string representation of the instance, in ISO-8601 format with milliseconds
1530      * accuracy
1531      * @since 10.1
1532      */
1533     public String toString(final TimeZone timeZone, final TimeScale utc) {
1534         return date.toString(timeZone, utc);
1535     }
1536 
1537     /**
1538      * Return a string representation of this date-time, rounded to the given precision.
1539      *
1540      * <p>The format used is ISO8601 without the UTC offset.</p>
1541      *
1542      *
1543      * @param timeScale      to use to compute components.
1544      * @param fractionDigits the number of digits to include after the decimal point in
1545      *                       the string representation of the seconds. The date and time
1546      *                       is first rounded as necessary. {@code fractionDigits} must be
1547      *                       greater than or equal to {@code 0}.
1548      * @return string representation of this date, time, and UTC offset
1549      * @see #toString(TimeScale)
1550      * @see DateTimeComponents#toString(int, int)
1551      * @see DateTimeComponents#toStringWithoutUtcOffset(int, int)
1552      * @since 12.2
1553      */
1554     public String toStringWithoutUtcOffset(final TimeScale timeScale, final int fractionDigits) {
1555         return date.toStringWithoutUtcOffset(timeScale, fractionDigits);
1556     }
1557 
1558     /** Get a time-shifted date.
1559      * <p>
1560      * Calling this method is equivalent to call <code>new FieldAbsoluteDate(this, dt)</code>.
1561      * </p>
1562      * @param dt time shift in seconds
1563      * @return a new date, shifted with respect to instance (which is immutable)
1564      * @see org.orekit.utils.FieldPVCoordinates#shiftedBy(double)
1565      * @see org.orekit.attitudes.FieldAttitude#shiftedBy(double)
1566      * @see org.orekit.orbits.FieldOrbit#shiftedBy(double)
1567      * @see org.orekit.propagation.FieldSpacecraftState#shiftedBy(double)
1568      */
1569     @Override
1570     public FieldAbsoluteDate<T> shiftedBy(final double dt) {
1571         return new FieldAbsoluteDate<>(this, dt);
1572     }
1573 
1574     /** Get a time-shifted date.
1575      * <p>
1576      * Calling this method is equivalent to call <code>new FieldAbsoluteDate(this, dt)</code>.
1577      * </p>
1578      * @param dt time shift
1579      * @return a new date, shifted with respect to instance (which is immutable)
1580      * @see org.orekit.utils.FieldPVCoordinates#shiftedBy(double)
1581      * @see org.orekit.attitudes.FieldAttitude#shiftedBy(double)
1582      * @see org.orekit.orbits.FieldOrbit#shiftedBy(double)
1583      * @see org.orekit.propagation.FieldSpacecraftState#shiftedBy(double)
1584      * @since 13.0
1585      */
1586     @Override
1587     public FieldAbsoluteDate<T> shiftedBy(final TimeOffset dt) {
1588         return new FieldAbsoluteDate<>(this, dt);
1589     }
1590 
1591     /** Get a time-shifted date.
1592      * <p>
1593      * Calling this method is equivalent to call <code>new FieldAbsoluteDate(this, dt, timeUnit)</code>.
1594      * </p>
1595      * @param dt time shift in time units
1596      * @param timeUnit {@link TimeUnit} for dt
1597      * @return a new date, shifted with respect to instance (which is immutable)
1598      * @see org.orekit.utils.FieldPVCoordinates#shiftedBy(double)
1599      * @see org.orekit.attitudes.FieldAttitude#shiftedBy(double)
1600      * @see org.orekit.orbits.FieldOrbit#shiftedBy(double)
1601      * @see org.orekit.propagation.FieldSpacecraftState#shiftedBy(double)
1602      * @since 12.1
1603      */
1604     public FieldAbsoluteDate<T> shiftedBy(final long dt, final TimeUnit timeUnit) {
1605         return new FieldAbsoluteDate<>(this, dt, timeUnit);
1606     }
1607 
1608 
1609     /** Transform the FieldAbsoluteDate in an AbsoluteDate.
1610      * @return AbsoluteDate of the FieldObject
1611      * */
1612     public AbsoluteDate toAbsoluteDate() {
1613         return date;
1614     }
1615 
1616     /** Check if the Field is semantically equal to zero.
1617      *
1618      * <p> Using {@link FieldElement#isZero()}
1619      *
1620      * @return true the Field is semantically equal to zero
1621      * @since 12.0
1622      */
1623     public boolean hasZeroField() {
1624         return fieldOffset.getAddendum().isZero();
1625     }
1626 
1627     /**
1628      * Return the given date as a Modified Julian Date <b>expressed in UTC</b>.
1629      *
1630      * @return double representation of the given date as Modified Julian Date.
1631      * @since 12.2
1632      */
1633     @DefaultDataContext
1634     public T getMJD() {
1635         return this.getMJD(TimeScalesFactory.getUTC());
1636     }
1637 
1638     /**
1639      * Return the given date as a Modified Julian Date expressed in given timescale.
1640      *
1641      * @param ts time scale
1642      * @return double representation of the given date as Modified Julian Date.
1643      * @since 12.2
1644      */
1645     public T getMJD(final TimeScale ts) {
1646         final T shift = fieldOffset.divide(Constants.JULIAN_DAY);
1647         return shift.add(date.getMJD(ts));
1648     }
1649 
1650     /**
1651      * Return the given date as a Julian Date <b>expressed in UTC</b>.
1652      *
1653      * @return double representation of the given date as Julian Date.
1654      * @since 12.2
1655      */
1656     @DefaultDataContext
1657     public T getJD() {
1658         return getJD(TimeScalesFactory.getUTC());
1659     }
1660 
1661     /**
1662      * Return the given date as a Julian Date expressed in given timescale.
1663      *
1664      * @param ts time scale
1665      * @return double representation of the given date as Julian Date.
1666      * @since 12.2
1667      */
1668     public T getJD(final TimeScale ts) {
1669         final T shift = fieldOffset.divide(Constants.JULIAN_DAY);
1670         return shift.add(date.getJD(ts));
1671     }
1672 
1673     /** Get day of year, preserving continuity as much as possible.
1674      * <p>
1675      * This is a continuous extension of the integer value returned by
1676      * {@link #getComponents(TimeZone) getComponents(utc)}{@link DateTimeComponents#getDate() .getDate()}{@link DateComponents#getDayOfYear() .getDayOfYear()}.
1677      * In order to have it remain as close as possible to its integer counterpart,
1678      * day 1.0 is considered to occur on January 1st at noon.
1679      * </p>
1680      * <p>
1681      * Continuity is preserved from day to day within a year, but of course
1682      * there is a discontinuity at year change, where it switches from 365.49999…
1683      * (or 366.49999… on leap years) to 0.5
1684      * </p>
1685      * @param utc time scale to compute date components
1686      * @return day of year, with day 1.0 occurring on January first at noon
1687      * @since 13.0
1688      */
1689     public T getDayOfYear(final TimeScale utc) {
1690         final int                  year         = date.getComponents(utc).getDate().getYear();
1691         final AbsoluteDate         newYearsEveD = new AbsoluteDate(year - 1, 12, 31, 12, 0, 0.0, utc);
1692         final FieldAbsoluteDate<T> newYearsEveF = new FieldAbsoluteDate<>(getField(), newYearsEveD);
1693         return durationFrom(newYearsEveF).divide(Constants.JULIAN_DAY);
1694     }
1695 
1696 }