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