Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/utils/timezone.py: 45%

119 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1""" 

2Timezone-related classes and functions. 

3""" 

4 

5import functools 

6import sys 

7import warnings 

8 

9try: 

10 import zoneinfo 

11except ImportError: 

12 from backports import zoneinfo 

13 

14from contextlib import ContextDecorator 

15from datetime import datetime, timedelta, timezone, tzinfo 

16 

17from asgiref.local import Local 

18 

19from django.conf import settings 

20from django.utils.deprecation import RemovedInDjango50Warning 

21 

22__all__ = [ 

23 "utc", 

24 "get_fixed_timezone", 

25 "get_default_timezone", 

26 "get_default_timezone_name", 

27 "get_current_timezone", 

28 "get_current_timezone_name", 

29 "activate", 

30 "deactivate", 

31 "override", 

32 "localtime", 

33 "now", 

34 "is_aware", 

35 "is_naive", 

36 "make_aware", 

37 "make_naive", 

38] 

39 

40# RemovedInDjango50Warning: sentinel for deprecation of is_dst parameters. 

41NOT_PASSED = object() 

42 

43 

44utc = timezone.utc 

45 

46 

47def get_fixed_timezone(offset): 

48 """Return a tzinfo instance with a fixed offset from UTC.""" 

49 if isinstance(offset, timedelta): 

50 offset = offset.total_seconds() // 60 

51 sign = "-" if offset < 0 else "+" 

52 hhmm = "%02d%02d" % divmod(abs(offset), 60) 

53 name = sign + hhmm 

54 return timezone(timedelta(minutes=offset), name) 

55 

56 

57# In order to avoid accessing settings at compile time, 

58# wrap the logic in a function and cache the result. 

59@functools.lru_cache() 

60def get_default_timezone(): 

61 """ 

62 Return the default time zone as a tzinfo instance. 

63 

64 This is the time zone defined by settings.TIME_ZONE. 

65 """ 

66 if settings.USE_DEPRECATED_PYTZ: 66 ↛ 67line 66 didn't jump to line 67, because the condition on line 66 was never true

67 import pytz 

68 

69 return pytz.timezone(settings.TIME_ZONE) 

70 return zoneinfo.ZoneInfo(settings.TIME_ZONE) 

71 

72 

73# This function exists for consistency with get_current_timezone_name 

74def get_default_timezone_name(): 

75 """Return the name of the default time zone.""" 

76 return _get_timezone_name(get_default_timezone()) 

77 

78 

79_active = Local() 

80 

81 

82def get_current_timezone(): 

83 """Return the currently active time zone as a tzinfo instance.""" 

84 return getattr(_active, "value", get_default_timezone()) 

85 

86 

87def get_current_timezone_name(): 

88 """Return the name of the currently active time zone.""" 

89 return _get_timezone_name(get_current_timezone()) 

90 

91 

92def _get_timezone_name(timezone): 

93 """ 

94 Return the offset for fixed offset timezones, or the name of timezone if 

95 not set. 

96 """ 

97 return timezone.tzname(None) or str(timezone) 

98 

99 

100# Timezone selection functions. 

101 

102# These functions don't change os.environ['TZ'] and call time.tzset() 

103# because it isn't thread safe. 

104 

105 

106def activate(timezone): 

107 """ 

108 Set the time zone for the current thread. 

109 

110 The ``timezone`` argument must be an instance of a tzinfo subclass or a 

111 time zone name. 

112 """ 

113 if isinstance(timezone, tzinfo): 

114 _active.value = timezone 

115 elif isinstance(timezone, str): 

116 if settings.USE_DEPRECATED_PYTZ: 

117 import pytz 

118 

119 _active.value = pytz.timezone(timezone) 

120 else: 

121 _active.value = zoneinfo.ZoneInfo(timezone) 

122 else: 

123 raise ValueError("Invalid timezone: %r" % timezone) 

124 

125 

126def deactivate(): 

