Coverage for gws-app/gws/lib/datetimex/_test.py: 0%
130 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
1import datetime as dt
3import gws
4import gws.lib.datetimex as dx
5import gws.test.util as u
8def test_set_local_time_zone():
9 # @TODO We must be root to do that, but the tests are run from the gws user.
10 if True:
11 return
13 dat = '2001-02-03T11:22:33'
14 cmd = f'date --date="{dat}" --iso-8601="seconds"'
16 # preserve the configured tz
17 orig_dt = u.exec(cmd)
18 orig_tz = u.exec('readlink /etc/localtime')
20 dx.set_local_time_zone('America/Detroit')
21 assert u.exec(cmd) == f'{dat}-05:00' # EST (UTC-5)
23 dx.set_local_time_zone('Asia/Kamchatka')
24 assert u.exec(cmd) == f'{dat}+12:00' # PETT (UTC+12)
26 # restore
27 u.exec(f'ln -fs {orig_tz} /etc/localtime')
28 assert u.exec(cmd) == orig_dt
31def test_time_zone():
32 s = 'Europe/Paris'
33 tz = dx.time_zone(s)
34 assert str(tz) == s
37def test_new():
38 a = dx.new(2024, 1, 2, 3, 4, 5)
39 b = dt.datetime(2024, 1, 2, 3, 4, 5).astimezone()
40 assert a.isoformat() == b.isoformat()
42 a = dx.new(2024, 1, 2, 3, 4, 5, tz='utc')
43 b = dt.datetime(2024, 1, 2, 3, 4, 5, tzinfo=dt.timezone.utc)
44 assert a.isoformat() == b.isoformat()
47def test_now():
48 a = dx.now()
49 b = dt.datetime.now().astimezone()
50 assert (b - a).total_seconds() < 2
53def test_parse():
54 s = '2000-01-02T03:04:05'
55 a = 2000, 1, 2, 3, 4, 5
57 # explicit tz
59 d = dx.parse('2000-01-02T03:04:05' + '+0000')
60 e = dt.datetime(*a, tzinfo=dx.time_zone('utc'))
61 assert d.isoformat() == e.isoformat()
63 d = dx.parse('2000-01-02T03:04:05' + 'Z')
64 e = dt.datetime(*a, tzinfo=dx.time_zone('utc'))
65 assert d.isoformat() == e.isoformat()
67 d = dx.parse(s + '+0900')
68 # NB, the sign is inverted, see https://github.com/eggert/tz/blob/2018g/etcetera#L38
69 e = dt.datetime(*a, tzinfo=dx.time_zone('Etc/GMT-9'))
70 assert d.isoformat() == e.isoformat()
72 # default tz
74 d = dx.parse(s, tz='Etc/GMT-5')
75 e = dt.datetime(*a, tzinfo=dx.time_zone('Etc/GMT-5'))
76 assert d.isoformat() == e.isoformat()
78 # local tz
80 d = dx.parse(s)
81 e = dt.datetime(*a, tzinfo=dx.time_zone(''))
82 assert d.isoformat() == e.isoformat()
84 # date only
86 d = dx.parse('2000-01-02')
87 e = dt.datetime(2000, 1, 2, tzinfo=dx.time_zone(''))
88 assert d.isoformat() == e.isoformat()
90 d = dx.parse('2000-01-02', tz='Etc/GMT-5')
91 e = dt.datetime(2000, 1, 2, tzinfo=dx.time_zone('Etc/GMT-5'))
92 assert d.isoformat() == e.isoformat()
94 # year only
96 d = dx.parse('2000')
97 e = dt.datetime(2000, 1, 1, tzinfo=dx.time_zone(''))
98 assert d.isoformat() == e.isoformat()
100 # iso basic
102 d = dx.parse('20120630T180000Z')
103 e = dt.datetime(2012, 6, 30, 18, tzinfo=dx.UTC)
104 assert d.isoformat() == e.isoformat()
106 # whitespace
108 d = dx.parse(' 20120630T180000Z ')
109 e = dt.datetime(2012, 6, 30, 18, tzinfo=dx.UTC)
110 assert d.isoformat() == e.isoformat()
112 # not supported
114 d = dx.parse('10:11:12')
115 assert d is None
117 d = dx.parse('2007-03-01T13:00:00Z/2008-05-11T15:30:00Z')
118 assert d is None
121def test_parse_duration():
122 assert dx.parse_duration('1 w') == 3600 * 24 * 7
123 assert dx.parse_duration('1 d') == 3600 * 24
124 assert dx.parse_duration('1 h') == 3600
125 assert dx.parse_duration('1 m') == 60
126 assert dx.parse_duration('1 s') == 1
129def test_parse_duration_errors():
130 with u.raises(dx.Error, match=f'invalid duration'):
131 dx.parse_duration('1 foo')
134def test_parse_time():
135 with dx.mock_now(dx.new(2023, 3, 26, 0, 0, 0, tz='Europe/Berlin')):
136 d = dx.parse_time('01:02:03', tz='Europe/Berlin')
137 assert dx.to_iso_string(d) == '2023-03-26T01:02:03+0100'
138 d = dx.parse_time('03:04:05', tz='Europe/Berlin')
139 assert dx.to_iso_string(d) == '2023-03-26T03:04:05+0200'
142def test_to_iso_string():
143 d = dt.datetime.fromisoformat('2022-10-31T16:42:22+09:00')
144 assert dx.to_iso_string(d) == '2022-10-31T16:42:22+0900'
145 assert dx.to_iso_string(d, sep='#') == '2022-10-31#16:42:22+0900'
147 d = dt.datetime.fromisoformat('2022-10-31T16:42:22+00:00')
148 assert dx.to_iso_string(d, with_tz='+') == '2022-10-31T16:42:22+0000'
149 assert dx.to_iso_string(d, with_tz='Z', sep='#') == '2022-10-31#16:42:22Z'
152def test_naive_to_iso_string():
153 n = dt.datetime(2022, 10, 31, 11, 22, 33)
154 d = dt.datetime(2022, 10, 31, 11, 22, 33, tzinfo=dx.time_zone(''))
156 assert dx.to_iso_string(n) == dx.to_iso_string(d)
160def test_to_iso_date_string():
161 d = dt.datetime.fromisoformat('2022-10-31T16:42:22+09:00')
162 assert dx.to_iso_date_string(d) == '2022-10-31'
163 d = dt.datetime.fromisoformat('2022-12-31T23:59:59+09:00')
164 assert dx.to_iso_date_string(d) == '2022-12-31'
165 d = dt.datetime.fromisoformat('2022-12-31T23:59:59-09:00')
166 assert dx.to_iso_date_string(d) == '2022-12-31'
169def test_add():
170 a = dt.datetime.fromisoformat('2000-01-30T03:04:05+00:00')
171 b = dx.add(a, days=5)
172 assert b.isoformat() == '2000-02-04T03:04:05+00:00'
173 b = dx.add(a, days=5, hours=-5)
174 assert b.isoformat() == '2000-02-03T22:04:05+00:00'
177def test_add_over_dst():
178 a = dx.new(2023, 3, 26, 0, 11, 22, tz='Europe/Berlin')
179 assert a.isoformat() == '2023-03-26T00:11:22+01:00'
181 assert dx.add(a, hours=1).isoformat() == '2023-03-26T01:11:22+01:00'
182 assert dx.add(a, hours=2).isoformat() == '2023-03-26T02:11:22+01:00' #
183 assert dx.add(a, hours=3).isoformat() == '2023-03-26T03:11:22+02:00' #
184 assert dx.add(a, hours=4).isoformat() == '2023-03-26T04:11:22+02:00'
186 t = a.timestamp()
188 assert dx.add(a, hours=1).timestamp() == t + 1.0 * 3600
189 assert dx.add(a, hours=2).timestamp() == t + 2.0 * 3600 #
190 assert dx.add(a, hours=3).timestamp() == t + 2.0 * 3600 #
191 assert dx.add(a, hours=4).timestamp() == t + 3.0 * 3600
194def _diff(years=0, months=0, weeks=0, days=0, hours=0, minutes=0, seconds=0, microseconds=0):
195 return dict(
196 years=years or 0,
197 months=months or 0,
198 weeks=weeks or 0,
199 days=days or 0,
200 hours=hours or 0,
201 minutes=minutes or 0,
202 seconds=seconds or 0,
203 microseconds=microseconds or 0,
204 )
207def test_difference():
208 h, m, s = 4, 5, 6
210 a = dt.datetime.fromisoformat('2000-01-30T03:04:05+00:00')
211 b = dx.add(a, seconds=3600 * h + 60 * m + s)
212 df = dx.difference(a, b)
214 assert vars(df) == _diff(hours=h, minutes=m, seconds=s)
217def test_total_difference_hours():
218 h, m, s = 4, 5, 6
220 a = dt.datetime.fromisoformat('2000-01-30T03:04:05+00:00')
221 b = dx.add(a, seconds=3600 * h + 60 * m + s)
222 df = dx.total_difference(a, b)
224 assert vars(df) == _diff(
225 hours=h,
226 minutes=h * 60 + m,
227 seconds=h * 3600 + m * 60 + s,
228 microseconds=(h * 3600 + m * 60 + s) * 1_000_000
229 )
232def test_total_difference_weeks():
233 w = 6
235 a = dt.datetime.fromisoformat('2000-01-30T03:04:05+00:00')
236 b = dx.add(a, weeks=w)
237 df = dx.total_difference(a, b)
239 assert vars(df) == _diff(
240 months=1,
241 weeks=w,
242 days=w * 7,
243 hours=w * 7 * 24,
244 minutes=w * 7 * 24 * 60,
245 seconds=w * 7 * 24 * 3600,
246 microseconds=(w * 7 * 24 * 3600) * 1_000_000
247 )