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