122 lines
4.8 KiB
Python
122 lines
4.8 KiB
Python
|
"""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()
|