|  | """Timezone helper functions. | 
|  |  | 
|  | This module uses pytz when it's available and fallbacks when it isn't. | 
|  | """ | 
|  |  | 
|  | from datetime import datetime, timedelta, tzinfo | 
|  | from threading import local | 
|  | import time as _time | 
|  |  | 
|  | try: | 
|  | import pytz | 
|  | except ImportError: | 
|  | pytz = None | 
|  |  | 
|  | from django.conf import settings | 
|  | from django.utils import six | 
|  |  | 
|  | __all__ = [ | 
|  | 'utc', 'get_default_timezone', 'get_current_timezone', | 
|  | 'activate', 'deactivate', 'override', | 
|  | 'is_naive', 'is_aware', 'make_aware', 'make_naive', | 
|  | ] | 
|  |  | 
|  |  | 
|  | # UTC and local time zones | 
|  |  | 
|  | ZERO = timedelta(0) | 
|  |  | 
|  | class UTC(tzinfo): | 
|  | """ | 
|  | UTC implementation taken from Python's docs. | 
|  |  | 
|  | Used only when pytz isn't available. | 
|  | """ | 
|  |  | 
|  | def __repr__(self): | 
|  | return "<UTC>" | 
|  |  | 
|  | def utcoffset(self, dt): | 
|  | return ZERO | 
|  |  | 
|  | def tzname(self, dt): | 
|  | return "UTC" | 
|  |  | 
|  | def dst(self, dt): | 
|  | return ZERO | 
|  |  | 
|  | class LocalTimezone(tzinfo): | 
|  | """ | 
|  | Local time implementation taken from Python's docs. | 
|  |  | 
|  | Used only when pytz isn't available, and most likely inaccurate. If you're | 
|  | having trouble with this class, don't waste your time, just install pytz. | 
|  | """ | 
|  |  | 
|  | def __init__(self): | 
|  | # This code is moved in __init__ to execute it as late as possible | 
|  | # See get_default_timezone(). | 
|  | self.STDOFFSET = timedelta(seconds=-_time.timezone) | 
|  | if _time.daylight: | 
|  | self.DSTOFFSET = timedelta(seconds=-_time.altzone) | 
|  | else: | 
|  | self.DSTOFFSET = self.STDOFFSET | 
|  | self.DSTDIFF = self.DSTOFFSET - self.STDOFFSET | 
|  | tzinfo.__init__(self) | 
|  |  | 
|  | def __repr__(self): | 
|  | return "<LocalTimezone>" | 
|  |  | 
|  | def utcoffset(self, dt): | 
|  | if self._isdst(dt): | 
|  | return self.DSTOFFSET | 
|  | else: | 
|  | return self.STDOFFSET | 
|  |  | 
|  | def dst(self, dt): | 
|  | if self._isdst(dt): | 
|  | return self.DSTDIFF | 
|  | else: | 
|  | return ZERO | 
|  |  | 
|  | def tzname(self, dt): | 
|  | return _time.tzname[self._isdst(dt)] | 
|  |  | 
|  | def _isdst(self, dt): | 
|  | tt = (dt.year, dt.month, dt.day, | 
|  | dt.hour, dt.minute, dt.second, | 
|  | dt.weekday(), 0, 0) | 
|  | stamp = _time.mktime(tt) | 
|  | tt = _time.localtime(stamp) | 
|  | return tt.tm_isdst > 0 | 
|  |  | 
|  |  | 
|  | utc = pytz.utc if pytz else UTC() | 
|  | """UTC time zone as a tzinfo instance.""" | 
|  |  | 
|  | # In order to avoid accessing the settings at compile time, | 
|  | # wrap the expression in a function and cache the result. | 
|  | _localtime = None | 
|  |  | 
|  | def get_default_timezone(): | 
|  | """ | 
|  | Returns the default time zone as a tzinfo instance. | 
|  |  | 
|  | This is the time zone defined by settings.TIME_ZONE. | 
|  |  | 
|  | See also :func:`get_current_timezone`. | 
|  | """ | 
|  | global _localtime | 
|  | if _localtime is None: | 
|  | if isinstance(settings.TIME_ZONE, six.string_types) and pytz is not None: | 
|  | _localtime = pytz.timezone(settings.TIME_ZONE) | 
|  | else: | 
|  | # This relies on os.environ['TZ'] being set to settings.TIME_ZONE. | 
|  | _localtime = LocalTimezone() | 
|  | return _localtime | 
|  |  | 
|  | # This function exists for consistency with get_current_timezone_name | 
|  | def get_default_timezone_name(): | 
|  | """ | 
|  | Returns the name of the default time zone. | 
|  | """ | 
|  | return _get_timezone_name(get_default_timezone()) | 
|  |  | 
|  | _active = local() | 
|  |  | 
|  | def get_current_timezone(): | 
|  | """ | 
|  | Returns the currently active time zone as a tzinfo instance. | 
|  | """ | 
|  | return getattr(_active, "value", get_default_timezone()) | 
|  |  | 
|  | def get_current_timezone_name(): | 
|  | """ | 
|  | Returns the name of the currently active time zone. | 
|  | """ | 
|  | return _get_timezone_name(get_current_timezone()) | 
|  |  | 
|  | def _get_timezone_name(timezone): | 
|  | """ | 
|  | Returns the name of ``timezone``. | 
|  | """ | 
|  | try: | 
|  | # for pytz timezones | 
|  | return timezone.zone | 
|  | except AttributeError: | 
|  | # for regular tzinfo objects | 
|  | local_now = datetime.now(timezone) | 
|  | return timezone.tzname(local_now) | 
|  |  | 
|  | # Timezone selection functions. | 
|  |  | 
|  | # These functions don't change os.environ['TZ'] and call time.tzset() | 
|  | # because it isn't thread safe. | 
|  |  | 
|  | def activate(timezone): | 
|  | """ | 
|  | Sets the time zone for the current thread. | 
|  |  | 
|  | The ``timezone`` argument must be an instance of a tzinfo subclass or a | 
|  | time zone name. If it is a time zone name, pytz is required. | 
|  | """ | 
|  | if isinstance(timezone, tzinfo): | 
|  | _active.value = timezone | 
|  | elif isinstance(timezone, six.string_types) and pytz is not None: | 
|  | _active.value = pytz.timezone(timezone) | 
|  | else: | 
|  | raise ValueError("Invalid timezone: %r" % timezone) | 
|  |  | 
|  | def deactivate(): | 
|  | """ | 
|  | Unsets the time zone for the current thread. | 
|  |  | 
|  | Django will then use the time zone defined by settings.TIME_ZONE. | 
|  | """ | 
|  | if hasattr(_active, "value"): | 
|  | del _active.value | 
|  |  | 
|  | class override(object): | 
|  | """ | 
|  | Temporarily set the time zone for the current thread. | 
|  |  | 
|  | This is a context manager that uses ``~django.utils.timezone.activate()`` | 
|  | to set the timezone on entry, and restores the previously active timezone | 
|  | on exit. | 
|  |  | 
|  | The ``timezone`` argument must be an instance of a ``tzinfo`` subclass, a | 
|  | time zone name, or ``None``. If is it a time zone name, pytz is required. | 
|  | If it is ``None``, Django enables the default time zone. | 
|  | """ | 
|  | def __init__(self, timezone): | 
|  | self.timezone = timezone | 
|  | self.old_timezone = getattr(_active, 'value', None) | 
|  |  | 
|  | def __enter__(self): | 
|  | if self.timezone is None: | 
|  | deactivate() | 
|  | else: | 
|  | activate(self.timezone) | 
|  |  | 
|  | def __exit__(self, exc_type, exc_value, traceback): | 
|  | if self.old_timezone is None: | 
|  | deactivate() | 
|  | else: | 
|  | _active.value = self.old_timezone | 
|  |  | 
|  |  | 
|  | # Templates | 
|  |  | 
|  | def template_localtime(value, use_tz=None): | 
|  | """ | 
|  | Checks if value is a datetime and converts it to local time if necessary. | 
|  |  | 
|  | If use_tz is provided and is not None, that will force the value to | 
|  | be converted (or not), overriding the value of settings.USE_TZ. | 
|  |  | 
|  | This function is designed for use by the template engine. | 
|  | """ | 
|  | should_convert = (isinstance(value, datetime) | 
|  | and (settings.USE_TZ if use_tz is None else use_tz) | 
|  | and not is_naive(value) | 
|  | and getattr(value, 'convert_to_local_time', True)) | 
|  | return localtime(value) if should_convert else value | 
|  |  | 
|  |  | 
|  | # Utilities | 
|  |  | 
|  | def localtime(value, timezone=None): | 
|  | """ | 
|  | Converts an aware datetime.datetime to local time. | 
|  |  | 
|  | Local time is defined by the current time zone, unless another time zone | 
|  | is specified. | 
|  | """ | 
|  | if timezone is None: | 
|  | timezone = get_current_timezone() | 
|  | value = value.astimezone(timezone) | 
|  | if hasattr(timezone, 'normalize'): | 
|  | # available for pytz time zones | 
|  | value = timezone.normalize(value) | 
|  | return value | 
|  |  | 
|  | def now(): | 
|  | """ | 
|  | Returns an aware or naive datetime.datetime, depending on settings.USE_TZ. | 
|  | """ | 
|  | if settings.USE_TZ: | 
|  | # timeit shows that datetime.now(tz=utc) is 24% slower | 
|  | return datetime.utcnow().replace(tzinfo=utc) | 
|  | else: | 
|  | return datetime.now() | 
|  |  | 
|  | # By design, these four functions don't perform any checks on their arguments. | 
|  | # The caller should ensure that they don't receive an invalid value like None. | 
|  |  | 
|  | def is_aware(value): | 
|  | """ | 
|  | Determines if a given datetime.datetime is aware. | 
|  |  | 
|  | The logic is described in Python's docs: | 
|  | http://docs.python.org/library/datetime.html#datetime.tzinfo | 
|  | """ | 
|  | return value.tzinfo is not None and value.tzinfo.utcoffset(value) is not None | 
|  |  | 
|  | def is_naive(value): | 
|  | """ | 
|  | Determines if a given datetime.datetime is naive. | 
|  |  | 
|  | The logic is described in Python's docs: | 
|  | http://docs.python.org/library/datetime.html#datetime.tzinfo | 
|  | """ | 
|  | return value.tzinfo is None or value.tzinfo.utcoffset(value) is None | 
|  |  | 
|  | def make_aware(value, timezone): | 
|  | """ | 
|  | Makes a naive datetime.datetime in a given time zone aware. | 
|  | """ | 
|  | if hasattr(timezone, 'localize'): | 
|  | # available for pytz time zones | 
|  | return timezone.localize(value, is_dst=None) | 
|  | else: | 
|  | # may be wrong around DST changes | 
|  | return value.replace(tzinfo=timezone) | 
|  |  | 
|  | def make_naive(value, timezone): | 
|  | """ | 
|  | Makes an aware datetime.datetime naive in a given time zone. | 
|  | """ | 
|  | value = value.astimezone(timezone) | 
|  | if hasattr(timezone, 'normalize'): | 
|  | # available for pytz time zones | 
|  | value = timezone.normalize(value) | 
|  | return value.replace(tzinfo=None) |