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