127 """ 

128 Unset the time zone for the current thread. 

129 

130 Django will then use the time zone defined by settings.TIME_ZONE. 

131 """ 

132 if hasattr(_active, "value"): 

133 del _active.value 

134 

135 

136class override(ContextDecorator): 

137 """ 

138 Temporarily set the time zone for the current thread. 

139 

140 This is a context manager that uses django.utils.timezone.activate() 

141 to set the timezone on entry and restores the previously active timezone 

142 on exit. 

143 

144 The ``timezone`` argument must be an instance of a ``tzinfo`` subclass, a 

145 time zone name, or ``None``. If it is ``None``, Django enables the default 

146 time zone. 

147 """ 

148 

149 def __init__(self, timezone): 

150 self.timezone = timezone 

151 

152 def __enter__(self): 

153 self.old_timezone = getattr(_active, "value", None) 

154 if self.timezone is None: 

155 deactivate() 

156 else: 

157 activate(self.timezone) 

158 

159 def __exit__(self, exc_type, exc_value, traceback): 

160 if self.old_timezone is None: 

161 deactivate() 

162 else: 

163 _active.value = self.old_timezone 

164 

165 

166# Templates 

167 

168 

169def template_localtime(value, use_tz=None): 

170 """ 

171 Check if value is a datetime and converts it to local time if necessary. 

172 

173 If use_tz is provided and is not None, that will force the value to 

174 be converted (or not), overriding the value of settings.USE_TZ. 

175 

176 This function is designed for use by the template engine. 

177 """ 

178 should_convert = ( 

179 isinstance(value, datetime) 

180 and (settings.USE_TZ if use_tz is None else use_tz) 

181 and not is_naive(value) 

182 and getattr(value, "convert_to_local_time", True) 

183 ) 

184 return localtime(value) if should_convert else value 

185 

186 

187# Utilities 

188 

189 

190def localtime(value=None, timezone=None): 

191 """ 

192 Convert an aware datetime.datetime to local time. 

193 

194 Only aware datetimes are allowed. When value is omitted, it defaults to 

195 now(). 

196 

197 Local time is defined by the current time zone, unless another time zone 

198 is specified. 

199 """ 

200 if value is None: 

201 value = now() 

202 if timezone is None: 

203 timezone = get_current_timezone() 

204 # Emulate the behavior of astimezone() on Python < 3.6. 

205 if is_naive(value): 

206 raise ValueError("localtime() cannot be applied to a naive datetime") 

207 return value.astimezone(timezone) 

208 

209 

210def localdate(value=None, timezone=None): 

211 """ 

212 Convert an aware datetime to local time and return the value's date. 

213 

214 Only aware datetimes are allowed. When value is omitted, it defaults to 

215 now(). 

216 

217 Local time is defined by the current time zone, unless another time zone is 

218 specified. 

219 """ 

220 return localtime(value, timezone).date() 

221 

222 

223def now(): 

224 """ 

225 Return an aware or naive datetime.datetime, depending on settings.USE_TZ. 

226 """ 

227 return datetime.now(tz=utc if settings.USE_TZ else None) 

228 

229 

230# By design, these four functions don't perform any checks on their arguments. 

231# The caller should ensure that they don't receive an invalid value like None. 

232 

233 

234def is_aware(value): 

235 """ 

236 Determine if a given datetime.datetime is aware. 

237 

238 The concept is defined in Python's docs: 

239 https://docs.python.org/library/datetime.html#datetime.tzinfo 

240 

241 Assuming value.tzinfo is either None or a proper datetime.tzinfo, 

242 value.utcoffset() implements the appropriate logic. 

243 """ 

244 return value.utcoffset() is not None 

245 

246 

247def is_naive(value): 

248 """ 

249 Determine if a given datetime.datetime is naive. 

250 

251 The concept is defined in Python's docs: 

252 https://docs.python.org/library/datetime.html#datetime.tzinfo 

253 

254 Assuming value.tzinfo is either None or a proper datetime.tzinfo, 

255 value.utcoffset() implements the appropriate logic. 

256 """ 

