def timezone(zone): r''' Return a datetime.tzinfo implementation for the given timezone >>> from datetime import datetime, timedelta >>> utc = timezone('UTC') >>> eastern = timezone('US/Eastern') >>> eastern.zone 'US/Eastern' >>> timezone(u'US/Eastern') is eastern True >>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc) >>> loc_dt = utc_dt.astimezone(eastern) >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' >>> loc_dt.strftime(fmt) '2002-10-27 01:00:00 EST (-0500)' >>> (loc_dt - timedelta(minutes=10)).strftime(fmt) '2002-10-27 00:50:00 EST (-0500)' >>> eastern.normalize(loc_dt - timedelta(minutes=10)).strftime(fmt) '2002-10-27 01:50:00 EDT (-0400)' >>> (loc_dt + timedelta(minutes=10)).strftime(fmt) '2002-10-27 01:10:00 EST (-0500)' Raises UnknownTimeZoneError if passed an unknown zone. >>> timezone('Asia/Shangri-La') Traceback (most recent call last): ... UnknownTimeZoneError: 'Asia/Shangri-La' >>> timezone(u'\N{TRADE MARK SIGN}') Traceback (most recent call last): ... UnknownTimeZoneError: u'\u2122' ''' if zone.upper() == 'UTC': return pytz.utc try: zone = zone.encode('US-ASCII') except UnicodeEncodeError: # All valid timezones are ASCII raise pytz.UnknownTimeZoneError(zone) zone = pytz._unmunge_zone(zone) if zone not in pytz._tzinfo_cache: if zone in all_timezones: pytz._tzinfo_cache[zone] = pytz.build_tzinfo( zone, caching_tz_opener(zone)) else: raise pytz.UnknownTimeZoneError(zone) return pytz._tzinfo_cache[zone]
def get_timezone(WindowsZoneName=True): """ Get the TimeZone Name if WindowsZoneName is True, then it returns the name used by the Microsoft Windows Platform otherwise it returns the Olsen name (used by all other platforms) Note: this needs to get tested on Windows """ log = logging.getLogger(__name__) localzone = tzlocal.get_localzone() if localzone is None: log.error('tzlocal did not provide a time zone configuration') raise pytz.UnknownTimeZoneError( 'Cannot find any time zone configuration') else: olsen_name = localzone.zone if WindowsZoneName: try: windows_name = tzlocal.windows_tz.tz_win[olsen_name] log.info('Mappped Olsen Time Zone Name (' + olsen_name + ') to Windows Time Zone Name (' + windows_name + ')') return windows_name except LookupError: log.error('Unable to map Olsen Time Zone Name (' + olsen_name + ') to Windows Time Zone Name') return 'Unknown' else: return olsen_name
def get_localzone(_root='/'): """No tzlocal; support basic Linux systems with a TZ variable or an /etc/timezone file""" # TZ environment variable? Either a tzinfo file or a timezone name tzenv = os.environ.get('TZ') if tzenv: if os.path.exists(tzenv): with open(tzenv, 'rb') as tzfile: return pytz.tzfile.build_tzinfo('local', tzfile) return pytz.timezone(tzenv) # /etc/timezone file? tzpath = os.path.join(_root, 'etc/timezone') if os.path.exists(tzpath): with open(tzpath, 'rb') as tzfile: tzname = tzfile.read().decode().strip() if '#' in tzname: # eg. 'Somewhere/Special # The Special Zone' tzname = tzname.split('#', 1)[0].strip() if ' ' in tzname: # eg. 'America/Dawson Creek'. Not really correct, but we'll handle it tzname = tzname.replace(' ', '_') return pytz.timezone(tzname) raise pytz.UnknownTimeZoneError( 'Can not find any timezone configuration')
def setReleaseDate(self, datetime: dtt.datetime, timezone: str) -> None: """ Set the release date for the product providing a Python datetime. :param datetime: Python datetime (without any timezone info). You must define the timezone in param 'timezone'! :param timezone: Timezone string, see also 'pytz.all_timezones' :return: None """ try: if not timezone: raise pytz.UnknownTimeZoneError("No timezone given.") givenZone = pytz.timezone(timezone) # set the source's timezone localizedDatetime = givenZone.localize(datetime) # make source timezone-aware datetimeUTC: dtt.datetime = localizedDatetime.astimezone(pytz.utc) # convert to UTC except pytz.UnknownTimeZoneError as e: logger.error("Could not set product release date. Invalid time zone string. %s", e, exc_info=True) except Exception as e: logger.error("Could not set product release date. %s", e, exc_info=True) else: self.__releaseDateStamp = datetimeUTC.timestamp()
def __init__(self, unit: str_type | DatetimeTZDtype = "ns", tz=None): if isinstance(unit, DatetimeTZDtype): # error: "str" has no attribute "tz" unit, tz = unit.unit, unit.tz # type: ignore[attr-defined] if unit != "ns": if isinstance(unit, str) and tz is None: # maybe a string like datetime64[ns, tz], which we support for # now. result = type(self).construct_from_string(unit) unit = result.unit tz = result.tz msg = (f"Passing a dtype alias like 'datetime64[ns, {tz}]' " "to DatetimeTZDtype is no longer supported. Use " "'DatetimeTZDtype.construct_from_string()' instead.") raise ValueError(msg) else: raise ValueError("DatetimeTZDtype only supports ns units") if tz: tz = timezones.maybe_get_tz(tz) tz = timezones.tz_standardize(tz) elif tz is not None: raise pytz.UnknownTimeZoneError(tz) if tz is None: raise TypeError("A 'tz' is required.") self._unit = unit self._tz = tz
def detect_timezone(): """Try and detect the timezone that Python is currently running in. We have a bunch of different methods for trying to figure this out (listed in order they are attempted). * Try and find /etc/timezone file (with timezone name). * Try and find /etc/localtime file (with timezone data). * Try and match a TZ to the current dst/offset/shortname. Returns: The detected local timezone as a tzinfo object Raises: pytz.UnknownTimeZoneError: If it was unable to detect a timezone. """ tz = _detect_timezone_etc_timezone() if tz is not None: return tz tz = _detect_timezone_etc_localtime() if tz is not None: return tz # Next we try and use a similiar method to what PHP does. # We first try to search on time.tzname, time.timezone, time.daylight to # match a pytz zone. warnings.warn("Had to fall back to worst detection method (the 'PHP' " "method).") tz = _detect_timezone_php() if tz is not None: return tz raise pytz.UnknownTimeZoneError("Unable to detect your timezone!")
def __init__(self, unit="ns", tz=None): if isinstance(unit, DatetimeTZDtype): unit, tz = unit.unit, unit.tz if unit != "ns": if isinstance(unit, str) and tz is None: # maybe a string like datetime64[ns, tz], which we support for # now. result = type(self).construct_from_string(unit) unit = result.unit tz = result.tz msg = ("Passing a dtype alias like 'datetime64[ns, {tz}]' " "to DatetimeTZDtype is deprecated. Use " "'DatetimeTZDtype.construct_from_string()' instead.") warnings.warn(msg.format(tz=tz), FutureWarning, stacklevel=2) else: raise ValueError("DatetimeTZDtype only supports ns units") if tz: tz = timezones.maybe_get_tz(tz) tz = timezones.tz_standardize(tz) elif tz is not None: raise pytz.UnknownTimeZoneError(tz) elif tz is None: raise TypeError("A 'tz' is required.") self._unit = unit self._tz = tz
def get_localzone_name(): # Windows is special. It has unique time zone names (in several # meanings of the word) available, but unfortunately, they can be # translated to the language of the operating system, so we need to # do a backwards lookup, by going through all time zones and see which # one matches. handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation" localtz = winreg.OpenKey(handle, TZLOCALKEYNAME) keyvalues = valuestodict(localtz) localtz.Close() if 'TimeZoneKeyName' in keyvalues: # Windows 7 (and Vista?) # For some reason this returns a string with loads of NUL bytes at # least on some systems. I don't know if this is a bug somewhere, I # just work around it. tzkeyname = keyvalues['TimeZoneKeyName'].split('\x00', 1)[0] else: # Windows 2000 or XP # This is the localized name: tzwin = keyvalues['StandardName'] # Open the list of timezones to look up the real name: TZKEYNAME = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones" tzkey = winreg.OpenKey(handle, TZKEYNAME) # Now, match this value to Time Zone information tzkeyname = None for i in range(winreg.QueryInfoKey(tzkey)[0]): subkey = winreg.EnumKey(tzkey, i) sub = winreg.OpenKey(tzkey, subkey) data = valuestodict(sub) sub.Close() if data['Std'] == tzwin: tzkeyname = subkey break tzkey.Close() handle.Close() if tzkeyname is None: raise LookupError('Can not find Windows timezone configuration') timezone = win_tz.get(tzkeyname) if timezone is None: # Nope, that didn't work. Try adding "Standard Time", # it seems to work a lot of times: timezone = win_tz.get(tzkeyname + " Standard Time") # Return what we have. if timezone is None: raise pytz.UnknownTimeZoneError('Can not find timezone ' + tzkeyname) return timezone
def __init__(self, unit="ns", tz=None): """ An ExtensionDtype for timezone-aware datetime data. Parameters ---------- unit : str, default "ns" The precision of the datetime data. Currently limited to ``"ns"``. tz : str, int, or datetime.tzinfo The timezone. Raises ------ pytz.UnknownTimeZoneError When the requested timezone cannot be found. Examples -------- >>> pd.core.dtypes.dtypes.DatetimeTZDtype(tz='UTC') datetime64[ns, UTC] >>> pd.core.dtypes.dtypes.DatetimeTZDtype(tz='dateutil/US/Central') datetime64[ns, tzfile('/usr/share/zoneinfo/US/Central')] """ if isinstance(unit, DatetimeTZDtype): unit, tz = unit.unit, unit.tz if unit != 'ns': if isinstance(unit, str) and tz is None: # maybe a string like datetime64[ns, tz], which we support for # now. result = type(self).construct_from_string(unit) unit = result.unit tz = result.tz msg = ( "Passing a dtype alias like 'datetime64[ns, {tz}]' " "to DatetimeTZDtype is deprecated. Use " "'DatetimeTZDtype.construct_from_string()' instead." ) warnings.warn(msg.format(tz=tz), FutureWarning, stacklevel=2) else: raise ValueError("DatetimeTZDtype only supports ns units") if tz: tz = timezones.maybe_get_tz(tz) tz = timezones.tz_standardize(tz) elif tz is not None: raise pytz.UnknownTimeZoneError(tz) elif tz is None: raise TypeError("A 'tz' is required.") self._unit = unit self._tz = tz
def get_windows_tz(iana_tz): """ Returns a valid windows TimeZone from a given pytz TimeZone (Iana/Olson Timezones) Note: Windows Timezones are SHIT!... no ... really THEY ARE HOLY F*****G SHIT!. """ timezone = IANA_TO_WIN.get( iana_tz.zone if isinstance(iana_tz, tzinfo) else iana_tz) if timezone is None: raise pytz.UnknownTimeZoneError("Can't find Iana TimeZone " + iana_tz.zone) return timezone
def detect_timezone(): """Try and detect the timezone that Python is currently running in. We have a bunch of different methods for trying to figure this out (listed in order they are attempted). * In windows, use win32timezone.TimeZoneInfo.local() * Try TZ environment variable. * Try and find /etc/timezone file (with timezone name). * Try and find /etc/localtime file (with timezone data). * Try and match a TZ to the current dst/offset/shortname. Returns: The detected local timezone as a tzinfo object Raises: pytz.UnknownTimeZoneError: If it was unable to detect a timezone. """ if sys.platform == "win32": tz = _detect_timezone_windows() if tz is not None: return tz # First we try the TZ variable tz = _detect_timezone_environ() if tz is not None: return tz # Second we try /etc/timezone and use the value in that tz = _detect_timezone_etc_timezone() if tz is not None: return tz # Next we try and see if something matches the tzinfo in /etc/localtime tz = _detect_timezone_etc_localtime() if tz is not None: return tz # Next we try and use a similar method to what PHP does. # We first try to search on time.tzname, time.timezone, time.daylight to # match a pytz zone. warnings.warn("Had to fall back to worst detection method (the 'PHP' " "method).") tz = _detect_timezone_php() if tz is not None: return tz raise pytz.UnknownTimeZoneError("Unable to detect your timezone!")
def get_iana_tz(windows_tz): """ Returns a valid pytz TimeZone (Iana/Olson Timezones) from a given windows TimeZone Note: Windows Timezones are SHIT! """ timezone = WIN_TO_IANA.get(windows_tz) if timezone is None: # Nope, that didn't work. Try adding "Standard Time", # it seems to work a lot of times: timezone = WIN_TO_IANA.get(windows_tz + ' Standard Time') # Return what we have. if timezone is None: raise pytz.UnknownTimeZoneError("Can't find Windows TimeZone " + windows_tz) return timezone
def _tz_from_env(tzenv): if tzenv[0] == ':': tzenv = tzenv[1:] # TZ specifies a file if os.path.exists(tzenv): with open(tzenv, 'rb') as tzfile: return pytz.tzfile.build_tzinfo('local', tzfile) # TZ specifies a zoneinfo zone. try: tz = pytz.timezone(tzenv) # That worked, so we return this: return tz except pytz.UnknownTimeZoneError: raise pytz.UnknownTimeZoneError( "tzlocal() does not support non-zoneinfo timezones like %s. \n" "Please use a timezone in the form of Continent/City")
def get_localzone( _root='/' ): """No tzlocal; support basic Linux systems with a TZ variable or an /etc/timezone file""" # /etc/timezone, ... file? for tzbase in ( 'etc/timezone', # Debian, Ubuntu, ... 'etc/sysconfig/clock' ): # RedHat, ... tzpath = os.path.join( _root, tzbase ) if os.path.exists( tzpath ): with open( tzpath, 'rb' ) as tzfile: tzname = tzfile.read().decode().strip() if '#' in tzname: # eg. 'Somewhere/Special # The Special Zone' tzname = tzname.split( '#', 1 )[0].strip() if ' ' in tzname: # eg. 'America/Dawson Creek'. Not really correct, but we'll handle it tzname = tzname.replace( ' ', '_' ) return pytz.timezone( tzname ) raise pytz.UnknownTimeZoneError( 'Can not find any timezone configuration' )
def _tzinfome(tzinfo): """Gets a tzinfo object from a string. Args: tzinfo: A string (or string like) object, or a datetime.tzinfo object. Returns: An datetime.tzinfo object. Raises: UnknownTimeZoneError: If the timezone given can't be decoded. """ if not isinstance(tzinfo, datetime.tzinfo): try: tzinfo = pytz.timezone(tzinfo) except AttributeError: raise pytz.UnknownTimeZoneError("Unknown timezone!") return tzinfo
def __set_timezone(self) -> Optional[BaseTzInfo]: """ Set timezone as BaseTzInfo from compatible timezone string. Raises: pytz.UnknownTimeZoneError: :raises pytz.UnknownTimeZoneError: If `self.timezone` is not in `list of tz database timezones <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>`_. :return: A valid timezone :rtype: Optional[BaseTzInfo] """ # If timezone is an unsafe string, we will handle a `pytz.UnknownTimeZoneError` exception # and pass a friendly message. try: return pytz.timezone(self.timezone) except pytz.UnknownTimeZoneError as unknown_timezone_error: raise pytz.UnknownTimeZoneError( f"The timezone {self.timezone} is invalid" " check valid types here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones" ) from unknown_timezone_error
def get_iana_tz(windows_tz): """ Returns a valid pytz TimeZone (Iana/Olson Timezones) from a given windows TimeZone :param windows_tz: windows format timezone usually returned by microsoft api response :return: :rtype: """ timezone = WIN_TO_IANA.get(windows_tz) if timezone is None: # Nope, that didn't work. Try adding "Standard Time", # it seems to work a lot of times: timezone = WIN_TO_IANA.get(windows_tz + ' Standard Time') # Return what we have. if timezone is None: raise pytz.UnknownTimeZoneError("Can't find Windows TimeZone " + windows_tz) return timezone
def get_timezone(): '''returns the current timezone specified for the company/facility or the default which is the value in /etc/localtime''' global _cached_timezone if _cached_timezone: return _cached_timezone else: try: company = Transaction().context.get('company') company = Pool().get('company.company')(company) tz = company.get_timezone except: tz = None if tz: _cached_timezone = pytz.timezone(tz) elif ospath.exists('/etc/localtime'): _cached_timezone = pytz.tzfile.build_tzinfo( 'local', open('/etc/localtime', 'rb')) else: raise pytz.UnknownTimeZoneError('Cannot find suitable time zone') return _cached_timezone
def _get_localzone(): if winreg is None: raise pytz.UnknownTimeZoneError('Runtime support not available') return pytz.timezone(get_localzone_name())
def _get_localzone(_root='/'): """Tries to find the local timezone configuration. This method prefers finding the timezone name and passing that to pytz, over passing in the localtime file, as in the later case the zoneinfo name is unknown. The parameter _root makes the function look for files like /etc/localtime beneath the _root directory. This is primarily used by the tests. In normal usage you call the function without parameters. """ tzenv = os.environ.get('TZ') if tzenv: return _tz_from_env(tzenv) # This is actually a pretty reliable way to test for the local time # zone on operating systems like OS X. On OS X especially this is the # only one that actually works. try: link_dst = os.readlink('/etc/localtime') except OSError: pass else: pos = link_dst.find('/zoneinfo/') if pos >= 0: zone_name = link_dst[pos + 10:] try: return pytz.timezone(zone_name) except pytz.UnknownTimeZoneError: pass # If we are on OS X now we are pretty sure that the rest of the # code will fail and just fall through until it hits the reading # of /etc/localtime and using it without name. At this point we # can invoke systemconfig which internally invokes ICU. ICU itself # does the same thing we do (readlink + compare file contents) but # since it knows where the zone files are that should be a bit # better than reimplementing the logic here. if sys.platform == 'darwin': c = subprocess.Popen(['systemsetup', '-gettimezone'], stdout=subprocess.PIPE) sys_result = c.communicate()[0] c.wait() tz_match = _systemconfig_tz.search(sys_result) if tz_match is not None: zone_name = tz_match.group(1) try: return pytz.timezone(zone_name) except pytz.UnknownTimeZoneError: pass # Now look for distribution specific configuration files # that contain the timezone name. tzpath = os.path.join(_root, 'etc/timezone') if os.path.exists(tzpath): with open(tzpath, 'rb') as tzfile: data = tzfile.read() # Issue #3 in tzlocal was that /etc/timezone was a zoneinfo file. # That's a misconfiguration, but we need to handle it gracefully: if data[:5] != 'TZif2': etctz = data.strip().decode() # Get rid of host definitions and comments: if ' ' in etctz: etctz, dummy = etctz.split(' ', 1) if '#' in etctz: etctz, dummy = etctz.split('#', 1) return pytz.timezone(etctz.replace(' ', '_')) # CentOS has a ZONE setting in /etc/sysconfig/clock, # OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and # Gentoo has a TIMEZONE setting in /etc/conf.d/clock # We look through these files for a timezone: zone_re = re.compile('\s*ZONE\s*=\s*\"') timezone_re = re.compile('\s*TIMEZONE\s*=\s*\"') end_re = re.compile('\"') for filename in ('etc/sysconfig/clock', 'etc/conf.d/clock'): tzpath = os.path.join(_root, filename) if not os.path.exists(tzpath): continue with open(tzpath, 'rt') as tzfile: for line in tzfile: # Look for the ZONE= setting. match = zone_re.match(line) if match is None: # No ZONE= setting. Look for the TIMEZONE= setting. match = timezone_re.match(line) if match is not None: # Some setting existed line = line[match.end():] etctz = line[:end_re.search(line).start()] # We found a timezone return pytz.timezone(etctz.replace(' ', '_')) # No explicit setting existed. Use localtime for filename in ('etc/localtime', 'usr/local/etc/localtime'): tzpath = os.path.join(_root, filename) if not os.path.exists(tzpath): continue with open(tzpath, 'rb') as tzfile: return pytz.tzfile.build_tzinfo('local', tzfile) raise pytz.UnknownTimeZoneError('Can not find any timezone configuration')
def _get_localzone(_root='/'): """Tries to find the local timezone configuration. This method prefers finding the timezone name and passing that to pytz, over passing in the localtime file, as in the later case the zoneinfo name is unknown. The parameter _root makes the function look for files like /etc/localtime beneath the _root directory. This is primarily used by the tests. In normal usage you call the function without parameters.""" tzenv = os.environ.get('TZ') if tzenv: try: return _tz_from_env(tzenv) except pytz.UnknownTimeZoneError: pass # Now look for distribution specific configuration files # that contain the timezone name. for configfile in ('etc/timezone', 'var/db/zoneinfo'): tzpath = os.path.join(_root, configfile) if os.path.exists(tzpath): with open(tzpath, 'rb') as tzfile: data = tzfile.read() # Issue #3 was that /etc/timezone was a zoneinfo file. # That's a misconfiguration, but we need to handle it gracefully: if data[:5] != 'TZif2': etctz = data.strip().decode() # Get rid of host definitions and comments: if ' ' in etctz: etctz, dummy = etctz.split(' ', 1) if '#' in etctz: etctz, dummy = etctz.split('#', 1) return pytz.timezone(etctz.replace(' ', '_')) # CentOS has a ZONE setting in /etc/sysconfig/clock, # OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and # Gentoo has a TIMEZONE setting in /etc/conf.d/clock # We look through these files for a timezone: zone_re = re.compile('\s*ZONE\s*=\s*\"') timezone_re = re.compile('\s*TIMEZONE\s*=\s*\"') end_re = re.compile('\"') for filename in ('etc/sysconfig/clock', 'etc/conf.d/clock'): tzpath = os.path.join(_root, filename) if not os.path.exists(tzpath): continue with open(tzpath, 'rt') as tzfile: data = tzfile.readlines() for line in data: # Look for the ZONE= setting. match = zone_re.match(line) if match is None: # No ZONE= setting. Look for the TIMEZONE= setting. match = timezone_re.match(line) if match is not None: # Some setting existed line = line[match.end():] etctz = line[:end_re.search(line).start()] # We found a timezone return pytz.timezone(etctz.replace(' ', '_')) # systemd distributions use symlinks that include the zone name, # see manpage of localtime(5) and timedatectl(1) tzpath = os.path.join(_root, 'etc/localtime') if os.path.exists(tzpath) and os.path.islink(tzpath): tzpath = os.path.realpath(tzpath) start = tzpath.find("/") + 1 while start is not 0: tzpath = tzpath[start:] try: return pytz.timezone(tzpath) except pytz.UnknownTimeZoneError: pass start = tzpath.find("/") + 1 # No explicit setting existed. Use localtime for filename in ('etc/localtime', 'usr/local/etc/localtime'): tzpath = os.path.join(_root, filename) if not os.path.exists(tzpath): continue with open(tzpath, 'rb') as tzfile: return pytz.tzfile.build_tzinfo('local', tzfile) raise pytz.UnknownTimeZoneError('Can not find any timezone configuration')
def _get_localzone(_root='/'): """Tries to find the local timezone configuration. This method prefers finding the timezone name and passing that to pytz, over passing in the localtime file, as in the later case the zoneinfo name is unknown. The parameter _root makes the function look for files like /etc/localtime beneath the _root directory. This is primarily used by the tests. In normal usage you call the function without parameters.""" tzenv = _try_tz_from_env() if tzenv: return tzenv # Now look for distribution specific configuration files # that contain the timezone name. for configfile in ('etc/timezone', 'var/db/zoneinfo'): tzpath = os.path.join(_root, configfile) try: with open(tzpath, 'rb') as tzfile: data = tzfile.read() # Issue #3 was that /etc/timezone was a zoneinfo file. # That's a misconfiguration, but we need to handle it gracefully: if data[:5] == b'TZif2': continue etctz = data.strip().decode() if not etctz: # Empty file, skip continue for etctz in data.decode().splitlines(): # Get rid of host definitions and comments: if ' ' in etctz: etctz, dummy = etctz.split(' ', 1) if '#' in etctz: etctz, dummy = etctz.split('#', 1) if not etctz: continue return pytz.timezone(etctz.replace(' ', '_')) except IOError: # File doesn't exist or is a directory continue # CentOS has a ZONE setting in /etc/sysconfig/clock, # OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and # Gentoo has a TIMEZONE setting in /etc/conf.d/clock # We look through these files for a timezone: zone_re = re.compile(r'\s*ZONE\s*=\s*\"') timezone_re = re.compile(r'\s*TIMEZONE\s*=\s*\"') end_re = re.compile('\"') for filename in ('etc/sysconfig/clock', 'etc/conf.d/clock'): tzpath = os.path.join(_root, filename) try: with open(tzpath, 'rt') as tzfile: data = tzfile.readlines() for line in data: # Look for the ZONE= setting. match = zone_re.match(line) if match is None: # No ZONE= setting. Look for the TIMEZONE= setting. match = timezone_re.match(line) if match is not None: # Some setting existed line = line[match.end():] etctz = line[:end_re.search(line).start()] # We found a timezone return pytz.timezone(etctz.replace(' ', '_')) except IOError: # File doesn't exist or is a directory continue # systemd distributions use symlinks that include the zone name, # see manpage of localtime(5) and timedatectl(1) tzpath = os.path.join(_root, 'etc/localtime') if os.path.exists(tzpath) and os.path.islink(tzpath): tzpath = os.path.realpath(tzpath) start = tzpath.find("/") + 1 while start is not 0: tzpath = tzpath[start:] try: return pytz.timezone(tzpath) except pytz.UnknownTimeZoneError: pass start = tzpath.find("/") + 1 # Are we under Termux on Android? It's not officially supported, because # there is no reasonable way to run tests for this, but let's make an effort. if os.path.exists('/system/bin/getprop'): import subprocess androidtz = subprocess.check_output( ['getprop', 'persist.sys.timezone']).strip().decode() if androidtz: return pytz.timezone(androidtz) # on some android devices getprop does not gives any results if hasattr(sys, 'getandroidapilevel'): try: # we are on android and use jnius to get tz in official android supported way from jnius import autoclass TimeZone = autoclass('java.util.TimeZone') androidtz = TimeZone.getDefault().getID() return pytz.timezone(androidtz) except ImportError: # we can't do anything about it pass # No explicit setting existed. Use localtime for filename in ('etc/localtime', 'usr/local/etc/localtime'): tzpath = os.path.join(_root, filename) if not os.path.exists(tzpath): continue with open(tzpath, 'rb') as tzfile: return pytz.tzfile.build_tzinfo('local', tzfile) raise pytz.UnknownTimeZoneError('Can not find any timezone configuration')
def detect_timezone(): """Try and detect the timezone that Python is currently running in. We have a bunch of different methods for trying to figure this out (listed in order they are attempted). * In windows, use win32timezone.TimeZoneInfo.local() * Try TZ environment variable. * Try and find /etc/timezone file (with timezone name). * Try and find /etc/localtime file (with timezone data). * Try and match a TZ to the current dst/offset/shortname. Returns: The detected local timezone as a tzinfo object Raises: pytz.UnknownTimeZoneError: If it was unable to detect a timezone. """ # Windows global win32timezone_to_en try: import win32timezone # Try and fetch the key_name for the timezone using Get(Dynamic)TimeZoneInformation tzi = DTZI_c() kernel32 = ctypes.windll.kernel32 getter = kernel32.GetTimeZoneInformation getter = getattr(kernel32, 'GetDynamicTimeZoneInformation', getter) # code is for daylight savings: 0 means disabled/not defined, 1 means enabled but inactive, 2 means enabled and active code = getter(ctypes.byref(tzi)) win32tz_key_name = tzi.key_name if not win32tz_key_name: # we're on Windows before Vista/Server 2008 - need to look up the standard_name in the registry # This will not work in some multilingual setups if running in a language other than the operating system default win32tz_name = tzi.standard_name if not win32timezone_to_en: win32timezone_to_en = dict( win32timezone.TimeZoneInfo._get_indexed_time_zone_keys( "Std")) win32tz_key_name = win32timezone_to_en.get(win32tz_name, win32tz_name) olson_name = win32tz_map.win32timezones.get(win32tz_key_name, None) if not olson_name: raise ValueError( u"Could not map win32 timezone name %s (English %s) to Olson timezone name" % (win32tz_name, win32tz_key_name)) return pytz.timezone(olson_name) except ImportError: pass # First we try the TZ variable tz = _detect_timezone_environ() if tz is not None: return tz # Second we try /etc/timezone and use the value in that tz = _detect_timezone_etc_timezone() if tz is not None: return tz # Next we try and see if something matches the tzinfo in /etc/localtime tz = _detect_timezone_etc_localtime() if tz is not None: return tz # Next we try and use a similiar method to what PHP does. # We first try to search on time.tzname, time.timezone, time.daylight to # match a pytz zone. warnings.warn("Had to fall back to worst detection method (the 'PHP' " "method).") tz = _detect_timezone_php() if tz is not None: return tz raise pytz.UnknownTimeZoneError("Unable to detect your timezone!")