1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.time;
18
19
20 import java.io.ByteArrayInputStream;
21 import java.io.ByteArrayOutputStream;
22 import java.io.IOException;
23 import java.io.ObjectInputStream;
24 import java.io.ObjectOutputStream;
25 import java.lang.reflect.Field;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.concurrent.ExecutorService;
30 import java.util.concurrent.Executors;
31 import java.util.concurrent.TimeUnit;
32
33 import org.hamcrest.MatcherAssert;
34 import org.hipparchus.random.RandomGenerator;
35 import org.hipparchus.random.Well1024a;
36 import org.hipparchus.util.Decimal64Field;
37 import org.junit.After;
38 import org.junit.Assert;
39 import org.junit.Before;
40 import org.junit.Test;
41 import org.orekit.OrekitMatchers;
42 import org.orekit.Utils;
43 import org.orekit.errors.OrekitException;
44 import org.orekit.errors.OrekitMessages;
45 import org.orekit.utils.Constants;
46
47 public class UTCScaleTest {
48
49 @Test
50 public void testAfter() {
51 AbsoluteDate d1 = new AbsoluteDate(new DateComponents(2020, 12, 31),
52 new TimeComponents(23, 59, 59),
53 utc);
54 Assert.assertEquals("2020-12-31T23:59:59.000Z", d1.toString());
55 }
56
57 @Test
58 public void testNoLeap() {
59 Assert.assertEquals("UTC", utc.toString());
60 AbsoluteDate d1 = new AbsoluteDate(new DateComponents(1999, 12, 31),
61 new TimeComponents(23, 59, 59),
62 utc);
63 AbsoluteDate d2 = new AbsoluteDate(new DateComponents(2000, 01, 01),
64 new TimeComponents(00, 00, 01),
65 utc);
66 Assert.assertEquals(2.0, d2.durationFrom(d1), 1.0e-10);
67 }
68
69 @Test
70 public void testLeap2006() {
71 AbsoluteDate leapDate =
72 new AbsoluteDate(new DateComponents(2006, 01, 01), TimeComponents.H00, utc);
73 AbsoluteDate d1 = leapDate.shiftedBy(-1);
74 AbsoluteDate d2 = leapDate.shiftedBy(+1);
75 Assert.assertEquals(2.0, d2.durationFrom(d1), 1.0e-10);
76
77 AbsoluteDate d3 = new AbsoluteDate(new DateComponents(2005, 12, 31),
78 new TimeComponents(23, 59, 59),
79 utc);
80 AbsoluteDate d4 = new AbsoluteDate(new DateComponents(2006, 01, 01),
81 new TimeComponents(00, 00, 01),
82 utc);
83 Assert.assertEquals(3.0, d4.durationFrom(d3), 1.0e-10);
84 }
85
86 @Test
87 public void testDuringLeap() {
88 AbsoluteDate d = new AbsoluteDate(new DateComponents(1983, 06, 30),
89 new TimeComponents(23, 59, 59),
90 utc);
91 Assert.assertEquals("1983-06-30T23:58:59.000", d.shiftedBy(-60).toString(utc));
92 Assert.assertEquals(60, utc.minuteDuration(d.shiftedBy(-60)));
93 Assert.assertFalse(utc.insideLeap(d.shiftedBy(-60)));
94 Assert.assertEquals("1983-06-30T23:59:59.000", d.toString(utc));
95 Assert.assertEquals(61, utc.minuteDuration(d));
96 Assert.assertFalse(utc.insideLeap(d));
97 d = d.shiftedBy(0.251);
98 Assert.assertEquals("1983-06-30T23:59:59.251", d.toString(utc));
99 Assert.assertEquals(61, utc.minuteDuration(d));
100 Assert.assertFalse(utc.insideLeap(d));
101 d = d.shiftedBy(0.251);
102 Assert.assertEquals("1983-06-30T23:59:59.502", d.toString(utc));
103 Assert.assertEquals(61, utc.minuteDuration(d));
104 Assert.assertFalse(utc.insideLeap(d));
105 d = d.shiftedBy(0.251);
106 Assert.assertEquals("1983-06-30T23:59:59.753", d.toString(utc));
107 Assert.assertEquals(61, utc.minuteDuration(d));
108 Assert.assertFalse(utc.insideLeap(d));
109 d = d.shiftedBy( 0.251);
110 Assert.assertEquals("1983-06-30T23:59:60.004", d.toString(utc));
111 Assert.assertEquals(61, utc.minuteDuration(d));
112 Assert.assertTrue(utc.insideLeap(d));
113 d = d.shiftedBy(0.251);
114 Assert.assertEquals("1983-06-30T23:59:60.255", d.toString(utc));
115 Assert.assertEquals(61, utc.minuteDuration(d));
116 Assert.assertTrue(utc.insideLeap(d));
117 d = d.shiftedBy(0.251);
118 Assert.assertEquals("1983-06-30T23:59:60.506", d.toString(utc));
119 Assert.assertEquals(61, utc.minuteDuration(d));
120 d = d.shiftedBy(0.251);
121 Assert.assertEquals("1983-06-30T23:59:60.757", d.toString(utc));
122 Assert.assertEquals(61, utc.minuteDuration(d));
123 Assert.assertTrue(utc.insideLeap(d));
124 d = d.shiftedBy(0.251);
125 Assert.assertEquals("1983-07-01T00:00:00.008", d.toString(utc));
126 Assert.assertEquals(60, utc.minuteDuration(d));
127 Assert.assertFalse(utc.insideLeap(d));
128 }
129
130 @Test
131 public void testWrapBeforeLeap() {
132 AbsoluteDate t = new AbsoluteDate("2015-06-30T23:59:59.999999", utc);
133 Assert.assertEquals("2015-06-30T23:59:60.000+00:00",
134 t.getComponents(utc).toString(utc.minuteDuration(t)));
135 }
136
137 @Test
138 public void testMinuteDuration() {
139 final AbsoluteDate t0 = new AbsoluteDate("1983-06-30T23:58:59.000", utc);
140 for (double dt = 0; dt < 63; dt += 0.3) {
141 if (dt < 1.0) {
142
143 Assert.assertEquals(60, utc.minuteDuration(t0.shiftedBy(dt)));
144 } else if (dt < 62.0) {
145
146 Assert.assertEquals(61, utc.minuteDuration(t0.shiftedBy(dt)));
147 } else {
148
149 Assert.assertEquals(60, utc.minuteDuration(t0.shiftedBy(dt)));
150 }
151 }
152 }
153
154
155
156
157
158
159
160 @Test
161 public void testMinuteDurationConsistentWithLeap() throws ReflectiveOperationException {
162
163
164 Field field = UTCScale.class.getDeclaredField("offsets");
165 field.setAccessible(true);
166 UTCTAIOffset[] offsets = (UTCTAIOffset[]) field.get(utc);
167
168
169 for (UTCTAIOffset offset : offsets) {
170
171 final AbsoluteDate start = offset.getDate();
172 final AbsoluteDate end = offset.getValidityStart();
173 AbsoluteDate d = start.shiftedBy(end.durationFrom(start) / 2.0);
174 int excess = utc.minuteDuration(d) - 60;
175 double leap = offset.getLeap();
176
177 Assert.assertTrue(
178 "at MJD" + offset.getMJD() + ": " + leap + " <= " + excess,
179 leap <= excess);
180 Assert.assertTrue(leap > (excess - 1));
181
182 d = start.shiftedBy(-30);
183 int newExcess = utc.minuteDuration(d) - 60;
184 double newLeap = offset.getLeap();
185
186 Assert.assertTrue(
187 "at MJD" + offset.getMJD() + ": " + newLeap + " <= " + newExcess,
188 newLeap <= newExcess);
189 Assert.assertTrue(leap > (excess - 1));
190 Assert.assertEquals(excess, newExcess);
191 Assert.assertEquals(leap, newLeap, 0.0);
192 MatcherAssert.assertThat("" + offset.getValidityStart(), leap,
193 OrekitMatchers.numberCloseTo(end.durationFrom(start), 1e-16, 1));
194 }
195 }
196
197 @Test
198 public void testSymmetry() {
199 TimeScale scale = TimeScalesFactory.getGPS();
200 for (double dt = -10000; dt < 10000; dt += 123.456789) {
201 AbsoluteDate date = AbsoluteDate.J2000_EPOCH.shiftedBy(dt * Constants.JULIAN_DAY);
202 double dt1 = scale.offsetFromTAI(date);
203 DateTimeComponents components = date.getComponents(scale);
204 double dt2 = scale.offsetToTAI(components.getDate(), components.getTime());
205 Assert.assertEquals( 0.0, dt1 + dt2, 1.0e-10);
206 }
207 }
208
209 @Test
210 public void testOffsets() {
211
212
213 checkOffset(1950, 1, 1, 0);
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229 checkOffset(1961, 1, 2, -(1.422818 + 1 * 0.001296));
230 checkOffset(1961, 8, 2, -(1.372818 + 213 * 0.001296));
231 checkOffset(1962, 1, 2, -(1.845858 + 1 * 0.0011232));
232 checkOffset(1963, 11, 2, -(1.945858 + 670 * 0.0011232));
233 checkOffset(1964, 1, 2, -(3.240130 - 365 * 0.001296));
234 checkOffset(1964, 4, 2, -(3.340130 - 274 * 0.001296));
235 checkOffset(1964, 9, 2, -(3.440130 - 121 * 0.001296));
236 checkOffset(1965, 1, 2, -(3.540130 + 1 * 0.001296));
237 checkOffset(1965, 3, 2, -(3.640130 + 60 * 0.001296));
238 checkOffset(1965, 7, 2, -(3.740130 + 182 * 0.001296));
239 checkOffset(1965, 9, 2, -(3.840130 + 244 * 0.001296));
240 checkOffset(1966, 1, 2, -(4.313170 + 1 * 0.002592));
241 checkOffset(1968, 2, 2, -(4.213170 + 762 * 0.002592));
242
243
244 checkOffset(1972, 3, 5, -10);
245 checkOffset(1972, 7, 14, -11);
246 checkOffset(1979, 12, 31, -18);
247 checkOffset(1980, 1, 22, -19);
248 checkOffset(2006, 7, 7, -33);
249
250 }
251
252 private void checkOffset(int year, int month, int day, double offset) {
253 AbsoluteDate date = new AbsoluteDate(year, month, day, utc);
254 Assert.assertEquals(offset, utc.offsetFromTAI(date), 1.0e-10);
255 }
256
257 @Test
258 public void testCreatingInLeapDateUTC() {
259 AbsoluteDate previous = null;
260 final double step = 0.0625;
261 for (double seconds = 59.0; seconds < 61.0; seconds += step) {
262 final AbsoluteDate date = new AbsoluteDate(2008, 12, 31, 23, 59, seconds, utc);
263 if (previous != null) {
264 Assert.assertEquals(step, date.durationFrom(previous), 1.0e-12);
265 }
266 previous = date;
267 }
268 AbsoluteDate ad0 = new AbsoluteDate("2008-12-31T23:59:60", utc);
269 Assert.assertTrue(ad0.toString(utc).startsWith("2008-12-31T23:59:"));
270 AbsoluteDate ad1 = new AbsoluteDate("2008-12-31T23:59:59", utc).shiftedBy(1);
271 Assert.assertEquals(0, ad1.durationFrom(ad0), 1.0e-15);
272 Assert.assertEquals(1, new AbsoluteDate("2009-01-01T00:00:00", utc).durationFrom(ad0), 1.0e-15);
273 Assert.assertEquals(2, new AbsoluteDate("2009-01-01T00:00:01", utc).durationFrom(ad0), 1.0e-15);
274 }
275
276 @Test
277 public void testCreatingInLeapDateLocalTime50HoursWest() {
278
279 AbsoluteDate previous = null;
280 final double step = 0.0625;
281 for (double seconds = 59.0; seconds < 61.0; seconds += step) {
282 final AbsoluteDate date = new AbsoluteDate(new DateComponents(2008, 12, 29),
283 new TimeComponents(21, 59, seconds, -50 * 60),
284 utc);
285 if (previous != null) {
286 Assert.assertEquals(step, date.durationFrom(previous), 1.0e-12);
287 }
288 previous = date;
289 }
290 AbsoluteDate ad0 = new AbsoluteDate("2008-12-29T21:59:60-50:00", utc);
291 Assert.assertTrue(ad0.toString(utc).startsWith("2008-12-31T23:59:"));
292 AbsoluteDate ad1 = new AbsoluteDate("2008-12-29T21:59:59-50:00", utc).shiftedBy(1);
293 Assert.assertEquals(0, ad1.durationFrom(ad0), 1.0e-15);
294 Assert.assertEquals(1, new AbsoluteDate("2008-12-29T22:00:00-50:00", utc).durationFrom(ad0), 1.0e-15);
295 Assert.assertEquals(2, new AbsoluteDate("2008-12-29T22:00:01-50:00", utc).durationFrom(ad0), 1.0e-15);
296 }
297
298 @Test
299 public void testCreatingInLeapDateLocalTime50HoursEast() {
300
301 AbsoluteDate previous = null;
302 final double step = 0.0625;
303 for (double seconds = 59.0; seconds < 61.0; seconds += step) {
304 final AbsoluteDate date = new AbsoluteDate(new DateComponents(2009, 1, 3),
305 new TimeComponents(1, 59, seconds, +50 * 60),
306 utc);
307 if (previous != null) {
308 Assert.assertEquals(step, date.durationFrom(previous), 1.0e-12);
309 }
310 previous = date;
311 }
312 AbsoluteDate ad0 = new AbsoluteDate("2009-01-03T01:59:60+50:00", utc);
313 Assert.assertTrue(ad0.toString(utc).startsWith("2008-12-31T23:59:"));
314 AbsoluteDate ad1 = new AbsoluteDate("2009-01-03T01:59:59+50:00", utc).shiftedBy(1);
315 Assert.assertEquals(0, ad1.durationFrom(ad0), 1.0e-15);
316 Assert.assertEquals(1, new AbsoluteDate("2009-01-03T02:00:00+50:00", utc).durationFrom(ad0), 1.0e-15);
317 Assert.assertEquals(2, new AbsoluteDate("2009-01-03T02:00:01+50:00", utc).durationFrom(ad0), 1.0e-15);
318 }
319
320 @Test
321 public void testDisplayDuringLeap() {
322 AbsoluteDate t0 = utc.getLastKnownLeapSecond().shiftedBy(-1.0);
323 for (double dt = 0.0; dt < 3.0; dt += 0.375) {
324 AbsoluteDate t = t0.shiftedBy(dt);
325 double seconds = t.getComponents(utc).getTime().getSecond();
326 if (dt < 2.0) {
327 Assert.assertEquals(dt + 59.0, seconds, 1.0e-12);
328 } else {
329 Assert.assertEquals(dt - 2.0, seconds, 1.0e-12);
330 }
331 }
332 }
333
334 @Test
335 public void testMultithreading() {
336
337
338 RandomGenerator random = new Well1024a(6392073424l);
339 List<AbsoluteDate> datesList = new ArrayList<AbsoluteDate>();
340 List<Double> offsetsList = new ArrayList<Double>();
341 AbsoluteDate reference = utc.getFirstKnownLeapSecond().shiftedBy(-Constants.JULIAN_YEAR);
342 double testRange = utc.getLastKnownLeapSecond().durationFrom(reference) + Constants.JULIAN_YEAR;
343 for (int i = 0; i < 10000; ++i) {
344 AbsoluteDate randomDate = reference.shiftedBy(random.nextDouble() * testRange);
345 datesList.add(randomDate);
346 offsetsList.add(utc.offsetFromTAI(randomDate));
347 }
348
349
350 ExecutorService executorService = Executors.newFixedThreadPool(100);
351
352 for (int i = 0; i < datesList.size(); ++i) {
353 final AbsoluteDate date = datesList.get(i);
354 final double offset = offsetsList.get(i);
355 executorService.execute(new Runnable() {
356 public void run() {
357 Assert.assertEquals(offset, utc.offsetFromTAI(date), 1.0e-12);
358 }
359 });
360 }
361
362 try {
363 executorService.shutdown();
364 executorService.awaitTermination(3, TimeUnit.SECONDS);
365 } catch (InterruptedException ie) {
366 Assert.fail(ie.getLocalizedMessage());
367 }
368
369 }
370
371 @Test
372 public void testIssue89() {
373 AbsoluteDate firstDayLastLeap = utc.getLastKnownLeapSecond().shiftedBy(10.0);
374 AbsoluteDate rebuilt = new AbsoluteDate(firstDayLastLeap.toString(utc), utc);
375 Assert.assertEquals(0.0, rebuilt.durationFrom(firstDayLastLeap), 1.0e-12);
376 }
377
378 @Test
379 public void testOffsetToTAIBeforeFirstLeapSecond() {
380 TimeScale scale = TimeScalesFactory.getUTC();
381
382 DateComponents dateComponents = new DateComponents(1950, 1, 1);
383 double actual = scale.offsetToTAI(dateComponents, TimeComponents.H00);
384 Assert.assertEquals(0.0, actual, 1.0e-10);
385 }
386
387 @Test
388 public void testEmptyOffsets() {
389 Utils.setDataRoot("no-data");
390
391 TimeScalesFactory.addUTCTAIOffsetsLoader(new UTCTAIOffsetsLoader() {
392 public List<OffsetModel> loadOffsets() {
393 return Collections.emptyList();
394 }
395 });
396
397 try {
398 TimeScalesFactory.getUTC();
399 Assert.fail("an exception should have been thrown");
400 } catch (OrekitException oe) {
401 Assert.assertEquals(OrekitMessages.NO_IERS_UTC_TAI_HISTORY_DATA_LOADED, oe.getSpecifier());
402 }
403
404 }
405
406 @Test
407 public void testInfinityRegularDate() {
408 TimeScale scale = TimeScalesFactory.getUTC();
409 Assert.assertEquals(-36.0,
410 scale.offsetFromTAI(AbsoluteDate.FUTURE_INFINITY),
411 1.0e-15);
412 Assert.assertEquals(0.0,
413 scale.offsetFromTAI(AbsoluteDate.PAST_INFINITY),
414 1.0e-15);
415 }
416
417 @Test
418 public void testInfinityFieldDate() {
419 TimeScale scale = TimeScalesFactory.getUTC();
420 Assert.assertEquals(-36.0,
421 scale.offsetFromTAI(FieldAbsoluteDate.getFutureInfinity(Decimal64Field.getInstance())).getReal(),
422 1.0e-15);
423 Assert.assertEquals(0.0,
424 scale.offsetFromTAI(FieldAbsoluteDate.getPastInfinity(Decimal64Field.getInstance())).getReal(),
425 1.0e-15);
426 }
427
428 @Test
429 public void testSerialization() throws IOException, ClassNotFoundException {
430 UTCScale utc = TimeScalesFactory.getUTC();
431
432 ByteArrayOutputStream bos = new ByteArrayOutputStream();
433 ObjectOutputStream oos = new ObjectOutputStream(bos);
434 oos.writeObject(utc);
435
436 Assert.assertTrue(bos.size() > 50);
437 Assert.assertTrue(bos.size() < 100);
438
439 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
440 ObjectInputStream ois = new ObjectInputStream(bis);
441 UTCScale deserialized = (UTCScale) ois.readObject();
442 Assert.assertTrue(utc == deserialized);
443
444 }
445
446 @Test
447 public void testFirstAndLast() {
448
449 AbsoluteDate first = utc.getFirstKnownLeapSecond();
450 AbsoluteDate last = utc.getLastKnownLeapSecond();
451
452
453
454 Assert.assertEquals(new AbsoluteDate(2015, 6, 30, 23, 59, 60, utc), last);
455 Assert.assertEquals(new AbsoluteDate(1960, 12, 31, 23, 59, 60, utc), first);
456 }
457
458 @Test
459 public void testGetUTCTAIOffsets() {
460 final List<UTCTAIOffset> offsets = utc.getUTCTAIOffsets();
461 Assert.assertEquals(40, offsets.size());
462 final UTCTAIOffset firstOffset = offsets.get(0);
463 final UTCTAIOffset lastOffset = offsets.get(offsets.size() - 1);
464 Assert.assertEquals(37300, firstOffset.getMJD());
465 Assert.assertEquals(57204, lastOffset.getMJD());
466 }
467
468 @Before
469 public void setUp() {
470 Utils.setDataRoot("regular-data");
471 utc = TimeScalesFactory.getUTC();
472 }
473
474 @After
475 public void tearDown() {
476 utc = null;
477 }
478
479 private UTCScale utc;
480
481 }