tzinfo.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. "Implementation of tzinfo classes for use with datetime.datetime."
  2. from __future__ import unicode_literals
  3. from datetime import timedelta, tzinfo
  4. import time
  5. import warnings
  6. from django.utils.deprecation import RemovedInDjango19Warning
  7. from django.utils.encoding import force_str, force_text, DEFAULT_LOCALE_ENCODING
  8. warnings.warn(
  9. "django.utils.tzinfo will be removed in Django 1.9. "
  10. "Use django.utils.timezone instead.",
  11. RemovedInDjango19Warning, stacklevel=2)
  12. # Python's doc say: "A tzinfo subclass must have an __init__() method that can
  13. # be called with no arguments". FixedOffset and LocalTimezone don't honor this
  14. # requirement. Defining __getinitargs__ is sufficient to fix copy/deepcopy as
  15. # well as pickling/unpickling.
  16. class FixedOffset(tzinfo):
  17. "Fixed offset in minutes east from UTC."
  18. def __init__(self, offset):
  19. warnings.warn(
  20. "django.utils.tzinfo.FixedOffset will be removed in Django 1.9. "
  21. "Use django.utils.timezone.get_fixed_timezone instead.",
  22. RemovedInDjango19Warning)
  23. if isinstance(offset, timedelta):
  24. self.__offset = offset
  25. offset = self.__offset.seconds // 60
  26. else:
  27. self.__offset = timedelta(minutes=offset)
  28. sign = '-' if offset < 0 else '+'
  29. self.__name = "%s%02d%02d" % (sign, abs(offset) / 60., abs(offset) % 60)
  30. def __repr__(self):
  31. return self.__name
  32. def __getinitargs__(self):
  33. return self.__offset,
  34. def utcoffset(self, dt):
  35. return self.__offset
  36. def tzname(self, dt):
  37. return self.__name
  38. def dst(self, dt):
  39. return timedelta(0)
  40. # This implementation is used for display purposes. It uses an approximation
  41. # for DST computations on dates >= 2038.
  42. # A similar implementation exists in django.utils.timezone. It's used for
  43. # timezone support (when USE_TZ = True) and focuses on correctness.
  44. class LocalTimezone(tzinfo):
  45. "Proxy timezone information from time module."
  46. def __init__(self, dt):
  47. warnings.warn(
  48. "django.utils.tzinfo.LocalTimezone will be removed in Django 1.9. "
  49. "Use django.utils.timezone.get_default_timezone instead.",
  50. RemovedInDjango19Warning)
  51. tzinfo.__init__(self)
  52. self.__dt = dt
  53. self._tzname = self.tzname(dt)
  54. def __repr__(self):
  55. return force_str(self._tzname)
  56. def __getinitargs__(self):
  57. return self.__dt,
  58. def utcoffset(self, dt):
  59. if self._isdst(dt):
  60. return timedelta(seconds=-time.altzone)
  61. else:
  62. return timedelta(seconds=-time.timezone)
  63. def dst(self, dt):
  64. if self._isdst(dt):
  65. return timedelta(seconds=-time.altzone) - timedelta(seconds=-time.timezone)
  66. else:
  67. return timedelta(0)
  68. def tzname(self, dt):
  69. is_dst = False if dt is None else self._isdst(dt)
  70. try:
  71. return force_text(time.tzname[is_dst], DEFAULT_LOCALE_ENCODING)
  72. except UnicodeDecodeError:
  73. return None
  74. def _isdst(self, dt):
  75. tt = (dt.year, dt.month, dt.day,
  76. dt.hour, dt.minute, dt.second,
  77. dt.weekday(), 0, 0)
  78. try:
  79. stamp = time.mktime(tt)
  80. except (OverflowError, ValueError):
  81. # 32 bit systems can't handle dates after Jan 2038, and certain
  82. # systems can't handle dates before ~1901-12-01:
  83. #
  84. # >>> time.mktime((1900, 1, 13, 0, 0, 0, 0, 0, 0))
  85. # OverflowError: mktime argument out of range
  86. # >>> time.mktime((1850, 1, 13, 0, 0, 0, 0, 0, 0))
  87. # ValueError: year out of range
  88. #
  89. # In this case, we fake the date, because we only care about the
  90. # DST flag.
  91. tt = (2037,) + tt[1:]
  92. stamp = time.mktime(tt)
  93. tt = time.localtime(stamp)
  94. return tt.tm_isdst > 0