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