1   /* Copyright 2002-2022 CS GROUP
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  
20  import org.hamcrest.CoreMatchers;
21  import org.hamcrest.MatcherAssert;
22  import org.hipparchus.util.FastMath;
23  import org.junit.Assert;
24  import org.junit.Test;
25  import org.orekit.errors.OrekitIllegalArgumentException;
26  import org.orekit.errors.OrekitMessages;
27  
28  
29  public class TimeComponentsTest {
30  
31      @Test(expected=IllegalArgumentException.class)
32      public void testOutOfRangeA() throws IllegalArgumentException {
33          new TimeComponents(-1, 10, 10);
34      }
35  
36      @Test(expected=IllegalArgumentException.class)
37      public void testOutOfRangeB() throws IllegalArgumentException {
38          new TimeComponents(24, 10, 10);
39      }
40  
41      @Test(expected=IllegalArgumentException.class)
42      public void testOutOfRangeC() throws IllegalArgumentException {
43          new TimeComponents(10, -1, 10);
44      }
45  
46      @Test(expected=IllegalArgumentException.class)
47      public void testOutOfRangeD() throws IllegalArgumentException {
48          new TimeComponents(10, 60, 10);
49      }
50  
51      @Test(expected=IllegalArgumentException.class)
52      public void testOutOfRangeE() throws IllegalArgumentException {
53          new TimeComponents(10, 10, -1);
54      }
55  
56      @Test(expected=IllegalArgumentException.class)
57      public void testOutOfRangeF() throws IllegalArgumentException {
58          new TimeComponents(10, 10, 61);
59      }
60  
61      @Test(expected=IllegalArgumentException.class)
62      public void testOutOfRangeG() throws IllegalArgumentException {
63          new TimeComponents(86399, 4.5);
64      }
65  
66      @Test(expected=IllegalArgumentException.class)
67      public void testOutOfRangeH() throws IllegalArgumentException {
68          new TimeComponents(0, -1.0);
69      }
70  
71      @Test
72      public void testInRange() {
73  
74          TimeComponents time = new TimeComponents(10, 10, 10);
75          Assert.assertEquals(10,   time.getHour());
76          Assert.assertEquals(10,   time.getMinute());
77          Assert.assertEquals(10.0, time.getSecond(), 1.0e-10);
78  
79          time = new TimeComponents(0.0);
80          Assert.assertEquals(0.0, time.getSecondsInUTCDay(), 1.0e-10);
81  
82          time = new TimeComponents(10, 10, 60.999);
83          Assert.assertEquals(10,   time.getHour());
84          Assert.assertEquals(10,   time.getMinute());
85          Assert.assertEquals(60.999, time.getSecond(), 1.0e-10);
86  
87          time = new TimeComponents(43200.0);
88          Assert.assertEquals(43200.0, time.getSecondsInUTCDay(), 1.0e-10);
89  
90          time = new TimeComponents(86399.999);
91          Assert.assertEquals(86399.999, time.getSecondsInUTCDay(), 1.0e-10);
92  
93          time = new TimeComponents(2, 30, 0, 180);
94          Assert.assertEquals(+9000.0, time.getSecondsInLocalDay(), 1.0e-5);
95          Assert.assertEquals(-1800.0, time.getSecondsInUTCDay(),   1.0e-5);
96      }
97  
98      @Test
99      public void testValues() {
100         Assert.assertEquals(    0.0, new TimeComponents( 0, 0, 0).getSecondsInLocalDay(), 1.0e-10);
101         Assert.assertEquals(21600.0, new TimeComponents( 6, 0, 0).getSecondsInLocalDay(), 1.0e-10);
102         Assert.assertEquals(43200.0, new TimeComponents(12, 0, 0).getSecondsInLocalDay(), 1.0e-10);
103         Assert.assertEquals(64800.0, new TimeComponents(18, 0, 0).getSecondsInLocalDay(), 1.0e-10);
104         Assert.assertEquals(86399.9, new TimeComponents(23, 59, 59.9).getSecondsInLocalDay(), 1.0e-10);
105     }
106 
107     @Test
108     public void testString() {
109         Assert.assertEquals("00:00:00.000+00:00", new TimeComponents(0).toString());
110         Assert.assertEquals("06:00:00.000+00:00", new TimeComponents(21600).toString());
111         Assert.assertEquals("12:00:00.000+00:00", new TimeComponents(43200).toString());
112         Assert.assertEquals("18:00:00.000+00:00", new TimeComponents(64800).toString());
113         Assert.assertEquals("23:59:59.89999999999418+00:00", new TimeComponents(86399.9).toString());
114         Assert.assertEquals("00:00:00.000+10:00", new TimeComponents( 0,  0,  0,    600).toString());
115         Assert.assertEquals("06:00:00.000+10:00", new TimeComponents( 6,  0,  0,    600).toString());
116         Assert.assertEquals("12:00:00.000-04:30", new TimeComponents(12,  0,  0,   -270).toString());
117         Assert.assertEquals("18:00:00.000-04:30", new TimeComponents(18,  0,  0,   -270).toString());
118         Assert.assertEquals("23:59:59.900-04:30", new TimeComponents(23, 59, 59.9, -270).toString());
119         // test leap seconds
120         Assert.assertEquals("23:59:60.500+00:00", TimeComponents.fromSeconds(86399, 0.5, 1, 61).toString());
121         // leap second on 1961 is between 1 and 2 seconds in duration
122         Assert.assertEquals("23:59:61.32281798015773+00:00", TimeComponents.fromSeconds(86399, 0.32281798015773, 2, 62).toString());
123         // test rounding
124         Assert.assertEquals("23:59:59.99999999998545+00:00", new TimeComponents(86399.99999999999).toString());
125         Assert.assertEquals("23:59:59.99999999999999+00:00", TimeComponents.fromSeconds(86399, FastMath.nextDown(1.0), 0, 60).toString());
126     }
127 
128     @Test
129     public void testParse() {
130         Assert.assertEquals(86399.9, TimeComponents.parseTime("235959.900").getSecondsInLocalDay(), 1.0e-10);
131         Assert.assertEquals(86399.9, TimeComponents.parseTime("23:59:59.900").getSecondsInLocalDay(), 1.0e-10);
132         Assert.assertEquals(86399.9, TimeComponents.parseTime("23:59:59,900").getSecondsInLocalDay(), 1.0e-10);
133         Assert.assertEquals(86399.9, TimeComponents.parseTime("235959.900Z").getSecondsInLocalDay(), 1.0e-10);
134         Assert.assertEquals(86399.9, TimeComponents.parseTime("23:59:59.900Z").getSecondsInLocalDay(), 1.0e-10);
135         Assert.assertEquals(86399.9, TimeComponents.parseTime("235959.900+10").getSecondsInLocalDay(), 1.0e-10);
136         Assert.assertEquals(86399.9, TimeComponents.parseTime("23:59:59.900+00").getSecondsInLocalDay(), 1.0e-10);
137         Assert.assertEquals(86399.9, TimeComponents.parseTime("235959.900-00:12").getSecondsInLocalDay(), 1.0e-10);
138         Assert.assertEquals(86399.9, TimeComponents.parseTime("23:59:59.900+00:00").getSecondsInLocalDay(), 1.0e-10);
139         Assert.assertEquals(86340.0, TimeComponents.parseTime("23:59").getSecondsInLocalDay(), 1.0e-10);
140     }
141 
142     @Test(expected=IllegalArgumentException.class)
143     public void testBadFormat() {
144         TimeComponents.parseTime("23h59m59s");
145     }
146 
147     @Test
148     public void testLocalTime() {
149         Assert.assertEquals(60, TimeComponents.parseTime("23:59:59+01:00").getMinutesFromUTC());
150     }
151 
152     @SuppressWarnings("unlikely-arg-type")
153     @Test
154     public void testComparisons() {
155         TimeComponents[] times = {
156                  new TimeComponents( 0,  0,  0.0),
157                  new TimeComponents( 0,  0,  1.0e-15),
158                  new TimeComponents( 0, 12,  3.0),
159                  new TimeComponents(15,  9,  3.0),
160                  new TimeComponents(23, 59, 59.0),
161                  new TimeComponents(23, 59, 60.0 - 1.0e-12)
162         };
163         for (int i = 0; i < times.length; ++i) {
164             for (int j = 0; j < times.length; ++j) {
165                 if (times[i].compareTo(times[j]) < 0) {
166                     Assert.assertTrue(times[j].compareTo(times[i]) > 0);
167                     Assert.assertFalse(times[i].equals(times[j]));
168                     Assert.assertFalse(times[j].equals(times[i]));
169                     Assert.assertTrue(times[i].hashCode() != times[j].hashCode());
170                     Assert.assertTrue(i < j);
171                 } else if (times[i].compareTo(times[j]) > 0) {
172                     Assert.assertTrue(times[j].compareTo(times[i]) < 0);
173                     Assert.assertFalse(times[i].equals(times[j]));
174                     Assert.assertFalse(times[j].equals(times[i]));
175                     Assert.assertTrue(times[i].hashCode() != times[j].hashCode());
176                     Assert.assertTrue(i > j);
177                 } else {
178                     Assert.assertTrue(times[j].compareTo(times[i]) == 0);
179                     Assert.assertTrue(times[i].equals(times[j]));
180                     Assert.assertTrue(times[j].equals(times[i]));
181                     Assert.assertTrue(times[i].hashCode() == times[j].hashCode());
182                     Assert.assertTrue(i == j);
183                 }
184             }
185         }
186         Assert.assertFalse(times[0].equals(this));
187     }
188 
189     @Test
190     public void testFromSeconds() {
191         // setup
192         double zeroUlp = FastMath.nextUp(0.0);
193         double one = FastMath.nextDown(1.0);
194         double sixty = FastMath.nextDown(60.0);
195         double sixtyOne = FastMath.nextDown(61.0);
196 
197         // action + verify
198         MatcherAssert.assertThat(TimeComponents.fromSeconds(0, 0, 0, 60).getSecond(),
199                 CoreMatchers.is(0.0));
200         MatcherAssert.assertThat(TimeComponents.fromSeconds(0, zeroUlp, 0, 60).getSecond(),
201                 CoreMatchers.is(zeroUlp));
202         MatcherAssert.assertThat(TimeComponents.fromSeconds(86399, one, 0, 60).getSecond(),
203                 CoreMatchers.is(sixty));
204         MatcherAssert.assertThat(TimeComponents.fromSeconds(86399, one, 1, 61).getSecond(),
205                 CoreMatchers.is(sixtyOne));
206         // I don't like this NaN behavior, but it matches the 10.1 implementation and
207         // GLONASSAnalyticalPropagatorTest relied on it.
208         // It seems more logical to throw an out of range exception in this case.
209         MatcherAssert.assertThat(TimeComponents.fromSeconds(86399, Double.NaN, 0, 60).getSecond(),
210                 CoreMatchers.is(Double.NaN));
211         MatcherAssert.assertThat(TimeComponents.fromSeconds(86399, Double.NaN, 0, 60).getMinute(),
212                 CoreMatchers.is(59));
213         MatcherAssert.assertThat(TimeComponents.fromSeconds(86399, Double.NaN, 1, 61).getSecond(),
214                 CoreMatchers.is(Double.NaN));
215         MatcherAssert.assertThat(TimeComponents.fromSeconds(86399, Double.NaN, 1, 61).getMinute(),
216                 CoreMatchers.is(59));
217 
218         // check errors
219         try {
220             TimeComponents.fromSeconds(0, FastMath.nextDown(0), 0, 60);
221             Assert.fail("Expected Exception");
222         } catch (OrekitIllegalArgumentException e) {
223             MatcherAssert.assertThat(e.getSpecifier(),
224                     CoreMatchers.is(OrekitMessages.OUT_OF_RANGE_SECONDS_NUMBER_DETAIL));
225         }
226         try {
227             TimeComponents.fromSeconds(86399, 1, 0, 60);
228             Assert.fail("Expected Exception");
229         } catch (OrekitIllegalArgumentException e) {
230             MatcherAssert.assertThat(e.getSpecifier(),
231                     CoreMatchers.is(OrekitMessages.OUT_OF_RANGE_SECONDS_NUMBER_DETAIL));
232         }
233         try {
234             TimeComponents.fromSeconds(86399, 1, 1, 61);
235             Assert.fail("Expected Exception");
236         } catch (OrekitIllegalArgumentException e) {
237             MatcherAssert.assertThat(e.getSpecifier(),
238                     CoreMatchers.is(OrekitMessages.OUT_OF_RANGE_SECONDS_NUMBER_DETAIL));
239         }
240         try {
241             TimeComponents.fromSeconds(0, 0, -1, 59);
242             Assert.fail("Expected Exception");
243         } catch (OrekitIllegalArgumentException e) {
244             MatcherAssert.assertThat(e.getSpecifier(),
245                     CoreMatchers.is(OrekitMessages.OUT_OF_RANGE_SECONDS_NUMBER_DETAIL));
246         }
247         try {
248             TimeComponents.fromSeconds(0, 0, 1, 59);
249             Assert.fail("Expected Exception");
250         } catch (OrekitIllegalArgumentException e) {
251             MatcherAssert.assertThat(e.getSpecifier(),
252                     CoreMatchers.is(OrekitMessages.OUT_OF_RANGE_SECONDS_NUMBER_DETAIL));
253         }
254     }
255 
256     @Test
257     public void testTimeComponentsDouble658() {
258         // setup
259         double zeroUlp = FastMath.nextUp(0.0);
260         double dayUlp = FastMath.ulp(86400.0);
261 
262         // action + verify
263         check(new TimeComponents(0.0), 0, 0, 0);
264         check(new TimeComponents(zeroUlp), 0, 0, zeroUlp);
265         check(new TimeComponents(86399.5), 23, 59, 59.5);
266         check(new TimeComponents(FastMath.nextDown(86400.0)), 23, 59, 60 - dayUlp);
267         check(new TimeComponents(86400), 23, 59, 60);
268         check(new TimeComponents(FastMath.nextUp(86400.0)), 23, 59, 60 + dayUlp);
269         check(new TimeComponents(86400.5), 23, 59, 60.5);
270         check(new TimeComponents(FastMath.nextDown(86401.0)), 23, 59, 61 - dayUlp);
271         try {
272             new TimeComponents(86401);
273             Assert.fail("Expected Exception");
274         } catch (OrekitIllegalArgumentException e) {
275             MatcherAssert.assertThat(e.getSpecifier(),
276                     CoreMatchers.is(OrekitMessages.OUT_OF_RANGE_SECONDS_NUMBER_DETAIL));
277             MatcherAssert.assertThat(e.getParts()[0], CoreMatchers.is(86400.0));
278         }
279         try {
280             new TimeComponents(-zeroUlp);
281             Assert.fail("Expected Exception");
282         } catch (OrekitIllegalArgumentException e) {
283             MatcherAssert.assertThat(e.getSpecifier(),
284                     CoreMatchers.is(OrekitMessages.OUT_OF_RANGE_SECONDS_NUMBER_DETAIL));
285             MatcherAssert.assertThat(e.getParts()[0], CoreMatchers.is(-zeroUlp));
286         }
287     }
288 
289     @Test
290     public void testTimeComponentsIntDouble658() {
291         // setup
292         double zeroUlp = FastMath.nextUp(0.0);
293         double sixtyUlp = FastMath.ulp(60.0);
294         double one = FastMath.nextDown(1.0);
295         double sixty = FastMath.nextDown(60.0);
296         double sixtyOne = FastMath.nextDown(61.0);
297 
298         // action + verify
299         check(new TimeComponents(0, 0.0), 0, 0, 0);
300         check(new TimeComponents(0, zeroUlp), 0, 0, zeroUlp);
301         check(new TimeComponents(86399, 0.5), 23, 59, 59.5);
302         check(new TimeComponents(86399, one), 23, 59, sixty);
303         check(new TimeComponents(86400, 0.0), 23, 59, 60);
304         check(new TimeComponents(86400, sixtyUlp), 23, 59, 60 + sixtyUlp);
305         check(new TimeComponents(86400, 0.5), 23, 59, 60.5);
306         check(new TimeComponents(86400, one), 23, 59, sixtyOne);
307         try {
308             new TimeComponents(86401, 0.0);
309             Assert.fail("Expected Exception");
310         } catch (OrekitIllegalArgumentException e) {
311             MatcherAssert.assertThat(e.getSpecifier(),
312                     CoreMatchers.is(OrekitMessages.OUT_OF_RANGE_SECONDS_NUMBER_DETAIL));
313             MatcherAssert.assertThat(e.getParts()[0], CoreMatchers.is(86400.0));
314         }
315         try {
316             new TimeComponents(86400, 1.0);
317             Assert.fail("Expected Exception");
318         } catch (OrekitIllegalArgumentException e) {
319             MatcherAssert.assertThat(e.getSpecifier(),
320                     CoreMatchers.is(OrekitMessages.OUT_OF_RANGE_SECONDS_NUMBER_DETAIL));
321             MatcherAssert.assertThat(e.getParts()[0], CoreMatchers.is(86400.0));
322         }
323         try {
324             new TimeComponents(0, -zeroUlp);
325             Assert.fail("Expected Exception");
326         } catch (OrekitIllegalArgumentException e) {
327             MatcherAssert.assertThat(e.getSpecifier(),
328                     CoreMatchers.is(OrekitMessages.OUT_OF_RANGE_SECONDS_NUMBER_DETAIL));
329             MatcherAssert.assertThat(e.getParts()[0], CoreMatchers.is(-zeroUlp));
330         }
331         try {
332             new TimeComponents(-1, 0.0);
333             Assert.fail("Expected Exception");
334         } catch (OrekitIllegalArgumentException e) {
335             MatcherAssert.assertThat(e.getSpecifier(),
336                     CoreMatchers.is(OrekitMessages.OUT_OF_RANGE_SECONDS_NUMBER_DETAIL));
337             MatcherAssert.assertThat(e.getParts()[0], CoreMatchers.is(-1.0));
338         }
339     }
340 
341     private void check(final TimeComponents tc, int hour, int minute, double second) {
342         MatcherAssert.assertThat(tc.getHour(), CoreMatchers.is(hour));
343         MatcherAssert.assertThat(tc.getMinute(), CoreMatchers.is(minute));
344         MatcherAssert.assertThat(tc.getSecond(), CoreMatchers.is(second));
345     }
346 
347 }