3 # Copyright 2009 Google Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
18 # Disable the invalid name warning as we are inheriting from a standard library
20 # pylint: disable-msg=C6409,W0212
23 Stripped down version of `python-datetime-tz` that only contains the "find local
34 # Need to patch pytz.utc to have a _utcoffset so you can normalize/localize
36 pytz
.utc
._utcoffset
= datetime
.timedelta()
39 timedelta
= datetime
.timedelta
42 def _tzinfome(tzinfo
):
43 """Gets a tzinfo object from a string.
46 tzinfo: A string (or string like) object, or a datetime.tzinfo object.
49 An datetime.tzinfo object.
52 UnknownTimeZoneError: If the timezone given can't be decoded.
54 if not isinstance(tzinfo
, datetime
.tzinfo
):
56 tzinfo
= pytz
.timezone(tzinfo
)
57 except AttributeError:
58 raise pytz
.UnknownTimeZoneError("Unknown timezone!")
62 # Our "local" timezone
67 """Get the local timezone.
70 The localtime timezone as a tzinfo object.
72 # pylint: disable-msg=W0603
75 _localtz
= detect_timezone()
79 def detect_timezone():
80 """Try and detect the timezone that Python is currently running in.
82 We have a bunch of different methods for trying to figure this out (listed in
83 order they are attempted).
84 * Try and find /etc/timezone file (with timezone name).
85 * Try and find /etc/localtime file (with timezone data).
86 * Try and match a TZ to the current dst/offset/shortname.
89 The detected local timezone as a tzinfo object
92 pytz.UnknownTimeZoneError: If it was unable to detect a timezone.
95 tz
= _detect_timezone_etc_timezone()
99 tz
= _detect_timezone_etc_localtime()
103 # Next we try and use a similiar method to what PHP does.
104 # We first try to search on time.tzname, time.timezone, time.daylight to
106 warnings
.warn("Had to fall back to worst detection method (the 'PHP' "
109 tz
= _detect_timezone_php()
113 raise pytz
.UnknownTimeZoneError("Unable to detect your timezone!")
115 def _detect_timezone_etc_timezone():
116 if os
.path
.exists("/etc/timezone"):
118 tz
= file("/etc/timezone").read().strip()
120 return pytz
.timezone(tz
)
121 except (IOError, pytz
.UnknownTimeZoneError
), ei
:
122 warnings
.warn("Your /etc/timezone file references a timezone (%r) that"
123 " is not valid (%r)." % (tz
, ei
))
125 # Problem reading the /etc/timezone file
127 warnings
.warn("Could not access your /etc/timezone file: %s" % eo
)
130 def _detect_timezone_etc_localtime():
132 if os
.path
.exists("/etc/localtime"):
133 localtime
= pytz
.tzfile
.build_tzinfo("/etc/localtime",
134 file("/etc/localtime"))
136 # See if we can find a "Human Name" for this..
137 for tzname
in pytz
.all_timezones
:
138 tz
= _tzinfome(tzname
)
140 if dir(tz
) != dir(localtime
):
143 for attrib
in dir(tz
):
144 # Ignore functions and specials
145 if callable(getattr(tz
, attrib
)) or attrib
.startswith("__"):
148 # This will always be different
149 if attrib
== "zone" or attrib
== "_tzinfos":
152 if getattr(tz
, attrib
) != getattr(localtime
, attrib
):
155 # We get here iff break didn't happen, i.e. no meaningful attributes
156 # differ between tz and localtime
158 matches
.append(tzname
)
160 #if len(matches) == 1:
161 # return _tzinfome(matches[0])
163 # # Warn the person about this!
164 # warning = "Could not get a human name for your timezone: "
165 # if len(matches) > 1:
166 # warning += ("We detected multiple matches for your /etc/localtime. "
167 # "(Matches where %s)" % matches)
169 # warning += "We detected no matches for your /etc/localtime."
170 # warnings.warn(warning)
174 return _tzinfome(matches
[0])
177 def _detect_timezone_php():
178 tomatch
= (time
.tzname
[0], time
.timezone
, time
.daylight
)
179 now
= datetime
.datetime
.now()
182 for tzname
in pytz
.all_timezones
:
184 tz
= pytz
.timezone(tzname
)
189 indst
= tz
.localize(now
).timetuple()[-1]
191 if tomatch
== (tz
._tzname
, -tz
._utcoffset
.seconds
, indst
):
192 matches
.append(tzname
)
194 # pylint: disable-msg=W0704
195 except AttributeError:
199 warnings
.warn("We detected multiple matches for the timezone, choosing "
200 "the first %s. (Matches where %s)" % (matches
[0], matches
))
201 return pytz
.timezone(matches
[0])