forked from daviddrysdale/python-phonenumbers
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtimezone.py
More file actions
132 lines (114 loc) · 5.34 KB
/
timezone.py
File metadata and controls
132 lines (114 loc) · 5.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
"""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'
>>> gb_number = phonenumbers.parse("+447986123456", "GB")
>>> tzlist = time_zones_for_number(gb_number)
>>> len(tzlist)
2
>>> str(tzlist[0])
'Atlantic/Reykjavik'
>>> str(tzlist[1])
'Europe/London'
"""
# 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
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 _can_be_geocoded(ntype):
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
# A similar method is implemented as phonenumberutil._is_number_geographical,
# which performs a stricter check, as it determines if a number has a
# geographical association. Also, if new phone number types were added, we
# should check if this other method should be updated too.
# TODO: Remove duplication by completing the login in the method in phonenumberutil.
# For more information, see the comments in that method.
def _can_be_geocoded(ntype):
return (ntype == PhoneNumberType.FIXED_LINE or
ntype == PhoneNumberType.MOBILE or
ntype == PhoneNumberType.FIXED_LINE_OR_MOBILE)
if __name__ == '__main__': # pragma no cover
import doctest
doctest.testmod()