pytz_support.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. ##############################################################################
  2. #
  3. # Copyright (c) 2007 Zope Foundation and Contributors.
  4. #
  5. # This software is subject to the provisions of the Zope Public License,
  6. # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
  7. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  8. # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  9. # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  10. # FOR A PARTICULAR PURPOSE
  11. #
  12. ##############################################################################
  13. from datetime import datetime, timedelta
  14. import pytz
  15. import pytz.reference
  16. from pytz.tzinfo import StaticTzInfo, memorized_timedelta
  17. from .interfaces import DateTimeError
  18. EPOCH = datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc)
  19. _numeric_timezone_data = {
  20. 'GMT': ('GMT', 0, 1, [], '', [(0, 0, 0)], 'GMT\000'),
  21. 'GMT+0': ('GMT+0', 0, 1, [], '', [(0, 0, 0)], 'GMT+0000\000'),
  22. 'GMT+1': ('GMT+1', 0, 1, [], '', [(3600, 0, 0)], 'GMT+0100\000'),
  23. 'GMT+2': ('GMT+2', 0, 1, [], '', [(7200, 0, 0)], 'GMT+0200\000'),
  24. 'GMT+3': ('GMT+3', 0, 1, [], '', [(10800, 0, 0)], 'GMT+0300\000'),
  25. 'GMT+4': ('GMT+4', 0, 1, [], '', [(14400, 0, 0)], 'GMT+0400\000'),
  26. 'GMT+5': ('GMT+5', 0, 1, [], '', [(18000, 0, 0)], 'GMT+0500\000'),
  27. 'GMT+6': ('GMT+6', 0, 1, [], '', [(21600, 0, 0)], 'GMT+0600\000'),
  28. 'GMT+7': ('GMT+7', 0, 1, [], '', [(25200, 0, 0)], 'GMT+0700\000'),
  29. 'GMT+8': ('GMT+8', 0, 1, [], '', [(28800, 0, 0)], 'GMT+0800\000'),
  30. 'GMT+9': ('GMT+9', 0, 1, [], '', [(32400, 0, 0)], 'GMT+0900\000'),
  31. 'GMT+10': ('GMT+10', 0, 1, [], '', [(36000, 0, 0)], 'GMT+1000\000'),
  32. 'GMT+11': ('GMT+11', 0, 1, [], '', [(39600, 0, 0)], 'GMT+1100\000'),
  33. 'GMT+12': ('GMT+12', 0, 1, [], '', [(43200, 0, 0)], 'GMT+1200\000'),
  34. 'GMT+13': ('GMT+13', 0, 1, [], '', [(46800, 0, 0)], 'GMT+1300\000'),
  35. 'GMT-1': ('GMT-1', 0, 1, [], '', [(-3600, 0, 0)], 'GMT-0100\000'),
  36. 'GMT-2': ('GMT-2', 0, 1, [], '', [(-7200, 0, 0)], 'GMT-0200\000'),
  37. 'GMT-3': ('GMT-3', 0, 1, [], '', [(-10800, 0, 0)], 'GMT-0300\000'),
  38. 'GMT-4': ('GMT-4', 0, 1, [], '', [(-14400, 0, 0)], 'GMT-0400\000'),
  39. 'GMT-5': ('GMT-5', 0, 1, [], '', [(-18000, 0, 0)], 'GMT-0500\000'),
  40. 'GMT-6': ('GMT-6', 0, 1, [], '', [(-21600, 0, 0)], 'GMT-0600\000'),
  41. 'GMT-7': ('GMT-7', 0, 1, [], '', [(-25200, 0, 0)], 'GMT-0700\000'),
  42. 'GMT-8': ('GMT-8', 0, 1, [], '', [(-28800, 0, 0)], 'GMT-0800\000'),
  43. 'GMT-9': ('GMT-9', 0, 1, [], '', [(-32400, 0, 0)], 'GMT-0900\000'),
  44. 'GMT-10': ('GMT-10', 0, 1, [], '', [(-36000, 0, 0)], 'GMT-1000\000'),
  45. 'GMT-11': ('GMT-11', 0, 1, [], '', [(-39600, 0, 0)], 'GMT-1100\000'),
  46. 'GMT-12': ('GMT-12', 0, 1, [], '', [(-43200, 0, 0)], 'GMT-1200\000'),
  47. 'GMT+0130': ('GMT+0130', 0, 1, [], '', [(5400, 0, 0)], 'GMT+0130\000'),
  48. 'GMT+0230': ('GMT+0230', 0, 1, [], '', [(9000, 0, 0)], 'GMT+0230\000'),
  49. 'GMT+0330': ('GMT+0330', 0, 1, [], '', [(12600, 0, 0)], 'GMT+0330\000'),
  50. 'GMT+0430': ('GMT+0430', 0, 1, [], '', [(16200, 0, 0)], 'GMT+0430\000'),
  51. 'GMT+0530': ('GMT+0530', 0, 1, [], '', [(19800, 0, 0)], 'GMT+0530\000'),
  52. 'GMT+0630': ('GMT+0630', 0, 1, [], '', [(23400, 0, 0)], 'GMT+0630\000'),
  53. 'GMT+0730': ('GMT+0730', 0, 1, [], '', [(27000, 0, 0)], 'GMT+0730\000'),
  54. 'GMT+0830': ('GMT+0830', 0, 1, [], '', [(30600, 0, 0)], 'GMT+0830\000'),
  55. 'GMT+0930': ('GMT+0930', 0, 1, [], '', [(34200, 0, 0)], 'GMT+0930\000'),
  56. 'GMT+1030': ('GMT+1030', 0, 1, [], '', [(37800, 0, 0)], 'GMT+1030\000'),
  57. 'GMT+1130': ('GMT+1130', 0, 1, [], '', [(41400, 0, 0)], 'GMT+1130\000'),
  58. 'GMT+1230': ('GMT+1230', 0, 1, [], '', [(45000, 0, 0)], 'GMT+1230\000'),
  59. 'GMT-0130': ('GMT-0130', 0, 1, [], '', [(-5400, 0, 0)], 'GMT-0130\000'),
  60. 'GMT-0230': ('GMT-0230', 0, 1, [], '', [(-9000, 0, 0)], 'GMT-0230\000'),
  61. 'GMT-0330': ('GMT-0330', 0, 1, [], '', [(-12600, 0, 0)], 'GMT-0330\000'),
  62. 'GMT-0430': ('GMT-0430', 0, 1, [], '', [(-16200, 0, 0)], 'GMT-0430\000'),
  63. 'GMT-0530': ('GMT-0530', 0, 1, [], '', [(-19800, 0, 0)], 'GMT-0530\000'),
  64. 'GMT-0630': ('GMT-0630', 0, 1, [], '', [(-23400, 0, 0)], 'GMT-0630\000'),
  65. 'GMT-0730': ('GMT-0730', 0, 1, [], '', [(-27000, 0, 0)], 'GMT-0730\000'),
  66. 'GMT-0830': ('GMT-0830', 0, 1, [], '', [(-30600, 0, 0)], 'GMT-0830\000'),
  67. 'GMT-0930': ('GMT-0930', 0, 1, [], '', [(-34200, 0, 0)], 'GMT-0930\000'),
  68. 'GMT-1030': ('GMT-1030', 0, 1, [], '', [(-37800, 0, 0)], 'GMT-1030\000'),
  69. 'GMT-1130': ('GMT-1130', 0, 1, [], '', [(-41400, 0, 0)], 'GMT-1130\000'),
  70. 'GMT-1230': ('GMT-1230', 0, 1, [], '', [(-45000, 0, 0)], 'GMT-1230\000'),
  71. }
  72. # These are the timezones not in pytz.common_timezones
  73. _old_zlst = [
  74. 'AST', 'AT', 'BST', 'BT', 'CCT',
  75. 'CET', 'CST', 'Cuba', 'EADT', 'EAST',
  76. 'EEST', 'EET', 'EST', 'Egypt', 'FST',
  77. 'FWT', 'GB-Eire', 'GMT+0100', 'GMT+0130', 'GMT+0200',
  78. 'GMT+0230', 'GMT+0300', 'GMT+0330', 'GMT+0400', 'GMT+0430',
  79. 'GMT+0500', 'GMT+0530', 'GMT+0600', 'GMT+0630', 'GMT+0700',
  80. 'GMT+0730', 'GMT+0800', 'GMT+0830', 'GMT+0900', 'GMT+0930',
  81. 'GMT+1', 'GMT+1000', 'GMT+1030', 'GMT+1100', 'GMT+1130',
  82. 'GMT+1200', 'GMT+1230', 'GMT+1300', 'GMT-0100', 'GMT-0130',
  83. 'GMT-0200', 'GMT-0300', 'GMT-0400', 'GMT-0500', 'GMT-0600',
  84. 'GMT-0630', 'GMT-0700', 'GMT-0730', 'GMT-0800', 'GMT-0830',
  85. 'GMT-0900', 'GMT-0930', 'GMT-1000', 'GMT-1030', 'GMT-1100',
  86. 'GMT-1130', 'GMT-1200', 'GMT-1230', 'GST', 'Greenwich',
  87. 'Hongkong', 'IDLE', 'IDLW', 'Iceland', 'Iran',
  88. 'Israel', 'JST', 'Jamaica', 'Japan', 'MEST',
  89. 'MET', 'MEWT', 'MST', 'NT', 'NZDT',
  90. 'NZST', 'NZT', 'PST', 'Poland', 'SST',
  91. 'SWT', 'Singapore', 'Turkey', 'UCT', 'UT',
  92. 'Universal', 'WADT', 'WAST', 'WAT', 'WET',
  93. 'ZP4', 'ZP5', 'ZP6',
  94. ]
  95. _old_zmap = {
  96. 'aest': 'GMT+10', 'aedt': 'GMT+11',
  97. 'aus eastern standard time': 'GMT+10',
  98. 'sydney standard time': 'GMT+10',
  99. 'tasmania standard time': 'GMT+10',
  100. 'e. australia standard time': 'GMT+10',
  101. 'aus central standard time': 'GMT+0930',
  102. 'cen. australia standard time': 'GMT+0930',
  103. 'w. australia standard time': 'GMT+8',
  104. 'central europe standard time': 'GMT+1',
  105. 'eastern standard time': 'US/Eastern',
  106. 'us eastern standard time': 'US/Eastern',
  107. 'central standard time': 'US/Central',
  108. 'mountain standard time': 'US/Mountain',
  109. 'pacific standard time': 'US/Pacific',
  110. 'mst': 'US/Mountain', 'pst': 'US/Pacific',
  111. 'cst': 'US/Central', 'est': 'US/Eastern',
  112. 'gmt+0000': 'GMT+0', 'gmt+0': 'GMT+0',
  113. 'gmt+0100': 'GMT+1', 'gmt+0200': 'GMT+2', 'gmt+0300': 'GMT+3',
  114. 'gmt+0400': 'GMT+4', 'gmt+0500': 'GMT+5', 'gmt+0600': 'GMT+6',
  115. 'gmt+0700': 'GMT+7', 'gmt+0800': 'GMT+8', 'gmt+0900': 'GMT+9',
  116. 'gmt+1000': 'GMT+10', 'gmt+1100': 'GMT+11', 'gmt+1200': 'GMT+12',
  117. 'gmt+1300': 'GMT+13',
  118. 'gmt-0100': 'GMT-1', 'gmt-0200': 'GMT-2', 'gmt-0300': 'GMT-3',
  119. 'gmt-0400': 'GMT-4', 'gmt-0500': 'GMT-5', 'gmt-0600': 'GMT-6',
  120. 'gmt-0700': 'GMT-7', 'gmt-0800': 'GMT-8', 'gmt-0900': 'GMT-9',
  121. 'gmt-1000': 'GMT-10', 'gmt-1100': 'GMT-11', 'gmt-1200': 'GMT-12',
  122. 'gmt+1': 'GMT+1', 'gmt+2': 'GMT+2', 'gmt+3': 'GMT+3',
  123. 'gmt+4': 'GMT+4', 'gmt+5': 'GMT+5', 'gmt+6': 'GMT+6',
  124. 'gmt+7': 'GMT+7', 'gmt+8': 'GMT+8', 'gmt+9': 'GMT+9',
  125. 'gmt+10': 'GMT+10', 'gmt+11': 'GMT+11', 'gmt+12': 'GMT+12',
  126. 'gmt+13': 'GMT+13',
  127. 'gmt-1': 'GMT-1', 'gmt-2': 'GMT-2', 'gmt-3': 'GMT-3',
  128. 'gmt-4': 'GMT-4', 'gmt-5': 'GMT-5', 'gmt-6': 'GMT-6',
  129. 'gmt-7': 'GMT-7', 'gmt-8': 'GMT-8', 'gmt-9': 'GMT-9',
  130. 'gmt-10': 'GMT-10', 'gmt-11': 'GMT-11', 'gmt-12': 'GMT-12',
  131. 'gmt+130': 'GMT+0130', 'gmt+0130': 'GMT+0130',
  132. 'gmt+230': 'GMT+0230', 'gmt+0230': 'GMT+0230',
  133. 'gmt+330': 'GMT+0330', 'gmt+0330': 'GMT+0330',
  134. 'gmt+430': 'GMT+0430', 'gmt+0430': 'GMT+0430',
  135. 'gmt+530': 'GMT+0530', 'gmt+0530': 'GMT+0530',
  136. 'gmt+630': 'GMT+0630', 'gmt+0630': 'GMT+0630',
  137. 'gmt+730': 'GMT+0730', 'gmt+0730': 'GMT+0730',
  138. 'gmt+830': 'GMT+0830', 'gmt+0830': 'GMT+0830',
  139. 'gmt+930': 'GMT+0930', 'gmt+0930': 'GMT+0930',
  140. 'gmt+1030': 'GMT+1030',
  141. 'gmt+1130': 'GMT+1130',
  142. 'gmt+1230': 'GMT+1230',
  143. 'gmt-130': 'GMT-0130', 'gmt-0130': 'GMT-0130',
  144. 'gmt-230': 'GMT-0230', 'gmt-0230': 'GMT-0230',
  145. 'gmt-330': 'GMT-0330', 'gmt-0330': 'GMT-0330',
  146. 'gmt-430': 'GMT-0430', 'gmt-0430': 'GMT-0430',
  147. 'gmt-530': 'GMT-0530', 'gmt-0530': 'GMT-0530',
  148. 'gmt-630': 'GMT-0630', 'gmt-0630': 'GMT-0630',
  149. 'gmt-730': 'GMT-0730', 'gmt-0730': 'GMT-0730',
  150. 'gmt-830': 'GMT-0830', 'gmt-0830': 'GMT-0830',
  151. 'gmt-930': 'GMT-0930', 'gmt-0930': 'GMT-0930',
  152. 'gmt-1030': 'GMT-1030',
  153. 'gmt-1130': 'GMT-1130',
  154. 'gmt-1230': 'GMT-1230',
  155. 'ut': 'Universal',
  156. 'bst': 'GMT+1', 'mest': 'GMT+2', 'sst': 'GMT+2',
  157. 'fst': 'GMT+2', 'wadt': 'GMT+8', 'eadt': 'GMT+11', 'nzdt': 'GMT+13',
  158. 'wet': 'GMT', 'wat': 'GMT-1', 'at': 'GMT-2', 'ast': 'GMT-4',
  159. 'nt': 'GMT-11', 'idlw': 'GMT-12', 'cet': 'GMT+1', 'cest': 'GMT+2',
  160. 'met': 'GMT+1',
  161. 'mewt': 'GMT+1', 'swt': 'GMT+1', 'fwt': 'GMT+1', 'eet': 'GMT+2',
  162. 'eest': 'GMT+3',
  163. 'bt': 'GMT+3', 'zp4': 'GMT+4', 'zp5': 'GMT+5', 'zp6': 'GMT+6',
  164. 'wast': 'GMT+7', 'cct': 'GMT+8', 'jst': 'GMT+9', 'east': 'GMT+10',
  165. 'gst': 'GMT+10', 'nzt': 'GMT+12', 'nzst': 'GMT+12', 'idle': 'GMT+12',
  166. 'ret': 'GMT+4', 'ist': 'GMT+0530', 'edt': 'GMT-4',
  167. }
  168. # some timezone definitions of the "-0400" are not working
  169. # when upgrading
  170. for hour in range(0, 13):
  171. hour = hour
  172. fhour = str(hour)
  173. if len(fhour) == 1:
  174. fhour = '0' + fhour
  175. _old_zmap['-%s00' % fhour] = 'GMT-%i' % hour
  176. _old_zmap['+%s00' % fhour] = 'GMT+%i' % hour
  177. def _static_timezone_factory(data):
  178. zone = data[0]
  179. cls = type(zone, (StaticTzInfo,), dict(
  180. zone=zone,
  181. _utcoffset=memorized_timedelta(data[5][0][0]),
  182. _tzname=data[6][:-1])) # strip the trailing null
  183. return cls()
  184. _numeric_timezones = dict((key, _static_timezone_factory(data))
  185. for key, data in _numeric_timezone_data.items())
  186. class Timezone:
  187. """
  188. Timezone information returned by PytzCache.__getitem__
  189. Adapts datetime.tzinfo object to DateTime._timezone interface
  190. """
  191. def __init__(self, tzinfo):
  192. self.tzinfo = tzinfo
  193. def info(self, t=None):
  194. if t is None:
  195. dt = datetime.utcnow().replace(tzinfo=pytz.utc)
  196. else:
  197. # can't use utcfromtimestamp past 2038
  198. dt = EPOCH + timedelta(0, t)
  199. # need to normalize tzinfo for the datetime to deal with
  200. # daylight savings time.
  201. normalized_dt = self.tzinfo.normalize(dt.astimezone(self.tzinfo))
  202. normalized_tzinfo = normalized_dt.tzinfo
  203. offset = normalized_tzinfo.utcoffset(normalized_dt)
  204. secs = offset.days * 24 * 60 * 60 + offset.seconds
  205. dst = normalized_tzinfo.dst(normalized_dt)
  206. if dst == timedelta(0):
  207. is_dst = 0
  208. else:
  209. is_dst = 1
  210. return secs, is_dst, normalized_tzinfo.tzname(normalized_dt)
  211. class PytzCache:
  212. """
  213. Reimplementation of the DateTime._cache class that uses for timezone info
  214. """
  215. _zlst = pytz.common_timezones + _old_zlst # used by DateTime.TimeZones
  216. _zmap = dict((name.lower(), name) for name in pytz.all_timezones)
  217. _zmap.update(_old_zmap) # These must take priority
  218. _zidx = _zmap.keys()
  219. def __getitem__(self, key):
  220. name = self._zmap.get(key.lower(), key) # fallback to key
  221. try:
  222. return Timezone(pytz.timezone(name))
  223. except pytz.UnknownTimeZoneError:
  224. try:
  225. return Timezone(_numeric_timezones[name])
  226. except KeyError:
  227. raise DateTimeError('Unrecognized timezone: %s' % key)