Skip to content

Datetime Tools

__all__ = ['ISO_FMT', 'cast_to_datetime', 'datetime_to_iso', 'array_time_difference', 'correct_week', 'arange_datetime', 'diff_seconds', 'subtract_timedelta', 'datetime2tow', 'subtract_timedelta_as_tow', 'tow2datetime', 'tow2zcount', 'zcount2tow', 'datetime2zcount', 'zcount2datetime'] module-attribute

Copyright 2020 The Aerospace Corporation

arange_datetime(start_datetime, duration_s, step_ms)

Create a list of datetimes in sequence.

The purpose of this function is to create a list that represents a sequence of datetimes of the specified duration with the specified step size.

This function is an analogue of the numpy.arange() function, but operates on datetimes.

Parameters

start_gpstime : datetime.datetime The datetime to start the sequence duration_s : float The duration of the sequence, in seconds step_ms : float The step size, in milliseconds

Returns

List[datetime.datetime] The sequence of datetime

Notes

Like numpy.arange, this does not include the final element. That is, if the start is at 0 with a duration of 5 and step of 1, the sequence would return [0, 1, 2, 3, 4]

See Also

numpy.arange() arange_gpstime()

Todo

.. todo:: Determine if this still works if a np.ndarray is returned instead of a list

Source code in gps_time/datetime.py
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
def arange_datetime(
    start_datetime: datetime.datetime, duration_s: float, step_ms: float
) -> List[datetime.datetime]:
    """Create a list of datetimes in sequence.

    The purpose of this function is to create a list that represents a
    sequence of datetimes of the specified duration with the specified step
    size.

    This function is an analogue of the `numpy.arange()` function, but
    operates on datetimes.

    Parameters
    ----------
    start_gpstime : datetime.datetime
        The datetime to start the sequence
    duration_s : float
        The duration of the sequence, in seconds
    step_ms : float
        The step size, in milliseconds

    Returns
    -------
    List[datetime.datetime]
        The sequence of datetime

    Notes
    -----
    Like `numpy.arange`, this does not include the final element. That is, if
    the start is at 0 with a duration of 5 and step of 1, the sequence would
    return [0, 1, 2, 3, 4]

    See Also
    --------
    `numpy.arange()`
    `arange_gpstime()`

    Todo
    ----
    .. todo:: Determine if this still works if a np.ndarray is returned
        instead of a list

    """
    times = []
    dt = datetime.timedelta(milliseconds=step_ms)
    duration = datetime.timedelta(seconds=duration_s)
    end_date = start_datetime + duration
    while True:
        date = start_datetime + len(times) * dt
        if date < end_date:
            times.append(date)
        else:
            break
    return times

array_time_difference(datetime_array1, datetime_array2)

Get time delta (sec) from arrays of datetime.

The purpose of this function is to compute the time between two arrays of datetime objects. If the first argument is \(T_{1}\) and the second argument is \(T_{2}\), then this function returns \(T_{1} - T_{2}\) in seconds. If a single DateTime object is given for one of the arguments, it is converted to a single element numpy array.

Parameters

datetime_array1 : np.ndarray The first date time array datetime_array2 : np.ndarray The second date time array

Returns

np.ndarray A NumPy array containing the time from the the second datetime array to the first

Source code in gps_time/datetime.py
 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
def array_time_difference(
    datetime_array1: np.ndarray, datetime_array2: np.ndarray
) -> np.ndarray:
    r"""Get time delta (sec) from arrays of datetime.

    The purpose of this function is to compute the time between two arrays of
    datetime objects. If the first argument is \(T_{1}\) and the second
    argument is \(T_{2}\), then this function returns
    \(T_{1} - T_{2}\) in seconds. If a single DateTime object is given for
    one of the arguments, it is converted to a single element numpy array.

    Parameters
    ----------
    datetime_array1 : np.ndarray
        The first date time array
    datetime_array2 : np.ndarray
        The second date time array

    Returns
    -------
    np.ndarray
        A NumPy array containing the time from the the second datetime
        array to the first

    """

    """
    Raises
    ------
    TypeError
        If the inputs are not arrays of datetimes
    """
    if isinstance(datetime_array1, datetime.datetime):
        datetime_array1 = np.array([datetime_array1])
    if isinstance(datetime_array2, datetime.datetime):
        datetime_array2 = np.array([datetime_array2])

    if not (
        isinstance(datetime_array1, np.ndarray)
        and isinstance(datetime_array2, np.ndarray)
    ):
        raise TypeError(
            """Both DateTimeArray1 and DateTimeArray2 must be
                        NumPy arrays. Use numpy.array() to convert a list to
                        an NumPy array."""
        )

    if not (all(isinstance(x, datetime.datetime) for x in datetime_array1)):
        raise TypeError("DateTimeArray1 must be an array of DateTime objects")
    if not (all(isinstance(x, datetime.datetime) for x in datetime_array2)):
        raise TypeError("DateTimeArray2 must be an array of DateTime objects")

    time_delta = datetime_array1 - datetime_array2

    return np.array([x.total_seconds() for x in time_delta])

