# -*- coding: utf-8 -*-"""This module provides an interface to the native time zone data on Windows,including :py:class:`datetime.tzinfo` implementations.Attempting to import this module on a non-Windows platform will raise an:py:obj:`ImportError`."""# This code was originally contributed by Jeffrey Harris.importdatetimeimportstructfromsix.movesimportwinregfromsiximporttext_typetry:importctypesfromctypesimportwintypesexceptValueError:# ValueError is raised on non-Windows systems for some horrible reason.raiseImportError("Running tzwin on non-Windows system")from._commonimporttzrangebase__all__=["tzwin","tzwinlocal","tzres"]ONEWEEK=datetime.timedelta(7)TZKEYNAMENT=r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"TZKEYNAME9X=r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones"TZLOCALKEYNAME=r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"def_settzkeyname():handle=winreg.ConnectRegistry(None,winreg.HKEY_LOCAL_MACHINE)try:winreg.OpenKey(handle,TZKEYNAMENT).Close()TZKEYNAME=TZKEYNAMENTexceptWindowsError:TZKEYNAME=TZKEYNAME9Xhandle.Close()returnTZKEYNAMETZKEYNAME=_settzkeyname()[docs]classtzres(object):""" Class for accessing ``tzres.dll``, which contains timezone name related resources. .. versionadded:: 2.5.0 """p_wchar=ctypes.POINTER(wintypes.WCHAR)# Pointer to a wide chardef__init__(self,tzres_loc='tzres.dll'):# Load the user32 DLL so we can load strings from tzresuser32=ctypes.WinDLL('user32')# Specify the LoadStringW functionuser32.LoadStringW.argtypes=(wintypes.HINSTANCE,wintypes.UINT,wintypes.LPWSTR,ctypes.c_int)self.LoadStringW=user32.LoadStringWself._tzres=ctypes.WinDLL(tzres_loc)self.tzres_loc=tzres_loc[docs]defload_name(self,offset):""" Load a timezone name from a DLL offset (integer). >>> from dateutil.tzwin import tzres >>> tzr = tzres() >>> print(tzr.load_name(112)) 'Eastern Standard Time' :param offset: A positive integer value referring to a string from the tzres dll. .. note:: Offsets found in the registry are generally of the form ``@tzres.dll,-114``. The offset in this case is 114, not -114. """resource=self.p_wchar()lpBuffer=ctypes.cast(ctypes.byref(resource),wintypes.LPWSTR)nchar=self.LoadStringW(self._tzres._handle,offset,lpBuffer,0)returnresource[:nchar] [docs]defname_from_string(self,tzname_str):""" Parse strings as returned from the Windows registry into the time zone name as defined in the registry. >>> from dateutil.tzwin import tzres >>> tzr = tzres() >>> print(tzr.name_from_string('@tzres.dll,-251')) 'Dateline Daylight Time' >>> print(tzr.name_from_string('Eastern Standard Time')) 'Eastern Standard Time' :param tzname_str: A timezone name string as returned from a Windows registry key. :return: Returns the localized timezone string from tzres.dll if the string is of the form `@tzres.dll,-offset`, else returns the input string. """ifnottzname_str.startswith('@'):returntzname_strname_splt=tzname_str.split(',-')try:offset=int(name_splt[1])except:raiseValueError("Malformed timezone string.")returnself.load_name(offset) classtzwinbase(tzrangebase):"""tzinfo class based on win32's timezones available in the registry."""def__init__(self):raiseNotImplementedError('tzwinbase is an abstract base class')def__eq__(self,other):# Compare on all relevant dimensions, including name.ifnotisinstance(other,tzwinbase):returnNotImplementedreturn(self._std_offset==other._std_offsetandself._dst_offset==other._dst_offsetandself._stddayofweek==other._stddayofweekandself._dstdayofweek==other._dstdayofweekandself._stdweeknumber==other._stdweeknumberandself._dstweeknumber==other._dstweeknumberandself._stdhour==other._stdhourandself._dsthour==other._dsthourandself._stdminute==other._stdminuteandself._dstminute==other._dstminuteandself._std_abbr==other._std_abbrandself._dst_abbr==other._dst_abbr)@staticmethoddeflist():"""Return a list of all time zones known to the system."""withwinreg.ConnectRegistry(None,winreg.HKEY_LOCAL_MACHINE)ashandle:withwinreg.OpenKey(handle,TZKEYNAME)astzkey:result=[winreg.EnumKey(tzkey,i)foriinrange(winreg.QueryInfoKey(tzkey)[0])]returnresultdefdisplay(self):""" Return the display name of the time zone. """returnself._displaydeftransitions(self,year):""" For a given year, get the DST on and off transition times, expressed always on the standard time side. For zones with no transitions, this function returns ``None``. :param year: The year whose transitions you would like to query. :return: Returns a :class:`tuple` of :class:`datetime.datetime` objects, ``(dston, dstoff)`` for zones with an annual DST transition, or ``None`` for fixed offset zones. """ifnotself.hasdst:returnNonedston=picknthweekday(year,self._dstmonth,self._dstdayofweek,self._dsthour,self._dstminute,self._dstweeknumber)dstoff=picknthweekday(year,self._stdmonth,self._stddayofweek,self._stdhour,self._stdminute,self._stdweeknumber)# Ambiguous dates default to the STD sidedstoff-=self._dst_base_offsetreturndston,dstoffdef_get_hasdst(self):returnself._dstmonth!=0@propertydef_dst_base_offset(self):returnself._dst_base_offset_[docs]classtzwin(tzwinbase):""" Time zone object created from the zone info in the Windows registry These are similar to :py:class:`dateutil.tz.tzrange` objects in that the time zone data is provided in the format of a single offset rule for either 0 or 2 time zone transitions per year. :param: name The name of a Windows time zone key, e.g. "Eastern Standard Time". The full list of keys can be retrieved with :func:`tzwin.list`. """def__init__(self,name):self._name=namewithwinreg.ConnectRegistry(None,winreg.HKEY_LOCAL_MACHINE)ashandle:tzkeyname=text_type("{kn}\\{name}").format(kn=TZKEYNAME,name=name)withwinreg.OpenKey(handle,tzkeyname)astzkey:keydict=valuestodict(tzkey)self._std_abbr=keydict["Std"]self._dst_abbr=keydict["Dlt"]self._display=keydict["Display"]# See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htmtup=struct.unpack("=3l16h",keydict["TZI"])stdoffset=-tup[0]-tup[1]# Bias + StandardBias * -1dstoffset=stdoffset-tup[2]# + DaylightBias * -1self._std_offset=datetime.timedelta(minutes=stdoffset)self._dst_offset=datetime.timedelta(minutes=dstoffset)# for the meaning see the win32 TIME_ZONE_INFORMATION structure docs# http://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx(self._stdmonth,self._stddayofweek,# Sunday = 0self._stdweeknumber,# Last = 5self._stdhour,self._stdminute)=tup[4:9](self._dstmonth,self._dstdayofweek,# Sunday = 0self._dstweeknumber,# Last = 5self._dsthour,self._dstminute)=tup[12:17]self._dst_base_offset_=self._dst_offset-self._std_offsetself.hasdst=self._get_hasdst()def__repr__(self):return"tzwin(%s)"%repr(self._name)def__reduce__(self):return(self.__class__,(self._name,)) [docs]classtzwinlocal(tzwinbase):""" Class representing the local time zone information in the Windows registry While :class:`dateutil.tz.tzlocal` makes system calls (via the :mod:`time` module) to retrieve time zone information, ``tzwinlocal`` retrieves the rules directly from the Windows registry and creates an object like :class:`dateutil.tz.tzwin`. Because Windows does not have an equivalent of :func:`time.tzset`, on Windows, :class:`dateutil.tz.tzlocal` instances will always reflect the time zone settings *at the time that the process was started*, meaning changes to the machine's time zone settings during the run of a program on Windows will **not** be reflected by :class:`dateutil.tz.tzlocal`. Because ``tzwinlocal`` reads the registry directly, it is unaffected by this issue. """def__init__(self):withwinreg.ConnectRegistry(None,winreg.HKEY_LOCAL_MACHINE)ashandle:withwinreg.OpenKey(handle,TZLOCALKEYNAME)astzlocalkey:keydict=valuestodict(tzlocalkey)self._std_abbr=keydict["StandardName"]self._dst_abbr=keydict["DaylightName"]try:tzkeyname=text_type('{kn}\\{sn}').format(kn=TZKEYNAME,sn=self._std_abbr)withwinreg.OpenKey(handle,tzkeyname)astzkey:_keydict=valuestodict(tzkey)self._display=_keydict["Display"]exceptOSError:self._display=Nonestdoffset=-keydict["Bias"]-keydict["StandardBias"]dstoffset=stdoffset-keydict["DaylightBias"]self._std_offset=datetime.timedelta(minutes=stdoffset)self._dst_offset=datetime.timedelta(minutes=dstoffset)# For reasons unclear, in this particular key, the day of week has been# moved to the END of the SYSTEMTIME structure.tup=struct.unpack("=8h",keydict["StandardStart"])(self._stdmonth,self._stdweeknumber,# Last = 5self._stdhour,self._stdminute)=tup[1:5]self._stddayofweek=tup[7]tup=struct.unpack("=8h",keydict["DaylightStart"])(self._dstmonth,self._dstweeknumber,# Last = 5self._dsthour,self._dstminute)=tup[1:5]self._dstdayofweek=tup[7]self._dst_base_offset_=self._dst_offset-self._std_offsetself.hasdst=self._get_hasdst()def__repr__(self):return"tzwinlocal()"def__str__(self):# str will return the standard name, not the daylight name.return"tzwinlocal(%s)"%repr(self._std_abbr)def__reduce__(self):return(self.__class__,()) defpicknthweekday(year,month,dayofweek,hour,minute,whichweek):""" dayofweek == 0 means Sunday, whichweek 5 means last instance """first=datetime.datetime(year,month,1,hour,minute)# This will work if dayofweek is ISO weekday (1-7) or Microsoft-style (0-6),# Because 7 % 7 = 0weekdayone=first.replace(day=((dayofweek-first.isoweekday())%7)+1)wd=weekdayone+((whichweek-1)*ONEWEEK)if(wd.month!=month):wd-=ONEWEEKreturnwddefvaluestodict(key):"""Convert a registry key's values to a dictionary."""dout={}size=winreg.QueryInfoKey(key)[1]tz_res=Noneforiinrange(size):key_name,value,dtype=winreg.EnumValue(key,i)ifdtype==winreg.REG_DWORDordtype==winreg.REG_DWORD_LITTLE_ENDIAN:# If it's a DWORD (32-bit integer), it's stored as unsigned - convert# that to a proper signed integerifvalue&(1<<31):value=value-(1<<32)elifdtype==winreg.REG_SZ:# If it's a reference to the tzres DLL, load the actual stringifvalue.startswith('@tzres'):tz_res=tz_resortzres()value=tz_res.name_from_string(value)value=value.rstrip('\x00')# Remove trailing nullsdout[key_name]=valuereturndout