4
4
5
5
import builtins
6
6
import datetime
7
- import numbers
7
+ import typing
8
8
from typing import Union
9
9
10
+ import isodate
11
+ import pytz
10
12
from dateutil import parser
11
13
from isodate import parse_duration
12
14
15
17
"""
16
18
17
19
18
- def now_utc ():
20
+ def now_utc () -> datetime . datetime :
19
21
"""
20
22
Current local date and time in UTC timezone
21
23
@@ -25,7 +27,7 @@ def now_utc():
25
27
return datetime .datetime .now (datetime .timezone .utc )
26
28
27
29
28
- def today_utc ():
30
+ def today_utc () -> datetime . date :
29
31
"""
30
32
Current date in UTC timezone
31
33
@@ -35,7 +37,7 @@ def today_utc():
35
37
return datetime .datetime .now (datetime .timezone .utc ).date ()
36
38
37
39
38
- def timestamp (dt : Union [numbers . Number , str ]):
40
+ def timestamp (dt : Union [float , str ]) -> Union [ int , float ] :
39
41
"""
40
42
Converts a number or a string to a timestamp
41
43
@@ -48,21 +50,21 @@ def timestamp(dt: Union[numbers.Number, str]):
48
50
:param dt: datetime to convert to timestamp
49
51
:return: unix timestamp
50
52
"""
51
- if isinstance (dt , numbers . Number ):
53
+ if isinstance (dt , ( int , float ) ):
52
54
return int (dt )
53
55
else :
54
- return _str_to_datetime (dt ).astimezone (datetime . timezone .utc ).timestamp ()
56
+ return _str_to_datetime (dt ).astimezone (pytz .utc ).timestamp ()
55
57
56
58
57
59
def _str_to_datetime (s : str ) -> datetime .datetime :
58
60
parsed_date = parser .isoparse (s )
59
61
if not parsed_date .tzinfo :
60
62
# Assume UTC if the input does not contain a timezone
61
- parsed_date = parsed_date .replace (tzinfo = datetime . timezone .utc )
62
- return parsed_date .astimezone (datetime . timezone .utc )
63
+ parsed_date = parsed_date .replace (tzinfo = pytz .utc )
64
+ return parsed_date .astimezone (pytz .utc )
63
65
64
66
65
- def max (* args ) :
67
+ def max (* args : typing . Any ) -> typing . Any :
66
68
"""
67
69
Returns biggest object of an iterable, or two or more arguments.
68
70
@@ -95,7 +97,7 @@ def day_delta(num_days: int, format: str = "%Y-%m-%dT%H:%M:%S.%f%z") -> str:
95
97
return (datetime .datetime .now (datetime .timezone .utc ) + datetime .timedelta (days = num_days )).strftime (format )
96
98
97
99
98
- def duration (datestring : str ) -> datetime .timedelta :
100
+ def duration (datestring : str ) -> Union [ datetime .timedelta , isodate . Duration ] :
99
101
"""
100
102
Converts ISO8601 duration to datetime.timedelta
101
103
@@ -111,10 +113,17 @@ def format_datetime(dt: Union[str, datetime.datetime], format: str) -> str:
111
113
112
114
Usage:
113
115
`"{{ format_datetime(config.start_date, '%Y-%m-%d') }}"`
116
+
117
+ CPython Datetime package has known bug with `stfrtime` method: '%s' formatting uses locale timezone
118
+ https://github.com/python/cpython/issues/77169
119
+ https://github.com/python/cpython/issues/56959
114
120
"""
115
121
if isinstance (dt , datetime .datetime ):
116
122
return dt .strftime (format )
117
- return _str_to_datetime (dt ).strftime (format )
123
+ dt_datetime = _str_to_datetime (dt )
124
+ if format == "%s" :
125
+ return str (int (dt_datetime .timestamp ()))
126
+ return dt_datetime .strftime (format )
118
127
119
128
120
129
_macros_list = [now_utc , today_utc , timestamp , max , day_delta , duration , format_datetime ]
0 commit comments