cast_to_datetime(iso_string)

Cast an ISO string to a datetime object.

Iso format is defined as YYYY-MM-DDTHH:MM:SS.SSSSSS, for this cast the formatters (- : . T) are all optional, technically all thats needed is a 20 digit integer with the values in the right place

Parameters

iso_string : str string to convert to datetime

Returns

datetime.datetime The datetime defined by the string

See Also

ISO_FMT

Source code in gps_time/datetime.py
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
def cast_to_datetime(iso_string: str) -> datetime.datetime:
    """Cast an ISO string to a datetime object.

    Iso format is defined as YYYY-MM-DDTHH:MM:SS.SSSSSS, for this cast the
    formatters (- : . T) are all optional, technically all thats needed is
    a 20 digit integer with the values in the right place

    Parameters
    ----------
    iso_string : str
        string to convert to datetime

    Returns
    -------
    datetime.datetime
        The datetime defined by the string

    See Also
    --------
    `ISO_FMT`

    """

    """    
    Raises
    ------
    IOError
        If the input does not contain an ISO datetime format
    """

    m = re.match(ISO_FMT, iso_string)
    if m is not None:
        y, m, d, h, minute, s, us = [int(v) if v is not None else v for v in m.groups()]
        if us is None:
            us = 0
        return datetime.datetime(year=y, month=m, day=d, hour=h, minute=minute, second=s, microsecond=us, tzinfo=datetime.timezone.utc)

    else:
        raise IOError("Value {} not in ISO Time Format".format(iso_string))

correct_week(week_num, tow, year)

Correct the week number for week rollovers.

Provide the mod 1024 week number and update to the actual GPS week based on the year

Parameters

week_num : int The mod 1024 week number tow : float The time of week year : int The year

Returns

int The full GPS week number

Source code in gps_time/datetime.py
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
def correct_week(week_num: int, tow: float, year: int) -> int:
    """Correct the week number for week rollovers.

    Provide the mod 1024 week number and update to the actual GPS week based
    on the year

    Parameters
    ----------
    week_num : int
        The mod 1024 week number
    tow : float
        The time of week
    year : int
        The year

    Returns
    -------
    int
        The full GPS week number

    """

    """
    Raises
    ------
    ValueError
        If the year is not an int
    ValueError
        If the week number and year are inconsistent
    """
    if not isinstance(year, int):
        raise ValueError("The year must be an int")

    # Get the year for the week number
    current_year = _gps_epoch_datetime + datetime.timedelta(
        days=7 * week_num, seconds=tow
    )

    # While the week number is before the desired year, keep adding 1024
    # weeks and compare. Note that if a match is found, the while loop
    # breaks. If it is not, the while loop exits to else, which raises and
    # error.
    while current_year.year <= year:

        # Break when the year and year expressed by the week number are the
        # same.
        if current_year.year == year:
            break

        # Add 1024 weeks to the week number and recompute the current year
        week_num += 1024
        current_year = _gps_epoch_datetime + datetime.timedelta(
            days=7 * week_num, seconds=tow
        )
    else:  # If the week number is not consistent with the year
        raise ValueError("WeekNum and Year are inconsistent.")

    return week_num

datetime2tow(date_time)

Convert date time to GPS Week and Time of Week.

The purpose of this function is to convert a datetime object to the GPS week number and the time of week. This returns the full GPS week number. The user must separately compute the mod 1024 week if that is desired.

Parameters

date_time : datetime.datetime A datetime object representing the desired times. If no tzinfo is provided, assumed to be UTC

Returns

Tuple[int, float] Two elements: 1) The GPS Week Number and 2) the time of week

