root / env / lib / python2.7 / site-packages / django / utils / timezone.py @ 1a305335
History | View | Annotate | Download (7.82 KB)
1 |
"""Timezone helper functions.
|
---|---|
2 |
|
3 |
This module uses pytz when it's available and fallbacks when it isn't.
|
4 |
"""
|
5 |
|
6 |
from datetime import datetime, timedelta, tzinfo |
7 |
from threading import local |
8 |
import time as _time |
9 |
|
10 |
try:
|
11 |
import pytz |
12 |
except ImportError: |
13 |
pytz = None
|
14 |
|
15 |
from django.conf import settings |
16 |
|
17 |
__all__ = [ |
18 |
'utc', 'get_default_timezone', 'get_current_timezone', |
19 |
'activate', 'deactivate', 'override', |
20 |
'is_naive', 'is_aware', 'make_aware', 'make_naive', |
21 |
] |
22 |
|
23 |
|
24 |
# UTC and local time zones
|
25 |
|
26 |
ZERO = timedelta(0)
|
27 |
|
28 |
class UTC(tzinfo): |
29 |
"""
|
30 |
UTC implementation taken from Python's docs.
|
31 |
|
32 |
Used only when pytz isn't available.
|
33 |
"""
|
34 |
|
35 |
def __repr__(self): |
36 |
return "<UTC>" |
37 |
|
38 |
def utcoffset(self, dt): |
39 |
return ZERO
|
40 |
|
41 |
def tzname(self, dt): |
42 |
return "UTC" |
43 |
|
44 |
def dst(self, dt): |
45 |
return ZERO
|
46 |
|
47 |
class LocalTimezone(tzinfo): |
48 |
"""
|
49 |
Local time implementation taken from Python's docs.
|
50 |
|
51 |
Used only when pytz isn't available, and most likely inaccurate. If you're
|
52 |
having trouble with this class, don't waste your time, just install pytz.
|
53 |
"""
|
54 |
|
55 |
def __init__(self): |
56 |
# This code is moved in __init__ to execute it as late as possible
|
57 |
# See get_default_timezone().
|
58 |
self.STDOFFSET = timedelta(seconds=-_time.timezone)
|
59 |
if _time.daylight:
|
60 |
self.DSTOFFSET = timedelta(seconds=-_time.altzone)
|
61 |
else:
|
62 |
self.DSTOFFSET = self.STDOFFSET |
63 |
self.DSTDIFF = self.DSTOFFSET - self.STDOFFSET |
64 |
tzinfo.__init__(self)
|
65 |
|
66 |
def __repr__(self): |
67 |
return "<LocalTimezone>" |
68 |
|
69 |
def utcoffset(self, dt): |
70 |
if self._isdst(dt): |
71 |
return self.DSTOFFSET |
72 |
else:
|
73 |
return self.STDOFFSET |
74 |
|
75 |
def dst(self, dt): |
76 |
if self._isdst(dt): |
77 |
return self.DSTDIFF |
78 |
else:
|
79 |
return ZERO
|
80 |
|
81 |
def tzname(self, dt): |
82 |
return _time.tzname[self._isdst(dt)] |
83 |
|
84 |
def _isdst(self, dt): |
85 |
tt = (dt.year, dt.month, dt.day, |
86 |
dt.hour, dt.minute, dt.second, |
87 |
dt.weekday(), 0, 0) |
88 |
stamp = _time.mktime(tt) |
89 |
tt = _time.localtime(stamp) |
90 |
return tt.tm_isdst > 0 |
91 |
|
92 |
|
93 |
utc = pytz.utc if pytz else UTC() |
94 |
"""UTC time zone as a tzinfo instance."""
|
95 |
|
96 |
# In order to avoid accessing the settings at compile time,
|
97 |
# wrap the expression in a function and cache the result.
|
98 |
# If you change settings.TIME_ZONE in tests, reset _localtime to None.
|
99 |
_localtime = None
|
100 |
|
101 |
def get_default_timezone(): |
102 |
"""
|
103 |
Returns the default time zone as a tzinfo instance.
|
104 |
|
105 |
This is the time zone defined by settings.TIME_ZONE.
|
106 |
|
107 |
See also :func:`get_current_timezone`.
|
108 |
"""
|
109 |
global _localtime
|
110 |
if _localtime is None: |
111 |
if isinstance(settings.TIME_ZONE, basestring) and pytz is not None: |
112 |
_localtime = pytz.timezone(settings.TIME_ZONE) |
113 |
else:
|
114 |
_localtime = LocalTimezone() |
115 |
return _localtime
|
116 |
|
117 |
# This function exists for consistency with get_current_timezone_name
|
118 |
def get_default_timezone_name(): |
119 |
"""
|
120 |
Returns the name of the default time zone.
|
121 |
"""
|
122 |
return _get_timezone_name(get_default_timezone())
|
123 |
|
124 |
_active = local() |
125 |
|
126 |
def get_current_timezone(): |
127 |
"""
|
128 |
Returns the currently active time zone as a tzinfo instance.
|
129 |
"""
|
130 |
return getattr(_active, "value", get_default_timezone()) |
131 |
|
132 |
def get_current_timezone_name(): |
133 |
"""
|
134 |
Returns the name of the currently active time zone.
|
135 |
"""
|
136 |
return _get_timezone_name(get_current_timezone())
|
137 |
|
138 |
def _get_timezone_name(timezone): |
139 |
"""
|
140 |
Returns the name of ``timezone``.
|
141 |
"""
|
142 |
try:
|
143 |
# for pytz timezones
|
144 |
return timezone.zone
|
145 |
except AttributeError: |
146 |
# for regular tzinfo objects
|
147 |
local_now = datetime.now(timezone) |
148 |
return timezone.tzname(local_now)
|
149 |
|
150 |
# Timezone selection functions.
|
151 |
|
152 |
# These functions don't change os.environ['TZ'] and call time.tzset()
|
153 |
# because it isn't thread safe.
|
154 |
|
155 |
def activate(timezone): |
156 |
"""
|
157 |
Sets the time zone for the current thread.
|
158 |
|
159 |
The ``timezone`` argument must be an instance of a tzinfo subclass or a
|
160 |
time zone name. If it is a time zone name, pytz is required.
|
161 |
"""
|
162 |
if isinstance(timezone, tzinfo): |
163 |
_active.value = timezone |
164 |
elif isinstance(timezone, basestring) and pytz is not None: |
165 |
_active.value = pytz.timezone(timezone) |
166 |
else:
|
167 |
raise ValueError("Invalid timezone: %r" % timezone) |
168 |
|
169 |
def deactivate(): |
170 |
"""
|
171 |
Unsets the time zone for the current thread.
|
172 |
|
173 |
Django will then use the time zone defined by settings.TIME_ZONE.
|
174 |
"""
|
175 |
if hasattr(_active, "value"): |
176 |
del _active.value
|
177 |
|
178 |
class override(object): |
179 |
"""
|
180 |
Temporarily set the time zone for the current thread.
|
181 |
|
182 |
This is a context manager that uses ``~django.utils.timezone.activate()``
|
183 |
to set the timezone on entry, and restores the previously active timezone
|
184 |
on exit.
|
185 |
|
186 |
The ``timezone`` argument must be an instance of a ``tzinfo`` subclass, a
|
187 |
time zone name, or ``None``. If is it a time zone name, pytz is required.
|
188 |
If it is ``None``, Django enables the default time zone.
|
189 |
"""
|
190 |
def __init__(self, timezone): |
191 |
self.timezone = timezone
|
192 |
self.old_timezone = getattr(_active, 'value', None) |
193 |
|
194 |
def __enter__(self): |
195 |
if self.timezone is None: |
196 |
deactivate() |
197 |
else:
|
198 |
activate(self.timezone)
|
199 |
|
200 |
def __exit__(self, exc_type, exc_value, traceback): |
201 |
if self.old_timezone is not None: |
202 |
_active.value = self.old_timezone
|
203 |
else:
|
204 |
del _active.value
|
205 |
|
206 |
|
207 |
# Templates
|
208 |
|
209 |
def localtime(value, use_tz=None): |
210 |
"""
|
211 |
Checks if value is a datetime and converts it to local time if necessary.
|
212 |
|
213 |
If use_tz is provided and is not None, that will force the value to
|
214 |
be converted (or not), overriding the value of settings.USE_TZ.
|
215 |
|
216 |
This function is designed for use by the template engine.
|
217 |
"""
|
218 |
if (isinstance(value, datetime) |
219 |
and (settings.USE_TZ if use_tz is None else use_tz) |
220 |
and not is_naive(value) |
221 |
and getattr(value, 'convert_to_local_time', True)): |
222 |
timezone = get_current_timezone() |
223 |
value = value.astimezone(timezone) |
224 |
if hasattr(timezone, 'normalize'): |
225 |
# available for pytz time zones
|
226 |
value = timezone.normalize(value) |
227 |
return value
|
228 |
|
229 |
|
230 |
# Utilities
|
231 |
|
232 |
def now(): |
233 |
"""
|
234 |
Returns an aware or naive datetime.datetime, depending on settings.USE_TZ.
|
235 |
"""
|
236 |
if settings.USE_TZ:
|
237 |
# timeit shows that datetime.now(tz=utc) is 24% slower
|
238 |
return datetime.utcnow().replace(tzinfo=utc)
|
239 |
else:
|
240 |
return datetime.now()
|
241 |
|
242 |
# By design, these four functions don't perform any checks on their arguments.
|
243 |
# The caller should ensure that they don't receive an invalid value like None.
|
244 |
|
245 |
def is_aware(value): |
246 |
"""
|
247 |
Determines if a given datetime.datetime is aware.
|
248 |
|
249 |
The logic is described in Python's docs:
|
250 |
http://docs.python.org/library/datetime.html#datetime.tzinfo
|
251 |
"""
|
252 |
return value.tzinfo is not None and value.tzinfo.utcoffset(value) is not None |
253 |
|
254 |
def is_naive(value): |
255 |
"""
|
256 |
Determines if a given datetime.datetime is naive.
|
257 |
|
258 |
The logic is described in Python's docs:
|
259 |
http://docs.python.org/library/datetime.html#datetime.tzinfo
|
260 |
"""
|
261 |
return value.tzinfo is None or value.tzinfo.utcoffset(value) is None |
262 |
|
263 |
def make_aware(value, timezone): |
264 |
"""
|
265 |
Makes a naive datetime.datetime in a given time zone aware.
|
266 |
"""
|
267 |
if hasattr(timezone, 'localize'): |
268 |
# available for pytz time zones
|
269 |
return timezone.localize(value, is_dst=None) |
270 |
else:
|
271 |
# may be wrong around DST changes
|
272 |
return value.replace(tzinfo=timezone)
|
273 |
|
274 |
def make_naive(value, timezone): |
275 |
"""
|
276 |
Makes an aware datetime.datetime naive in a given time zone.
|
277 |
"""
|
278 |
value = value.astimezone(timezone) |
279 |
if hasattr(timezone, 'normalize'): |
280 |
# available for pytz time zones
|
281 |
value = timezone.normalize(value) |
282 |
return value.replace(tzinfo=None) |