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 testRoundingOffsetPositive() {
172         checkRoundingOffset(3,
173                             new TimeOffset(2L, TimeOffset.SECOND, 2345L, TimeOffset.MICROSECOND),
174                             new TimeOffset(2L, TimeOffset.SECOND, 2000L, TimeOffset.MICROSECOND));
175         checkRoundingOffset(3,
176                             new TimeOffset(2L, TimeOffset.SECOND, 2500L, TimeOffset.MICROSECOND),
177                             new TimeOffset(2L, TimeOffset.SECOND, 3000L, TimeOffset.MICROSECOND));
178         checkRoundingOffset(3,
179                             new TimeOffset(2L, TimeOffset.SECOND, 2500L, TimeOffset.MICROSECOND, -1, TimeOffset.ATTOSECOND),
180                             new TimeOffset(2L, TimeOffset.SECOND, 2000L, TimeOffset.MICROSECOND));
181         checkRoundingOffset(18,
182                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
183                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND));
184         checkRoundingOffset(17,
185                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
186                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345680L, TimeOffset.ATTOSECOND));
187         checkRoundingOffset(16,
188                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
189                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345700L, TimeOffset.ATTOSECOND));
190         checkRoundingOffset(15,
191                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
192                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012346000L, TimeOffset.ATTOSECOND));
193         checkRoundingOffset(14,
194                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
195                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012350000L, TimeOffset.ATTOSECOND));
196         checkRoundingOffset(13,
197                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
198                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012300000L, TimeOffset.ATTOSECOND));
199         checkRoundingOffset(12,
200                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
201                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012000000L, TimeOffset.ATTOSECOND));
202         checkRoundingOffset(11,
203                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
204                             new TimeOffset(6L, TimeOffset.SECOND, 123456789010000000L, TimeOffset.ATTOSECOND));
205         checkRoundingOffset(10,
206                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
207                             new TimeOffset(6L, TimeOffset.SECOND, 123456789000000000L, TimeOffset.ATTOSECOND));
208         checkRoundingOffset(9,
209                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
210                             new TimeOffset(6L, TimeOffset.SECOND, 123456789000000000L, TimeOffset.ATTOSECOND));
211         checkRoundingOffset(8,
212                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
213                             new TimeOffset(6L, TimeOffset.SECOND, 123456790000000000L, TimeOffset.ATTOSECOND));
214         checkRoundingOffset(7,
215                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
216                             new TimeOffset(6L, TimeOffset.SECOND, 123456800000000000L, TimeOffset.ATTOSECOND));
217         checkRoundingOffset(6,
218                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
219                             new TimeOffset(6L, TimeOffset.SECOND, 123457000000000000L, TimeOffset.ATTOSECOND));
220         checkRoundingOffset(5,
221                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
222                             new TimeOffset(6L, TimeOffset.SECOND, 123460000000000000L, TimeOffset.ATTOSECOND));
223         checkRoundingOffset(4,
224                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
225                             new TimeOffset(6L, TimeOffset.SECOND, 123500000000000000L, TimeOffset.ATTOSECOND));
226         checkRoundingOffset(3,
227                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
228                             new TimeOffset(6L, TimeOffset.SECOND, 123000000000000000L, TimeOffset.ATTOSECOND));
229         checkRoundingOffset(2,
230                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
231                             new TimeOffset(6L, TimeOffset.SECOND, 120000000000000000L, TimeOffset.ATTOSECOND));
232         checkRoundingOffset(1,
233                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
234                             new TimeOffset(6L, TimeOffset.SECOND, 100000000000000000L, TimeOffset.ATTOSECOND));
235         checkRoundingOffset(0,
236                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND),
237                             new TimeOffset(6L, TimeOffset.SECOND,                  0L, TimeOffset.ATTOSECOND));
238     }
239 
240     @Test
241     public void testRoundingOffsetNegative() {
242         checkRoundingOffset(3,
243                             new TimeOffset(2L, TimeOffset.SECOND, 2345L, TimeOffset.MICROSECOND).negate(),
244                             new TimeOffset(2L, TimeOffset.SECOND, 2000L, TimeOffset.MICROSECOND).negate());
245         checkRoundingOffset(3,
246                             new TimeOffset(2L, TimeOffset.SECOND, 2500L, TimeOffset.MICROSECOND).negate(),
247                             new TimeOffset(2L, TimeOffset.SECOND, 2000L, TimeOffset.MICROSECOND).negate());
248         checkRoundingOffset(3,
249                             new TimeOffset(2L, TimeOffset.SECOND, 2500L, TimeOffset.MICROSECOND, 1, TimeOffset.ATTOSECOND).negate(),
250                             new TimeOffset(2L, TimeOffset.SECOND, 3000L, TimeOffset.MICROSECOND).negate());
251         checkRoundingOffset(18,
252                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
253                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate());
254         checkRoundingOffset(17,
255                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
256                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345680L, TimeOffset.ATTOSECOND).negate());
257         checkRoundingOffset(16,
258                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
259                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345700L, TimeOffset.ATTOSECOND).negate());
260         checkRoundingOffset(15,
261                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
262                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012346000L, TimeOffset.ATTOSECOND).negate());
263         checkRoundingOffset(14,
264                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
265                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012350000L, TimeOffset.ATTOSECOND).negate());
266         checkRoundingOffset(13,
267                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
268                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012300000L, TimeOffset.ATTOSECOND).negate());
269         checkRoundingOffset(12,
270                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
271                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012000000L, TimeOffset.ATTOSECOND).negate());
272         checkRoundingOffset(11,
273                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
274                             new TimeOffset(6L, TimeOffset.SECOND, 123456789010000000L, TimeOffset.ATTOSECOND).negate());
275         checkRoundingOffset(10,
276                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
277                             new TimeOffset(6L, TimeOffset.SECOND, 123456789000000000L, TimeOffset.ATTOSECOND).negate());
278         checkRoundingOffset(9,
279                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
280                             new TimeOffset(6L, TimeOffset.SECOND, 123456789000000000L, TimeOffset.ATTOSECOND).negate());
281         checkRoundingOffset(8,
282                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
283                             new TimeOffset(6L, TimeOffset.SECOND, 123456790000000000L, TimeOffset.ATTOSECOND).negate());
284         checkRoundingOffset(7,
285                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
286                             new TimeOffset(6L, TimeOffset.SECOND, 123456800000000000L, TimeOffset.ATTOSECOND).negate());
287         checkRoundingOffset(6,
288                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
289                             new TimeOffset(6L, TimeOffset.SECOND, 123457000000000000L, TimeOffset.ATTOSECOND).negate());
290         checkRoundingOffset(5,
291                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
292                             new TimeOffset(6L, TimeOffset.SECOND, 123460000000000000L, TimeOffset.ATTOSECOND).negate());
293         checkRoundingOffset(4,
294                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
295                             new TimeOffset(6L, TimeOffset.SECOND, 123500000000000000L, TimeOffset.ATTOSECOND).negate());
296         checkRoundingOffset(3,
297                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
298                             new TimeOffset(6L, TimeOffset.SECOND, 123000000000000000L, TimeOffset.ATTOSECOND).negate());
299         checkRoundingOffset(2,
300                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
301                             new TimeOffset(6L, TimeOffset.SECOND, 120000000000000000L, TimeOffset.ATTOSECOND).negate());
302         checkRoundingOffset(1,
303                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
304                             new TimeOffset(6L, TimeOffset.SECOND, 100000000000000000L, TimeOffset.ATTOSECOND).negate());
305         checkRoundingOffset(0,
306                             new TimeOffset(6L, TimeOffset.SECOND, 123456789012345678L, TimeOffset.ATTOSECOND).negate(),
307                             new TimeOffset(6L, TimeOffset.SECOND,                  0L, TimeOffset.ATTOSECOND).negate());
308     }
309 
310     private void checkRoundingOffset(final int fractionDigits, final TimeOffset base, final TimeOffset expected) {
311         Assertions.assertEquals(expected, base.getRoundedOffset(fractionDigits));
312     }
313 
314     @Test
315     public void testRoundingOffsetSpecial() {
316         Assertions.assertEquals(TimeOffset.ZERO, TimeOffset.NaN.getRoundedOffset(3));
317         Assertions.assertEquals(TimeOffset.ZERO, TimeOffset.POSITIVE_INFINITY.getRoundedOffset(3));
318         Assertions.assertEquals(TimeOffset.ZERO, TimeOffset.NEGATIVE_INFINITY.getRoundedOffset(3));
319     }
320 
321     @Test
322     public void testToString() {
323         Assertions.assertEquals("NaN", TimeOffset.NaN.toString());
324         Assertions.assertEquals("+∞",  TimeOffset.POSITIVE_INFINITY.toString());
325         Assertions.assertEquals("-∞",  TimeOffset.NEGATIVE_INFINITY.toString());
326         Assertions.assertEquals("0.000000000000000000", TimeOffset.ZERO.toString());
327         Assertions.assertEquals("0.000001000000000000", TimeOffset.MICROSECOND.toString());
328         Assertions.assertEquals("0.001000000000000000", TimeOffset.MILLISECOND.toString());
329         Assertions.assertEquals("1.000000000000000000", TimeOffset.SECOND.toString());
330         Assertions.assertEquals("60.000000000000000000", TimeOffset.MINUTE.toString());
331         Assertions.assertEquals("3600.000000000000000000", TimeOffset.HOUR.toString());
332         Assertions.assertEquals("86400.000000000000000000", TimeOffset.DAY.toString());
333         Assertions.assertEquals("0.002345000000000000",
334                                 new TimeOffset(2345, TimeOffset.MICROSECOND).toString());
335         Assertions.assertEquals("-0.002345000000000000",
336                                 new TimeOffset(2345, TimeOffset.MICROSECOND).negate().toString());
337         Assertions.assertEquals("2.002345000000000000",
338                                 new TimeOffset(  2, TimeOffset.SECOND, 2345, TimeOffset.MICROSECOND).toString());
339         Assertions.assertEquals("-12.002345000000000000",
340                                 new TimeOffset(12, TimeOffset.SECOND, 2345, TimeOffset.MICROSECOND).negate().toString());
341         Assertions.assertEquals("-11.997655000000000000",
342                                 new TimeOffset(-12, TimeOffset.SECOND, 2345, TimeOffset.MICROSECOND).toString());
343     }
344 
345     @Test
346     public void testPositiveDoubleConstructor() {
347         final double d = 123.4567890123456789;
348         final TimeOffset so = new TimeOffset(d);
349         Assertions.assertEquals(123L, so.getSeconds());
350         // error is 1676 attosecond because the primitive double is not accurate enough
351         Assertions.assertEquals(456789012345680576L, so.getAttoSeconds());
352         Assertions.assertTrue(so.isFinite());
353         Assertions.assertEquals(d, so.toDouble(), 1.0e-16);
354     }
355 
356     @Test
357     public void testNegativeDoubleConstructor() {
358         final double d = -123.4567890123456789;
359         final TimeOffset so = new TimeOffset(d);
360         Assertions.assertEquals(-124L, so.getSeconds());
361         // error is 1676 attosecond because the primitive double is not accurate enough
362         Assertions.assertEquals(543210987654319424L, so.getAttoSeconds());
363         Assertions.assertTrue(so.isFinite());
364         Assertions.assertEquals(d, so.toDouble(), 1.0e-16);
365     }
366 
367     @Test
368     public void testSmallNegativeDoubleConstructor() {
369         final TimeOffset so1 = new TimeOffset(-1.0e-17);
370         Assertions.assertEquals(-1L, so1.getSeconds());
371         Assertions.assertEquals(999999999999999990L, so1.getAttoSeconds());
372         Assertions.assertTrue(so1.isFinite());
373         final TimeOffset so2 = new TimeOffset(FastMath.nextDown(0.0));
374         Assertions.assertEquals(-1L, so2.getSeconds());
375         Assertions.assertEquals(1000000000000000000L, so2.getAttoSeconds());
376         Assertions.assertTrue(so2.isFinite());
377     }
378 
379     @Test
380     public void testNaNDouble() {
381 
382         final TimeOffset nan = new TimeOffset(Double.NaN);
383         Assertions.assertEquals(0L, nan.getSeconds());
384         Assertions.assertTrue(nan.isNaN());
385         Assertions.assertFalse(nan.isInfinite());
386         Assertions.assertEquals(Long.MAX_VALUE, nan.getRoundedTime(TimeUnit.DAYS));
387         Assertions.assertTrue(Double.isNaN(nan.toDouble()));
388 
389         Assertions.assertEquals(0L, TimeOffset.NaN.getSeconds());
390         Assertions.assertTrue(TimeOffset.NaN.isNaN());
391         Assertions.assertFalse(TimeOffset.NaN.isInfinite());
392         Assertions.assertEquals(Long.MAX_VALUE, TimeOffset.NaN.getRoundedTime(TimeUnit.DAYS));
393         Assertions.assertTrue(Double.isNaN(TimeOffset.NaN.toDouble()));
394 
395     }
396 
397     @Test
398     public void testPositiveInfinity() {
399 
400         final TimeOffset pos = new TimeOffset(Double.POSITIVE_INFINITY);
401         Assertions.assertEquals(Long.MAX_VALUE, pos.getSeconds());
402         Assertions.assertFalse(pos.isNaN());
403         Assertions.assertTrue(pos.isInfinite());
404         Assertions.assertFalse(pos.isNegativeInfinity());
405         Assertions.assertTrue(pos.isPositiveInfinity());
406         Assertions.assertEquals(Long.MAX_VALUE, pos.getRoundedTime(TimeUnit.DAYS));
407         Assertions.assertTrue(Double.isInfinite(pos.toDouble()));
408         Assertions.assertTrue(pos.toDouble() > 0);
409 
410         Assertions.assertEquals(Long.MAX_VALUE, TimeOffset.POSITIVE_INFINITY.getSeconds());
411         Assertions.assertFalse(TimeOffset.POSITIVE_INFINITY.isNaN());
412         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.isInfinite());
413         Assertions.assertFalse(TimeOffset.POSITIVE_INFINITY.isNegativeInfinity());
414         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.isPositiveInfinity());
415         Assertions.assertEquals(Long.MAX_VALUE, TimeOffset.POSITIVE_INFINITY.getRoundedTime(TimeUnit.DAYS));
416         Assertions.assertTrue(Double.isInfinite(TimeOffset.POSITIVE_INFINITY.toDouble()));
417         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.toDouble() > 0);
418 
419     }
420 
421     @Test
422     public void testNegativeInfinity() {
423 
424         final TimeOffset neg = new TimeOffset(Double.NEGATIVE_INFINITY);
425         Assertions.assertEquals(Long.MIN_VALUE, neg.getSeconds());
426         Assertions.assertFalse(neg.isNaN());
427         Assertions.assertTrue(neg.isInfinite());
428         Assertions.assertTrue(neg.isNegativeInfinity());
429         Assertions.assertFalse(neg.isPositiveInfinity());
430         Assertions.assertEquals(Long.MIN_VALUE, neg.getRoundedTime(TimeUnit.DAYS));
431         Assertions.assertTrue(Double.isInfinite(neg.toDouble()));
432         Assertions.assertTrue(neg.toDouble() < 0);
433 
434         Assertions.assertEquals(Long.MIN_VALUE, TimeOffset.NEGATIVE_INFINITY.getSeconds());
435         Assertions.assertFalse(TimeOffset.NEGATIVE_INFINITY.isNaN());
436         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.isInfinite());
437         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.isNegativeInfinity());
438         Assertions.assertFalse(TimeOffset.NEGATIVE_INFINITY.isPositiveInfinity());
439         Assertions.assertEquals(Long.MIN_VALUE, TimeOffset.NEGATIVE_INFINITY.getRoundedTime(TimeUnit.DAYS));
440         Assertions.assertTrue(Double.isInfinite(TimeOffset.NEGATIVE_INFINITY.toDouble()));
441         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.toDouble() < 0);
442 
443     }
444 
445     @Test
446     public void testOutOfRangeDouble() {
447 
448         final double limit = (double) Long.MAX_VALUE;
449 
450         final TimeOffset plus = new TimeOffset(limit);
451         Assertions.assertEquals(limit, plus.getRoundedTime(TimeUnit.SECONDS), 1.0e-15 * limit);
452         Assertions.assertFalse(plus.isNaN());
453         Assertions.assertFalse(plus.isInfinite());
454 
455         final TimeOffset minus = new TimeOffset(-limit);
456         Assertions.assertEquals(-limit, minus.getRoundedTime(TimeUnit.SECONDS), 1.0e-15 * limit);
457         Assertions.assertFalse(minus.isNaN());
458         Assertions.assertFalse(minus.isInfinite());
459 
460         final TimeOffset afterPlus = new TimeOffset(FastMath.nextAfter(limit, Double.POSITIVE_INFINITY));
461         Assertions.assertFalse(afterPlus.isNaN());
462         Assertions.assertTrue(afterPlus.isInfinite());
463         Assertions.assertTrue(afterPlus.getSeconds() > 0L);
464         Assertions.assertFalse(TimeOffset.POSITIVE_INFINITY.isNaN());
465         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.isInfinite());
466         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.getSeconds() > 0L);
467 
468         final TimeOffset beforeMinus = new TimeOffset(FastMath.nextAfter(-limit, Double.NEGATIVE_INFINITY));
469         Assertions.assertFalse(beforeMinus.isNaN());
470         Assertions.assertTrue(beforeMinus.isInfinite());
471         Assertions.assertTrue(beforeMinus.getSeconds() < 0L);
472         Assertions.assertFalse(beforeMinus.isNaN());
473         Assertions.assertTrue(beforeMinus.isInfinite());
474         Assertions.assertFalse(TimeOffset.NEGATIVE_INFINITY.isNaN());
475         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.isInfinite());
476         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.getSeconds() < 0L);
477 
478     }
479 
480     @Test
481     public void testSumConstructor() {
482         final TimeOffset so = new TimeOffset(new TimeOffset(1L, 902000000000000000L),
483                                              new TimeOffset(3L, 904000000000000000L),
484                                              new TimeOffset(5L, 906000000000000000L),
485                                              new TimeOffset(7L, 908000000000000000L),
486                                              new TimeOffset(9L, 910000000000000000L),
487                                              new TimeOffset(11L, 912000000000000000L),
488                                              new TimeOffset(13L, 914000000000000000L),
489                                              new TimeOffset(15L, 916000000000000000L),
490                                              new TimeOffset(17L, 918000000000000000L),
491                                              new TimeOffset(19L, 920000000000000000L),
492                                              new TimeOffset(21L, 922000000000000000L),
493                                              new TimeOffset(23L, 924000000000000000L));
494         Assertions.assertEquals(154L,                so.getSeconds());
495         Assertions.assertEquals(956000000000000000L, so.getAttoSeconds());
496     }
497 
498     @Test
499     public void testDaysTimeUnit() {
500 
501         final TimeOffset days = new TimeOffset(2, TimeUnit.DAYS);
502         Assertions.assertEquals(172800L, days.getSeconds());
503         Assertions.assertEquals(0L,      days.getAttoSeconds());
504         Assertions.assertTrue(days.isFinite());
505 
506     }
507 
508     @Test
509     public void testOutOfRangeDays() {
510         doTestOutOfRange(106751991167300L, TimeUnit.DAYS);
511     }
512 
513     @Test
514     public void testHoursTimeUnit() {
515 
516         final TimeOffset hours = new TimeOffset(2, TimeUnit.HOURS);
517         Assertions.assertEquals(7200L, hours.getSeconds());
518         Assertions.assertEquals(0L,    hours.getAttoSeconds());
519         Assertions.assertTrue(hours.isFinite());
520 
521     }
522 
523     @Test
524     public void testOutOfRangeHours() {
525         doTestOutOfRange(2562047788015215L, TimeUnit.HOURS);
526     }
527 
528     @Test
529     public void testMinutesTimeUnit() {
530 
531         final TimeOffset minutes = new TimeOffset(2, TimeUnit.MINUTES);
532         Assertions.assertEquals(120L, minutes.getSeconds());
533         Assertions.assertEquals(0L,   minutes.getAttoSeconds());
534         Assertions.assertTrue(minutes.isFinite());
535 
536     }
537 
538     @Test
539     public void testOutOfRangeMinutes() {
540         doTestOutOfRange(153722867280912929L, TimeUnit.MINUTES);
541     }
542 
543     @Test
544     public void testSecondsTimeUnit() {
545 
546         final TimeOffset seconds = new TimeOffset(2, TimeUnit.SECONDS);
547         Assertions.assertEquals(2L, seconds.getSeconds());
548         Assertions.assertEquals(0L, seconds.getAttoSeconds());
549         Assertions.assertTrue(seconds.isFinite());
550 
551     }
552 
553     @Test
554     public void testMilliSecondsTimeUnit() {
555 
556         final TimeOffset milliSeconds = new TimeOffset(2, TimeUnit.MILLISECONDS);
557         Assertions.assertEquals(0L,                milliSeconds.getSeconds());
558         Assertions.assertEquals(2000000000000000L, milliSeconds.getAttoSeconds());
559         Assertions.assertTrue(milliSeconds.isFinite());
560 
561     }
562 
563     @Test
564     public void testMicroSecondsTimeUnit() {
565 
566         final TimeOffset microSeconds = new TimeOffset(2, TimeUnit.MICROSECONDS);
567         Assertions.assertEquals(0L,             microSeconds.getSeconds());
568         Assertions.assertEquals(2000000000000L, microSeconds.getAttoSeconds());
569         Assertions.assertTrue(microSeconds.isFinite());
570 
571     }
572 
573     @Test
574     public void testNanoTimeUnit() {
575 
576         final TimeOffset nanoSeconds = new TimeOffset(2, TimeUnit.NANOSECONDS);
577         Assertions.assertEquals(0L,          nanoSeconds.getSeconds());
578         Assertions.assertEquals(2000000000L, nanoSeconds.getAttoSeconds());
579         Assertions.assertTrue(nanoSeconds.isFinite());
580 
581     }
582 
583     private void doTestOutOfRange(final long time, final TimeUnit unit) {
584 
585         final TimeOffset plus = new TimeOffset(time, unit);
586         Assertions.assertEquals( time, plus.getRoundedTime(unit));
587         Assertions.assertTrue(plus.isFinite());
588         Assertions.assertFalse(plus.isNaN());
589         Assertions.assertFalse(plus.isInfinite());
590 
591         final TimeOffset minus = new TimeOffset(-time, unit);
592         Assertions.assertEquals(-time, minus.getRoundedTime(unit));
593         Assertions.assertTrue(minus.isFinite());
594         Assertions.assertFalse(minus.isNaN());
595         Assertions.assertFalse(minus.isInfinite());
596 
597         final TimeOffset afterPlus = new TimeOffset(time + 1L, unit);
598         Assertions.assertEquals(Long.MAX_VALUE, afterPlus.getRoundedTime(unit));
599         Assertions.assertFalse(afterPlus.isFinite());
600         Assertions.assertFalse(afterPlus.isNaN());
601         Assertions.assertTrue(afterPlus.isInfinite());
602 
603         final TimeOffset beforeMinus = new TimeOffset(-time - 1L, unit);
604         Assertions.assertEquals(Long.MIN_VALUE, beforeMinus.getRoundedTime(unit));
605         Assertions.assertFalse(beforeMinus.isFinite());
606         Assertions.assertFalse(beforeMinus.isNaN());
607         Assertions.assertTrue(beforeMinus.isInfinite());
608 
609     }
610 
611     @Test
612     public void testSymmetry() {
613 
614          for (long time : new long[] {
615             Long.MIN_VALUE,
616             -4000000000000000001L, -4000000000000000000L, -3999999999999999999L,
617             -3000000000000000001L, -3000000000000000000L, -2999999999999999999L,
618             -2000000000000000001L, -2000000000000000000L, -1999999999999999999L,
619             -153722867280912930L, -153722867280912929L,
620             -2562047788015216L, -2562047788015215L,
621             -106751991167301L, -106751991167300L,
622             -86401L, -86400L, -86399L, -43201L, -43200L, -43199L,
623             -3601L, -3600L, -3599L, -1801L, -1800L, -1799L,
624             -61L, -60L, -59L, -31L, -30L, -29L,
625             -1L, 0L, 1L,
626             29L, 30L, 31L, 59L, 60L, 61L,
627             1799L, 1800L, 1801L, 3599L, 3600L, 3601L,
628             43199L, 43200L, 43201L, 86399L, 86400L, 86401L,
629             106751991167300L, 106751991167301L,
630             2562047788015215L, 2562047788015216L,
631             153722867280912929L, 153722867280912930L,
632             1999999999999999999L, 2000000000000000000L, 2000000000000000001L,
633             2999999999999999999L, 3000000000000000000L, 3000000000000000001L,
634             3999999999999999999L, 4000000000000000000L, 4000000000000000001L,
635             Long.MAX_VALUE
636         }) {
637             for (final TimeUnit tu : TimeUnit.values()) {
638                 final TimeOffset timeOffset = new TimeOffset(time, tu);
639                 final long rebuilt = timeOffset.getRoundedTime(tu);
640                 if (timeOffset.isInfinite()) {
641                     Assertions.assertEquals(time < 0 ? Long.MIN_VALUE : Long.MAX_VALUE, rebuilt);
642                 } else {
643                     Assertions.assertEquals(time, rebuilt);
644                 }
645             }
646         }
647     }
648 
649     @Test
650     public void testAdd() {
651         final TimeOffset a1 = new TimeOffset(1234L, 5678L).add(new TimeOffset(76L, -876L));
652         Assertions.assertEquals(1310L, a1.getSeconds());
653         Assertions.assertEquals(4802L, a1.getAttoSeconds());
654         Assertions.assertTrue(a1.isFinite());
655 
656         final TimeOffset a2 = new TimeOffset(1L, 500000000000000000L).add(new TimeOffset(2L, 500000000000000001L));
657         Assertions.assertEquals(4L, a2.getSeconds());
658         Assertions.assertEquals(1L, a2.getAttoSeconds());
659         Assertions.assertTrue(a2.isFinite());
660 
661         final TimeOffset a3 = new TimeOffset(1234L, 23L).add(new TimeOffset(76L, -876L));
662         Assertions.assertEquals(1309L,               a3.getSeconds());
663         Assertions.assertEquals(999999999999999147L, a3.getAttoSeconds());
664         Assertions.assertTrue(a3.isFinite());
665     }
666 
667     @Test
668     public void testAddSpecialValues() {
669 
670         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.HOUR).isNaN());
671         Assertions.assertTrue(TimeOffset.HOUR.add(TimeOffset.NaN).isNaN());
672         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.add(TimeOffset.HOUR).isPositiveInfinity());
673         Assertions.assertTrue(TimeOffset.HOUR.add(TimeOffset.POSITIVE_INFINITY).isPositiveInfinity());
674         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.add(TimeOffset.HOUR).isNegativeInfinity());
675         Assertions.assertTrue(TimeOffset.HOUR.add(TimeOffset.NEGATIVE_INFINITY).isNegativeInfinity());
676 
677         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.NaN).isNaN());
678         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.NaN).isNaN());
679         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.add(TimeOffset.NaN).isNaN());
680         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.POSITIVE_INFINITY).isNaN());
681         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.add(TimeOffset.NaN).isNaN());
682         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.NEGATIVE_INFINITY).isNaN());
683 
684         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.POSITIVE_INFINITY).isNaN());
685         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.add(TimeOffset.NaN).isNaN());
686         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.add(TimeOffset.POSITIVE_INFINITY).isPositiveInfinity());
687         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.add(TimeOffset.POSITIVE_INFINITY).isNaN());
688         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.add(TimeOffset.NEGATIVE_INFINITY).isNaN());
689 
690         Assertions.assertTrue(TimeOffset.NaN.add(TimeOffset.NEGATIVE_INFINITY).isNaN());
691         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.add(TimeOffset.NaN).isNaN());
692         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.add(TimeOffset.NEGATIVE_INFINITY).isNaN());
693         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.add(TimeOffset.POSITIVE_INFINITY).isNaN());
694         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.add(TimeOffset.NEGATIVE_INFINITY).isNegativeInfinity());
695 
696     }
697 
698     @Test
699     public void testSubtract() {
700         final TimeOffset s1 = new TimeOffset(1234L, 5678L).subtract(new TimeOffset(76L, 876L));
701         Assertions.assertEquals(1158L, s1.getSeconds());
702         Assertions.assertEquals(4802L, s1.getAttoSeconds());
703         Assertions.assertTrue(s1.isFinite());
704 
705         final TimeOffset s2 = new TimeOffset(1L, 0L).subtract(new TimeOffset(2L, 1L));
706         Assertions.assertEquals(-2L, s2.getSeconds());
707         Assertions.assertEquals(999999999999999999L, s2.getAttoSeconds());
708         Assertions.assertTrue(s2.isFinite());
709 
710         final TimeOffset s3 = new TimeOffset(1234L, 999999999999999999L).subtract(new TimeOffset(76L, 123456L));
711         Assertions.assertEquals(1158L,               s3.getSeconds());
712         Assertions.assertEquals(999999999999876543L, s3.getAttoSeconds());
713         Assertions.assertTrue(s3.isFinite());
714     }
715 
716     @Test
717     public void testSubtractSpecialValues() {
718 
719         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.HOUR).isNaN());
720         Assertions.assertTrue(TimeOffset.HOUR.subtract(TimeOffset.NaN).isNaN());
721         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.subtract(TimeOffset.HOUR).isPositiveInfinity());
722         Assertions.assertTrue(TimeOffset.HOUR.subtract(TimeOffset.POSITIVE_INFINITY).isNegativeInfinity());
723         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.subtract(TimeOffset.HOUR).isNegativeInfinity());
724         Assertions.assertTrue(TimeOffset.HOUR.subtract(TimeOffset.NEGATIVE_INFINITY).isPositiveInfinity());
725 
726         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.NaN).isNaN());
727         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.NaN).isNaN());
728         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.subtract(TimeOffset.NaN).isNaN());
729         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.POSITIVE_INFINITY).isNaN());
730         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.subtract(TimeOffset.NaN).isNaN());
731         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.NEGATIVE_INFINITY).isNaN());
732 
733         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.POSITIVE_INFINITY).isNaN());
734         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.subtract(TimeOffset.NaN).isNaN());
735         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.subtract(TimeOffset.POSITIVE_INFINITY).isNaN());
736         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.subtract(TimeOffset.POSITIVE_INFINITY).isNegativeInfinity());
737         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.subtract(TimeOffset.NEGATIVE_INFINITY).isPositiveInfinity());
738 
739         Assertions.assertTrue(TimeOffset.NaN.subtract(TimeOffset.NEGATIVE_INFINITY).isNaN());
740         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.subtract(TimeOffset.NaN).isNaN());
741         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.subtract(TimeOffset.NEGATIVE_INFINITY).isPositiveInfinity());
742         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.subtract(TimeOffset.POSITIVE_INFINITY).isNegativeInfinity());
743         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.subtract(TimeOffset.NEGATIVE_INFINITY).isNaN());
744 
745     }
746 
747     @Test
748     public void testMultiply() {
749         try {
750             new TimeOffset(1L, 45L).multiply(-1);
751         } catch (OrekitException oe) {
752             Assertions.assertEquals(OrekitMessages.NOT_POSITIVE, oe.getSpecifier());
753             Assertions.assertEquals(-1, (Long) oe.getParts()[0]);
754         }
755         checkComponents(new TimeOffset(1L, 45L).multiply(0), 0L, 0L);
756         checkComponents(new TimeOffset(1L, 45L).multiply(1), 1L, 45L);
757         checkComponents(new TimeOffset(1L, 45L).multiply(3), 3L, 135L);
758         checkComponents(new TimeOffset(1234L, 123456789012345678L).multiply(7233L), 8926414L, 962954926296288974L);
759         checkComponents(new TimeOffset(1234L, 999999999999999999L).multiply(23012696L), 28420679559L, 999999999976987304L);
760         checkComponents(new TimeOffset(1234L, 999999999999999999L).multiply(123456789012L),
761                         152469134429819L, 999999876543210988L);
762          try {
763              new TimeOffset(10000000000L, 1L).multiply(123456789012L);
764             Assertions.fail("an exception should have been thrown");
765         } catch (OrekitException oe) {
766             Assertions.assertEquals(LocalizedCoreFormats.OVERFLOW_IN_MULTIPLICATION, oe.getSpecifier());
767             Assertions.assertEquals(10000000000L, (Long) oe.getParts()[0]);
768             Assertions.assertEquals(123456789012L, (Long) oe.getParts()[1]);
769         }
770 
771         try {
772             new TimeOffset(922382683L, 717054400620018329L).multiply(1573105907129L);
773             Assertions.fail("an exception should have been thrown");
774         } catch (OrekitException oe) {
775             Assertions.assertEquals(LocalizedCoreFormats.OVERFLOW_IN_MULTIPLICATION, oe.getSpecifier());
776             Assertions.assertEquals(922382683L, (Long) oe.getParts()[0]);
777             Assertions.assertEquals(1573105907129L, (Long) oe.getParts()[1]);
778         }
779     }
780 
781     @Test
782     public void testMultiplySpecialValues() {
783         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.multiply(0).isNaN());
784         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.multiply(3).isNegativeInfinity());
785         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.multiply(0).isNaN());
786         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.multiply(3).isPositiveInfinity());
787         Assertions.assertTrue(TimeOffset.NaN.multiply(0).isNaN());
788         Assertions.assertTrue(TimeOffset.NaN.multiply(3).isNaN());
789     }
790 
791     @Test
792     public void testDivide() {
793         try {
794             new TimeOffset(1L, 45L).divide(0);
795             Assertions.fail("an exception should have been thrown");
796         } catch (OrekitException oe) {
797             Assertions.assertEquals(OrekitMessages.NOT_STRICTLY_POSITIVE, oe.getSpecifier());
798             Assertions.assertEquals(0, (Integer) oe.getParts()[0]);
799         }
800         checkComponents(new TimeOffset(1L, 45L).divide(1), 1L, 45L);
801         checkComponents(new TimeOffset(3L, 135L).divide(3), 1L, 45L);
802         checkComponents(new TimeOffset(8926414L, 962954926296288974L).divide(7233), 1234L, 123456789012345678L);
803         checkComponents(new TimeOffset(28420679559L, 999999999976987304L).divide(23012696), 1234L, 999999999999999999L);
804         checkComponents(new TimeOffset(1L, 0L).divide(1000000000), 0L, 1000000000L);
805 
806         // we consider a 15 nanosecond per UTC second slope for TAI-UTC offset (this is what was used in 1961)
807         // then 1 day in UTC corresponds to 1 day + 1296 µs in TAI, and we perform the computation the other way round
808         // we start from the 1 day + 1296 µs duration in TAI and recover the 1296 µs change in TAI-UTC offset
809         checkComponents(new TimeOffset(86400L, 1296000000000000L).multiply(15).divide(1000000015),
810                         0L, 1296000000000000L);
811 
812     }
813 
814     @Test
815     public void testRandomDivide() {
816         final RandomGenerator random = new Well1024a(0x83977774b8d4eb2eL);
817         for (int i = 0; i < 1000000; i++) {
818             final TimeOffset t = new TimeOffset(random.nextLong(1000L * 365L * 86400L),
819                                                 random.nextLong(1000000000000000000L));
820             final int p = FastMath.max(1, random.nextInt(10000000));
821             Assertions.assertEquals(0, t.compareTo(t.multiply(p).divide(p)));
822         }
823 
824     }
825 
826     @Test
827     public void testDivideSpecialValues() {
828         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.divide(3).isNegativeInfinity());
829         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.divide(3).isPositiveInfinity());
830         Assertions.assertTrue(TimeOffset.NaN.divide(3).isNaN());
831     }
832 
833     @Test
834     public void testNegate() {
835         for (long s = -1000L; s < 1000L; s += 10L) {
836             for (long a = -1000L; a < 1000L; a += 10L) {
837                 final TimeOffset st = new TimeOffset(s, a);
838                 Assertions.assertTrue(st.add(st.negate()).isZero());
839             }
840         }
841         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.negate().isNegativeInfinity());
842         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.negate().isPositiveInfinity());
843         Assertions.assertTrue(TimeOffset.NaN.negate().isNaN());
844         Assertions.assertTrue(TimeOffset.ZERO.negate().isZero());
845     }
846 
847     @Test
848     public void testCompareFinite() {
849         Assertions.assertEquals(0, TimeOffset.ZERO.compareTo(new TimeOffset(0L, 0L)));
850         Assertions.assertEquals(0, new TimeOffset(1L, 1L).compareTo(new TimeOffset(1L, 1L)));
851         Assertions.assertTrue(TimeOffset.MICROSECOND.compareTo(TimeOffset.MILLISECOND) < 0);
852         Assertions.assertTrue(TimeOffset.MILLISECOND.compareTo(TimeOffset.MICROSECOND) > 0);
853         Assertions.assertEquals(0, new TimeOffset(1, 2).compareTo(new TimeOffset(1, 2)));
854         Assertions.assertTrue(new TimeOffset(1, 1).compareTo(new TimeOffset(1, 2))  < 0);
855         Assertions.assertTrue(new TimeOffset(1, 2).compareTo(new TimeOffset(1, 1))  > 0);
856         Assertions.assertEquals(0, new TimeOffset(2, 1).compareTo(new TimeOffset(2, 1)));
857         Assertions.assertTrue(new TimeOffset(1, 1).compareTo(new TimeOffset(2, 1))  < 0);
858         Assertions.assertTrue(new TimeOffset(2, 1).compareTo(new TimeOffset(1, 1))  > 0);
859     }
860 
861     @Test
862     public void testCompareSpecialCases() {
863 
864         Assertions.assertEquals(0, TimeOffset.NaN.compareTo(TimeOffset.NaN));
865         Assertions.assertTrue(TimeOffset.NaN.compareTo(TimeOffset.ATTOSECOND)        >  0);
866         Assertions.assertTrue(TimeOffset.NaN.compareTo(TimeOffset.POSITIVE_INFINITY) >  0);
867         Assertions.assertTrue(TimeOffset.NaN.compareTo(TimeOffset.NEGATIVE_INFINITY) >  0);
868 
869         Assertions.assertTrue(TimeOffset.ATTOSECOND.compareTo(TimeOffset.NaN)               <  0);
870         Assertions.assertEquals(0, TimeOffset.ATTOSECOND.compareTo(TimeOffset.ATTOSECOND));
871         Assertions.assertTrue(TimeOffset.ATTOSECOND.compareTo(TimeOffset.POSITIVE_INFINITY) <  0);
872         Assertions.assertTrue(TimeOffset.ATTOSECOND.compareTo(TimeOffset.NEGATIVE_INFINITY) >  0);
873 
874         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.compareTo(TimeOffset.NaN)               <  0);
875         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.compareTo(TimeOffset.ATTOSECOND)        >  0);
876         Assertions.assertEquals(0, TimeOffset.POSITIVE_INFINITY.compareTo(TimeOffset.POSITIVE_INFINITY));
877         Assertions.assertTrue(TimeOffset.POSITIVE_INFINITY.compareTo(TimeOffset.NEGATIVE_INFINITY) >  0);
878 
879         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.compareTo(TimeOffset.NaN)               <  0);
880         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.compareTo(TimeOffset.ATTOSECOND)        <  0);
881         Assertions.assertTrue(TimeOffset.NEGATIVE_INFINITY.compareTo(TimeOffset.POSITIVE_INFINITY) <  0);
882         Assertions.assertEquals(0, TimeOffset.NEGATIVE_INFINITY.compareTo(TimeOffset.NEGATIVE_INFINITY));
883 
884     }
885 
886     @Test
887     public void testEquals() {
888         TimeOffset[] st = new TimeOffset[] {
889           new TimeOffset(200L, 300L), new TimeOffset(200L, 199L), new TimeOffset(199L, 300L),
890           TimeOffset.POSITIVE_INFINITY, TimeOffset.NEGATIVE_INFINITY,
891           TimeOffset.NaN, TimeOffset.DAY, TimeOffset.ZERO, TimeOffset.ATTOSECOND
892         };
893         for (int i = 0; i < st.length; i++) {
894             for (int j = 0; j < st.length; j++) {
895                 if (i == j) {
896                     Assertions.assertEquals(st[i], st[j]);
897                 } else {
898 
899                     Assertions.assertNotEquals(st[i], st[j]);
900                 }
901             }
902         }
903         final TimeOffset timeOffset = new TimeOffset(200L, 300L);
904         Assertions.assertEquals(st[0], timeOffset);
905         Assertions.assertNotSame(st[0], timeOffset);
906         Assertions.assertEquals(0,      st[0].compareTo(timeOffset));
907         Assertions.assertEquals(484,         st[0].hashCode());
908         Assertions.assertEquals(484, timeOffset.hashCode());
909         Assertions.assertEquals(254, TimeOffset.NaN.hashCode());
910         Assertions.assertEquals(-2130771969, TimeOffset.NEGATIVE_INFINITY.hashCode());
911         Assertions.assertEquals(-2147418369, TimeOffset.POSITIVE_INFINITY.hashCode());
912         Assertions.assertEquals(0, TimeOffset.ZERO.hashCode());
913         Assertions.assertEquals(1, TimeOffset.ATTOSECOND.hashCode());
914         Assertions.assertNotEquals(timeOffset, "timeOffset");
915     }
916 
917     @Test
918     public void testMultiples() {
919         for (int n = 0; n < 100; ++n) {
920             checkMultiple(n, TimeOffset.ZERO, TimeOffset.ZERO);
921         }
922         checkMultiple(1000, TimeOffset.ATTOSECOND, TimeOffset.FEMTOSECOND);
923         checkMultiple(1000, TimeOffset.FEMTOSECOND, TimeOffset.PICOSECOND);
924         checkMultiple(1000, TimeOffset.PICOSECOND, TimeOffset.NANOSECOND);
925         checkMultiple(1000, TimeOffset.NANOSECOND, TimeOffset.MICROSECOND);
926         checkMultiple(1000, TimeOffset.MICROSECOND, TimeOffset.MILLISECOND);
927         checkMultiple(1000, TimeOffset.MILLISECOND, TimeOffset.SECOND);
928         checkMultiple(60, TimeOffset.SECOND, TimeOffset.MINUTE);
929         checkMultiple(60, TimeOffset.MINUTE, TimeOffset.HOUR);
930         checkMultiple(24, TimeOffset.HOUR, TimeOffset.DAY);
931         checkMultiple(86401, TimeOffset.SECOND, TimeOffset.DAY_WITH_POSITIVE_LEAP);
932     }
933 
934     @Test
935     public void testParseEmpty() {
936         doTestParseError("");
937     }
938 
939     @Test
940     public void testParseExtraCharacters() {
941         doTestParseError("-1.2e3!xyz");
942     }
943 
944     @Test
945     public void testParseMiddleSign() {
946         doTestParseError("-1.2-3");
947     }
948 
949     @Test
950     public void testParseMinusAfterExponent() {
951         doTestParseError("-1.2e+3-1");
952     }
953 
954     @Test
955     public void testParsePlusAfterExponent() {
956         doTestParseError("-1.2e+3+1");
957     }
958 
959     @Test
960     public void testParseOverflowA() {
961         doTestParseError("10000000000000000000");
962     }
963 
964     @Test
965     public void testParseOverflowB() {
966         doTestParseError("99999999999999999999");
967     }
968 
969     @Test
970     public void testParseOverflowC() {
971         doTestParseError("9223372036854775808");
972     }
973 
974     @Test
975     public void testParseOverflowD() {
976         doTestParseError("1.0e10000000000");
977     }
978 
979     @Test
980     public void testParseOverflowE() {
981         doTestParseError("1.0e99999999999");
982     }
983 
984     @Test
985     public void testParseOverflowF() {
986         doTestParseError("1.0e2147483648");
987     }
988 
989     @Test
990     public void testParseRepeatedSeparator() {
991         doTestParseError("1.0.0");
992     }
993 
994     @Test
995     public void testParseRepeatedExponent() {
996         doTestParseError("1.0e2e3");
997     }
998 
999     private void doTestParseError(final String s) {
1000         try {
1001             TimeOffset.parse(s);
1002             Assertions.fail("an exception should have been thrown");
1003         } catch (OrekitException oe) {
1004             Assertions.assertEquals(OrekitMessages.CANNOT_PARSE_DATA, oe.getSpecifier());
1005             Assertions.assertEquals(s, oe.getParts()[0]);
1006         }
1007     }
1008 
1009     @Test
1010     public void testParseSpecialValues() {
1011         Assertions.assertTrue(TimeOffset.parse("NaN").isNaN());
1012         Assertions.assertTrue(TimeOffset.parse("NAN").isNaN());
1013         Assertions.assertTrue(TimeOffset.parse("nan").isNaN());
1014         Assertions.assertTrue(TimeOffset.parse("-∞").isNegativeInfinity());
1015         Assertions.assertTrue(TimeOffset.parse("+∞").isPositiveInfinity());
1016     }
1017 
1018     @Test
1019     public void testParseLargeExponents(){
1020         Assertions.assertTrue(TimeOffset.parse("-1.0e100").isNegativeInfinity());
1021         Assertions.assertTrue(TimeOffset.parse("+1.0e100").isPositiveInfinity());
1022         Assertions.assertTrue(TimeOffset.parse("-0.1e100").isNegativeInfinity());
1023         Assertions.assertTrue(TimeOffset.parse("+0.1e100").isPositiveInfinity());
1024         Assertions.assertTrue(TimeOffset.parse("-1.1e100").isNegativeInfinity());
1025         Assertions.assertTrue(TimeOffset.parse("+1.1e100").isPositiveInfinity());
1026         checkComponents(TimeOffset.parse("0.0e200000"), 0L, 0L);
1027     }
1028 
1029     @Test
1030     public void testParse() {
1031         checkComponents(TimeOffset.parse("0"), 0L, 0L);
1032         checkComponents(TimeOffset.parse("1"), 1L, 0L);
1033         checkComponents(TimeOffset.parse("-1"), -1L, 0L);
1034         checkComponents(TimeOffset.parse("+0.5"), 0L, 500000000000000000L);
1035         checkComponents(TimeOffset.parse("-0.5"), -1L, 500000000000000000L);
1036         checkComponents(TimeOffset.parse("+.5"), 0L, 500000000000000000L);
1037         checkComponents(TimeOffset.parse("-.5"), -1L, 500000000000000000L);
1038         checkComponents(TimeOffset.parse("17.42357e+02"), 1742L, 357000000000000000L);
1039         checkComponents(TimeOffset.parse("9223372036854775807"), Long.MAX_VALUE, 0L);
1040 
1041         // these are the offsets for linear UTC/TAI models before 1972
1042         checkComponents(TimeOffset.parse("1.4228180"), 1L, 422818000000000000L);
1043         checkComponents(TimeOffset.parse("1.3728180"), 1L, 372818000000000000L);
1044         checkComponents(TimeOffset.parse("1.8458580"), 1L, 845858000000000000L);
1045         checkComponents(TimeOffset.parse("1.9458580"), 1L, 945858000000000000L);
1046         checkComponents(TimeOffset.parse("3.2401300"), 3L, 240130000000000000L);
1047         checkComponents(TimeOffset.parse("3.3401300"), 3L, 340130000000000000L);
1048         checkComponents(TimeOffset.parse("3.4401300"), 3L, 440130000000000000L);
1049         checkComponents(TimeOffset.parse("3.5401300"), 3L, 540130000000000000L);
1050         checkComponents(TimeOffset.parse("3.6401300"), 3L, 640130000000000000L);
1051         checkComponents(TimeOffset.parse("3.7401300"), 3L, 740130000000000000L);
1052         checkComponents(TimeOffset.parse("3.8401300"), 3L, 840130000000000000L);
1053         checkComponents(TimeOffset.parse("4.3131700"), 4L, 313170000000000000L);
1054         checkComponents(TimeOffset.parse("4.2131700"), 4L, 213170000000000000L);
1055 
1056         // these are the drifts for linear UTC/TAI models before 1972
1057         checkComponents(TimeOffset.parse("0.001296"), 0L, 1296000000000000L);
1058         checkComponents(TimeOffset.parse("0.0011232"), 0L, 1123200000000000L);
1059         checkComponents(TimeOffset.parse("0.002592"), 0L, 2592000000000000L);
1060 
1061         // cases with exponents
1062         checkComponents(TimeOffset.parse("0.001234e-05"), 0L, 12340000000L);
1063         checkComponents(TimeOffset.parse("-0.001234E+05"), -124L, 600000000000000000L);
1064         checkComponents(TimeOffset.parse("-0.001234E-05"), -1L, 999999987660000000L);
1065         checkComponents(TimeOffset.parse("0.001e-15"), 0L, 1L);
1066         checkComponents(TimeOffset.parse("-0.001e-15"), -1L, 999999999999999999L);
1067         checkComponents(TimeOffset.parse("-12E-1"), -2L, 800000000000000000L);
1068         checkComponents(TimeOffset.parse("-12E0"), -12L, 0L);
1069         checkComponents(TimeOffset.parse("-12E-0"), -12L, 0L);
1070         checkComponents(TimeOffset.parse("-12E+0"), -12L, 0L);
1071         checkComponents(TimeOffset.parse("1.234e-50"), 0L, 0L);
1072         checkComponents(TimeOffset.parse("1.e2"), 100L, 0L);
1073 
1074         // ignoring extra digits after separator
1075         checkComponents(TimeOffset.parse("0.12345678901234567890123456"), 0L, 123456789012345678L);
1076 
1077         // various resolutions
1078         checkComponents(TimeOffset.parse("12.3456e-20"), 0L, 0L);
1079         checkComponents(TimeOffset.parse("12.3456e-19"), 0L, 1L);
1080         checkComponents(TimeOffset.parse("12.3456e-18"), 0L, 12L);
1081         checkComponents(TimeOffset.parse("12.3456e-17"), 0L, 123L);
1082         checkComponents(TimeOffset.parse("12.3456e-16"), 0L, 1234L);
1083         checkComponents(TimeOffset.parse("12.3456e-15"), 0L, 12345L);
1084         checkComponents(TimeOffset.parse("12.3456e-14"), 0L, 123456L);
1085         checkComponents(TimeOffset.parse("12.3456e-13"), 0L, 1234560L);
1086         checkComponents(TimeOffset.parse("12.3456e-12"), 0L, 12345600L);
1087         checkComponents(TimeOffset.parse("12.3456e-11"), 0L, 123456000L);
1088         checkComponents(TimeOffset.parse("12.3456e-10"), 0L, 1234560000L);
1089         checkComponents(TimeOffset.parse("12.3456e-09"), 0L, 12345600000L);
1090         checkComponents(TimeOffset.parse("12.3456e-08"), 0L, 123456000000L);
1091         checkComponents(TimeOffset.parse("12.3456e-07"), 0L, 1234560000000L);
1092         checkComponents(TimeOffset.parse("12.3456e-06"), 0L, 12345600000000L);
1093         checkComponents(TimeOffset.parse("12.3456e-05"), 0L, 123456000000000L);
1094         checkComponents(TimeOffset.parse("12.3456e-04"), 0L, 1234560000000000L);
1095         checkComponents(TimeOffset.parse("12.3456e-03"), 0L, 12345600000000000L);
1096         checkComponents(TimeOffset.parse("12.3456e-02"), 0L, 123456000000000000L);
1097         checkComponents(TimeOffset.parse("12.3456e-01"), 1L, 234560000000000000L);
1098         checkComponents(TimeOffset.parse("12.3456e+00"), 12L, 345600000000000000L);
1099         checkComponents(TimeOffset.parse("12.3456e+01"), 123L, 456000000000000000L);
1100         checkComponents(TimeOffset.parse("12.3456e+02"), 1234L, 560000000000000000L);
1101         checkComponents(TimeOffset.parse("12.3456e+03"), 12345L, 600000000000000000L);
1102         checkComponents(TimeOffset.parse("12.3456e+04"), 123456L, 0L);
1103         checkComponents(TimeOffset.parse("12.3456e+05"), 1234560L, 0L);
1104         checkComponents(TimeOffset.parse("12.3456e+06"), 12345600L, 0L);
1105         checkComponents(TimeOffset.parse("12.3456e+07"), 123456000L, 0L);
1106         checkComponents(TimeOffset.parse("12.3456e+08"), 1234560000L, 0L);
1107         checkComponents(TimeOffset.parse("12.3456e+09"), 12345600000L, 0L);
1108         checkComponents(TimeOffset.parse("12.3456e+10"), 123456000000L, 0L);
1109         checkComponents(TimeOffset.parse("12.3456e+11"), 1234560000000L, 0L);
1110         checkComponents(TimeOffset.parse("12.3456e+12"), 12345600000000L, 0L);
1111         checkComponents(TimeOffset.parse("12.3456e+13"), 123456000000000L, 0L);
1112         checkComponents(TimeOffset.parse("12.3456e+14"), 1234560000000000L, 0L);
1113         checkComponents(TimeOffset.parse("12.3456e+15"), 12345600000000000L, 0L);
1114         checkComponents(TimeOffset.parse("12.3456e+16"), 123456000000000000L, 0L);
1115         checkComponents(TimeOffset.parse("12.3456e+17"), 1234560000000000000L, 0L);
1116 
1117         // truncating to upper attosecond (NOT rounding!)
1118         checkComponents(TimeOffset.parse("+1234.567890123456785012e-4"), 0L, 123456789012345678L);
1119         checkComponents(TimeOffset.parse("-1234.567890123456785012e-4"), -1L, 876543210987654322L);
1120         checkComponents(TimeOffset.parse("+1234.567890123456784012e-4"), 0L, 123456789012345678L);
1121         checkComponents(TimeOffset.parse("-1234.567890123456784012e-4"), -1L, 876543210987654322L);
1122         checkComponents(TimeOffset.parse("+9999.999999999999994000e-4"), 0L, 999999999999999999L);
1123         checkComponents(TimeOffset.parse("+9999.999999999999995000e-4"), 0L, 999999999999999999L);
1124         checkComponents(TimeOffset.parse("-9999.999999999999994000e-4"), -1L, 1L);
1125         checkComponents(TimeOffset.parse("-9999.999999999999995000e-4"), -1L, 1L);
1126         checkComponents(TimeOffset.parse("9.0e-20"), 0L, 0L);
1127         checkComponents(TimeOffset.parse("4.0e-19"), 0L, 0L);
1128         checkComponents(TimeOffset.parse("5.0e-19"), 0L, 0L);
1129 
1130         try {
1131             TimeOffset.parse("A");
1132         } catch (OrekitException oe) {
1133             Assertions.assertEquals(OrekitMessages.CANNOT_PARSE_DATA, oe.getSpecifier());
1134             Assertions.assertEquals("A", oe.getParts()[0]);
1135         }
1136 
1137     }
1138 
1139     private void checkMultiple(final int n, final TimeOffset small, final TimeOffset large) {
1140         Assertions.assertTrue(small.multiply(n).subtract(large).isZero());
1141     }
1142 
1143     private void checkComponents(final TimeOffset st , final long seconds, final long attoseconds) {
1144         Assertions.assertEquals(seconds,     st.getSeconds());
1145         Assertions.assertEquals(attoseconds, st.getAttoSeconds());
1146     }
1147 
1148 }