Source code in gps_time/datetime.py
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
def datetime2tow(date_time: datetime.datetime) -> Tuple[int, float]:
    """Convert date time to GPS Week and Time of Week.

    The purpose of this function is to convert a datetime object to the GPS
    week number and the time of week. This returns the full GPS week number.
    The user must separately compute the mod 1024 week if that is desired.

    Parameters
    ----------
    date_time : datetime.datetime
        A datetime object representing the desired times. If no tzinfo is 
        provided, assumed to be UTC

    Returns
    -------
    Tuple[int, float]
        Two elements: 1) The GPS Week Number and 2) the time of week
    """

    """
    Raises
    ------
    TypeError
        If the input is not a datetime
    """

    # Ensure the argument is a datetime object
    if not isinstance(date_time, datetime.datetime):
        raise TypeError("DateTime arg must be a datetime object.")

    if date_time.tzinfo is None:
        date_time=date_time.replace(tzinfo=datetime.timezone.utc)

    # Find the week number
    week_num = (date_time - _gps_epoch_datetime).days // 7

    # Determine the first day of the week and compute the time since the start
    # of the week, in seconds
    week_start = _gps_epoch_datetime + datetime.timedelta(days=week_num * 7)
    time_since_week_start = date_time - week_start
    time_of_week = time_since_week_start.total_seconds()

    # Returns the week number and the time of week
    return int(week_num), float(time_of_week)

datetime2zcount(date_time)

Convert a datetime to z-count and week number.

This function takes a datetime and returns a week number and z-count. It accomplishes this by first calling datetime2tow() and then tow2zcount().

Parameters

date_time : datetime.datetime The datetime

Returns

Tuple[int, float] The week number and z-count

Source code in gps_time/datetime.py
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
def datetime2zcount(date_time: datetime.datetime) -> Tuple[int, float]:
    """Convert a datetime to z-count and week number.

    This function takes a datetime and returns a week number and z-count. It
    accomplishes this by first calling datetime2tow() and then tow2zcount().

    Parameters
    ----------
    date_time : datetime.datetime
        The datetime

    Returns
    -------
    Tuple[int, float]
        The week number and z-count

    """
    week_num, tow = datetime2tow(date_time)
    week_num, zcount = tow2zcount(week_num, tow)

    return week_num, zcount

datetime_to_iso(date_time)

Convert a datetime to an iso string.

The purpose of this function is to convert a datetime object to a string in the standard ISO format.

Parameters

date_time : datetime.datetime A datetime object

Returns

str A string containing the ISO formatted time, i.e. YYYY-MM-DDTHH:MM:SS.SSSSSS

Todo

.. todo:: Determine Usefulness This appears to alias the datetime built-in isoformat() function. Determine if this function should still be included or it provides additional functionality

Source code in gps_time/datetime.py
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
def datetime_to_iso(date_time: datetime.datetime) -> str:
    """Convert a datetime to an iso string.

    The purpose of this function is to convert a datetime object to a string
    in the standard ISO format.

    Parameters
    ----------
    date_time : datetime.datetime
        A datetime object

    Returns
    -------
    str
        A string containing the ISO formatted time, i.e.
        YYYY-MM-DDTHH:MM:SS.SSSSSS

    Todo
    ----
    .. todo:: Determine Usefulness
        This appears to alias the datetime built-in isoformat() function.
        Determine if this function should still be included or it provides
        additional functionality

    """
    return "T".join(str(date_time).split(" "))

diff_seconds(dt_obj, dt_array)

Get the time diff in seconds between a single date time and an array.

This function is uses to find the time difference between a single datetime and an array of datetimes. It returns the value of the single datetime minus the array of datetimes

Parameters

dt_obj : datetime.datetime A single datetime object dt_array : Iterable[datetime.datetime] An array of datetime objects

Returns

np.ndarray An array of time differences between dt_obj and each element of dt_array

Source code in gps_time/datetime.py
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
def diff_seconds(
    dt_obj: datetime.datetime, dt_array: Iterable[datetime.datetime]
) -> np.ndarray:
    """Get the time diff in seconds between a single date time and an array.

    This function is uses to find the time difference between a single datetime
    and an array of datetimes. It returns the value of the single datetime
    minus the array of datetimes

    Parameters
    ----------
    dt_obj : datetime.datetime
        A single datetime object
    dt_array : Iterable[datetime.datetime]
        An array of datetime objects

    Returns
    -------
    np.ndarray
        An array of time differences between dt_obj and each element of
        dt_array

    """
    return np.array([(dt_obj - dt).total_seconds() for dt in dt_array])

