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