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() try: if data['Std'] == tzwin: tzkeyname = subkey break except: continue 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 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 create_meeting(self, email_address, start_time, end_time, subject, body, required_attendees, optional_attendees, location): """ create_meeting will create an event in the specified email_address user's calandar and send email to the required and optional attendee email addresses. :param email_address: meeting organizer :param start_time: start time of the meeting :param end_time: end time of the meeting :param subject: subject of the meeting/email :param body: body email meeting invitation :param required_attendees: list of required attendee email addresses :param location: list of optional attendee email addresses :return: response from MS Graph API post to calendar/events endpoint """ ms_graph_calender_event_url = u'{0}/users/{1}/calendar/events'.format( self.ms_graph_url, email_address) # Get the time zone of the organizer. ms_graph_timezone_url = u'{0}/users/{1}/mailboxSettings/timeZone'.format( self.ms_graph_url, email_address) response = self.ms_graph_session.get(ms_graph_timezone_url) self.check_ms_graph_response_code(response.status_code) if response.status_code == 200: response_json = response.json() windows_time_zone = response_json["value"] else: # If the timezone is not found (not set) then default to UTC time windows_time_zone = "UTC" # Convert the Windows time zone to IANA format. iana_time_zone = win_tz.get(windows_time_zone) # Use pytz with IANA time zone. to_zone = timezone(iana_time_zone) # Convert the start time to the time zone of the user mailbox start = datetime.datetime.utcfromtimestamp(start_time / 1000) start_tz = start.replace( tzinfo=pytz.utc).astimezone(to_zone).strftime(TIME_FORMAT) # Convert the end time to the time zone of the user mailbox end = datetime.datetime.utcfromtimestamp(end_time / 1000) end_tz = end.replace( tzinfo=pytz.utc).astimezone(to_zone).strftime(TIME_FORMAT) LOG.debug("Windows time zone = %s", windows_time_zone) LOG.debug("IANA time zone = %s", iana_time_zone) LOG.debug("meeting start = %s", start_tz) LOG.debug("meeting end = %s", end_tz) # Create attendee list in required format. If no required/optional attendees are specified set to empty string. if not required_attendees: required_attendees = "" if not optional_attendees: optional_attendees = "" required_list = [{ 'emailAddress': { 'address': address.strip() }, 'type': "required" } for address in required_attendees.split(',')] optional_list = [{ 'emailAddress': { 'address': address.strip() }, 'type': "optional" } for address in optional_attendees.split(',')] attendees = required_list + optional_list # Format the calendar event json. event_json = { "subject": subject, "body": { "contentType": "HTML", "content": body }, "start": { "dateTime": start_tz, "timeZone": windows_time_zone }, "end": { "dateTime": end_tz, "timeZone": windows_time_zone }, "location": { "displayName": location }, "attendees": attendees } response = self.ms_graph_session.post( ms_graph_calender_event_url, headers={'Content-Type': 'application/json'}, json=event_json) self.check_ms_graph_response_code(response.status_code) return response
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. tzenv = utils._tz_name_from_env() if tzenv: return tzenv 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 later # 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: # Don't support XP any longer 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 utils.ZoneInfoNotFoundError(tzkeyname) if keyvalues.get("DynamicDaylightTimeDisabled", 0) == 1: # DST is disabled, so don't return the timezone name, # instead return Etc/GMT+offset tz = pds.timezone(timezone) has_dst, std_offset, dst_offset = _get_dst_info(tz) if not has_dst: # The DST is turned off in the windows configuration, # but this timezone doesn't have DST so it doesn't matter return timezone if std_offset is None: raise utils.ZoneInfoNotFoundError( f"{tzkeyname} claims to not have a non-DST time!?") if std_offset % 3600: # I can't convert this to an hourly offset raise utils.ZoneInfoNotFoundError( f"tzlocal can't support disabling DST in the {timezone} zone.") # This has whole hours as offset, return it as Etc/GMT return f"Etc/GMT{-std_offset//3600:+.0f}" return timezone