subtract_timedelta(datetime_array, time_delta)

Subtract a time delta from an array of datetimes.

This function is used to subtract an array of time deltas in seconds from an array of datetimes.

Parameters

datetime_array : np.ndarray An array of datetimes time_delta : np.ndarray An array of timedeltas, in seconds

Returns

np.ndarray An array of datetimes that are the input datetime array with the time delta subtracted from them

.. todo:: Add checks for inputs

Source code in gps_time/datetime.py
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
def subtract_timedelta(
    datetime_array: np.ndarray, time_delta: np.ndarray
) -> np.ndarray:
    """Subtract a time delta from an array of datetimes.

    This function is used to subtract an array of time deltas in seconds from
    an array of datetimes.

    Parameters
    ----------
    datetime_array : np.ndarray
        An array of datetimes
    time_delta : np.ndarray
        An array of timedeltas, in seconds

    Returns
    -------
    np.ndarray
        An array of datetimes that are the input datetime array with the
        time delta subtracted from them

    .. todo:: Add checks for inputs

    """
    return datetime_array - np.array(
        [datetime.timedelta(seconds=s) for s in time_delta]
    )

subtract_timedelta_as_tow(datetime_array, time_delta)

Subtract time delta from an array of datetimes and return as week/TOW.

This function is used to subtract an array of time deltas in seconds from an array of datetimes. It does this by calling subtract_timedelta() to get an array of new datetimes then using datetime2tow() to cast the datetimes in terms of week numbers and times of week.

Parameters

datetime_array : np.ndarray An array of datetimes time_delta : np.ndarray An array of timedeltas, in seconds

Returns

np.ndarray An array of week numbers and times of weeks that are the input datetime array with the time delta subtracted from them

Source code in gps_time/datetime.py
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
def subtract_timedelta_as_tow(
    datetime_array: np.ndarray, time_delta: np.ndarray
) -> np.ndarray:
    """Subtract time delta from an array of datetimes and return as week/TOW.

    This function is used to subtract an array of time deltas in seconds from
    an array of datetimes. It does this by calling subtract_timedelta() to get
    an array of new datetimes then using datetime2tow() to cast the datetimes
    in terms of week numbers and times of week.

    Parameters
    ----------
    datetime_array : np.ndarray
        An array of datetimes
    time_delta : np.ndarray
        An array of timedeltas, in seconds

    Returns
    -------
    np.ndarray
        An array of week numbers and times of weeks that are the input
        datetime array with the time delta subtracted from them

    """
    d = subtract_timedelta(datetime_array, time_delta)
    return np.array([datetime2tow(_d) for _d in d])

tow2datetime(week_num, tow, year=None)

Convert GPS Week and Time of Week to datetime.

The purpose of this function is to convert a GPS Week number and a time of week into a DateTime object. The week number represents the number of weeks since 6 January 1980 and the time of week is the number of seconds since midnight Sunday night. Note that the GPS week is sometimes expressed as a mod 1024 week. If this is the case, the Year argument can be used to correct for mod 1024 weeks. If the week number is not consistent with the Year, then an error is raised.

Parameters

week_num : int GPS Week Number (not limited to 1024) tow : float Time of Week (seconds since midnight Sunday Morning) year : Optional[int], optional If not None, used to correct the week_num from mod 1024 week to the actual week number (weeks since 6 Jan 1980), by default None

Returns

datetime.datetime object that represents the current time

Source code in gps_time/datetime.py
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
def tow2datetime(
    week_num: int, tow: float, year: Optional[int] = None
) -> datetime.datetime:
    """Convert GPS Week and Time of Week to datetime.

    The purpose of this function is to convert a GPS Week number and a time of
    week into a DateTime object. The week number represents the number of weeks
    since 6 January 1980 and the time of week is the number of seconds since
    midnight Sunday night. Note that the GPS week is sometimes expressed as a
    mod 1024 week. If this is the case, the Year argument can be used to
    correct for mod 1024 weeks. If the week number is not consistent with the
    Year, then an error is raised.

    Parameters
    ----------
    week_num : int
        GPS Week Number (not limited to 1024)
    tow : float
        Time of Week (seconds since midnight Sunday Morning)
    year : Optional[int], optional
        If not None, used to correct the week_num from mod 1024 week to
        the actual week number (weeks since 6 Jan 1980), by default None

    Returns
    -------
    datetime.datetime
        object that represents the current time

    """
    # Correct the week number if a year is given
    if year is not None:
        week_num = correct_week(week_num, tow, year)

    date_time_out = (
        _gps_epoch_datetime
        + datetime.timedelta(days=week_num * 7)
        + datetime.timedelta(seconds=tow)
    )

    # Return a datetime object that stores the current week
    return date_time_out