257 return value.utcoffset() is None 

258 

259 

260def make_aware(value, timezone=None, is_dst=NOT_PASSED): 

261 """Make a naive datetime.datetime in a given time zone aware.""" 

262 if is_dst is NOT_PASSED: 262 ↛ 265line 262 didn't jump to line 265, because the condition on line 262 was never false

263 is_dst = None 

264 else: 

265 warnings.warn( 

266 "The is_dst argument to make_aware(), used by the Trunc() " 

267 "database functions and QuerySet.datetimes(), is deprecated as it " 

268 "has no effect with zoneinfo time zones.", 

269 RemovedInDjango50Warning, 

270 ) 

271 if timezone is None: 271 ↛ 272line 271 didn't jump to line 272, because the condition on line 271 was never true

272 timezone = get_current_timezone() 

273 if _is_pytz_zone(timezone): 273 ↛ 275line 273 didn't jump to line 275, because the condition on line 273 was never true

274 # This method is available for pytz time zones. 

275 return timezone.localize(value, is_dst=is_dst) 

276 else: 

277 # Check that we won't overwrite the timezone of an aware datetime. 

278 if is_aware(value): 278 ↛ 279line 278 didn't jump to line 279, because the condition on line 278 was never true

279 raise ValueError("make_aware expects a naive datetime, got %s" % value) 

280 # This may be wrong around DST changes! 

281 return value.replace(tzinfo=timezone) 

282 

283 

284def make_naive(value, timezone=None): 

285 """Make an aware datetime.datetime naive in a given time zone.""" 

286 if timezone is None: 

287 timezone = get_current_timezone() 

288 # Emulate the behavior of astimezone() on Python < 3.6. 

289 if is_naive(value): 

290 raise ValueError("make_naive() cannot be applied to a naive datetime") 

291 return value.astimezone(timezone).replace(tzinfo=None) 

292 

293 

294_PYTZ_IMPORTED = False 

295 

296 

297def _pytz_imported(): 

298 """ 

299 Detects whether or not pytz has been imported without importing pytz. 

300 

301 Copied from pytz_deprecation_shim with thanks to Paul Ganssle. 

302 """ 

303 global _PYTZ_IMPORTED 

304 

305 if not _PYTZ_IMPORTED and "pytz" in sys.modules: 

306 _PYTZ_IMPORTED = True 

307 

308 return _PYTZ_IMPORTED 

309 

310 

311def _is_pytz_zone(tz): 

312 """Checks if a zone is a pytz zone.""" 

313 # See if pytz was already imported rather than checking 

314 # settings.USE_DEPRECATED_PYTZ to *allow* manually passing a pytz timezone, 

315 # which some of the test cases (at least) rely on. 

316 if not _pytz_imported(): 316 ↛ 317line 316 didn't jump to line 317, because the condition on line 316 was never true

317 return False 

318 

319 # If tz could be pytz, then pytz is needed here. 

320 import pytz 

321 

322 _PYTZ_BASE_CLASSES = (pytz.tzinfo.BaseTzInfo, pytz._FixedOffset) 

323 # In releases prior to 2018.4, pytz.UTC was not a subclass of BaseTzInfo 

324 if not isinstance(pytz.UTC, pytz._FixedOffset): 324 ↛ 327line 324 didn't jump to line 327, because the condition on line 324 was never false

325 _PYTZ_BASE_CLASSES = _PYTZ_BASE_CLASSES + (type(pytz.UTC),) 

326 

327 return isinstance(tz, _PYTZ_BASE_CLASSES) 

328 

329 

330def _datetime_ambiguous_or_imaginary(dt, tz): 

331 if _is_pytz_zone(tz): 

332 import pytz 

333 

334 try: 

335 tz.utcoffset(dt) 

336 except (pytz.AmbiguousTimeError, pytz.NonExistentTimeError): 

337 return True 

338 else: 

339 return False 

340 

341 return tz.utcoffset(dt.replace(fold=not dt.fold)) != tz.utcoffset(dt)