Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/django/utils/timezone.py: 45%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

80 statements  

1""" 

2Timezone-related classes and functions. 

3""" 

4 

5import functools 

6import zoneinfo 

7from contextlib import ContextDecorator 

8from datetime import datetime, timedelta, timezone, tzinfo 

9 

10from asgiref.local import Local 

11 

12from django.conf import settings 

13 

14__all__ = [ 

15 "get_fixed_timezone", 

16 "get_default_timezone", 

17 "get_default_timezone_name", 

18 "get_current_timezone", 

19 "get_current_timezone_name", 

20 "activate", 

21 "deactivate", 

22 "override", 

23 "localtime", 

24 "localdate", 

25 "now", 

26 "is_aware", 

27 "is_naive", 

28 "make_aware", 

29 "make_naive", 

30] 

31 

32 

33def get_fixed_timezone(offset): 

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

35 if isinstance(offset, timedelta): 

36 offset = offset.total_seconds() // 60 

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

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

39 name = sign + hhmm 

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

41 

42 

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

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

45@functools.lru_cache 

46def get_default_timezone(): 

47 """ 

48 Return the default time zone as a tzinfo instance. 

49 

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

51 """ 

52 return zoneinfo.ZoneInfo(settings.TIME_ZONE) 

53 

54 

55# This function exists for consistency with get_current_timezone_name 

56def get_default_timezone_name(): 

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

58 return _get_timezone_name(get_default_timezone()) 

59 

60 

61_active = Local() 

62 

63 

64def get_current_timezone(): 

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

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

67 

68 

69def get_current_timezone_name(): 

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

71 return _get_timezone_name(get_current_timezone()) 

72 

73 

74def _get_timezone_name(timezone): 

75 """ 

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

77 not set. 

78 """ 

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

80 

81 

82# Timezone selection functions. 

83 

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

85# because it isn't thread safe. 

86 

87 

88def activate(timezone): 

89 """ 

90 Set the time zone for the current thread. 

91 

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

93 time zone name. 

94 """ 

95 if isinstance(timezone, tzinfo): 

96 _active.value = timezone 

97 elif isinstance(timezone, str): 

98 _active.value = zoneinfo.ZoneInfo(timezone) 

99 else: 

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

101 

102 

103def deactivate(): 

104 """ 

105 Unset the time zone for the current thread. 

106 

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

108 """ 

109 if hasattr(_active, "value"): 

110 del _active.value 

111 

112 

113class override(ContextDecorator): 

114 """ 

115 Temporarily set the time zone for the current thread. 

116 

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

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

119 on exit. 

120 

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

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

123 time zone. 

124 """ 

125 

126 def __init__(self, timezone): 

127 self.timezone = timezone 

128 

129 def __enter__(self): 

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

131 if self.timezone is None: 

132 deactivate() 

133 else: 

134 activate(self.timezone) 

135 

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

137 if self.old_timezone is None: 

138 deactivate() 

139 else: 

140 _active.value = self.old_timezone 

141 

142 

143# Templates 

144 

145 

146def template_localtime(value, use_tz=None): 

147 """ 

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

149 

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

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

152 

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

154 """ 

155 should_convert = ( 

156 isinstance(value, datetime) 

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

158 and not is_naive(value) 

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

160 ) 

161 return localtime(value) if should_convert else value 

162 

163 

164# Utilities 

165 

166 

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

168 """ 

169 Convert an aware datetime.datetime to local time. 

170 

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

172 now(). 

173 

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

175 is specified. 

176 """ 

177 if value is None: 

178 value = now() 

179 if timezone is None: 

180 timezone = get_current_timezone() 

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

182 if is_naive(value): 

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

184 return value.astimezone(timezone) 

185 

186 

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

188 """ 

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

190 

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

192 now(). 

193 

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

195 specified. 

196 """ 

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

198 

199 

200def now(): 

201 """ 

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

203 """ 

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

205 

206 

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

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

209 

210 

211def is_aware(value): 

212 """ 

213 Determine if a given datetime.datetime is aware. 

214 

215 The concept is defined in Python's docs: 

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

217 

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

219 value.utcoffset() implements the appropriate logic. 

220 """ 

221 return value.utcoffset() is not None 

222 

223 

224def is_naive(value): 

225 """ 

226 Determine if a given datetime.datetime is naive. 

227 

228 The concept is defined in Python's docs: 

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

230 

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

232 value.utcoffset() implements the appropriate logic. 

233 """ 

234 return value.utcoffset() is None 

235 

236 

237def make_aware(value, timezone=None): 

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

239 if timezone is None: 

240 timezone = get_current_timezone() 

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

242 if is_aware(value): 

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

244 # This may be wrong around DST changes! 

245 return value.replace(tzinfo=timezone) 

246 

247 

248def make_naive(value, timezone=None): 

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

250 if timezone is None: 

251 timezone = get_current_timezone() 

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

253 if is_naive(value): 

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

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

256 

257 

258def _datetime_ambiguous_or_imaginary(dt, tz): 

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