tow2zcount(week_num, tow, year=None)

Convert a week number and time of week into week and zcount.

The Z-Count is the time of week in seconds divided by 1.5. This function is used to convert from a time of week and week number to z-count.

Parameters

week_num : int The week number tow : float The time of week (seconds) year : Optional[int], optional If not None, adjusts the week number to account for week roll overs. Otherwise, is passed through, by default None

Returns

Tuple[int, float] The week number and z-count

Notes

This function returns floating point z-count. Use another method to cast as int if required

Source code in gps_time/datetime.py
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
def tow2zcount(
    week_num: int, tow: float, year: Optional[int] = None
) -> Tuple[int, float]:
    """Convert a week number and time of week into week and zcount.

    The Z-Count is the time of week in seconds divided by 1.5. This function is
    used to convert from a time of week and week number to z-count.

    Parameters
    ----------
    week_num : int
        The week number
    tow : float
        The time of week (seconds)
    year : Optional[int], optional
        If not None, adjusts the week number to account for week roll
        overs. Otherwise, is passed through, by default None

    Returns
    -------
    Tuple[int, float]
        The week number and z-count

    Notes
    -----
    This function returns floating point z-count. Use another method to
    cast as int if required

    """
    # If not None, correct the week number base on the year
    if year is not None:
        week_num = correct_week(week_num, tow, year)

    # Z-count is the week number divided by 1.5
    zcount = tow / 1.5

    return week_num, zcount

zcount2datetime(week_num, zcount, year=None)

Convert a week number and time of week into a datetime.

The Z-Count is the time of week divided by 1.5. This function is used to convert from a z-count and week number to the equivalent datetime. It accomplished this by calling zcount2tow() and then tow2datetime().

Parameters

week_num : int The week number zcount : float The z-count (1.5 sec epochs) year : Optional[int], optional If not None, adjusts the week number to account for week roll overs. Otherwise, is passed through, by default None

Returns

datetime.datetime The datetime representing the zcount

Source code in gps_time/datetime.py
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
def zcount2datetime(
    week_num: int, zcount: float, year: Optional[int] = None
) -> datetime.datetime:
    """Convert a week number and time of week into a datetime.

    The Z-Count is the time of week divided by 1.5. This function is used to
    convert from a z-count and week number to the equivalent datetime. It
    accomplished this by calling zcount2tow() and then tow2datetime().

    Parameters
    ----------
    week_num : int
        The week number
    zcount : float
        The z-count (1.5 sec epochs)
    year : Optional[int], optional
        If not None, adjusts the week number to account for week roll
        overs. Otherwise, is passed through, by default None

    Returns
    -------
    datetime.datetime
        The datetime representing the zcount

    """
    week_num, tow = zcount2tow(week_num, zcount, year=year)
    date_time = tow2datetime(week_num, tow)

    return date_time

zcount2tow(week_num, zcount, year=None)

Convert a week number and time of week into week and zcount.

The Z-Count is the time of week divided by 1.5. This function is used to convert from a z-count and week number to time of week.

Parameters

week_num : int The week number zcount : float The z-count (1.5 sec epochs) year : Optional[int], optional If not None, adjusts the week number to account for week roll overs. Otherwise, is passed through, by default None

Returns

Tuple[int, float] The week number and time of week

Source code in gps_time/datetime.py
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
def zcount2tow(
    week_num: int, zcount: float, year: Optional[int] = None
) -> Tuple[int, float]:
    """Convert a week number and time of week into week and zcount.

    The Z-Count is the time of week divided by 1.5. This function is used to
    convert from a z-count and week number to time of week.

    Parameters
    ----------
    week_num : int
        The week number
    zcount : float
        The z-count (1.5 sec epochs)
    year : Optional[int], optional
        If not None, adjusts the week number to account for week roll
        overs. Otherwise, is passed through, by default None

    Returns
    -------
    Tuple[int, float]
        The week number and time of week

    """
    tow = zcount * 1.5

    # If not None, correct the week number base on the year
    if year is not None:
        week_num = correct_week(week_num, tow, year)

    return week_num, tow