"""Phone number to time zone mapping functionality >>> import phonenumbers >>> from phonenumbers.timezone import time_zones_for_number >>> ro_number = phonenumbers.parse("+40721234567", "RO") >>> tzlist = time_zones_for_number(ro_number) >>> len(tzlist) 1 >>> str(tzlist[0]) 'Europe/Bucharest' >>> dual_number = phonenumbers.parse("+976136234567", "US") >>> tzlist = time_zones_for_number(dual_number) >>> len(tzlist) 2 >>> str(tzlist[0]) 'Asia/Choibalsan' >>> str(tzlist[1]) 'Asia/Ulaanbaatar' """ # Based very loosely on original Java code: # java/geocoder/src/com/google/i18n/phonenumbers/PhoneNumberToTimeZonesMapper.java # Copyright (C) 2013 The Libphonenumber Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from .util import prnt, u, U_PLUS from .phonenumberutil import PhoneNumberType, number_type from .phonenumberutil import PhoneNumberFormat, format_number from .phonenumberutil import is_number_type_geographical try: from .tzdata import TIMEZONE_DATA, TIMEZONE_LONGEST_PREFIX except ImportError: # pragma no cover # Before the generated code exists, the carrierdata/ directory is empty. # The generation process imports this module, creating a circular # dependency. The hack below works around this. import os import sys if (os.path.basename(sys.argv[0]) == "buildmetadatafromxml.py" or os.path.basename(sys.argv[0]) == "buildprefixdata.py"): prnt("Failed to import generated data (but OK as during autogeneration)", file=sys.stderr) TIMEZONE_DATA = {'4411': u('Europe/London')} TIMEZONE_LONGEST_PREFIX = 4 else: raise __all__ = ['UNKNOWN_TIMEZONE', 'time_zones_for_geographical_number', 'time_zones_for_number'] # This is defined by ICU as the unknown time zone. UNKNOWN_TIMEZONE = u("Etc/Unknown") _UNKNOWN_TIME_ZONE_LIST = (UNKNOWN_TIMEZONE,) def time_zones_for_geographical_number(numobj): """Returns a list of time zones to which a phone number belongs. This method assumes the validity of the number passed in has already been checked, and that the number is geo-localizable. We consider fixed-line and mobile numbers possible candidates for geo-localization. Arguments: numobj -- a valid phone number for which we want to get the time zones to which it belongs Returns a list of the corresponding time zones or a single element list with the default unknown time zone if no other time zone was found or if the number was invalid""" e164_num = format_number(numobj, PhoneNumberFormat.E164) if not e164_num.startswith(U_PLUS): # pragma no cover # Can only hit this arm if there's an internal error in the rest of # the library raise Exception("Expect E164 number to start with +") for prefix_len in range(TIMEZONE_LONGEST_PREFIX, 0, -1): prefix = e164_num[1:(1 + prefix_len)] if prefix in TIMEZONE_DATA: return TIMEZONE_DATA[prefix] return _UNKNOWN_TIME_ZONE_LIST def time_zones_for_number(numobj): """As time_zones_for_geographical_number() but explicitly checks the validity of the number passed in. Arguments: numobj -- a valid phone number for which we want to get the time zones to which it belongs Returns a list of the corresponding time zones or a single element list with the default unknown time zone if no other time zone was found or if the number was invalid""" ntype = number_type(numobj) if ntype == PhoneNumberType.UNKNOWN: return _UNKNOWN_TIME_ZONE_LIST elif not is_number_type_geographical(ntype, numobj.country_code): return _country_level_time_zones_for_number(numobj) return time_zones_for_geographical_number(numobj) def _country_level_time_zones_for_number(numobj): """Returns the list of time zones corresponding to the country calling code of a number. Arguments: numobj -- the phone number to look up Returns a list of the corresponding time zones or a single element list with the default unknown time zone if no other time zone was found or if the number was invalid""" cc = str(numobj.country_code) for prefix_len in range(TIMEZONE_LONGEST_PREFIX, 0, -1): prefix = cc[:(1 + prefix_len)] if prefix in TIMEZONE_DATA: return TIMEZONE_DATA[prefix] return _UNKNOWN_TIME_ZONE_LIST if __name__ == '__main__': # pragma no cover import doctest doctest.testmod()