2
2
from random import random, randint
3
3
from subprocess import Popen, PIPE
4
from datetime import datetime
5
from os.path import exists, join
7
from dateutil.parser import parse
8
from dateutil.tz import gettz, tzutc, tzlocal, tzoffset
5
10
from ibid.plugins import Processor, match
6
11
from ibid.config import Option
7
from ibid.utils import file_in_path, unicode_output
12
from ibid.utils import file_in_path, unicode_output, human_join, format_date, json_webservice
13
from ibid.compat import defaultdict
108
114
event.addresponse(u"I can't do that: %s", result)
116
class TimezoneException(Exception):
119
MONTH_SHORT = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
120
MONTH_LONG = ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')
121
OTHER_STUFF = ('am', 'pm', 'st', 'nd', 'rd', 'th')
123
help['timezone'] = "Converts times between timezones."
124
class TimeZone(Processor):
125
u"""when is <time> <place|timezone> in <place|timezone>
126
time in <place|timezone>"""
129
zoneinfo = Option('zoneinfo', 'Timezone info directory', '/usr/share/zoneinfo')
132
timezones = defaultdict(list)
135
iso3166 = join(self.zoneinfo, 'iso3166.tab')
137
for line in open(iso3166).readlines():
138
if not line.startswith('#'):
139
code, name = line.strip().split('\t')
140
self.countries[code] = name
142
zones = join(self.zoneinfo, 'zone.tab')
144
for line in open(zones).readlines():
145
if not line.startswith('#'):
146
code, coordinates, zone = line.strip().split('\t', 2)
148
zone, comment = zone.split('\t')
149
self.timezones[code].append(zone)
151
def _find_timezone(self, string):
154
if string.upper() in ('GMT', 'UTC', 'UCT', 'ZULU'):
159
for code, name in self.countries.items():
160
if name.lower() == string.lower():
163
if string.replace('.', '').upper() in self.timezones:
164
ccode = string.replace('.', '').upper()
167
if len(self.timezones[ccode]) == 1:
168
zone = gettz(self.timezones[ccode][0])
170
raise TimezoneException(u'%s has multiple timezones: %s' % (self.countries[ccode], human_join(self.timezones[ccode])))
174
for zones in self.timezones.values():
176
if string.replace(' ', '_').lower() in name.lower():
177
possibles.append(name)
179
if len(possibles) == 1:
180
zone = gettz(possibles[0])
181
elif len(possibles) > 1:
182
raise TimezoneException(u'Multiple timezones found: %s' % (human_join(possibles)))
184
zone = self._geonames_lookup(string)
186
raise TimezoneException(u"I don't know about the %s timezone" % (string,))
190
def _geonames_lookup(self, place):
191
search = json_webservice('http://ws.geonames.org/searchJSON', {'q': place, 'maxRows': 1})
192
if search['totalResultsCount'] == 0:
195
city = search['geonames'][0]
196
timezone = json_webservice('http://ws.geonames.org/timezoneJSON', {'lat': city['lat'], 'lng': city['lng']})
198
if 'timezoneId' in timezone:
199
return gettz(timezone['timezoneId'])
201
if 'rawOffset' in timezone:
202
offset = timezone['rawOffset']
203
return tzoffset('UTC%s%s' % (offset>=0 and '+' or '', offset), offset*3600)
205
@match(r'^when\s+is\s+((?:[0-9.:/hT -]|%s)+)(?:\s+(.+))?\s+in\s+(.+)$' % '|'.join(MONTH_SHORT+MONTH_LONG+OTHER_STUFF))
206
def convert(self, event, time, from_, to):
207
source = time and parse(time) or datetime.now()
211
from_zone = self._find_timezone(from_)
213
from_zone = tzlocal()
215
to_zone = self._find_timezone(to)
216
except TimezoneException, e:
217
event.addresponse(unicode(e))
220
source = source.replace(tzinfo=from_zone)
221
result = source.astimezone(to_zone)
223
event.addresponse(time and u'%(source)s is %(destination)s' or 'It is %(destination)s', {
224
'source': format_date(source, tolocaltime=False),
225
'destination': format_date(result, tolocaltime=False),
228
@match(r"^(?:(?:what(?:'?s|\s+is)\s+the\s+)?time\s+in|what\s+time\s+is\s+it\s+in)\s+(.+)$")
229
def time(self, event, place):
230
self.convert(event, None, None, place)
110
232
# vi: set et sta sw=4 ts=4: