-
Notifications
You must be signed in to change notification settings - Fork 27
/
test_time_conversions.py
461 lines (378 loc) · 18 KB
/
test_time_conversions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
"""Test timing conversions between reference frames.
"""
__authors__ = "Ashwin Kanhere, Sriramya Bhamidipati"
__date__ = "28 Jul 2022"
from datetime import datetime, timedelta, timezone
from pytz import timezone as py_timezone
import pytest
import numpy as np
from gnss_lib_py.navdata.navdata import NavData
import gnss_lib_py.utils.time_conversions as tc
from gnss_lib_py.utils.constants import GPS_EPOCH_0
# pylint: disable=protected-access
@pytest.fixture(name="check_leapseconds")
def leapseconds_table():
"""Table with reference for when leapseconds were added
Returns
-------
leapseconds_ref_table : np.ndarray
Array of reference times and leap seconds for validation
"""
leapseconds_ref_table = np.transpose([[GPS_EPOCH_0, 0],
[datetime(1981, 7, 1, 0, 0, tzinfo=timezone.utc), 1],
[datetime(1982, 7, 1, 0, 0, tzinfo=timezone.utc), 2],
[datetime(1983, 7, 1, 0, 0, tzinfo=timezone.utc), 3],
[datetime(1985, 7, 1, 0, 0, tzinfo=timezone.utc), 4],
[datetime(1988, 1, 1, 0, 0, tzinfo=timezone.utc), 5],
[datetime(1990, 1, 1, 0, 0, tzinfo=timezone.utc), 6],
[datetime(1991, 1, 1, 0, 0, tzinfo=timezone.utc), 7],
[datetime(1992, 7, 1, 0, 0, tzinfo=timezone.utc), 8],
[datetime(1993, 7, 1, 0, 0, tzinfo=timezone.utc), 9],
[datetime(1994, 7, 1, 0, 0, tzinfo=timezone.utc), 10],
[datetime(1996, 1, 1, 0, 0, tzinfo=timezone.utc), 11],
[datetime(1997, 7, 1, 0, 0, tzinfo=timezone.utc), 12],
[datetime(1999, 1, 1, 0, 0, tzinfo=timezone.utc), 13],
[datetime(2006, 1, 1, 0, 0, tzinfo=timezone.utc), 14],
[datetime(2009, 1, 1, 0, 0, tzinfo=timezone.utc), 15],
[datetime(2012, 7, 1, 0, 0, tzinfo=timezone.utc), 16],
[datetime(2015, 7, 1, 0, 0, tzinfo=timezone.utc), 17],
[datetime(2017, 1, 1, 0, 0, tzinfo=timezone.utc), 18]])
return leapseconds_ref_table
def test_get_leap_seconds(check_leapseconds):
"""Test to validate leap seconds based on input time.
Parameters
----------
check_leapseconds : np.ndarray
Array of times at which leap seconds changed and changed values
"""
input_millis = 1000.0 * (datetime(2022, 7, 28, 0, 0, tzinfo=timezone.utc) \
- tc.GPS_EPOCH_0).total_seconds()
valseconds = tc.get_leap_seconds(input_millis)
assert valseconds == 18
buffer_secs = 3.0
num_leapsecarray = len(check_leapseconds[0,:])
for row in range(num_leapsecarray):
input_datetime = check_leapseconds[0,row] + timedelta(seconds = buffer_secs)
valdatetime = tc.get_leap_seconds(input_datetime)
assert valdatetime == check_leapseconds[1,row]
input_millis = 1000.0 * ( (check_leapseconds[0,row] \
- tc.GPS_EPOCH_0).total_seconds() \
+ buffer_secs)
valseconds = tc.get_leap_seconds(input_millis)
assert valseconds == check_leapseconds[1,row]
# Testing that datetime_to_tow raises error for time before start of
# GPS epoch
with pytest.raises(RuntimeError):
input_time = datetime(1900, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
_ = tc.get_leap_seconds(input_time)
def test_datetime_to_tow():
"""Test that datetime conversion to GPS or UTC secs does not fail.
Verified by using an online gps time calculator [1]_.
References
----------
.. [1] https://www.labsat.co.uk/index.php/en/gps-time-calculator
"""
input_time = datetime(2022, 7, 28, 12, 0, 0, tzinfo=timezone.utc)
output_wk, output_tow = tc.datetime_to_tow(input_time)
assert output_wk == 2220
assert output_tow == 388818.0
# Test equivalent conversion from TOW to datetime
rev_time = tc.tow_to_datetime(output_wk, output_tow)
assert input_time == rev_time
# Testing that datetime_to_tow raises error for time before start of
# GPS epoch
with pytest.raises(RuntimeError):
input_time = datetime(1900, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
_ = tc.datetime_to_tow(input_time)
def test_millis_since_gps_epoch_to_tow():
"""Test milliseconds since gps epoch to time of week.
Test that conversion from milliseconds since GPS epoch to GPS or
UTC seconds of the week does not fail.
Given a UTC time epoch, an online GPS Time converter [2]_ provides
seconds since GPS epoch while a GPS Time calculator [3]_ gives GPS
seconds of the week.
References
----------
.. [2] https://www.andrews.edu/~tzs/timeconv/timeconvert.php?
Accessed July 28, 2022.
.. [3] https://www.labsat.co.uk/index.php/en/gps-time-calculator
Accessed as of July 28, 2022.
"""
# These two are for 30th june 2016 (1151280017) and leap seconds: 17
input_millis = 1151280017.0*1000.0
output_wk, output_tow = tc.gps_millis_to_tow(input_millis)
assert output_wk == 1903.0
assert output_tow == 345617.0
# Testing reverse conversion
gps_millis = tc.tow_to_gps_millis(output_wk, output_tow)
assert gps_millis == input_millis
input_millis3 = 1303041618.0*1000.0
output_wk3, output_tow3 = tc.gps_millis_to_tow(input_millis3)
assert output_wk3 == 2154.0
assert output_tow3 == 302418.0
# Testing reverse conversion
gps_millis3 = tc.tow_to_gps_millis(output_wk3, output_tow3)
assert gps_millis3 == input_millis3
def test_tow_to_unix_millis():
"""Test TOW to milliseconds since Unix epoch and back.
Given UTC time, milli seconds since the UNIX epoch were calculated
from an online calculator [4]_. The UTC time was converted to GPS
time and TOW using another online calculator [5]_.
References
----------
.. [4] https://currentmillis.com/
Accessed August 10, 2022.
.. [5] https://www.labsat.co.uk/index.php/en/gps-time-calculator
Accessed as of July 28, 2022.
"""
gps_week = 2222
gps_tow = 330687.
exp_unix_millis = 1660161069000.
out_unix_millis = tc.tow_to_unix_millis(gps_week, gps_tow)
assert out_unix_millis == exp_unix_millis
# Testing reverse conversion
rev_gps_week, rev_tow = tc.unix_millis_to_tow(exp_unix_millis)
assert gps_week == rev_gps_week
assert gps_tow == rev_tow
def test_datetime_to_unix_millis():
"""Test UTC datetime to milliseconds since UNIX epoch conversion
and back
Datetime to UNIX milliseconds conversion was obtained using an
online convertor [6]_.
References
----------
.. [6] https://currentmillis.com/
Accessed August 10, 2022.
"""
t_datetime = datetime(2022, 8, 10, 19, 51, 9, tzinfo=timezone.utc)
exp_unix_millis = 1660161069000.
out_unix_millis = tc.datetime_to_unix_millis(t_datetime)
assert exp_unix_millis == out_unix_millis
# Testing reverse conversion
t_rev = tc.unix_millis_to_datetime(out_unix_millis)
assert t_datetime == t_rev
def test_datetime_to_gps_millis():
"""Test UTC datetime to milliseconds since GPS epoch conversion
and back
Datetime to GPS milliseconds conversion was obtained using an
online convertor [7]_.
References
----------
.. [7] https://www.labsat.co.uk/index.php/en/gps-time-calculator
Accessed as of July 28, 2022.
"""
t_datetime = datetime(2022, 8, 10, 19, 51, 9, tzinfo=timezone.utc)
exp_gps_millis = 1344196287000.
out_gps_millis = tc.datetime_to_gps_millis(t_datetime)
assert exp_gps_millis == out_gps_millis
# Testing reverse conversion
t_rev = tc.gps_millis_to_datetime(out_gps_millis)
assert t_datetime == t_rev
def test_gps_unix_millis():
"""Test milliseconds since GPS epoch to milliseconds since UNIX epoch.
Given UTC time, milliseconds since the UNIX epoch were calculated
from an online calculator [8]_. The UTC time was converted to seconds
(and hence milliseconds) since GPS epoch using another online
calculator [9]_.
References
----------
.. [8] https://currentmillis.com/
Accessed August 10, 2022.
.. [9] https://www.labsat.co.uk/index.php/en/gps-time-calculator
Accessed as of July 28, 2022.
"""
unix_millis = 1660161069000.
exp_gps_millis = 1344196287000.
out_gps_millis = tc.unix_to_gps_millis(unix_millis)
assert exp_gps_millis == out_gps_millis
# Testing reverse conversion
rev_unix_millis = tc.gps_to_unix_millis(exp_gps_millis)
assert unix_millis == rev_unix_millis
def test_gps_unix_millis_vect():
"""Test vectorized version of unix_to_gps_millis and gps_to_unix_millis.
Notes
-----
Test based on the test implemented in test_gps_unix_millis
"""
delta_times = np.arange(10)
unix_millis_vect = 1660161069000. + delta_times
exp_gps_millis_vect = 1344196287000. + delta_times
out_gps_millis_vect = tc.unix_to_gps_millis(unix_millis_vect)
np.testing.assert_almost_equal(exp_gps_millis_vect, out_gps_millis_vect)
# Testing reverse conversion
rev_unix_millis_vect = tc.gps_to_unix_millis(exp_gps_millis_vect)
np.testing.assert_almost_equal(unix_millis_vect, rev_unix_millis_vect)
def test_tz_conversion():
"""Checking internal timezone conversions to UTC
Checks that when timezone information is None or attribute doesn't
exist, the timezone is changed to UTC.
Also checks that if time is in non-UTC frame of reference, the time
is converted to UTC before being returned.
"""
local_time = datetime(2022, 8, 10, 19, 51, 9)
exp_utc_time = datetime(2022, 8, 10, 19, 51, 9, tzinfo=timezone.utc)
with pytest.warns(RuntimeWarning):
out_utc_time = tc.tzinfo_to_utc(local_time)
assert exp_utc_time == out_utc_time
# Check time conversion when timezone other than UTC is given
us_western = py_timezone('US/Pacific')
western_time = us_western.localize(datetime(2022, 8, 10, 12, 51, 9))
out_utc_time = tc.tzinfo_to_utc(western_time)
assert exp_utc_time == out_utc_time
def test_array_conversions():
"""Test array conversions between time types.
"""
num_checks = 10 # number of times to check
datetimes_list = [datetime(np.random.randint(1981,2024),
np.random.randint(1,13),
np.random.randint(1,29),
np.random.randint(0,24),
np.random.randint(0,60),
np.random.randint(0,60),
np.random.randint(0,1000000),
tzinfo=timezone.utc
) for _ in range(num_checks)]
datetimes_np = np.array(datetimes_list)
# Datetime <--> GPS Millis
gps_millis = tc.datetime_to_gps_millis(datetimes_list)
assert len(gps_millis) == num_checks
assert isinstance(gps_millis,np.ndarray)
assert gps_millis.dtype is np.dtype(np.float64)
datetimes_back = tc.gps_millis_to_datetime(gps_millis)
np.testing.assert_array_equal(datetimes_back, datetimes_np)
gps_millis = tc.datetime_to_gps_millis(datetimes_np)
assert len(gps_millis) == num_checks
assert isinstance(gps_millis,np.ndarray)
assert gps_millis.dtype is np.dtype(np.float64)
datetimes_back = tc.gps_millis_to_datetime(gps_millis)
np.testing.assert_array_equal(datetimes_back, datetimes_np)
# Datetime <--> UNIX Millis
unix_millis = tc.datetime_to_unix_millis(datetimes_list)
assert len(unix_millis) == num_checks
assert isinstance(unix_millis,np.ndarray)
assert unix_millis.dtype is np.dtype(np.float64)
datetimes_back = tc.unix_millis_to_datetime(unix_millis)
np.testing.assert_array_equal(datetimes_back, datetimes_np)
unix_millis = tc.datetime_to_unix_millis(datetimes_np)
assert len(unix_millis) == num_checks
assert isinstance(unix_millis,np.ndarray)
assert unix_millis.dtype is np.dtype(np.float64)
datetimes_back = tc.unix_millis_to_datetime(unix_millis)
np.testing.assert_array_equal(datetimes_back, datetimes_np)
# Datetime <--> TOW
gps_week, tow = tc.datetime_to_tow(datetimes_list)
assert len(gps_week) == num_checks
assert gps_week.dtype == np.int64
assert len(tow) == num_checks
assert isinstance(gps_week,np.ndarray)
assert isinstance(tow,np.ndarray)
datetimes_back = tc.tow_to_datetime(gps_week, tow)
np.testing.assert_array_equal(datetimes_back, datetimes_np)
gps_week, tow = tc.datetime_to_tow(datetimes_np)
assert len(gps_week) == num_checks
assert gps_week.dtype == np.int64
assert len(tow) == num_checks
assert isinstance(gps_week,np.ndarray)
assert isinstance(tow,np.ndarray)
datetimes_back = tc.tow_to_datetime(gps_week, tow)
np.testing.assert_array_equal(datetimes_back, datetimes_np)
# GPS Millis <--> UNIX Millis
unix_millis = tc.gps_to_unix_millis(gps_millis.tolist())
assert len(unix_millis) == num_checks
assert isinstance(unix_millis,np.ndarray)
assert unix_millis.dtype is np.dtype(np.float64)
gps_millis_back = tc.unix_to_gps_millis(unix_millis)
np.testing.assert_array_equal(gps_millis_back, gps_millis)
unix_millis = tc.gps_to_unix_millis(gps_millis)
assert len(unix_millis) == num_checks
assert isinstance(unix_millis,np.ndarray)
assert unix_millis.dtype is np.dtype(np.float64)
gps_millis_back = tc.unix_to_gps_millis(unix_millis)
np.testing.assert_array_equal(gps_millis_back, gps_millis)
# GPS Millis <--> TOW
gps_week, tow = tc.gps_millis_to_tow(gps_millis.tolist())
assert len(gps_week) == num_checks
assert gps_week.dtype == np.int64
assert len(tow) == num_checks
assert isinstance(gps_week,np.ndarray)
assert isinstance(tow,np.ndarray)
gps_millis_back = tc.tow_to_gps_millis(gps_week, tow)
np.testing.assert_array_equal(gps_millis_back, gps_millis)
gps_week, tow = tc.gps_millis_to_tow(gps_millis)
assert len(gps_week) == num_checks
assert gps_week.dtype == np.int64
assert len(tow) == num_checks
assert isinstance(gps_week,np.ndarray)
assert isinstance(tow,np.ndarray)
gps_millis_back = tc.tow_to_gps_millis(gps_week, tow)
np.testing.assert_array_equal(gps_millis_back, gps_millis)
# UNIX Millis <--> TOW
gps_week, tow = tc.unix_millis_to_tow(unix_millis.tolist())
assert len(gps_week) == num_checks
assert gps_week.dtype == np.int64
assert len(tow) == num_checks
assert isinstance(gps_week,np.ndarray)
assert isinstance(tow,np.ndarray)
unix_millis_back = tc.tow_to_unix_millis(gps_week, tow)
np.testing.assert_array_equal(unix_millis_back, unix_millis)
gps_week, tow = tc.unix_millis_to_tow(unix_millis)
assert len(gps_week) == num_checks
assert gps_week.dtype == np.int64
assert len(tow) == num_checks
assert isinstance(gps_week,np.ndarray)
assert isinstance(tow,np.ndarray)
unix_millis_back = tc.tow_to_unix_millis(gps_week, tow)
np.testing.assert_array_equal(unix_millis_back, unix_millis)
def test_zero_arrays():
"""Test zero array conversions between time types.
"""
datetimes_list = datetime(np.random.randint(1981,2024),
np.random.randint(1,13),
np.random.randint(1,29),
np.random.randint(0,24),
np.random.randint(0,60),
np.random.randint(0,60),
tzinfo=timezone.utc
)
datetimes_np = np.array(datetimes_list)
# Datetime <--> GPS Millis
gps_millis = tc.datetime_to_gps_millis(datetimes_np)
datetimes_back = tc.gps_millis_to_datetime(np.array(gps_millis))
np.testing.assert_array_equal(datetimes_back, datetimes_np)
# Datetime <--> UNIX Millis
unix_millis = tc.datetime_to_unix_millis(datetimes_np)
datetimes_back = tc.unix_millis_to_datetime(np.array(unix_millis))
np.testing.assert_array_equal(datetimes_back, datetimes_np)
datetimes_back = tc.unix_millis_to_datetime(int(unix_millis))
np.testing.assert_array_equal(datetimes_back, datetimes_np)
# Datetime <--> TOW
gps_week, tow = tc.datetime_to_tow(datetimes_np)
datetimes_back = tc.tow_to_datetime(np.array(gps_week),
np.array(tow))
np.testing.assert_array_equal(datetimes_back, datetimes_np)
# GPS Millis <--> UNIX Millis
unix_millis = tc.gps_to_unix_millis(np.array(gps_millis))
gps_millis_back = tc.unix_to_gps_millis(np.array(unix_millis))
np.testing.assert_array_equal(gps_millis_back, gps_millis)
# GPS Millis <--> TOW
gps_week, tow = tc.gps_millis_to_tow(np.array(gps_millis))
gps_millis_back = tc.tow_to_gps_millis(np.array(gps_week),
np.array(tow))
np.testing.assert_array_equal(gps_millis_back, gps_millis)
# UNIX Millis <--> TOW
gps_week, tow = tc.unix_millis_to_tow(np.array(unix_millis))
unix_millis_back = tc.tow_to_unix_millis(np.array(gps_week),
np.array(tow))
np.testing.assert_array_equal(unix_millis_back, unix_millis)
def test_gps_datetime_to_gps_millis():
"""Test conversion of GPS datetime to GPS millis.
"""
utc_time = datetime(2022, 8, 10, 19, 51, 9, tzinfo=timezone.utc)
gps_time = datetime(2022, 8, 10, 19, 51, 27, tzinfo=timezone.utc)
gps_millis_for_gps_time = tc.gps_datetime_to_gps_millis(gps_time)
gps_millis_for_utc_time = tc.datetime_to_gps_millis(utc_time)
np.testing.assert_equal(gps_millis_for_gps_time, gps_millis_for_utc_time)
#^ The same time stamp in GPS time corresponds to 18 seconds
# earlier in UTC time.
gps_millis_for_gps_time = tc.gps_datetime_to_gps_millis(np.array(gps_time))
np.testing.assert_equal(gps_millis_for_gps_time, gps_millis_for_utc_time)