1   /* Copyright 2022-2025 Luc Maisonobe
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.time;
18  
19  import org.hipparchus.exception.LocalizedCoreFormats;
20  import org.hipparchus.random.RandomGenerator;
21  import org.hipparchus.random.Well1024a;
22  import org.hipparchus.util.FastMath;
23  import org.junit.jupiter.api.Assertions;
24  import org.junit.jupiter.api.Test;
25  import org.orekit.errors.OrekitException;
26  import org.orekit.errors.OrekitMessages;
27  
28  import java.util.concurrent.TimeUnit;
29  
30  public class TimeOffsetTest {
31  
32      @Test
33      public void testLongsConstructor() {
34          final TimeOffset so01 = new TimeOffset(1234L, 5678L);
35          Assertions.assertEquals(1234L,               so01.getSeconds());
36          Assertions.assertEquals(5678L,               so01.getAttoSeconds());
37          Assertions.assertTrue(so01.isFinite());
38          final TimeOffset so02 = new TimeOffset(1234L, -5678L);
39          Assertions.assertEquals(1233L,               so02.getSeconds());
40          Assertions.assertEquals(999999999999994322L, so02.getAttoSeconds());
41          Assertions.assertTrue(so02.isFinite());
42          final TimeOffset so03 = new TimeOffset(1234L, -1L);
43          Assertions.assertEquals(1233L,               so03.getSeconds());
44          Assertions.assertEquals(999999999999999999L, so03.getAttoSeconds());
45          Assertions.assertTrue(so03.isFinite());
46          final TimeOffset so04 = new TimeOffset(1234L, -9223372036854775808L);
47          Assertions.assertEquals(1224L,               so04.getSeconds());
48          Assertions.assertEquals(776627963145224192L, so04.getAttoSeconds());
49          Assertions.assertTrue(so04.isFinite());
50          final TimeOffset so05 = new TimeOffset(1234L, 9223372036854775807L);
51          Assertions.assertEquals(1243L,               so05.getSeconds());
52          Assertions.assertEquals(223372036854775807L, so05.getAttoSeconds());
53          Assertions.assertTrue(so05.isFinite());
54          final TimeOffset so06 = new TimeOffset(1234L, 0L);
55          Assertions.assertEquals(1234L,               so06.getSeconds());
56          Assertions.assertEquals(0L,                  so06.getAttoSeconds());
57          Assertions.assertTrue(so06.isFinite());
58          final TimeOffset so07 = new TimeOffset(-1234L, 5678L);
59          Assertions.assertEquals(-1234L,              so07.getSeconds());
60          Assertions.assertEquals(5678L,               so07.getAttoSeconds());
61          Assertions.assertTrue(so07.isFinite());
62          final TimeOffset so08 = new TimeOffset(-1234L, -5678L);
63          Assertions.assertEquals(-1235L,              so08.getSeconds());
64          Assertions.assertEquals(999999999999994322L, so08.getAttoSeconds());
65          Assertions.assertTrue(so08.isFinite());
66          final TimeOffset so09 = new TimeOffset(-1234L, -1L);
67          Assertions.assertEquals(-1235L,              so09.getSeconds());
68          Assertions.assertEquals(999999999999999999L, so09.getAttoSeconds());
69          Assertions.assertTrue(so09.isFinite());
70          final TimeOffset so10 = new TimeOffset(-1234L, -9223372036854775808L);
71          Assertions.assertEquals(-1244L,              so10.getSeconds());
72          Assertions.assertEquals(776627963145224192L, so10.getAttoSeconds());
73          Assertions.assertTrue(so10.isFinite());
74          final TimeOffset so11 = new TimeOffset(-1234L, 9223372036854775807L);
75          Assertions.assertEquals(-1225L,              so11.getSeconds());
76          Assertions.assertEquals(223372036854775807L, so11.getAttoSeconds());
77          Assertions.assertTrue(so11.isFinite());
78          final TimeOffset so12 = new TimeOffset(-1234L, 0L);
79          Assertions.assertEquals(-1234L,              so12.getSeconds());
80          Assertions.assertEquals(0L,                  so12.getAttoSeconds());
81          Assertions.assertTrue(so12.isFinite());
82      }
83  
84      @Test
85      public void testMultiplicativeConstructor() {
86          final TimeOffset s101 = new TimeOffset(1L, 10000000000000000L);
87          Assertions.assertEquals(1.01, s101.toDouble(), 1.0e-15);
88          final TimeOffset p303 = new TimeOffset(3, s101);
89          Assertions.assertEquals(3L, p303.getSeconds());
90          Assertions.assertEquals(30000000000000000L, p303.getAttoSeconds());
91          final TimeOffset m303 = new TimeOffset(-3, s101);
92          Assertions.assertEquals(-4L, m303.getSeconds());
93          Assertions.assertEquals(970000000000000000L, m303.getAttoSeconds());
94      }
95  
96      @Test
97      public void testLinear2Constructor() {
98          final TimeOffset p3004 = new TimeOffset(3, TimeOffset.SECOND, 4, TimeOffset.MILLISECOND);
99          Assertions.assertEquals(3L, p3004.getSeconds());
100         Assertions.assertEquals(4000000000000000L, p3004.getAttoSeconds());
101         final TimeOffset m3004 = new TimeOffset(-3, TimeOffset.SECOND, -4, TimeOffset.MILLISECOND);
102         Assertions.assertEquals(-4L, m3004.getSeconds());
103         Assertions.assertEquals(996000000000000000L, m3004.getAttoSeconds());
104     }
105 
106     @Test
107     public void testLinear3Constructor() {
108         final TimeOffset p3004005 = new TimeOffset(3, TimeOffset.SECOND,
109                                                    4, TimeOffset.MILLISECOND,
110                                                    5, TimeOffset.MICROSECOND);
111         Assertions.assertEquals(3L, p3004005.getSeconds());
112         Assertions.assertEquals(4005000000000000L, p3004005.getAttoSeconds());
113         final TimeOffset m3004005 = new TimeOffset(-3, TimeOffset.SECOND,
114                                                    -4, TimeOffset.MILLISECOND,
115                                                    -5, TimeOffset.MICROSECOND);
116         Assertions.assertEquals(-4L, m3004005.getSeconds());
117         Assertions.assertEquals(995995000000000000L, m3004005.getAttoSeconds());
118     }
119 
120     @Test
121     public void testLinear4Constructor() {
122         final TimeOffset p3004005006 = new TimeOffset(3, TimeOffset.SECOND,
123                                                       4, TimeOffset.MILLISECOND,
124                                                       5, TimeOffset.MICROSECOND,
125                                                       6, TimeOffset.NANOSECOND);
126         Assertions.assertEquals(3L, p3004005006.getSeconds());
127         Assertions.assertEquals(4005006000000000L, p3004005006.getAttoSeconds());
128         final TimeOffset m3004005006 = new TimeOffset(-3, TimeOffset.SECOND,
129                                                       -4, TimeOffset.MILLISECOND,
130                                                       -5, TimeOffset.MICROSECOND,
131                                                       -6, TimeOffset.NANOSECOND);
132         Assertions.assertEquals(-4L, m3004005006.getSeconds());
133         Assertions.assertEquals(995994994000000000L, m3004005006.getAttoSeconds());
134     }
135 
136     @Test
137     public void testLinear5Constructor() {
138         final TimeOffset p3004005006007 = new TimeOffset(3, TimeOffset.SECOND,
139                                                          4, TimeOffset.MILLISECOND,
140                                                          5, TimeOffset.MICROSECOND,
141                                                          6, TimeOffset.NANOSECOND,
142                                                          7, TimeOffset.PICOSECOND);
143         Assertions.assertEquals(3L, p3004005006007.getSeconds());
144         Assertions.assertEquals(4005006007000000L, p3004005006007.getAttoSeconds());
145         final TimeOffset m3004005006007 = new TimeOffset(-3, TimeOffset.SECOND,
146                                                          -4, TimeOffset.MILLISECOND,
147                                                          -5, TimeOffset.MICROSECOND,
148                                                          -6, TimeOffset.NANOSECOND,
149                                                          -7, TimeOffset.PICOSECOND);
150         Assertions.assertEquals(-4L, m3004005006007.getSeconds());
151         Assertions.assertEquals(995994993993000000L, m3004005006007.getAttoSeconds());
152     }
153 
154     @Test
155     public void testZero() {
156         Assertions.assertTrue(new TimeOffset(0, 0).isZero());
157         Assertions.assertFalse(new TimeOffset(0, 1).isZero());
158         Assertions.assertFalse(new TimeOffset(1, 0).isZero());
159         Assertions.assertFalse(new TimeOffset(1, 1).isZero());
160     }
161 
162     @Test
163     public void testRoundSeconds() {
164         Assertions.assertEquals(1L,
165                                 new TimeOffset(1L, 499999999999999999L).getRoundedTime(TimeUnit.SECONDS));
166         Assertions.assertEquals(2L,
167                                 new TimeOffset(1L, 500000000000000000L).getRoundedTime(TimeUnit.SECONDS));
168     }
169 
170     @Test
171     public void testPositiveDoubleContructor() {
172         final double d = 123.4567890123456789;
173         final TimeOffset so = new TimeOffset(d);
174         Assertions.assertEquals(123L, so.getSeconds());
175         // error is 1676 attosecond because the primitive double is not accurate enough
176         Assertions.assertEquals(456789012345680576L, so.getAttoSeconds());
177         Assertions.assertTrue(so.isFinite());
178         Assertions.assertEquals(d, so.toDouble(), 1.0e-16);
179     }
180 
181     @Test
182     public void testNegativeDoubleContructor() {
183         final double d = -123.4567890123456789;
184         final TimeOffset so = new TimeOffset(d);
185         Assertions.assertEquals(-124L, so.getSeconds());
186         // error is 1676 attosecond because the primitive double is not accurate enough
187         Assertions.assertEquals(543210987654319424L, so.getAttoSeconds());
188         Assertions.assertTrue(so.isFinite());
189         Assertions.assertEquals(d, so.toDouble(), 1.0e-16);
190     }
191 
192     @Test
193     public void testSmallNegativeDoubleContructor() {
194         final TimeOffset so1 = new TimeOffset(-1.0e-17);
195         Assertions.assertEquals(-1L, so1.getSeconds());
196         Assertions.assertEquals(999999999999999990L, so1.getAttoSeconds());
197         Assertions.assertTrue(so1.isFinite());
198         final TimeOffset so2 = new TimeOffset(FastMath.nextDown(0.0));
199         Assertions.assertEquals(-1L, so2.getSeconds());
200         Assertions.assertEquals(1000000000000000000L, so2.getAttoSeconds());
201         Assertions.assertTrue(so2.isFinite());
202     }
203 
204     @Test
205     public void testNaNDouble() {
206 
207         final TimeOffset nan = new TimeOffset(Double.NaN);
208         Assertions.assertEquals(0L, nan.getSeconds());
209         Assertions.assertTrue(nan.isNaN());
210         Assertions.assertFalse(nan.isInfinite());
211         Assertions.assertEquals(Long.MAX_VALUE, nan.getRoundedTime(TimeUnit.DAYS));
212         Assertions.assertTrue(Double.isNaN(nan.toDouble()));
213 
214         Assertions.assertEquals(0L, TimeOffset.NaN.getSeconds());
215         Assertions.assertTrue(TimeOffset.NaN.isNaN());
216         Assertions.assertFalse(TimeOffset.NaN.isInfinite());
217         Assertions.assertEquals(Long.MAX_VALUE, TimeOffset.NaN.getRoundedTime(TimeUnit.DAYS));
218         Assertions.assertTrue(Double.isNaN(TimeOffset.NaN.toDouble()));
219 
220     }
221 
222     @Test
223     public void testPositiveInfinity() {
224 
225         final TimeOffset pos = new TimeOffset(Double.POSITIVE_INFINITY);
226         Assertions.assertEquals(Long.MAX_VALUE, pos.getSeconds());
227         Assertions.assertFalse(pos.isNaN());
228         Assertions.assertTrue(pos.isInfinite());
229         Assertions.assertFalse(pos.isNegativeInfinity());
230         Assertions.assertTrue(pos.isPositiveInfinity());
231         Assertions.assertEquals(Long.MAX_VALUE, pos.getRoundedTime(TimeUnit.DAYS));
232         Assertions.assertTrue(Double.isInfinite(pos.toDouble()));
233         Assertions.assertTrue(pos.toDouble() > 0);
234 
235         Assertions.assertEquals(Long.MAX_VALUE, TimeOffset.POSITIVE_INFINITY.getSeconds());
236         Assertions.assertFalse(TimeOffset.POSITIVE_INFINITY.isNaN());
237         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.isInfinite());
238         Assertions.assertFalse(TimeOffset.POSITIVE_INFINITY.isNegativeInfinity());
239         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.isPositiveInfinity());
240         Assertions.assertEquals(Long.MAX_VALUE, TimeOffset.POSITIVE_INFINITY.getRoundedTime(TimeUnit.DAYS));
241         Assertions.assertTrue(Double.isInfinite(TimeOffset.POSITIVE_INFINITY.toDouble()));
242         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.toDouble() > 0);
243 
244     }
245 
246     @Test
247     public void testNegativeInfinity() {
248 
249         final TimeOffset neg = new TimeOffset(Double.NEGATIVE_INFINITY);
250         Assertions.assertEquals(Long.MIN_VALUE, neg.getSeconds());
251         Assertions.assertFalse(neg.isNaN());
252         Assertions.assertTrue(neg.isInfinite());
253         Assertions.assertTrue(neg.isNegativeInfinity());
254         Assertions.assertFalse(neg.isPositiveInfinity());
255         Assertions.assertEquals(Long.MIN_VALUE, neg.getRoundedTime(TimeUnit.DAYS));
256         Assertions.assertTrue(Double.isInfinite(neg.toDouble()));
257         Assertions.assertTrue(neg.toDouble() < 0);
258 
259         Assertions.assertEquals(Long.MIN_VALUE, TimeOffset.NEGATIVE_INFINITY.getSeconds());
260         Assertions.assertFalse(TimeOffset.NEGATIVE_INFINITY.isNaN());
261         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.isInfinite());
262         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.isNegativeInfinity());
263         Assertions.assertFalse(TimeOffset.NEGATIVE_INFINITY.isPositiveInfinity());
264         Assertions.assertEquals(Long.MIN_VALUE, TimeOffset.NEGATIVE_INFINITY.getRoundedTime(TimeUnit.DAYS));
265         Assertions.assertTrue(Double.isInfinite(TimeOffset.NEGATIVE_INFINITY.toDouble()));
266         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.toDouble() < 0);
267 
268     }
269 
270     @Test
271     public void testOutOfRangeDouble() {
272 
273         final double limit = (double) Long.MAX_VALUE;
274 
275         final TimeOffset plus = new TimeOffset(limit);
276         Assertions.assertEquals(limit, plus.getRoundedTime(TimeUnit.SECONDS), 1.0e-15 * limit);
277         Assertions.assertFalse(plus.isNaN());
278         Assertions.assertFalse(plus.isInfinite());
279 
280         final TimeOffset minus = new TimeOffset(-limit);
281         Assertions.assertEquals(-limit, minus.getRoundedTime(TimeUnit.SECONDS), 1.0e-15 * limit);
282         Assertions.assertFalse(minus.isNaN());
283         Assertions.assertFalse(minus.isInfinite());
284 
285         final TimeOffset afterPlus = new TimeOffset(FastMath.nextAfter(limit, Double.POSITIVE_INFINITY));
286         Assertions.assertFalse(afterPlus.isNaN());
287         Assertions.assertTrue(afterPlus.isInfinite());
288         Assertions.assertTrue(afterPlus.getSeconds() > 0L);
289         Assertions.assertFalse(TimeOffset.POSITIVE_INFINITY.isNaN());
290         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.isInfinite());
291         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.getSeconds() > 0L);
292 
293         final TimeOffset beforeMinus = new TimeOffset(FastMath.nextAfter(-limit, Double.NEGATIVE_INFINITY));
294         Assertions.assertFalse(beforeMinus.isNaN());
295         Assertions.assertTrue(beforeMinus.isInfinite());
296         Assertions.assertTrue(beforeMinus.getSeconds() < 0L);
297         Assertions.assertFalse(beforeMinus.isNaN());
298         Assertions.assertTrue(beforeMinus.isInfinite());
299         Assertions.assertFalse(TimeOffset.NEGATIVE_INFINITY.isNaN());
300         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.isInfinite());
301         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.getSeconds() < 0L);
302 
303     }
304 
305     @Test
306     public void testSumConstructor() {
307         final TimeOffset so = new TimeOffset(new TimeOffset(1L, 902000000000000000L),
308                                              new TimeOffset(3L, 904000000000000000L),
309                                              new TimeOffset(5L, 906000000000000000L),
310                                              new TimeOffset(7L, 908000000000000000L),
311                                              new TimeOffset(9L, 910000000000000000L),
312                                              new TimeOffset(11L, 912000000000000000L),
313                                              new TimeOffset(13L, 914000000000000000L),
314                                              new TimeOffset(15L, 916000000000000000L),
315                                              new TimeOffset(17L, 918000000000000000L),
316                                              new TimeOffset(19L, 920000000000000000L),
317                                              new TimeOffset(21L, 922000000000000000L),
318                                              new TimeOffset(23L, 924000000000000000L));
319         Assertions.assertEquals(154L,                so.getSeconds());
320         Assertions.assertEquals(956000000000000000L, so.getAttoSeconds());
321     }
322 
323     @Test
324     public void testDaysTimeUnit() {
325 
326         final TimeOffset days = new TimeOffset(2, TimeUnit.DAYS);
327         Assertions.assertEquals(172800L, days.getSeconds());
328         Assertions.assertEquals(0L,      days.getAttoSeconds());
329         Assertions.assertTrue(days.isFinite());
330 
331     }
332 
333     @Test
334     public void testOutOfRangeDays() {
335         doTestOutOfRange(106751991167300L, TimeUnit.DAYS);
336     }
337 
338     @Test
339     public void testHoursTimeUnit() {
340 
341         final TimeOffset hours = new TimeOffset(2, TimeUnit.HOURS);
342         Assertions.assertEquals(7200L, hours.getSeconds());
343         Assertions.assertEquals(0L,    hours.getAttoSeconds());
344         Assertions.assertTrue(hours.isFinite());
345 
346     }
347 
348     @Test
349     public void testOutOfRangeHours() {
350         doTestOutOfRange(2562047788015215L, TimeUnit.HOURS);
351     }
352 
353     @Test
354     public void testMinutesTimeUnit() {
355 
356         final TimeOffset minutes = new TimeOffset(2, TimeUnit.MINUTES);
357         Assertions.assertEquals(120L, minutes.getSeconds());
358         Assertions.assertEquals(0L,   minutes.getAttoSeconds());
359         Assertions.assertTrue(minutes.isFinite());
360 
361     }
362 
363     @Test
364     public void testOutOfRangeMinutes() {
365         doTestOutOfRange(153722867280912929L, TimeUnit.MINUTES);
366     }
367 
368     @Test
369     public void testSecondsTimeUnit() {
370 
371         final TimeOffset seconds = new TimeOffset(2, TimeUnit.SECONDS);
372         Assertions.assertEquals(2L, seconds.getSeconds());
373         Assertions.assertEquals(0L, seconds.getAttoSeconds());
374         Assertions.assertTrue(seconds.isFinite());
375 
376     }
377 
378     @Test
379     public void testMilliSecondsTimeUnit() {
380 
381         final TimeOffset milliSeconds = new TimeOffset(2, TimeUnit.MILLISECONDS);
382         Assertions.assertEquals(0L,                milliSeconds.getSeconds());
383         Assertions.assertEquals(2000000000000000L, milliSeconds.getAttoSeconds());
384         Assertions.assertTrue(milliSeconds.isFinite());
385 
386     }
387 
388     @Test
389     public void testMicroSecondsTimeUnit() {
390 
391         final TimeOffset microSeconds = new TimeOffset(2, TimeUnit.MICROSECONDS);
392         Assertions.assertEquals(0L,             microSeconds.getSeconds());
393         Assertions.assertEquals(2000000000000L, microSeconds.getAttoSeconds());
394         Assertions.assertTrue(microSeconds.isFinite());
395 
396     }
397 
398     @Test
399     public void testNanoTimeUnit() {
400 
401         final TimeOffset nanoSeconds = new TimeOffset(2, TimeUnit.NANOSECONDS);
402         Assertions.assertEquals(0L,          nanoSeconds.getSeconds());
403         Assertions.assertEquals(2000000000L, nanoSeconds.getAttoSeconds());
404         Assertions.assertTrue(nanoSeconds.isFinite());
405 
406     }
407 
408     private void doTestOutOfRange(final long time, final TimeUnit unit) {
409 
410         final TimeOffset plus = new TimeOffset(time, unit);
411         Assertions.assertEquals( time, plus.getRoundedTime(unit));
412         Assertions.assertTrue(plus.isFinite());
413         Assertions.assertFalse(plus.isNaN());
414         Assertions.assertFalse(plus.isInfinite());
415 
416         final TimeOffset minus = new TimeOffset(-time, unit);
417         Assertions.assertEquals(-time, minus.getRoundedTime(unit));
418         Assertions.assertTrue(minus.isFinite());
419         Assertions.assertFalse(minus.isNaN());
420         Assertions.assertFalse(minus.isInfinite());
421 
422         final TimeOffset afterPlus = new TimeOffset(time + 1L, unit);
423         Assertions.assertEquals(Long.MAX_VALUE, afterPlus.getRoundedTime(unit));
424         Assertions.assertFalse(afterPlus.isFinite());
425         Assertions.assertFalse(afterPlus.isNaN());
426         Assertions.assertTrue(afterPlus.isInfinite());
427 
428         final TimeOffset beforeMinus = new TimeOffset(-time - 1L, unit);
429         Assertions.assertEquals(Long.MIN_VALUE, beforeMinus.getRoundedTime(unit));
430         Assertions.assertFalse(beforeMinus.isFinite());
431         Assertions.assertFalse(beforeMinus.isNaN());
432         Assertions.assertTrue(beforeMinus.isInfinite());
433 
434     }
435 
436     @Test
437     public void testSymmetry() {
438 
439          for (long time : new long[] {
440             Long.MIN_VALUE,
441             -4000000000000000001L, -4000000000000000000L, -3999999999999999999L,
442             -3000000000000000001L, -3000000000000000000L, -2999999999999999999L,
443             -2000000000000000001L, -2000000000000000000L, -1999999999999999999L,
444             -153722867280912930L, -153722867280912929L,
445             -2562047788015216L, -2562047788015215L,
446             -106751991167301L, -106751991167300L,
447             -86401L, -86400L, -86399L, -43201L, -43200L, -43199L,
448             -3601L, -3600L, -3599L, -1801L, -1800L, -1799L,
449             -61L, -60L, -59L, -31L, -30L, -29L,
450             -1L, 0L, 1L,
451             29L, 30L, 31L, 59L, 60L, 61L,
452             1799L, 1800L, 1801L, 3599L, 3600L, 3601L,
453             43199L, 43200L, 43201L, 86399L, 86400L, 86401L,
454             106751991167300L, 106751991167301L,
455             2562047788015215L, 2562047788015216L,
456             153722867280912929L, 153722867280912930L,
457             1999999999999999999L, 2000000000000000000L, 2000000000000000001L,
458             2999999999999999999L, 3000000000000000000L, 3000000000000000001L,
459             3999999999999999999L, 4000000000000000000L, 4000000000000000001L,
460             Long.MAX_VALUE
461         }) {
462             for (final TimeUnit tu : TimeUnit.values()) {
463                 final TimeOffset timeOffset = new TimeOffset(time, tu);
464                 final long rebuilt = timeOffset.getRoundedTime(tu);
465                 if (timeOffset.isInfinite()) {
466                     Assertions.assertEquals(time < 0 ? Long.MIN_VALUE : Long.MAX_VALUE, rebuilt);
467                 } else {
468                     Assertions.assertEquals(time, rebuilt);
469                 }
470             }
471         }
472     }
473 
474     @Test
475     public void testAdd() {
476         final TimeOffset a1 = new TimeOffset(1234L, 5678L).add(new TimeOffset(76L, -876L));
477         Assertions.assertEquals(1310L, a1.getSeconds());
478         Assertions.assertEquals(4802L, a1.getAttoSeconds());
479         Assertions.assertTrue(a1.isFinite());
480 
481         final TimeOffset a2 = new TimeOffset(1L, 500000000000000000L).add(new TimeOffset(2L, 500000000000000001L));
482         Assertions.assertEquals(4L, a2.getSeconds());
483         Assertions.assertEquals(1L, a2.getAttoSeconds());
484         Assertions.assertTrue(a2.isFinite());
485 
486         final TimeOffset a3 = new TimeOffset(1234L, 23L).add(new TimeOffset(76L, -876L));
487         Assertions.assertEquals(1309L,               a3.getSeconds());
488         Assertions.assertEquals(999999999999999147L, a3.getAttoSeconds());
489         Assertions.assertTrue(a3.isFinite());
490     }
491 
492     @Test
493     public void testAddSpecialValues() {
494 
495         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.HOUR).isNaN());
496         Assertions.assertTrue(TimeOffset.HOUR.add(TimeOffset.NaN).isNaN());
497         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.add(TimeOffset.HOUR).isPositiveInfinity());
498         Assertions.assertTrue(TimeOffset.HOUR.add(TimeOffset.POSITIVE_INFINITY).isPositiveInfinity());
499         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.add(TimeOffset.HOUR).isNegativeInfinity());
500         Assertions.assertTrue(TimeOffset.HOUR.add(TimeOffset.NEGATIVE_INFINITY).isNegativeInfinity());
501 
502         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.NaN).isNaN());
503         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.NaN).isNaN());
504         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.add(TimeOffset.NaN).isNaN());
505         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.POSITIVE_INFINITY).isNaN());
506         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.add(TimeOffset.NaN).isNaN());
507         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.NEGATIVE_INFINITY).isNaN());
508 
509         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.POSITIVE_INFINITY).isNaN());
510         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.add(TimeOffset.NaN).isNaN());
511         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.add(TimeOffset.POSITIVE_INFINITY).isPositiveInfinity());
512         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.add(TimeOffset.POSITIVE_INFINITY).isNaN());
513         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.add(TimeOffset.NEGATIVE_INFINITY).isNaN());
514 
515         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.NEGATIVE_INFINITY).isNaN());
516         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.add(TimeOffset.NaN).isNaN());
517         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.add(TimeOffset.NEGATIVE_INFINITY).isNaN());
518         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.add(TimeOffset.POSITIVE_INFINITY).isNaN());
519         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.add(TimeOffset.NEGATIVE_INFINITY).isNegativeInfinity());
520 
521     }
522 
523     @Test
524     public void testSubtract() {
525         final TimeOffset s1 = new TimeOffset(1234L, 5678L).subtract(new TimeOffset(76L, 876L));
526         Assertions.assertEquals(1158L, s1.getSeconds());
527         Assertions.assertEquals(4802L, s1.getAttoSeconds());
528         Assertions.assertTrue(s1.isFinite());
529 
530         final TimeOffset s2 = new TimeOffset(1L, 0L).subtract(new TimeOffset(2L, 1L));
531         Assertions.assertEquals(-2L, s2.getSeconds());
532         Assertions.assertEquals(999999999999999999L, s2.getAttoSeconds());
533         Assertions.assertTrue(s2.isFinite());
534 
535         final TimeOffset s3 = new TimeOffset(1234L, 999999999999999999L).subtract(new TimeOffset(76L, 123456L));
536         Assertions.assertEquals(1158L,               s3.getSeconds());
537         Assertions.assertEquals(999999999999876543L, s3.getAttoSeconds());
538         Assertions.assertTrue(s3.isFinite());
539     }
540 
541     @Test
542     public void testSubtractSpecialValues() {
543 
544         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.HOUR).isNaN());
545         Assertions.assertTrue(TimeOffset.HOUR.subtract(TimeOffset.NaN).isNaN());
546         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.subtract(TimeOffset.HOUR).isPositiveInfinity());
547         Assertions.assertTrue(TimeOffset.HOUR.subtract(TimeOffset.POSITIVE_INFINITY).isNegativeInfinity());
548         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.subtract(TimeOffset.HOUR).isNegativeInfinity());
549         Assertions.assertTrue(TimeOffset.HOUR.subtract(TimeOffset.NEGATIVE_INFINITY).isPositiveInfinity());
550 
551         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.NaN).isNaN());
552         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.NaN).isNaN());
553         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.subtract(TimeOffset.NaN).isNaN());
554         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.POSITIVE_INFINITY).isNaN());
555         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.subtract(TimeOffset.NaN).isNaN());
556         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.NEGATIVE_INFINITY).isNaN());
557 
558         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.POSITIVE_INFINITY).isNaN());
559         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.subtract(TimeOffset.NaN).isNaN());
560         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.subtract(TimeOffset.POSITIVE_INFINITY).isNaN());
561         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.subtract(TimeOffset.POSITIVE_INFINITY).isNegativeInfinity());
562         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.subtract(TimeOffset.NEGATIVE_INFINITY).isPositiveInfinity());
563 
564         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.NEGATIVE_INFINITY).isNaN());
565         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.subtract(TimeOffset.NaN).isNaN());
566         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.subtract(TimeOffset.NEGATIVE_INFINITY).isPositiveInfinity());
567         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.subtract(TimeOffset.POSITIVE_INFINITY).isNegativeInfinity());
568         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.subtract(TimeOffset.NEGATIVE_INFINITY).isNaN());
569 
570     }
571 
572     @Test
573     public void testMultiply() {
574         try {
575             new TimeOffset(1L, 45L).multiply(-1);
576         } catch (OrekitException oe) {
577             Assertions.assertEquals(OrekitMessages.NOT_POSITIVE, oe.getSpecifier());
578             Assertions.assertEquals(-1, (Long) oe.getParts()[0]);
579         }
580         checkComponents(new TimeOffset(1L, 45L).multiply(0), 0L, 0L);
581         checkComponents(new TimeOffset(1L, 45L).multiply(1), 1L, 45L);
582         checkComponents(new TimeOffset(1L, 45L).multiply(3), 3L, 135L);
583         checkComponents(new TimeOffset(1234L, 123456789012345678L).multiply(7233L), 8926414L, 962954926296288974L);
584         checkComponents(new TimeOffset(1234L, 999999999999999999L).multiply(23012696L), 28420679559L, 999999999976987304L);
585         checkComponents(new TimeOffset(1234L, 999999999999999999L).multiply(123456789012L),
586                         152469134429819L, 999999876543210988L);
587          try {
588              new TimeOffset(10000000000L, 1L).multiply(123456789012L);
589             Assertions.fail("an exception should have been thrown");
590         } catch (OrekitException oe) {
591             Assertions.assertEquals(LocalizedCoreFormats.OVERFLOW_IN_MULTIPLICATION, oe.getSpecifier());
592             Assertions.assertEquals(10000000000L, (Long) oe.getParts()[0]);
593             Assertions.assertEquals(123456789012L, (Long) oe.getParts()[1]);
594         }
595 
596         try {
597             new TimeOffset(922382683L, 717054400620018329L).multiply(1573105907129L);
598             Assertions.fail("an exception should have been thrown");
599         } catch (OrekitException oe) {
600             Assertions.assertEquals(LocalizedCoreFormats.OVERFLOW_IN_MULTIPLICATION, oe.getSpecifier());
601             Assertions.assertEquals(922382683L, (Long) oe.getParts()[0]);
602             Assertions.assertEquals(1573105907129L, (Long) oe.getParts()[1]);
603         }
604     }
605 
606     @Test
607     public void testMultiplySpecialValues() {
608         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.multiply(0).isNaN());
609         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.multiply(3).isNegativeInfinity());
610         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.multiply(0).isNaN());
611         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.multiply(3).isPositiveInfinity());
612         Assertions.assertTrue(TimeOffset.NaN.multiply(0).isNaN());
613         Assertions.assertTrue(TimeOffset.NaN.multiply(3).isNaN());
614     }
615 
616     @Test
617     public void testDivide() {
618         try {
619             new TimeOffset(1L, 45L).divide(0);
620             Assertions.fail("an exception should have been thrown");
621         } catch (OrekitException oe) {
622             Assertions.assertEquals(OrekitMessages.NOT_STRICTLY_POSITIVE, oe.getSpecifier());
623             Assertions.assertEquals(0, (Integer) oe.getParts()[0]);
624         }
625         checkComponents(new TimeOffset(1L, 45L).divide(1), 1L, 45L);
626         checkComponents(new TimeOffset(3L, 135L).divide(3), 1L, 45L);
627         checkComponents(new TimeOffset(8926414L, 962954926296288974L).divide(7233), 1234L, 123456789012345678L);
628         checkComponents(new TimeOffset(28420679559L, 999999999976987304L).divide(23012696), 1234L, 999999999999999999L);
629         checkComponents(new TimeOffset(1L, 0L).divide(1000000000), 0L, 1000000000L);
630 
631         // we consider a 15 nanosecond per UTC second slope for TAI-UTC offset (this is what was used in 1961)
632         // then 1 day in UTC corresponds to 1 day + 1296 µs in TAI, and we perform the computation the other way round
633         // we start from the 1 day + 1296 µs duration in TAI and recover the 1296 µs change in TAI-UTC offset
634         checkComponents(new TimeOffset(86400L, 1296000000000000L).multiply(15).divide(1000000015),
635                         0L, 1296000000000000L);
636 
637     }
638 
639     @Test
640     public void testRandomDivide() {
641         final RandomGenerator random = new Well1024a(0x83977774b8d4eb2eL);
642         for (int i = 0; i < 1000000; i++) {
643             final TimeOffset t = new TimeOffset(random.nextLong(1000L * 365L * 86400L),
644                                                 random.nextLong(1000000000000000000L));
645             final int p = FastMath.max(1, random.nextInt(10000000));
646             Assertions.assertEquals(0, t.compareTo(t.multiply(p).divide(p)));
647         }
648 
649     }
650 
651     @Test
652     public void testDivideSpecialValues() {
653         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.divide(3).isNegativeInfinity());
654         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.divide(3).isPositiveInfinity());
655         Assertions.assertTrue(TimeOffset.NaN.divide(3).isNaN());
656     }
657 
658     @Test
659     public void testNegate() {
660         for (long s = -1000L; s < 1000L; s += 10L) {
661             for (long a = -1000L; a < 1000L; a += 10L) {
662                 final TimeOffset st = new TimeOffset(s, a);
663                 Assertions.assertTrue(st.add(st.negate()).isZero());
664             }
665         }
666         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.negate().isNegativeInfinity());
667         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.negate().isPositiveInfinity());
668         Assertions.assertTrue(TimeOffset.NaN.negate().isNaN());
669         Assertions.assertTrue(TimeOffset.ZERO.negate().isZero());
670     }
671 
672     @Test
673     public void testCompareFinite() {
674         Assertions.assertTrue(TimeOffset.ZERO.compareTo(new TimeOffset(0L, 0L)) == 0);
675         Assertions.assertTrue(new TimeOffset(1L, 1L).compareTo(new TimeOffset(1L, 1L)) == 0);
676         Assertions.assertTrue(TimeOffset.MICROSECOND.compareTo(TimeOffset.MILLISECOND) < 0);
677         Assertions.assertTrue(TimeOffset.MILLISECOND.compareTo(TimeOffset.MICROSECOND) > 0);
678         Assertions.assertTrue(new TimeOffset(1, 2).compareTo(new TimeOffset(1, 2)) == 0);
679         Assertions.assertTrue(new TimeOffset(1, 1).compareTo(new TimeOffset(1, 2))  < 0);
680         Assertions.assertTrue(new TimeOffset(1, 2).compareTo(new TimeOffset(1, 1))  > 0);
681         Assertions.assertTrue(new TimeOffset(2, 1).compareTo(new TimeOffset(2, 1)) == 0);
682         Assertions.assertTrue(new TimeOffset(1, 1).compareTo(new TimeOffset(2, 1))  < 0);
683         Assertions.assertTrue(new TimeOffset(2, 1).compareTo(new TimeOffset(1, 1))  > 0);
684     }
685 
686     @Test
687     public void testCompareSpecialCases() {
688 
689         Assertions.assertTrue(TimeOffset.NaN.compareTo(TimeOffset.NaN)               == 0);
690         Assertions.assertTrue(TimeOffset.NaN.compareTo(TimeOffset.ATTOSECOND)        >  0);
691         Assertions.assertTrue(TimeOffset.NaN.compareTo(TimeOffset.POSITIVE_INFINITY) >  0);
692         Assertions.assertTrue(TimeOffset.NaN.compareTo(TimeOffset.NEGATIVE_INFINITY) >  0);
693 
694         Assertions.assertTrue(TimeOffset.ATTOSECOND.compareTo(TimeOffset.NaN)               <  0);
695         Assertions.assertTrue(TimeOffset.ATTOSECOND.compareTo(TimeOffset.ATTOSECOND)        == 0);
696         Assertions.assertTrue(TimeOffset.ATTOSECOND.compareTo(TimeOffset.POSITIVE_INFINITY) <  0);
697         Assertions.assertTrue(TimeOffset.ATTOSECOND.compareTo(TimeOffset.NEGATIVE_INFINITY) >  0);
698 
699         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.compareTo(TimeOffset.NaN)               <  0);
700         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.compareTo(TimeOffset.ATTOSECOND)        >  0);
701         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.compareTo(TimeOffset.POSITIVE_INFINITY) == 0);
702         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.compareTo(TimeOffset.NEGATIVE_INFINITY) >  0);
703 
704         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.compareTo(TimeOffset.NaN)               <  0);
705         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.compareTo(TimeOffset.ATTOSECOND)        <  0);
706         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.compareTo(TimeOffset.POSITIVE_INFINITY) <  0);
707         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.compareTo(TimeOffset.NEGATIVE_INFINITY) == 0);
708 
709     }
710 
711     @Test
712     public void testEquals() {
713         TimeOffset[] st = new TimeOffset[] {
714           new TimeOffset(200L, 300L), new TimeOffset(200L, 199L), new TimeOffset(199L, 300L),
715           TimeOffset.POSITIVE_INFINITY, TimeOffset.NEGATIVE_INFINITY,
716           TimeOffset.NaN, TimeOffset.DAY, TimeOffset.ZERO, TimeOffset.ATTOSECOND
717         };
718         for (int i = 0; i < st.length; i++) {
719             for (int j = 0; j < st.length; j++) {
720                 if (i == j) {
721                     Assertions.assertEquals(st[i], st[j]);
722                 } else {
723 
724                     Assertions.assertNotEquals(st[i], st[j]);
725                 }
726             }
727         }
728         final TimeOffset timeOffset = new TimeOffset(200L, 300L);
729         Assertions.assertEquals(st[0], timeOffset);
730         Assertions.assertNotSame(st[0], timeOffset);
731         Assertions.assertEquals(0,      st[0].compareTo(timeOffset));
732         Assertions.assertEquals(484,         st[0].hashCode());
733         Assertions.assertEquals(484, timeOffset.hashCode());
734         Assertions.assertEquals(254, TimeOffset.NaN.hashCode());
735         Assertions.assertEquals(-2130771969, TimeOffset.NEGATIVE_INFINITY.hashCode());
736         Assertions.assertEquals(-2147418369, TimeOffset.POSITIVE_INFINITY.hashCode());
737         Assertions.assertEquals(0, TimeOffset.ZERO.hashCode());
738         Assertions.assertEquals(1, TimeOffset.ATTOSECOND.hashCode());
739         Assertions.assertNotEquals(timeOffset, "timeOffset");
740     }
741 
742     @Test
743     public void testMultiples() {
744         for (int n = 0; n < 100; ++n) {
745             checkMultiple(n, TimeOffset.ZERO, TimeOffset.ZERO);
746         }
747         checkMultiple(1000, TimeOffset.ATTOSECOND, TimeOffset.FEMTOSECOND);
748         checkMultiple(1000, TimeOffset.FEMTOSECOND, TimeOffset.PICOSECOND);
749         checkMultiple(1000, TimeOffset.PICOSECOND, TimeOffset.NANOSECOND);
750         checkMultiple(1000, TimeOffset.NANOSECOND, TimeOffset.MICROSECOND);
751         checkMultiple(1000, TimeOffset.MICROSECOND, TimeOffset.MILLISECOND);
752         checkMultiple(1000, TimeOffset.MILLISECOND, TimeOffset.SECOND);
753         checkMultiple(60, TimeOffset.SECOND, TimeOffset.MINUTE);
754         checkMultiple(60, TimeOffset.MINUTE, TimeOffset.HOUR);
755         checkMultiple(24, TimeOffset.HOUR, TimeOffset.DAY);
756         checkMultiple(86401, TimeOffset.SECOND, TimeOffset.DAY_WITH_POSITIVE_LEAP);
757     }
758 
759     @Test
760     public void testParseEmpty() {
761         doTestParseError("");
762     }
763 
764     @Test
765     public void testParseExtraCharacters() {
766         doTestParseError("-1.2e3!xyz");
767     }
768 
769     @Test
770     public void testParseMiddleSign() {
771         doTestParseError("-1.2-3");
772     }
773 
774     @Test
775     public void testParseMinusAfterExponent() {
776         doTestParseError("-1.2e+3-1");
777     }
778 
779     @Test
780     public void testParsePlusAfterExponent() {
781         doTestParseError("-1.2e+3+1");
782     }
783 
784     @Test
785     public void testParseOverflowA() {
786         doTestParseError("10000000000000000000");
787     }
788 
789     @Test
790     public void testParseOverflowB() {
791         doTestParseError("99999999999999999999");
792     }
793 
794     @Test
795     public void testParseOverflowC() {
796         doTestParseError("9223372036854775808");
797     }
798 
799     @Test
800     public void testParseOverflowD() {
801         doTestParseError("1.0e10000000000");
802     }
803 
804     @Test
805     public void testParseOverflowE() {
806         doTestParseError("1.0e99999999999");
807     }
808 
809     @Test
810     public void testParseOverflowF() {
811         doTestParseError("1.0e2147483648");
812     }
813 
814     @Test
815     public void testParseRepeatedSeparator() {
816         doTestParseError("1.0.0");
817     }
818 
819     @Test
820     public void testParseRepeatedExponent() {
821         doTestParseError("1.0e2e3");
822     }
823 
824     private void doTestParseError(final String s) {
825         try {
826             TimeOffset.parse(s);
827             Assertions.fail("an exception should have been thrown");
828         } catch (OrekitException oe) {
829             Assertions.assertEquals(OrekitMessages.CANNOT_PARSE_DATA, oe.getSpecifier());
830             Assertions.assertEquals(s, oe.getParts()[0]);
831         }
832     }
833 
834     @Test
835     public void testParseSpecialValues() {
836         Assertions.assertTrue(TimeOffset.parse("NaN").isNaN());
837         Assertions.assertTrue(TimeOffset.parse("NAN").isNaN());
838         Assertions.assertTrue(TimeOffset.parse("nan").isNaN());
839         Assertions.assertTrue(TimeOffset.parse("-∞").isNegativeInfinity());
840         Assertions.assertTrue(TimeOffset.parse("+∞").isPositiveInfinity());
841     }
842 
843     @Test
844     public void testParseLargeExponents(){
845         Assertions.assertTrue(TimeOffset.parse("-1.0e100").isNegativeInfinity());
846         Assertions.assertTrue(TimeOffset.parse("+1.0e100").isPositiveInfinity());
847         Assertions.assertTrue(TimeOffset.parse("-0.1e100").isNegativeInfinity());
848         Assertions.assertTrue(TimeOffset.parse("+0.1e100").isPositiveInfinity());
849         Assertions.assertTrue(TimeOffset.parse("-1.1e100").isNegativeInfinity());
850         Assertions.assertTrue(TimeOffset.parse("+1.1e100").isPositiveInfinity());
851         checkComponents(TimeOffset.parse("0.0e200000"), 0L, 0L);
852     }
853 
854     @Test
855     public void testParse() {
856         checkComponents(TimeOffset.parse("0"), 0L, 0L);
857         checkComponents(TimeOffset.parse("1"), 1L, 0L);
858         checkComponents(TimeOffset.parse("-1"), -1L, 0L);
859         checkComponents(TimeOffset.parse("+0.5"), 0L, 500000000000000000L);
860         checkComponents(TimeOffset.parse("-0.5"), -1L, 500000000000000000L);
861         checkComponents(TimeOffset.parse("+.5"), 0L, 500000000000000000L);
862         checkComponents(TimeOffset.parse("-.5"), -1L, 500000000000000000L);
863         checkComponents(TimeOffset.parse("17.42357e+02"), 1742L, 357000000000000000L);
864         checkComponents(TimeOffset.parse("9223372036854775807"), Long.MAX_VALUE, 0L);
865 
866         // these are the offsets for linear UTC/TAI models before 1972
867         checkComponents(TimeOffset.parse("1.4228180"), 1L, 422818000000000000L);
868         checkComponents(TimeOffset.parse("1.3728180"), 1L, 372818000000000000L);
869         checkComponents(TimeOffset.parse("1.8458580"), 1L, 845858000000000000L);
870         checkComponents(TimeOffset.parse("1.9458580"), 1L, 945858000000000000L);
871         checkComponents(TimeOffset.parse("3.2401300"), 3L, 240130000000000000L);
872         checkComponents(TimeOffset.parse("3.3401300"), 3L, 340130000000000000L);
873         checkComponents(TimeOffset.parse("3.4401300"), 3L, 440130000000000000L);
874         checkComponents(TimeOffset.parse("3.5401300"), 3L, 540130000000000000L);
875         checkComponents(TimeOffset.parse("3.6401300"), 3L, 640130000000000000L);
876         checkComponents(TimeOffset.parse("3.7401300"), 3L, 740130000000000000L);
877         checkComponents(TimeOffset.parse("3.8401300"), 3L, 840130000000000000L);
878         checkComponents(TimeOffset.parse("4.3131700"), 4L, 313170000000000000L);
879         checkComponents(TimeOffset.parse("4.2131700"), 4L, 213170000000000000L);
880 
881         // these are the drifts for linear UTC/TAI models before 1972
882         checkComponents(TimeOffset.parse("0.001296"), 0L, 1296000000000000L);
883         checkComponents(TimeOffset.parse("0.0011232"), 0L, 1123200000000000L);
884         checkComponents(TimeOffset.parse("0.002592"), 0L, 2592000000000000L);
885 
886         // cases with exponents
887         checkComponents(TimeOffset.parse("0.001234e-05"), 0L, 12340000000L);
888         checkComponents(TimeOffset.parse("-0.001234E+05"), -124L, 600000000000000000L);
889         checkComponents(TimeOffset.parse("-0.001234E-05"), -1L, 999999987660000000L);
890         checkComponents(TimeOffset.parse("0.001e-15"), 0L, 1L);
891         checkComponents(TimeOffset.parse("-0.001e-15"), -1L, 999999999999999999L);
892         checkComponents(TimeOffset.parse("-12E-1"), -2L, 800000000000000000L);
893         checkComponents(TimeOffset.parse("-12E0"), -12L, 0L);
894         checkComponents(TimeOffset.parse("-12E-0"), -12L, 0L);
895         checkComponents(TimeOffset.parse("-12E+0"), -12L, 0L);
896         checkComponents(TimeOffset.parse("1.234e-50"), 0L, 0L);
897         checkComponents(TimeOffset.parse("1.e2"), 100L, 0L);
898 
899         // ignoring extra digits after separator
900         checkComponents(TimeOffset.parse("0.12345678901234567890123456"), 0L, 123456789012345678L);
901 
902         // various resolutions
903         checkComponents(TimeOffset.parse("12.3456e-20"), 0L, 0L);
904         checkComponents(TimeOffset.parse("12.3456e-19"), 0L, 1L);
905         checkComponents(TimeOffset.parse("12.3456e-18"), 0L, 12L);
906         checkComponents(TimeOffset.parse("12.3456e-17"), 0L, 123L);
907         checkComponents(TimeOffset.parse("12.3456e-16"), 0L, 1234L);
908         checkComponents(TimeOffset.parse("12.3456e-15"), 0L, 12345L);
909         checkComponents(TimeOffset.parse("12.3456e-14"), 0L, 123456L);
910         checkComponents(TimeOffset.parse("12.3456e-13"), 0L, 1234560L);
911         checkComponents(TimeOffset.parse("12.3456e-12"), 0L, 12345600L);
912         checkComponents(TimeOffset.parse("12.3456e-11"), 0L, 123456000L);
913         checkComponents(TimeOffset.parse("12.3456e-10"), 0L, 1234560000L);
914         checkComponents(TimeOffset.parse("12.3456e-09"), 0L, 12345600000L);
915         checkComponents(TimeOffset.parse("12.3456e-08"), 0L, 123456000000L);
916         checkComponents(TimeOffset.parse("12.3456e-07"), 0L, 1234560000000L);
917         checkComponents(TimeOffset.parse("12.3456e-06"), 0L, 12345600000000L);
918         checkComponents(TimeOffset.parse("12.3456e-05"), 0L, 123456000000000L);
919         checkComponents(TimeOffset.parse("12.3456e-04"), 0L, 1234560000000000L);
920         checkComponents(TimeOffset.parse("12.3456e-03"), 0L, 12345600000000000L);
921         checkComponents(TimeOffset.parse("12.3456e-02"), 0L, 123456000000000000L);
922         checkComponents(TimeOffset.parse("12.3456e-01"), 1L, 234560000000000000L);
923         checkComponents(TimeOffset.parse("12.3456e+00"), 12L, 345600000000000000L);
924         checkComponents(TimeOffset.parse("12.3456e+01"), 123L, 456000000000000000L);
925         checkComponents(TimeOffset.parse("12.3456e+02"), 1234L, 560000000000000000L);
926         checkComponents(TimeOffset.parse("12.3456e+03"), 12345L, 600000000000000000L);
927         checkComponents(TimeOffset.parse("12.3456e+04"), 123456L, 0L);
928         checkComponents(TimeOffset.parse("12.3456e+05"), 1234560L, 0L);
929         checkComponents(TimeOffset.parse("12.3456e+06"), 12345600L, 0L);
930         checkComponents(TimeOffset.parse("12.3456e+07"), 123456000L, 0L);
931         checkComponents(TimeOffset.parse("12.3456e+08"), 1234560000L, 0L);
932         checkComponents(TimeOffset.parse("12.3456e+09"), 12345600000L, 0L);
933         checkComponents(TimeOffset.parse("12.3456e+10"), 123456000000L, 0L);
934         checkComponents(TimeOffset.parse("12.3456e+11"), 1234560000000L, 0L);
935         checkComponents(TimeOffset.parse("12.3456e+12"), 12345600000000L, 0L);
936         checkComponents(TimeOffset.parse("12.3456e+13"), 123456000000000L, 0L);
937         checkComponents(TimeOffset.parse("12.3456e+14"), 1234560000000000L, 0L);
938         checkComponents(TimeOffset.parse("12.3456e+15"), 12345600000000000L, 0L);
939         checkComponents(TimeOffset.parse("12.3456e+16"), 123456000000000000L, 0L);
940         checkComponents(TimeOffset.parse("12.3456e+17"), 1234560000000000000L, 0L);
941 
942         // truncating to upper attosecond (NOT rounding!)
943         checkComponents(TimeOffset.parse("+1234.567890123456785012e-4"), 0L, 123456789012345678L);
944         checkComponents(TimeOffset.parse("-1234.567890123456785012e-4"), -1L, 876543210987654322L);
945         checkComponents(TimeOffset.parse("+1234.567890123456784012e-4"), 0L, 123456789012345678L);
946         checkComponents(TimeOffset.parse("-1234.567890123456784012e-4"), -1L, 876543210987654322L);
947         checkComponents(TimeOffset.parse("+9999.999999999999994000e-4"), 0L, 999999999999999999L);
948         checkComponents(TimeOffset.parse("+9999.999999999999995000e-4"), 0L, 999999999999999999L);
949         checkComponents(TimeOffset.parse("-9999.999999999999994000e-4"), -1L, 1L);
950         checkComponents(TimeOffset.parse("-9999.999999999999995000e-4"), -1L, 1L);
951         checkComponents(TimeOffset.parse("9.0e-20"), 0L, 0L);
952         checkComponents(TimeOffset.parse("4.0e-19"), 0L, 0L);
953         checkComponents(TimeOffset.parse("5.0e-19"), 0L, 0L);
954 
955         try {
956             TimeOffset.parse("A");
957         } catch (OrekitException oe) {
958             Assertions.assertEquals(OrekitMessages.CANNOT_PARSE_DATA, oe.getSpecifier());
959             Assertions.assertEquals("A", oe.getParts()[0]);
960         }
961 
962     }
963 
964     private void checkMultiple(final int n, final TimeOffset small, final TimeOffset large) {
965         Assertions.assertTrue(small.multiply(n).subtract(large).isZero());
966     }
967 
968     private void checkComponents(final TimeOffset st , final long seconds, final long attoseconds) {
969         Assertions.assertEquals(seconds,     st.getSeconds());
970         Assertions.assertEquals(attoseconds, st.getAttoSeconds());
971     }
972 
973 }