1   /* Copyright 2002-2018 CS Systèmes d'Information
2    * Licensed to CS Systèmes d'Information (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  
20  import java.io.IOException;
21  import java.util.Date;
22  import java.util.TimeZone;
23  
24  import org.hipparchus.Field;
25  import org.hipparchus.RealFieldElement;
26  import org.hipparchus.util.Decimal64Field;
27  import org.hipparchus.util.FastMath;
28  import org.hipparchus.util.Precision;
29  import org.junit.Assert;
30  import org.junit.Before;
31  import org.junit.Test;
32  import org.orekit.Utils;
33  import org.orekit.errors.OrekitException;
34  import org.orekit.errors.OrekitIllegalArgumentException;
35  import org.orekit.errors.OrekitMessages;
36  import org.orekit.utils.Constants;
37  
38  public class FieldAbsoluteDateTest {
39  
40      private TimeScale utc;
41  
42      @Before
43      public void setUp() throws OrekitException {
44          Utils.setDataRoot("regular-data");
45          utc = TimeScalesFactory.getUTC();
46      }
47  
48      @Test
49      public void testStandardEpoch() throws OrekitException {
50          doTestStandardEpoch(Decimal64Field.getInstance());
51      }
52  
53      @Test
54      public void testStandardEpochStrings() throws OrekitException {
55          doTestStandardEpochStrings(Decimal64Field.getInstance());
56      }
57  
58      @Test
59      public void testJulianEpochRate() throws OrekitException {
60          doTestJulianEpochRate(Decimal64Field.getInstance());
61      }
62  
63      @Test
64      public void testBesselianEpochRate() throws OrekitException {
65          doTestBesselianEpochRate(Decimal64Field.getInstance());
66      }
67  
68      @Test
69      public void testLieske() throws OrekitException {
70          doTestLieske(Decimal64Field.getInstance());
71      }
72  
73      @Test
74      public void testParse() throws OrekitException {
75          doTestParse(Decimal64Field.getInstance());
76      }
77  
78      @Test
79      public void testLocalTimeParsing() throws OrekitException {
80          doTestLocalTimeParsing(Decimal64Field.getInstance());
81      }
82  
83      @Test
84      public void testTimeZoneDisplay() throws OrekitException {
85          doTestTimeZoneDisplay(Decimal64Field.getInstance());
86      }
87  
88      @Test
89      public void testLocalTimeLeapSecond() throws OrekitException, IOException {
90          doTestLocalTimeLeapSecond(Decimal64Field.getInstance());
91      }
92  
93      @Test
94      public void testTimeZoneLeapSecond() throws OrekitException {
95          doTestTimeZoneLeapSecond(Decimal64Field.getInstance());
96      }
97  
98      @Test
99      public void testParseLeap() throws OrekitException {
100         doTestParseLeap(Decimal64Field.getInstance());
101     }
102 
103     @Test
104     public void testOutput() {
105         doTestOutput(Decimal64Field.getInstance());
106     }
107 
108     @Test
109     public void testJ2000() {
110         doTestJ2000(Decimal64Field.getInstance());
111     }
112 
113     @Test
114     public void testFraction() {
115         doTestFraction(Decimal64Field.getInstance());
116     }
117 
118     @Test
119     public void testScalesOffset() {
120         doTestScalesOffset(Decimal64Field.getInstance());
121     }
122 
123     @Test
124     public void testUTC() {
125         doTestUTC(Decimal64Field.getInstance());
126     }
127 
128     @Test
129     public void test1970() {
130         doTest1970(Decimal64Field.getInstance());
131     }
132 
133     @Test
134     public void testUtcGpsOffset() {
135         doTestUtcGpsOffset(Decimal64Field.getInstance());
136     }
137 
138     @Test
139     public void testGpsDate() {
140         doTestGpsDate(Decimal64Field.getInstance());
141     }
142 
143     @Test
144     public void testMJDDate() throws OrekitException {
145         doTestMJDDate(Decimal64Field.getInstance());
146     }
147 
148     @Test
149     public void testJDDate() {
150         doTestJDDate(Decimal64Field.getInstance());
151     }
152 
153     @Test
154     public void testOffsets() {
155         doTestOffsets(Decimal64Field.getInstance());
156     }
157 
158     @Test
159     public void testBeforeAndAfterLeap() {
160         doTestBeforeAndAfterLeap(Decimal64Field.getInstance());
161     }
162 
163     @Test
164     public void testSymmetry() {
165         doTestSymmetry(Decimal64Field.getInstance());
166     }
167 
168     @Test
169     public void testEquals() {
170         doTestEquals(Decimal64Field.getInstance());
171     }
172 
173     @Test
174     public void testComponents() throws OrekitException {
175         doTestComponents(Decimal64Field.getInstance());
176     }
177 
178     @Test
179     public void testMonth() throws OrekitException {
180         doTestMonth(Decimal64Field.getInstance());
181     }
182 
183     @Test
184     public void testCCSDSUnsegmentedNoExtension() throws OrekitException {
185         doTestCCSDSUnsegmentedNoExtension(Decimal64Field.getInstance());
186     }
187 
188     @Test
189     public void testCCSDSUnsegmentedWithExtendedPreamble() throws OrekitException {
190         doTestCCSDSUnsegmentedWithExtendedPreamble(Decimal64Field.getInstance());
191     }
192 
193     @Test
194     public void testCCSDSDaySegmented() throws OrekitException {
195         doTestCCSDSDaySegmented(Decimal64Field.getInstance());
196     }
197 
198     @Test
199     public void testCCSDSCalendarSegmented() throws OrekitException {
200         doTestCCSDSCalendarSegmented(Decimal64Field.getInstance());
201     }
202 
203     @Test
204     public void testExpandedConstructors() throws OrekitException {
205         doTestExpandedConstructors(Decimal64Field.getInstance());
206     }
207 
208     @Test
209     public void testHashcode() {
210         doTestHashcode(Decimal64Field.getInstance());
211     }
212 
213     @Test
214     public void testInfinity() {
215         doTestInfinity(Decimal64Field.getInstance());
216     }
217 
218     @Test
219     public void testAccuracy() {
220         doTestAccuracy(Decimal64Field.getInstance());
221     }
222 
223     @Test
224     public void testAccuracyIssue348() throws OrekitException {
225         doTestAccuracyIssue348(Decimal64Field.getInstance());
226     }
227 
228     @Test
229     public void testIterationAccuracy() {
230         doTestIterationAccuracy(Decimal64Field.getInstance());
231     }
232 
233     @Test
234     public void testIssue142() throws OrekitException {
235         doTestIssue142(Decimal64Field.getInstance());
236     }
237 
238     @Test
239     public void testIssue148() throws OrekitException {
240         doTestIssue148(Decimal64Field.getInstance());
241     }
242 
243     @Test
244     public void testIssue149() throws OrekitException {
245         doTestIssue149(Decimal64Field.getInstance());
246     }
247 
248     @Test
249     public void testWrapAtMinuteEnd() throws OrekitException {
250         doTestWrapAtMinuteEnd(Decimal64Field.getInstance());
251     }
252 
253     private <T extends RealFieldElement<T>> void doTestStandardEpoch(final Field<T> field) throws OrekitException {
254 
255         TimeScale tai = TimeScalesFactory.getTAI();
256         TimeScale tt  = TimeScalesFactory.getTT();
257 
258         FieldAbsoluteDate<T> JuEp  = FieldAbsoluteDate.getJulianEpoch(field);
259         FieldAbsoluteDate<T> MJuEp = FieldAbsoluteDate.getModifiedJulianEpoch(field);
260         FieldAbsoluteDate<T> FiEp  = FieldAbsoluteDate.getFiftiesEpoch(field);
261         FieldAbsoluteDate<T> CCSDS = FieldAbsoluteDate.getCCSDSEpoch(field);
262         FieldAbsoluteDate<T> GaEp  = FieldAbsoluteDate.getGalileoEpoch(field);
263         FieldAbsoluteDate<T> GPSEp = FieldAbsoluteDate.getGPSEpoch(field);
264         FieldAbsoluteDate<T> JTTEP = FieldAbsoluteDate.getJ2000Epoch(field);
265 
266         Assert.assertEquals(-210866760000000l, JuEp.toDate(tt).getTime());
267         Assert.assertEquals(-3506716800000l, MJuEp.toDate(tt).getTime());
268         Assert.assertEquals(-631152000000l, FiEp.toDate(tt).getTime());
269         Assert.assertEquals(-378691200000l, CCSDS.toDate(tai).getTime());
270         Assert.assertEquals(935280032000l,  GaEp.toDate(tai).getTime());
271         Assert.assertEquals(315964819000l,  GPSEp.toDate(tai).getTime());
272         Assert.assertEquals(946728000000l,  JTTEP.toDate(tt).getTime());
273 
274     }
275 
276     private <T extends RealFieldElement<T>> void doTestStandardEpochStrings(final Field<T> field) throws OrekitException {
277 
278         Assert.assertEquals("-4712-01-01T12:00:00.000",
279                             FieldAbsoluteDate.getJulianEpoch(field).toString(TimeScalesFactory.getTT()));
280         Assert.assertEquals("1858-11-17T00:00:00.000",
281                             FieldAbsoluteDate.getModifiedJulianEpoch(field).toString(TimeScalesFactory.getTT()));
282         Assert.assertEquals("1950-01-01T00:00:00.000",
283                             FieldAbsoluteDate.getFiftiesEpoch(field).toString(TimeScalesFactory.getTT()));
284         Assert.assertEquals("1958-01-01T00:00:00.000",
285                             FieldAbsoluteDate.getCCSDSEpoch(field).toString(TimeScalesFactory.getTAI()));
286         Assert.assertEquals("1999-08-22T00:00:00.000",
287                             FieldAbsoluteDate.getGalileoEpoch(field).toString(TimeScalesFactory.getUTC()));
288         Assert.assertEquals("1980-01-06T00:00:00.000",
289                             FieldAbsoluteDate.getGPSEpoch(field).toString(TimeScalesFactory.getUTC()));
290         Assert.assertEquals("2000-01-01T12:00:00.000",
291                             FieldAbsoluteDate.getJ2000Epoch(field).toString(TimeScalesFactory.getTT()));
292         Assert.assertEquals("1970-01-01T00:00:00.000",
293                             FieldAbsoluteDate.getJavaEpoch(field).toString(TimeScalesFactory.getUTC()));
294     }
295 
296     private <T extends RealFieldElement<T>> void doTestJulianEpochRate(final Field<T> field) throws OrekitException {
297 
298         for (int i = 0; i < 10; ++i) {
299             FieldAbsoluteDate<T> j200i = FieldAbsoluteDate.createJulianEpoch(field.getZero().add(2000.0+i));
300             FieldAbsoluteDate<T> j2000 = FieldAbsoluteDate.getJ2000Epoch(field);
301             double expected    = i * Constants.JULIAN_YEAR;
302             Assert.assertEquals(expected, j200i.durationFrom(j2000).getReal(), 4.0e-15 * expected);
303         }
304 
305     }
306 
307     private <T extends RealFieldElement<T>> void doTestBesselianEpochRate(final Field<T> field) throws OrekitException {
308 
309         for (int i = 0; i < 10; ++i) {
310             FieldAbsoluteDate<T> b195i = FieldAbsoluteDate.createBesselianEpoch(field.getZero().add(1950.0 + i));
311             FieldAbsoluteDate<T> b1950 = FieldAbsoluteDate.createBesselianEpoch(field.getZero().add(1950.0));
312             double expected    = i * Constants.BESSELIAN_YEAR;
313             Assert.assertEquals(expected, b195i.durationFrom(b1950).getReal(), 4.0e-15 * expected);
314         }
315 
316     }
317 
318     private <T extends RealFieldElement<T>> void doTestLieske(final Field<T> field) throws OrekitException {
319 
320         // the following test values correspond to table 1 in the paper:
321         // Precession Matrix Based on IAU (1976) System of Astronomical Constants,
322         // Jay H. Lieske, Astronomy and Astrophysics, vol. 73, no. 3, Mar. 1979, p. 282-284
323         // http://articles.adsabs.harvard.edu/cgi-bin/nph-iarticle_query?1979A%26A....73..282L&defaultprint=YES&filetype=.pdf
324 
325         // published table, with limited accuracy
326 
327 
328         final double publishedEpsilon = 1.0e-6 * Constants.JULIAN_YEAR;
329         checkEpochs(field, 1899.999142, 1900.000000, publishedEpsilon);
330         checkEpochs(field, 1900.000000, 1900.000858, publishedEpsilon);
331         checkEpochs(field, 1950.000000, 1949.999790, publishedEpsilon);
332         checkEpochs(field, 1950.000210, 1950.000000, publishedEpsilon);
333         checkEpochs(field, 2000.000000, 1999.998722, publishedEpsilon);
334         checkEpochs(field, 2000.001278, 2000.000000, publishedEpsilon);
335 
336         // recomputed table, using directly Lieske formulas (i.e. *not* Orekit implementation) with high accuracy
337         final double accurateEpsilon = 1.2e-13 * Constants.JULIAN_YEAR;
338         checkEpochs(field, 1899.99914161068724704, 1900.00000000000000000, accurateEpsilon);
339         checkEpochs(field, 1900.00000000000000000, 1900.00085837097878165, accurateEpsilon);
340         checkEpochs(field, 1950.00000000000000000, 1949.99979044229979466, accurateEpsilon);
341         checkEpochs(field, 1950.00020956217615449, 1950.00000000000000000, accurateEpsilon);
342         checkEpochs(field, 2000.00000000000000000, 1999.99872251362080766, accurateEpsilon);
343         checkEpochs(field, 2000.00127751366506194, 2000.00000000000000000, accurateEpsilon);
344 
345     }
346 
347     private <T extends RealFieldElement<T>> void checkEpochs(final Field<T> field, final double besselianEpoch, final double julianEpoch, final double epsilon) {
348         final FieldAbsoluteDate<T> b = FieldAbsoluteDate.createBesselianEpoch(field.getZero().add(besselianEpoch));
349         final FieldAbsoluteDate<T> j = FieldAbsoluteDate.createJulianEpoch(field.getZero().add(julianEpoch));
350         Assert.assertEquals(0.0, b.durationFrom(j).getReal(), epsilon);
351     }
352 
353     private <T extends RealFieldElement<T>> void doTestParse(final Field<T> field) throws OrekitException {
354 
355         Assert.assertEquals(FieldAbsoluteDate.getModifiedJulianEpoch(field),
356                             new FieldAbsoluteDate<>(field, "1858-W46-3", TimeScalesFactory.getTT()));
357         Assert.assertEquals(FieldAbsoluteDate.getJulianEpoch(field),
358                             new FieldAbsoluteDate<>(field, "-4712-01-01T12:00:00.000", TimeScalesFactory.getTT()));
359         Assert.assertEquals(FieldAbsoluteDate.getFiftiesEpoch(field),
360                             new FieldAbsoluteDate<>(field, "1950-01-01", TimeScalesFactory.getTT()));
361         Assert.assertEquals(FieldAbsoluteDate.getCCSDSEpoch(field),
362                             new FieldAbsoluteDate<>(field, "1958-001", TimeScalesFactory.getTAI()));
363     }
364 
365     private <T extends RealFieldElement<T>> void doTestLocalTimeParsing(final Field<T> field) throws OrekitException {
366         TimeScale utc = TimeScalesFactory.getUTC();
367         Assert.assertEquals(new FieldAbsoluteDate<>(field, "2011-12-31T23:00:00",       utc),
368                             new FieldAbsoluteDate<>(field, "2012-01-01T03:30:00+04:30", utc));
369         Assert.assertEquals(new FieldAbsoluteDate<>(field, "2011-12-31T23:00:00",       utc),
370                             new FieldAbsoluteDate<>(field, "2012-01-01T03:30:00+0430",  utc));
371         Assert.assertEquals(new FieldAbsoluteDate<>(field, "2011-12-31T23:30:00",       utc),
372                             new FieldAbsoluteDate<>(field, "2012-01-01T03:30:00+04",    utc));
373         Assert.assertEquals(new FieldAbsoluteDate<>(field, "2012-01-01T05:17:00",       utc),
374                             new FieldAbsoluteDate<>(field, "2011-12-31T22:17:00-07:00", utc));
375         Assert.assertEquals(new FieldAbsoluteDate<>(field, "2012-01-01T05:17:00",       utc),
376                             new FieldAbsoluteDate<>(field, "2011-12-31T22:17:00-0700",  utc));
377         Assert.assertEquals(new FieldAbsoluteDate<>(field, "2012-01-01T05:17:00",       utc),
378                             new FieldAbsoluteDate<>(field, "2011-12-31T22:17:00-07",    utc));
379     }
380 
381     private <T extends RealFieldElement<T>> void doTestTimeZoneDisplay(final Field<T> field) throws OrekitException {
382         final TimeScale utc = TimeScalesFactory.getUTC();
383         final FieldAbsoluteDate<T> date = new FieldAbsoluteDate<>(field, "2000-01-01T01:01:01.000", utc);
384         Assert.assertEquals("2000-01-01T01:01:01.000",       date.toString());
385         Assert.assertEquals("2000-01-01T11:01:01.000+10:00", date.toString( 600));
386         Assert.assertEquals("1999-12-31T23:01:01.000-02:00", date.toString(-120));
387 
388         // winter time, Europe is one hour ahead of UTC
389         final TimeZone tz = TimeZone.getTimeZone("Europe/Paris");
390         Assert.assertEquals("2001-01-22T11:30:00.000+01:00",
391                             new FieldAbsoluteDate<>(field, "2001-01-22T10:30:00", utc).toString(tz));
392 
393         // summer time, Europe is two hours ahead of UTC
394         Assert.assertEquals("2001-06-23T11:30:00.000+02:00",
395                             new FieldAbsoluteDate<>(field, "2001-06-23T09:30:00", utc).toString(tz));
396 
397     }
398 
399     private <T extends RealFieldElement<T>> void doTestLocalTimeLeapSecond(final Field<T> field) throws OrekitException, IOException {
400 
401         TimeScale utc = TimeScalesFactory.getUTC();
402         FieldAbsoluteDate<T> beforeLeap = new FieldAbsoluteDate<>(field, "2012-06-30T23:59:59.8", utc);
403         FieldAbsoluteDate<T> inLeap     = new FieldAbsoluteDate<>(field, "2012-06-30T23:59:60.5", utc);
404         Assert.assertEquals(0.7, inLeap.durationFrom(beforeLeap).getReal(), 1.0e-12);
405        for (int minutesFromUTC = -1500; minutesFromUTC < -1499; ++minutesFromUTC) {
406             DateTimeComponents dtcBeforeLeap = beforeLeap.getComponents(minutesFromUTC);
407             DateTimeComponents dtcInsideLeap = inLeap.getComponents(minutesFromUTC);
408 
409 
410             Assert.assertEquals(dtcBeforeLeap.getDate(), dtcInsideLeap.getDate());
411 
412             Assert.assertEquals(dtcBeforeLeap.getTime().getHour(), dtcInsideLeap.getTime().getHour());
413             Assert.assertEquals(dtcBeforeLeap.getTime().getMinute(), dtcInsideLeap.getTime().getMinute());
414             Assert.assertEquals(minutesFromUTC, dtcBeforeLeap.getTime().getMinutesFromUTC());
415             Assert.assertEquals(minutesFromUTC, dtcInsideLeap.getTime().getMinutesFromUTC());
416             Assert.assertEquals(59.8, dtcBeforeLeap.getTime().getSecond(), 1.0e-10);
417             Assert.assertEquals(60.5, dtcInsideLeap.getTime().getSecond(), 1.0e-10);
418         }
419 
420     }
421 
422     private <T extends RealFieldElement<T>> void doTestTimeZoneLeapSecond(final Field<T> field) throws OrekitException {
423 
424         TimeScale utc = TimeScalesFactory.getUTC();
425         final TimeZone tz = TimeZone.getTimeZone("Europe/Paris");
426         FieldAbsoluteDate<T> localBeforeMidnight = new FieldAbsoluteDate<>(field, "2012-06-30T21:59:59.800", utc);
427         Assert.assertEquals("2012-06-30T23:59:59.800+02:00",
428                             localBeforeMidnight.toString(tz));
429         Assert.assertEquals("2012-07-01T00:00:00.800+02:00",
430                             localBeforeMidnight.shiftedBy(1.0).toString(tz));
431 
432         FieldAbsoluteDate<T> beforeLeap = new FieldAbsoluteDate<>(field, "2012-06-30T23:59:59.8", utc);
433         FieldAbsoluteDate<T> inLeap     = new FieldAbsoluteDate<>(field, "2012-06-30T23:59:60.5", utc);
434         Assert.assertEquals(0.7, inLeap.durationFrom(beforeLeap).getReal(), 1.0e-12);
435         Assert.assertEquals("2012-07-01T01:59:59.800+02:00", beforeLeap.toString(tz));
436         Assert.assertEquals("2012-07-01T01:59:60.500+02:00", inLeap.toString(tz));
437 
438     }
439 
440     private <T extends RealFieldElement<T>> void doTestParseLeap(final Field<T> field) throws OrekitException {
441         TimeScale utc = TimeScalesFactory.getUTC();
442         FieldAbsoluteDate<T> beforeLeap = new FieldAbsoluteDate<>(field, "2012-06-30T23:59:59.8", utc);
443         FieldAbsoluteDate<T> inLeap     = new FieldAbsoluteDate<>(field, "2012-06-30T23:59:60.5", utc);
444         Assert.assertEquals(0.7, inLeap.durationFrom(beforeLeap).getReal(), 1.0e-12);
445         Assert.assertEquals("2012-06-30T23:59:60.500", inLeap.toString(utc));
446     }
447 
448     private <T extends RealFieldElement<T>> void doTestOutput(final Field<T> field) {
449         TimeScale tt = TimeScalesFactory.getTT();
450         Assert.assertEquals("1950-01-01T01:01:01.000",
451                             FieldAbsoluteDate.getFiftiesEpoch(field).shiftedBy(3661.0).toString(tt));
452         Assert.assertEquals("2000-01-01T13:01:01.000",
453                             FieldAbsoluteDate.getJ2000Epoch(field).shiftedBy(3661.0).toString(tt));
454     }
455 
456     private <T extends RealFieldElement<T>> void doTestJ2000(final Field<T> field) {
457         FieldAbsoluteDate<T> FAD = new FieldAbsoluteDate<>(field);
458         Assert.assertEquals("2000-01-01T12:00:00.000",
459                             FAD.toString(TimeScalesFactory.getTT()));
460         Assert.assertEquals("2000-01-01T11:59:27.816",
461                             FAD.toString(TimeScalesFactory.getTAI()));
462         Assert.assertEquals("2000-01-01T11:58:55.816",
463                             FAD.toString(utc));
464         Assert.assertEquals("2000-01-01T12:00:00.000",
465                             FieldAbsoluteDate.getJ2000Epoch(field).toString(TimeScalesFactory.getTT()));
466         Assert.assertEquals("2000-01-01T11:59:27.816",
467                             FieldAbsoluteDate.getJ2000Epoch(field).toString(TimeScalesFactory.getTAI()));
468         Assert.assertEquals("2000-01-01T11:58:55.816",
469                             FieldAbsoluteDate.getJ2000Epoch(field).toString(utc));
470     }
471 
472     private <T extends RealFieldElement<T>> void doTestFraction(final Field<T> field) {
473         FieldAbsoluteDate<T> d =
474             new FieldAbsoluteDate<>(field, new DateComponents(2000, 01, 01), new TimeComponents(11, 59, 27.816),
475                              TimeScalesFactory.getTAI());
476         Assert.assertEquals(0, d.durationFrom(FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), 1.0e-10);
477     }
478 
479     private <T extends RealFieldElement<T>> void doTestScalesOffset(final Field<T> field) {
480         FieldAbsoluteDate<T> date = new FieldAbsoluteDate<>(field, new DateComponents(2006, 02, 24),
481                                                             new TimeComponents(15, 38, 00),
482                                                             utc);
483         Assert.assertEquals(33,
484                             date.timeScalesOffset(TimeScalesFactory.getTAI(), utc).getReal(),
485                             1.0e-10);
486     }
487 
488     private <T extends RealFieldElement<T>> void doTestUTC(final Field<T> field) {
489         FieldAbsoluteDate<T> date = new FieldAbsoluteDate<>(field, new DateComponents(2002, 01, 01),
490                                                             new TimeComponents(00, 00, 01),
491                                                             utc);
492         Assert.assertEquals("2002-01-01T00:00:01.000", date.toString());
493     }
494 
495     private <T extends RealFieldElement<T>> void doTest1970(final Field<T> field) {
496         FieldAbsoluteDate<T> date = new FieldAbsoluteDate<>(field, new Date(0l), utc);
497         Assert.assertEquals("1970-01-01T00:00:00.000", date.toString());
498     }
499 
500     private <T extends RealFieldElement<T>> void doTestUtcGpsOffset(final Field<T> field) {
501         FieldAbsoluteDate<T> date1   = new FieldAbsoluteDate<>(field, new DateComponents(2005, 8, 9),
502                                                                new TimeComponents(16, 31, 17),
503                                                                utc);
504         FieldAbsoluteDate<T> date2   = new FieldAbsoluteDate<>(field, new DateComponents(2006, 8, 9),
505                                                                new TimeComponents(16, 31, 17),
506                                                                utc);
507         FieldAbsoluteDate<T> dateRef = new FieldAbsoluteDate<>(field, new DateComponents(1980, 1, 6),
508                                                                TimeComponents.H00,
509                                                                utc);
510 
511         // 13 seconds offset between GPS time and UTC in 2005
512         long noLeapGap = ((9347 * 24 + 16) * 60 + 31) * 60 + 17;
513         long realGap   = (long) date1.durationFrom(dateRef).getReal();
514         Assert.assertEquals(13l, realGap - noLeapGap);
515 
516         // 14 seconds offset between GPS time and UTC in 2006
517         noLeapGap = ((9712 * 24 + 16) * 60 + 31) * 60 + 17;
518         realGap   = (long) date2.durationFrom(dateRef).getReal();
519         Assert.assertEquals(14l, realGap - noLeapGap);
520 
521     }
522 
523     private <T extends RealFieldElement<T>> void doTestGpsDate(final Field<T> field) {
524         FieldAbsoluteDate<T> date = FieldAbsoluteDate.createGPSDate(1387, field.getZero().add(318677000.0));
525         FieldAbsoluteDate<T> ref  = new FieldAbsoluteDate<>(field, new DateComponents(2006, 8, 9),
526                                                             new TimeComponents(16, 31, 03),
527                                                             utc);
528         Assert.assertEquals(0, date.durationFrom(ref).getReal(), 1.0e-15);
529     }
530 
531     private <T extends RealFieldElement<T>> void doTestMJDDate(final Field<T> field) throws OrekitException {
532         FieldAbsoluteDate<T> dateA = FieldAbsoluteDate.createMJDDate(51544, field.getZero().add(0.5 * Constants.JULIAN_DAY),
533                                                                      TimeScalesFactory.getTT());
534         Assert.assertEquals(0.0, FieldAbsoluteDate.getJ2000Epoch(field).durationFrom(dateA).getReal(), 1.0e-15);
535         FieldAbsoluteDate<T> dateB = FieldAbsoluteDate.createMJDDate(53774, field.getZero(), TimeScalesFactory.getUTC());
536         FieldAbsoluteDate<T> dateC = new FieldAbsoluteDate<>(field, "2006-02-08T00:00:00", TimeScalesFactory.getUTC());
537         Assert.assertEquals(0.0, dateC.durationFrom(dateB).getReal(), 1.0e-15);
538     }
539 
540     private <T extends RealFieldElement<T>> void doTestJDDate(final Field<T> field) {
541         final FieldAbsoluteDate<T> date = FieldAbsoluteDate.createJDDate(2400000, field.getZero().add(0.5 * Constants.JULIAN_DAY),
542                                                                          TimeScalesFactory.getTT());
543         Assert.assertEquals(0.0, FieldAbsoluteDate.getModifiedJulianEpoch(field).durationFrom(date).getReal(), 1.0e-15);
544     }
545 
546     private <T extends RealFieldElement<T>> void doTestOffsets(final Field<T> field) {
547         final TimeScale tai = TimeScalesFactory.getTAI();
548         FieldAbsoluteDate<T> leapStartUTC = new FieldAbsoluteDate<>(field, 1976, 12, 31, 23, 59, 59, utc);
549         FieldAbsoluteDate<T> leapEndUTC   = new FieldAbsoluteDate<>(field, 1977,  1,  1,  0,  0,  0, utc);
550         FieldAbsoluteDate<T> leapStartTAI = new FieldAbsoluteDate<>(field, 1977,  1,  1,  0,  0, 14, tai);
551         FieldAbsoluteDate<T> leapEndTAI   = new FieldAbsoluteDate<>(field, 1977,  1,  1,  0,  0, 16, tai);
552         Assert.assertEquals(leapStartUTC, leapStartTAI);
553         Assert.assertEquals(leapEndUTC, leapEndTAI);
554         Assert.assertEquals(1, leapEndUTC.offsetFrom(leapStartUTC, utc).getReal(), 1.0e-10);
555         Assert.assertEquals(1, leapEndTAI.offsetFrom(leapStartTAI, utc).getReal(), 1.0e-10);
556         Assert.assertEquals(2, leapEndUTC.offsetFrom(leapStartUTC, tai).getReal(), 1.0e-10);
557         Assert.assertEquals(2, leapEndTAI.offsetFrom(leapStartTAI, tai).getReal(), 1.0e-10);
558         Assert.assertEquals(2, leapEndUTC.durationFrom(leapStartUTC).getReal(),    1.0e-10);
559         Assert.assertEquals(2, leapEndTAI.durationFrom(leapStartTAI).getReal(),    1.0e-10);
560     }
561 
562     private <T extends RealFieldElement<T>> void doTestBeforeAndAfterLeap(final Field<T> field) {
563         final TimeScale tai = TimeScalesFactory.getTAI();
564         FieldAbsoluteDate<T> leapStart = new FieldAbsoluteDate<>(field, 1977,  1,  1,  0,  0, 14, tai);
565         FieldAbsoluteDate<T> leapEnd   = new FieldAbsoluteDate<>(field, 1977,  1,  1,  0,  0, 16, tai);
566         for (int i = -10; i < 10; ++i) {
567             final double dt = 1.1 * (2 * i - 1);
568             FieldAbsoluteDate<T> d1 = leapStart.shiftedBy(dt);
569             FieldAbsoluteDate<T> d2 = new FieldAbsoluteDate<>(leapStart, dt, tai);
570             FieldAbsoluteDate<T> d3 = new FieldAbsoluteDate<>(leapStart, dt, utc);
571             FieldAbsoluteDate<T> d4 = new FieldAbsoluteDate<>(leapEnd,   dt, tai);
572             FieldAbsoluteDate<T> d5 = new FieldAbsoluteDate<>(leapEnd,   dt, utc);
573             Assert.assertTrue(FastMath.abs(d1.durationFrom(d2).getReal()) < 1.0e-10);
574             if (dt < 0) {
575                 Assert.assertTrue(FastMath.abs(d2.durationFrom(d3).getReal()) < 1.0e-10);
576                 Assert.assertTrue(d4.durationFrom(d5).getReal() > (1.0 - 1.0e-10));
577             } else {
578                 Assert.assertTrue(d2.durationFrom(d3).getReal() < (-1.0 + 1.0e-10));
579                 Assert.assertTrue(FastMath.abs(d4.durationFrom(d5).getReal()) < 1.0e-10);
580             }
581         }
582     }
583 
584     private <T extends RealFieldElement<T>> void doTestSymmetry(final Field<T> field) {
585         final TimeScale tai = TimeScalesFactory.getTAI();
586         FieldAbsoluteDate<T> leapStart = new FieldAbsoluteDate<>(field, 1977,  1,  1,  0,  0, 14, tai);
587         for (int i = -10; i < 10; ++i) {
588             final double dt = 1.1 * (2 * i - 1);
589             Assert.assertEquals(dt, new FieldAbsoluteDate<>(leapStart, dt, utc).offsetFrom(leapStart, utc).getReal(), 1.0e-10);
590             Assert.assertEquals(dt, new FieldAbsoluteDate<>(leapStart, dt, tai).offsetFrom(leapStart, tai).getReal(), 1.0e-10);
591             Assert.assertEquals(dt, leapStart.shiftedBy(dt).durationFrom(leapStart).getReal(), 1.0e-10);
592         }
593     }
594 
595     @SuppressWarnings("unlikely-arg-type")
596     private <T extends RealFieldElement<T>> void doTestEquals(final Field<T> field) {
597         FieldAbsoluteDate<T> d1 =
598             new FieldAbsoluteDate<>(field, new DateComponents(2006, 2, 25),
599                                     new TimeComponents(17, 10, 34),
600                                     utc);
601         FieldAbsoluteDate<T> d2 = new FieldAbsoluteDate<>(field, new DateComponents(2006, 2, 25),
602                                                           new TimeComponents(17, 10, 0),
603                                                           utc).shiftedBy(34);
604         Assert.assertTrue(d1.equals(d2));
605         Assert.assertFalse(d1.equals(this));
606     }
607 
608     private <T extends RealFieldElement<T>> void doTestComponents(final Field<T> field) throws OrekitException {
609         // this is NOT J2000.0,
610         // it is either a few seconds before or after depending on time scale
611         DateComponents date = new DateComponents(2000, 1, 1);
612         TimeComponents time = new TimeComponents(11, 59, 10);
613         TimeScale[] scales = {
614             TimeScalesFactory.getTAI(), TimeScalesFactory.getUTC(),
615             TimeScalesFactory.getTT(), TimeScalesFactory.getTCG()
616         };
617         for (int i = 0; i < scales.length; ++i) {
618             FieldAbsoluteDate<T> in = new FieldAbsoluteDate<>(field, date, time, scales[i]);
619             for (int j = 0; j < scales.length; ++j) {
620                 DateTimeComponents pair = in.getComponents(scales[j]);
621                 if (i == j) {
622                     Assert.assertEquals(date, pair.getDate());
623                     Assert.assertEquals(time, pair.getTime());
624                 } else {
625                     Assert.assertNotSame(date, pair.getDate());
626                     Assert.assertNotSame(time, pair.getTime());
627                 }
628             }
629         }
630     }
631 
632     private <T extends RealFieldElement<T>> void doTestMonth(final Field<T> field) throws OrekitException {
633         TimeScale utc = TimeScalesFactory.getUTC();
634         Assert.assertEquals(new FieldAbsoluteDate<>(field, 2011, 2, 23, utc),
635                             new FieldAbsoluteDate<>(field, 2011, Month.FEBRUARY, 23, utc));
636         Assert.assertEquals(new FieldAbsoluteDate<>(field, 2011, 2, 23, 1, 2, 3.4, utc),
637                             new FieldAbsoluteDate<>(field, 2011, Month.FEBRUARY, 23, 1, 2, 3.4, utc));
638     }
639 
640     private <T extends RealFieldElement<T>> void doTestCCSDSUnsegmentedNoExtension(final Field<T> field) throws OrekitException {
641         FieldAbsoluteDate<T> reference = new FieldAbsoluteDate<>(field, "2002-05-23T12:34:56.789", utc);
642         double lsb = FastMath.pow(2.0, -24);
643 
644         byte[] timeCCSDSEpoch = new byte[] { 0x53, 0x7F, 0x40, -0x70, -0x37, -0x05, -0x19 };
645         for (int preamble = 0x00; preamble < 0x80; ++preamble) {
646             if (preamble == 0x1F) {
647                 // using CCSDS reference epoch
648                 FieldAbsoluteDate<T> ccsds1 =
649                                 FieldAbsoluteDate.parseCCSDSUnsegmentedTimeCode(field, (byte) preamble, (byte) 0x0, timeCCSDSEpoch, null);
650                 Assert.assertEquals(0, ccsds1.durationFrom(reference).getReal(), lsb / 2);
651             } else {
652                 try {
653                     FieldAbsoluteDate.parseCCSDSUnsegmentedTimeCode(field, (byte) preamble, (byte) 0x0, timeCCSDSEpoch, null);
654                     Assert.fail("an exception should have been thrown");
655                 } catch (OrekitException iae) {
656                     // expected
657                 }
658 
659             }
660         }
661 
662         // missing epoch
663         byte[] timeJ2000Epoch = new byte[] { 0x04, 0x7E, -0x0B, -0x10, -0x07, 0x16, -0x79 };
664         try {
665             FieldAbsoluteDate.parseCCSDSUnsegmentedTimeCode(field, (byte) 0x2F, (byte) 0x0, timeJ2000Epoch, null);
666             Assert.fail("an exception should have been thrown");
667         } catch (OrekitException iae) {
668             // expected
669         }
670 
671         // using J2000.0 epoch
672         FieldAbsoluteDate<T> ccsds3 =
673                         FieldAbsoluteDate.parseCCSDSUnsegmentedTimeCode(field, (byte) 0x2F, (byte) 0x0, timeJ2000Epoch,
674                                                                         FieldAbsoluteDate.getJ2000Epoch(field));
675         Assert.assertEquals(0, ccsds3.durationFrom(reference).getReal(), lsb / 2);
676 
677     }
678 
679     private <T extends RealFieldElement<T>> void doTestCCSDSUnsegmentedWithExtendedPreamble(final Field<T> field) throws OrekitException {
680 
681         FieldAbsoluteDate<T> reference = new FieldAbsoluteDate<>(field, "2095-03-03T22:02:45.789012345678901", utc);
682         int leap = (int) FastMath.rint(utc.offsetFromTAI(reference.toAbsoluteDate()));
683         double lsb = FastMath.pow(2.0, -48);
684 
685         byte extendedPreamble = (byte) -0x80;
686         byte identification   = (byte)  0x10;
687         byte coarseLength1    = (byte)  0x0C; // four (3 + 1) bytes
688         byte fineLength1      = (byte)  0x03; // 3 bytes
689         byte coarseLength2    = (byte)  0x20; // 1 additional byte for coarse time
690         byte fineLength2      = (byte)  0x0C; // 3 additional bytes for fine time
691         byte[] timeCCSDSEpoch = new byte[] {
692              0x01,  0x02,  0x03,  0x04,  (byte)(0x05 - leap), // 5 bytes for coarse time (seconds)
693             -0x37, -0x04, -0x4A, -0x74, -0x2C, -0x3C          // 6 bytes for fine time (sub-seconds)
694         };
695         byte preamble1 = (byte) (extendedPreamble | identification | coarseLength1 | fineLength1);
696         byte preamble2 = (byte) (coarseLength2 | fineLength2);
697         FieldAbsoluteDate<T> ccsds1 =
698                         FieldAbsoluteDate.parseCCSDSUnsegmentedTimeCode(field, preamble1, preamble2, timeCCSDSEpoch, null);
699         Assert.assertEquals(0, ccsds1.durationFrom(reference).getReal(), lsb / 2);
700 
701     }
702 
703     private <T extends RealFieldElement<T>> void doTestCCSDSDaySegmented(final Field<T> field) throws OrekitException {
704         FieldAbsoluteDate<T> reference = new FieldAbsoluteDate<>(field, "2002-05-23T12:34:56.789012345678", TimeScalesFactory.getUTC());
705         double lsb = 1.0e-13;
706         byte[] timeCCSDSEpoch = new byte[] { 0x3F, 0x55, 0x02, -0x4D, 0x2C, -0x6B, 0x00, -0x44, 0x61, 0x4E };
707 
708         for (int preamble = 0x00; preamble < 0x100; ++preamble) {
709             if (preamble == 0x42) {
710                 // using CCSDS reference epoch
711 
712                 FieldAbsoluteDate<T> ccsds1 =
713                                 FieldAbsoluteDate.parseCCSDSDaySegmentedTimeCode(field, (byte) preamble, timeCCSDSEpoch, null);
714                 Assert.assertEquals(0, ccsds1.durationFrom(reference).getReal(), lsb / 2);
715             } else {
716                 try {
717                     FieldAbsoluteDate.parseCCSDSDaySegmentedTimeCode(field, (byte) preamble, timeCCSDSEpoch, null);
718                     Assert.fail("an exception should have been thrown");
719                 } catch (OrekitException iae) {
720                     // expected
721                 }
722 
723             }
724         }
725 
726         // missing epoch
727         byte[] timeJ2000Epoch = new byte[] { 0x03, 0x69, 0x02, -0x4D, 0x2C, -0x6B, 0x00, -0x44, 0x61, 0x4E };
728         try {
729             FieldAbsoluteDate.parseCCSDSDaySegmentedTimeCode(field, (byte) 0x4A, timeJ2000Epoch, null);
730             Assert.fail("an exception should have been thrown");
731         } catch (OrekitException iae) {
732             // expected
733         }
734 
735         // using J2000.0 epoch
736         FieldAbsoluteDate<T> ccsds3 =
737                         FieldAbsoluteDate.parseCCSDSDaySegmentedTimeCode(field, (byte) 0x4A, timeJ2000Epoch, DateComponents.J2000_EPOCH);
738         Assert.assertEquals(0, ccsds3.durationFrom(reference).getReal(), lsb / 2);
739 
740         // limit to microsecond
741         byte[] timeMicrosecond = new byte[] { 0x03, 0x69, 0x02, -0x4D, 0x2C, -0x6B, 0x00, 0x0C };
742         FieldAbsoluteDate<T> ccsds4 =
743                         FieldAbsoluteDate.parseCCSDSDaySegmentedTimeCode(field, (byte) 0x49, timeMicrosecond, DateComponents.J2000_EPOCH);
744         Assert.assertEquals(-0.345678e-6, ccsds4.durationFrom(reference).getReal(), lsb / 2);
745 
746     }
747 
748     private <T extends RealFieldElement<T>> void doTestCCSDSCalendarSegmented(final Field<T> field) throws OrekitException {
749 
750         FieldAbsoluteDate<T> reference = new FieldAbsoluteDate<>(field, "2002-05-23T12:34:56.789012345678", TimeScalesFactory.getUTC());
751         double lsb = 1.0e-13;
752         FieldAbsoluteDate<T> FAD = new FieldAbsoluteDate<>(field);
753         // month of year / day of month variation
754         byte[] timeMonthDay = new byte[] { 0x07, -0x2E, 0x05, 0x17, 0x0C, 0x22, 0x38, 0x4E, 0x5A, 0x0C, 0x22, 0x38, 0x4E };
755         for (int preamble = 0x00; preamble < 0x100; ++preamble) {
756             if (preamble == 0x56) {
757                 FieldAbsoluteDate<T> ccsds1 =
758                     FAD.parseCCSDSCalendarSegmentedTimeCode((byte) preamble, timeMonthDay);
759                 Assert.assertEquals(0, ccsds1.durationFrom(reference).getReal(), lsb / 2);
760             } else {
761                 try {
762                     FAD.parseCCSDSCalendarSegmentedTimeCode((byte) preamble, timeMonthDay);
763                     Assert.fail("an exception should have been thrown");
764                 } catch (OrekitException iae) {
765                     // expected
766                 } catch (IllegalArgumentException iae) {
767                     // should happen when preamble specifies day of year variation
768                     // since there is no day 1303 (= 5 * 256 + 23) in any year ...
769                     Assert.assertEquals(preamble & 0x08, 0x08);
770                 }
771 
772             }
773         }
774 
775         // day of year variation
776         byte[] timeDay = new byte[] { 0x07, -0x2E, 0x00, -0x71, 0x0C, 0x22, 0x38, 0x4E, 0x5A, 0x0C, 0x22, 0x38, 0x4E };
777         for (int preamble = 0x00; preamble < 0x100; ++preamble) {
778             if (preamble == 0x5E) {
779                 FieldAbsoluteDate<T> ccsds1 =
780                     FAD.parseCCSDSCalendarSegmentedTimeCode((byte) preamble, timeDay);
781                 Assert.assertEquals(0, ccsds1.durationFrom(reference).getReal(), lsb / 2);
782             } else {
783                 try {
784                     FAD.parseCCSDSCalendarSegmentedTimeCode((byte) preamble, timeDay);
785                     Assert.fail("an exception should have been thrown");
786                 } catch (OrekitException iae) {
787                     // expected
788                 } catch (IllegalArgumentException iae) {
789                     // should happen when preamble specifies month of year / day of month variation
790                     // since there is no month 0 in any year ...
791                     Assert.assertEquals(preamble & 0x08, 0x00);
792                 }
793 
794             }
795         }
796 
797         // limit to microsecond
798         byte[] timeMicrosecond = new byte[] { 0x07, -0x2E, 0x00, -0x71, 0x0C, 0x22, 0x38, 0x4E, 0x5A, 0x0C };
799         FieldAbsoluteDate<T> ccsds4 =
800             FAD.parseCCSDSCalendarSegmentedTimeCode((byte) 0x5B, timeMicrosecond);
801         Assert.assertEquals(-0.345678e-6, ccsds4.durationFrom(reference).getReal(), lsb / 2);
802 
803     }
804 
805     private <T extends RealFieldElement<T>> void doTestExpandedConstructors(final Field<T> field) throws OrekitException {
806         Assert.assertEquals(new FieldAbsoluteDate<>(field, new DateComponents(2002, 05, 28),
807                                                     new TimeComponents(15, 30, 0),
808                                                     TimeScalesFactory.getUTC()),
809                      new FieldAbsoluteDate<>(field, 2002, 05, 28, 15, 30, 0, TimeScalesFactory.getUTC()));
810         Assert.assertEquals(new FieldAbsoluteDate<>(field, new DateComponents(2002, 05, 28), TimeComponents.H00,
811                                                     TimeScalesFactory.getUTC()),
812                      new FieldAbsoluteDate<>(field, 2002, 05, 28, TimeScalesFactory.getUTC()));
813         try {
814             new FieldAbsoluteDate<>(field, 2002, 05, 28, 25, 30, 0, TimeScalesFactory.getUTC());
815         } catch (OrekitIllegalArgumentException oiae) {
816             Assert.assertEquals(OrekitMessages.NON_EXISTENT_HMS_TIME, oiae.getSpecifier());
817             Assert.assertEquals(25, ((Integer) oiae.getParts()[0]).intValue());
818             Assert.assertEquals(30, ((Integer) oiae.getParts()[1]).intValue());
819             Assert.assertEquals( 0, ((Double) oiae.getParts()[2]).doubleValue(), 1.0e-15);
820         }
821     }
822 
823     private <T extends RealFieldElement<T>> void doTestHashcode(final Field<T> field) {
824         FieldAbsoluteDate<T> d1 =
825             new FieldAbsoluteDate<>(field, new DateComponents(2006, 2, 25),
826                                     new TimeComponents(17, 10, 34),
827                                     utc);
828         FieldAbsoluteDate<T> d2 = new FieldAbsoluteDate<>(field, new DateComponents(2006, 2, 25),
829                                                           new TimeComponents(17, 10, 0),
830                                                           utc).shiftedBy(34);
831         Assert.assertEquals(d1.hashCode(), d2.hashCode());
832         Assert.assertTrue(d1.hashCode() != d1.shiftedBy(1.0e-3).hashCode());
833     }
834 
835     private <T extends RealFieldElement<T>> void doTestInfinity(final Field<T> field) {
836         Assert.assertTrue(FieldAbsoluteDate.getJulianEpoch(field).compareTo(FieldAbsoluteDate.getPastInfinity(field)) > 0);
837         Assert.assertTrue(FieldAbsoluteDate.getJulianEpoch(field).compareTo(FieldAbsoluteDate.getFutureInfinity(field)) < 0);
838         Assert.assertTrue(FieldAbsoluteDate.getJ2000Epoch(field).compareTo(FieldAbsoluteDate.getPastInfinity(field)) > 0);
839         Assert.assertTrue(FieldAbsoluteDate.getJ2000Epoch(field).compareTo(FieldAbsoluteDate.getFutureInfinity(field)) < 0);
840         Assert.assertTrue(FieldAbsoluteDate.getPastInfinity(field).compareTo(FieldAbsoluteDate.getJulianEpoch(field)) < 0);
841         Assert.assertTrue(FieldAbsoluteDate.getPastInfinity(field).compareTo(FieldAbsoluteDate.getJ2000Epoch(field)) < 0);
842         Assert.assertTrue(FieldAbsoluteDate.getPastInfinity(field).compareTo(FieldAbsoluteDate.getFutureInfinity(field)) < 0);
843         Assert.assertTrue(FieldAbsoluteDate.getFutureInfinity(field).compareTo(FieldAbsoluteDate.getJulianEpoch(field)) > 0);
844         Assert.assertTrue(FieldAbsoluteDate.getFutureInfinity(field).compareTo(FieldAbsoluteDate.getJ2000Epoch(field)) > 0);
845         Assert.assertTrue(FieldAbsoluteDate.getFutureInfinity(field).compareTo(FieldAbsoluteDate.getPastInfinity(field)) > 0);
846         Assert.assertTrue(Double.isInfinite(FieldAbsoluteDate.getFutureInfinity(field).durationFrom(FieldAbsoluteDate.getJ2000Epoch(field)).getReal()));
847         Assert.assertTrue(Double.isInfinite(FieldAbsoluteDate.getFutureInfinity(field).durationFrom(FieldAbsoluteDate.getPastInfinity(field)).getReal()));
848         Assert.assertTrue(Double.isInfinite(FieldAbsoluteDate.getPastInfinity(field).durationFrom(FieldAbsoluteDate.getJ2000Epoch(field)).getReal()));
849         Assert.assertEquals("5881610-07-11T23:59:59.999",  FieldAbsoluteDate.getFutureInfinity(field).toString());
850         Assert.assertEquals("-5877490-03-03T00:00:00.000", FieldAbsoluteDate.getPastInfinity(field).toString());
851     }
852 
853     private <T extends RealFieldElement<T>> void doTestAccuracy(final Field<T> field) {
854         TimeScale tai = TimeScalesFactory.getTAI();
855         double sec = 0.281;
856         FieldAbsoluteDate<T> t = new FieldAbsoluteDate<>(field, 2010, 6, 21, 18, 42, sec, tai);
857         double recomputedSec = t.getComponents(tai).getTime().getSecond();
858         Assert.assertEquals(sec, recomputedSec, FastMath.ulp(sec));
859     }
860 
861     private <T extends RealFieldElement<T>> void doTestAccuracyIssue348(final Field<T> field)
862         throws OrekitException {
863         FieldAbsoluteDate<T> tF = new FieldAbsoluteDate<>(field,
864                                                           new DateComponents(1970, 01, 01),
865                                                           new TimeComponents(3, 25, 45.6789),
866                                                           TimeScalesFactory.getUTC());
867         AbsoluteDate tA = tF.toAbsoluteDate();
868         double delta = -0.01;
869         T recomputedDelta = tF.shiftedBy(delta).durationFrom(tA);
870         Assert.assertEquals(delta, recomputedDelta.getReal(), 1.0e-17);
871     }
872 
873     private <T extends RealFieldElement<T>> void doTestIterationAccuracy(final Field<T> field) {
874 
875         final TimeScale tai = TimeScalesFactory.getTAI();
876         final FieldAbsoluteDate<T> t0 = new FieldAbsoluteDate<>(field, 2010, 6, 21, 18, 42, 0.281, tai);
877 
878         // 0.1 is not representable exactly in double precision
879         // we will accumulate error, between -0.5ULP and -3ULP at each iteration
880         checkIteration(0.1, t0, 10000, 3.0, -1.19, 1.0e-4);
881 
882         // 0.125 is representable exactly in double precision
883         // error will be null
884         checkIteration(0.125, t0, 10000, 1.0e-15, 0.0, 1.0e-15);
885     }
886 
887     private <T extends RealFieldElement<T>> void checkIteration(final double step, final FieldAbsoluteDate<T> t0, final int nMax,
888                                 final double maxErrorFactor,
889                                 final double expectedMean, final double meanTolerance) {
890         final double epsilon = FastMath.ulp(step);
891         FieldAbsoluteDate<T> iteratedDate = t0;
892         double mean = 0;
893         for (int i = 1; i < nMax; ++i) {
894             iteratedDate = iteratedDate.shiftedBy(step);
895             FieldAbsoluteDate<T> directDate = t0.shiftedBy(i * step);
896             final T error = iteratedDate.durationFrom(directDate);
897             mean += error.getReal() / (i * epsilon);
898             Assert.assertEquals(0.0, iteratedDate.durationFrom(directDate).getReal(), maxErrorFactor * i * epsilon);
899         }
900         mean /= nMax;
901         Assert.assertEquals(expectedMean, mean, meanTolerance);
902     }
903 
904     private <T extends RealFieldElement<T>> void doTestIssue142(final Field<T> field) throws OrekitException {
905         final FieldAbsoluteDate<T> epoch = FieldAbsoluteDate.getJavaEpoch(field);
906         final TimeScale utc = TimeScalesFactory.getUTC();
907 
908         Assert.assertEquals("1970-01-01T00:00:00.000", epoch.toString(utc));
909         Assert.assertEquals(0.0, epoch.durationFrom(new FieldAbsoluteDate<>(field, 1970, 1, 1, utc)).getReal(), 1.0e-15);
910         Assert.assertEquals(8.000082,
911                             epoch.durationFrom(new FieldAbsoluteDate<>(field, DateComponents.JAVA_EPOCH, TimeScalesFactory.getTAI())).getReal(),
912                             1.0e-15);
913 
914         //Milliseconds - April 1, 2006, in UTC
915         long msOffset = 1143849600000l;
916         final FieldAbsoluteDate<T> ad = new FieldAbsoluteDate<>(epoch, msOffset / 1000, TimeScalesFactory.getUTC());
917         Assert.assertEquals("2006-04-01T00:00:00.000", ad.toString(utc));
918     }
919 
920     private <T extends RealFieldElement<T>> void doTestIssue148(final Field<T> field) throws OrekitException {
921         final TimeScale utc = TimeScalesFactory.getUTC();
922         FieldAbsoluteDate<T> t0 = new FieldAbsoluteDate<>(field, 2012, 6, 30, 23, 59, 50.0, utc);
923         DateTimeComponents components = t0.shiftedBy(11.0 - 200 * Precision.EPSILON).getComponents(utc);
924         Assert.assertEquals(2012, components.getDate().getYear());
925         Assert.assertEquals(   6, components.getDate().getMonth());
926         Assert.assertEquals(  30, components.getDate().getDay());
927         Assert.assertEquals(  23, components.getTime().getHour());
928         Assert.assertEquals(  59, components.getTime().getMinute());
929         Assert.assertEquals(  61 - 200 * Precision.EPSILON,
930                             components.getTime().getSecond(), 1.0e-15);
931     }
932 
933     private <T extends RealFieldElement<T>> void doTestIssue149(final Field<T> field) throws OrekitException {
934         final TimeScale utc = TimeScalesFactory.getUTC();
935         FieldAbsoluteDate<T> t0 = new FieldAbsoluteDate<>(field, 2012, 6, 30, 23, 59, 59, utc);
936         DateTimeComponents components = t0.shiftedBy(1.0 - Precision.EPSILON).getComponents(utc);
937         Assert.assertEquals(2012, components.getDate().getYear());
938         Assert.assertEquals(   6, components.getDate().getMonth());
939         Assert.assertEquals(  30, components.getDate().getDay());
940         Assert.assertEquals(  23, components.getTime().getHour());
941         Assert.assertEquals(  59, components.getTime().getMinute());
942         Assert.assertEquals(  60 - Precision.EPSILON,
943                             components.getTime().getSecond(), 1.0e-15);
944     }
945 
946     private <T extends RealFieldElement<T>> void doTestWrapAtMinuteEnd(final Field<T> field) throws OrekitException {
947         TimeScale tai = TimeScalesFactory.getTAI();
948         TimeScale utc = TimeScalesFactory.getUTC();
949         FieldAbsoluteDate<T> date0 = new FieldAbsoluteDate<>(field, DateComponents.J2000_EPOCH, TimeComponents.H12, tai);
950         FieldAbsoluteDate<T> ref = date0.shiftedBy(496891466.0).shiftedBy(0.7320114066633323);
951         FieldAbsoluteDate<T> date = ref.shiftedBy(33 * -597.9009700426262);
952         DateTimeComponents dtc = date.getComponents(utc);
953         Assert.assertEquals(2015, dtc.getDate().getYear());
954         Assert.assertEquals(   9, dtc.getDate().getMonth());
955         Assert.assertEquals(  30, dtc.getDate().getDay());
956         Assert.assertEquals(   7, dtc.getTime().getHour());
957         Assert.assertEquals(  54, dtc.getTime().getMinute());
958         Assert.assertEquals(60 - 9.094947e-13, dtc.getTime().getSecond(), 1.0e-15);
959         Assert.assertEquals("2015-09-30T07:55:00.000",
960                             date.toString(utc));
961         FieldAbsoluteDate<T> beforeMidnight = new FieldAbsoluteDate<>(field, 2008, 2, 29, 23, 59, 59.9994, utc);
962         FieldAbsoluteDate<T> stillBeforeMidnight = beforeMidnight.shiftedBy(2.0e-4);
963         Assert.assertEquals(59.9994, beforeMidnight.getComponents(utc).getTime().getSecond(), 1.0e-15);
964         Assert.assertEquals(59.9996, stillBeforeMidnight.getComponents(utc).getTime().getSecond(), 1.0e-15);
965         Assert.assertEquals("2008-02-29T23:59:59.999", beforeMidnight.toString(utc));
966         Assert.assertEquals("2008-03-01T00:00:00.000", stillBeforeMidnight.toString(utc));
967     }
968 
969 }