root / env / lib / python2.7 / site-packages / django / utils / timezone.py @ 1a305335
History | View | Annotate | Download (7.82 KB)
1 | 1a305335 | officers | """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) |