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

1import datetime as dt 

2 

3import gws 

4import gws.lib.datetimex as dx 

5import gws.test.util as u 

6 

7 

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 

12 

13 dat = '2001-02-03T11:22:33' 

14 cmd = f'date --date="{dat}" --iso-8601="seconds"' 

15 

16 # preserve the configured tz 

17 orig_dt = u.exec(cmd) 

18 orig_tz = u.exec('readlink /etc/localtime') 

19 

20 dx.set_local_time_zone('America/Detroit') 

21 assert u.exec(cmd) == f'{dat}-05:00' # EST (UTC-5) 

22 

23 dx.set_local_time_zone('Asia/Kamchatka') 

24 assert u.exec(cmd) == f'{dat}+12:00' # PETT (UTC+12) 

25 

26 # restore 

27 u.exec(f'ln -fs {orig_tz} /etc/localtime') 

28 assert u.exec(cmd) == orig_dt 

29 

30 

31def test_time_zone(): 

32 s = 'Europe/Paris' 

33 tz = dx.time_zone(s) 

34 assert str(tz) == s 

35 

36 

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() 

41 

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() 

45 

46 

47def test_now(): 

48 a = dx.now() 

49 b = dt.datetime.now().astimezone() 

50 assert (b - a).total_seconds() < 2 

51 

52 

53def test_parse(): 

54 s = '2000-01-02T03:04:05' 

55 a = 2000, 1, 2, 3, 4, 5 

56 

57 # explicit tz 

58 

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() 

62 

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() 

66 

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() 

71 

72 # default tz 

73 

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() 

77 

78 # local tz 

79 

80 d = dx.parse(s) 

81 e = dt.datetime(*a, tzinfo=dx.time_zone('')) 

82 assert d.isoformat() == e.isoformat() 

83 

84 # date only 

85 

86 d = dx.parse('2000-01-02') 

87 e = dt.datetime(2000, 1, 2, tzinfo=dx.time_zone('')) 

88 assert d.isoformat() == e.isoformat() 

89 

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() 

93 

94 # year only 

95 

96 d = dx.parse('2000') 

97 e = dt.datetime(2000, 1, 1, tzinfo=dx.time_zone('')) 

98 assert d.isoformat() == e.isoformat() 

99 

100 # iso basic 

101 

102 d = dx.parse('20120630T180000Z') 

103 e = dt.datetime(2012, 6, 30, 18, tzinfo=dx.UTC) 

104 assert d.isoformat() == e.isoformat() 

105 

106 # whitespace 

107 

108 d = dx.parse(' 20120630T180000Z ') 

109 e = dt.datetime(2012, 6, 30, 18, tzinfo=dx.UTC) 

110 assert d.isoformat() == e.isoformat() 

111 

112 # not supported 

113 

114 d = dx.parse('10:11:12') 

115 assert d is None 

116 

117 d = dx.parse('2007-03-01T13:00:00Z/2008-05-11T15:30:00Z') 

118 assert d is None 

119 

120 

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 

127 

128 

129def test_parse_duration_errors(): 

130 with u.raises(dx.Error, match=f'invalid duration'): 

131 dx.parse_duration('1 foo') 

132 

133 

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' 

140 

141 

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' 

146 

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' 

150 

151 

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('')) 

155 

156 assert dx.to_iso_string(n) == dx.to_iso_string(d) 

157 

158 

159 

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' 

167 

168 

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' 

175 

176 

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' 

180 

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' 

185 

186 t = a.timestamp() 

187 

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 

192 

193 

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 ) 

205 

206 

207def test_difference(): 

208 h, m, s = 4, 5, 6 

209 

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) 

213 

214 assert vars(df) == _diff(hours=h, minutes=m, seconds=s) 

215 

216 

217def test_total_difference_hours(): 

218 h, m, s = 4, 5, 6 

219 

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) 

223 

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 ) 

230 

231 

232def test_total_difference_weeks(): 

233 w = 6 

234 

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) 

238 

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 )