Skip to content

Commit

Permalink
troubleshoot datetime
Browse files Browse the repository at this point in the history
  • Loading branch information
NeonDaniel committed Feb 26, 2019
1 parent 85199f2 commit 28c5595
Show file tree
Hide file tree
Showing 97 changed files with 106 additions and 357 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# <img src='https://raw.githack.com/FortAwesome/Font-Awesome/master/svgs/solid/calendar.svg' card_color='#22a7f0' width='50' height='50' style='vertical-align:bottom'/> Date and Time
# <img src='https://rawgithub.com/FortAwesome/Font-Awesome/master/advanced-options/raw-svg/solid/calendar.svg' card_color='#22a7f0' width='50' height='50' style='vertical-align:bottom'/> Date and Time
Get the time, date, day of the week

## About
Expand Down
198 changes: 51 additions & 147 deletions __init__.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,23 @@
# limitations under the License.

import datetime
# import tzlocal
from astral import Astral
from pytz import timezone
from geopy.geocoders import Nomimatim
from geopy.geocoders import Nominatim
from timezonefinder import TimezoneFinder as Tf
import time
import re
import pytz
import time
import tzlocal
from astral import Astral

from adapt.intent import IntentBuilder
import mycroft.audio
from mycroft.skills.core import MycroftSkill, intent_handler
# from mycroft.util.format import nice_time
from mycroft.util.format import pronounce_number, nice_date
from mycroft.util.format import pronounce_number
from mycroft.util.log import LOG
from mycroft.util.lang.format_de import nice_time_de, pronounce_ordinal_de
from mycroft.messagebus.message import Message
from mycroft import MycroftSkill, intent_handler, intent_file_handler
from mycroft.util.parse import extract_datetime, fuzzy_match
from mycroft.util.time import now_utc, default_timezone

# TODO:
# * what time is it in Sydney
# * what day is it in Sydney
# * what day is july 4th
# * what day is Christmas 2020

# TODO: This is temporary until nice_time() gets fixed in mycroft-core's
# next release


# TODO: This is temporary until nice_time() gets fixed in mycroft-core's next release
def nice_time(dt, lang, speech=True, use_24hour=False, use_ampm=False):
"""
Format a time to a comfortable human format
Expand All @@ -59,7 +48,8 @@ def nice_time(dt, lang, speech=True, use_24hour=False, use_ampm=False):
"""

# If language is German, use nice_time_de
if lang.lower().startswith("de"):
lang_lower = str(lang).lower()
if lang_lower.startswith("de"):
return nice_time_de(dt, speech, use_24hour, use_ampm)

if use_24hour:
Expand Down Expand Up @@ -129,6 +119,7 @@ def nice_time(dt, lang, speech=True, use_24hour=False, use_ampm=False):

return speak


def nice_date_de(local_date):

# dates are returned as, for example:
Expand All @@ -149,6 +140,7 @@ def nice_date_de(local_date):
+ de_months[local_date.month - 1] \
+ " " + pronounce_number(local_date.year, lang = "de")


class TimeSkill(MycroftSkill):

def __init__(self):
Expand Down Expand Up @@ -176,83 +168,40 @@ def use_24hour(self):
return self.config_core.get('time_format') == 'full'

def get_timezone(self, locale):
self.log.debug("GET_TIMEZONE: "+str(locale))
try:
coord = self.coordinates.geocode(locale).raw
time_zone = self.tzfinder.timezone_at(lng=float(coord.get('lon')), lat=float(coord.get('lat')))
return timezone(time_zone)
except:
try:
# Fallback Attempt using astral
return timezone(self.astral[locale].timezone)
except Exception as e:
# try:
# # This handles codes like "America/Los_Angeles"
# return timezone(locale)
# except Exception as e:
LOG.error(e)
return None
except Exception as e:
LOG.error(e)
try:
# Fallback Attempt using astral
return timezone(self.astral[locale].timezone)
except Exception as e:
LOG.error(e)
try:
# This handles codes like "America/Los_Angeles"
return timezone(locale)
except Exception as e:
LOG.error(e)
return None

def get_local_datetime(self, location):
nowUTC = datetime.datetime.now(timezone('UTC'))
try:
# This handles codes like "America/Los_Angeles"
return pytz.timezone(locale)
except:
pass

# Check lookup table for other timezones. This can also
# be a translation layer.
# E.g. "china = GMT+8"
#
# TODO: timezone.lookup.value

# Now we gotta get a little fuzzy
# Look at the pytz list of all timezones. It consists of
# Location/Name pairs. For example:
# ["Africa/Abidjan", "Africa/Accra", ... "America/Denver", ...
# "America/New_York", ..., "America/North_Dakota/Center", ...
# "Cuba", ..., "EST", ..., "Egypt", ..., "Etc/GMT+3", ...
# "Etc/Zulu", ... "US/Eastern", ... "UTC", ..., "Zulu"]
target = locale.lower()
best = None
for name in pytz.all_timezones:
normalized = name.lower().replace("_", " ").split("/")
if len(normalized) == 1:
pct = fuzzy_match(normalized[0], target)
elif len(normalized) == 2:
pct = fuzzy_match(normalized[1], target)
# TODO: if pct <
if not best or pct >= best[0]:
best = (pct, name)
if best and best[0] > 0.8:
# solid choice
return pytz.timezone(best[1])
if best and best[0] > 0.3:
if self.ask_yesno("did you mean "+ best[1]) == "yes":
return pytz.timezone(best[1])

return None

def get_local_datetime(self, location, dtUTC=None):
if not dtUTC:
dtUTC = now_utc()
if self.display_tz:
# User requested times be shown in some timezone
tz = self.display_tz
else:
# Use default timezone
tz = default_timezone()
tz = self.get_timezone(self.location_timezone)

if location:
tz = self.get_timezone(location)
if not tz:
self.speak_dialog("time.tz.not.found", {"location": location})
return None

return dtUTC.astimezone(tz)
return nowUTC.astimezone(tz)

def get_display_current_time(self, location=None):
def get_display_time(self, location=None):
# Get a formatted digital clock time based on the user preferences
dt = self.get_local_datetime(location)
if not dt:
Expand All @@ -261,19 +210,14 @@ def get_display_current_time(self, location=None):
return nice_time(dt, self.lang, speech=False,
use_24hour=self.use_24hour)

def get_spoken_current_time(self, location=None):
def get_spoken_time(self, location=None):
# Get a formatted spoken time based on the user preferences
dt = self.get_local_datetime(location)
if not dt:
return

say_am_pm = bool(location) # speak AM/PM when talking about somewhere else
s = nice_time(dt, self.lang, speech=True,
use_24hour=self.use_24hour, use_ampm=say_am_pm)
# HACK: Mimic 2 has a bug with saying "AM". Work around it for now.
if say_am_pm:
s = s.replace("AM", "A.M.")
return s
return nice_time(dt, self.lang, speech=True,
use_24hour=self.use_24hour)

def display(self, display_time):
# Map characters to the display encoding for a Mark 1
Expand Down Expand Up @@ -310,23 +254,13 @@ def display(self, display_time):
xoffset = (32 - (4*(len(display_time))-2)) / 2
for c in display_time:
if c in code_dict:
self.enclosure.mouth_display(img_code=code_dict[c],
x=xoffset, refresh=False)
# self.enclosure.mouth_display(img_code=code_dict[c],
# x=xoffset, refresh=False)
if c == ":":
xoffset += 2 # colon is 1 pixels + a space
else:
xoffset += 4 # digits are 3 pixels + a space

if self._is_alarm_set():
# Show a dot in the upper-left
self.enclosure.mouth_display(img_code="CIAACA", x=1, refresh=False)
else:
self.enclosure.mouth_display(img_code="CIAAAA", x=1, refresh=False)

def _is_alarm_set(self):
msg = self.bus.wait_for_response(Message("private.mycroftai.has_alarm"))
return msg and msg.data.get("active_alarms", 0) > 0

def _is_display_idle(self):
# check if the display is being used by another skill right now
# or _get_active() == "TimeSkill"
Expand All @@ -341,7 +275,7 @@ def update_display(self, force=False):
if self.settings.get("show_time", False):
# user requested display of time while idle
if (force is True) or self._is_display_idle():
current_time = self.get_display_current_time()
current_time = self.get_display_time()
if self.displayed_time != current_time:
self.displayed_time = current_time
self.display(current_time)
Expand All @@ -359,37 +293,11 @@ def update_display(self, force=False):
self.enclosure.display_manager.remove_active()
self.displayed_time = None

@intent_file_handler("what.time.is.it.intent")
def handle_query_time_alt(self, message):
self.log.info("FORWARDING PADATIOUS INTENT MATCH ")
self.handle_query_time(message)

def _extract_location(self, message):
if "Location" in message.data:
return message.data["Location"]

utt = message.data.get('utterance') or ""
rx_file = self.find_resource('location.rx', 'regex')
if rx_file:
with open(rx_file) as f:
for pat in f.read().splitlines():
pat = pat.strip()
if pat and pat[0] == "#":
continue
res = re.search(pat, utt)
if res:
try:
return res.group("Location")
except IndexError:
pass
return None

@intent_handler(IntentBuilder("").require("Query").require("Time").
optionally("Location"))
def handle_query_time(self, message):
location = self._extract_location(message)
self.log.info("LOCATION: "+str(location))
current_time = self.get_spoken_current_time(location)
location = message.data.get("Location")
current_time = self.get_spoken_time(location)
if not current_time:
return

Expand All @@ -399,7 +307,7 @@ def handle_query_time(self, message):
# and briefly show the time
self.answering_query = True
self.enclosure.deactivate_mouth_events()
self.display(self.get_display_current_time(location))
self.display(self.get_display_time(location))
time.sleep(5)
mycroft.audio.wait_while_speaking()
self.enclosure.mouth_reset()
Expand All @@ -411,17 +319,14 @@ def handle_query_time(self, message):
optionally("Location"))
def handle_show_time(self, message):
self.display_tz = None
location = self._get_location(message)
self.log.info("Location: "+str(location))
location = message.data.get("Location")
if location:
tz = self.get_timezone(location)
if not tz:
self.speak_dialog("time.tz.not.found", {"location": location})
return
else:
self.display_tz = tz
else:
self.display_tz = None

# show time immediately
self.settings["show_time"] = True
Expand All @@ -430,24 +335,23 @@ def handle_show_time(self, message):
@intent_handler(IntentBuilder("").require("Query").require("Date").
optionally("Location"))
def handle_query_date(self, message):
utt = message.data.get('utterance') or ""
day = extract_datetime(utt)[0]
local_date = self.get_local_datetime(message.data.get("Location"))
if not local_date:
return

location = self._extract_location(message)
if location:
# TODO: Timezone math!
day = self.get_local_datetime(location, dtUTC=day)
# Get the current date
# If language is German, use nice_date_de
# otherwise use locale

self.log.info("Day: "+str(day))
if self.lang.lower().startswith("de"):
speak = nice_date_de(day)
lang_lower = str(self.lang).lower()
if lang_lower.startswith("de"):
speak = nice_date_de(local_date)
else:
speak = nice_date(day)

speak = local_date.strftime("%A, %B %-d, %Y")
if self.config_core.get('date_format') == 'MDY':
show = day.strftime("%-m/%-d/%Y")
show = local_date.strftime("%-m/%-d/%Y")
else:
show = day.strftime("%Y/%-d/%-m")
show = local_date.strftime("%Y/%-d/%-m")

# speak it
self.speak_dialog("date", {"date": speak})
Expand Down
4 changes: 2 additions & 2 deletions dialog/de-de/date.dialog
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{date}}
es ist {{date}}
heute ist der {{date}}
{{date}}
Es ist der {{date}}
Es ist {{date}}
6 changes: 3 additions & 3 deletions dialog/de-de/time.current.dialog
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{{time}}
es ist {{time}}
{{time}}
Es ist {{time}}
Es ist {{time}}
Aktuell {{time}}
es ist aktuell {{time}}
Zur Zeit ist {{time}}
2 changes: 1 addition & 1 deletion dialog/de-de/time.tz.not.found.dialog
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Ich konnte die Zeitzone für {{location}} nicht finden
Ich konnte die Zeitzone {{location}} nicht finden
8 changes: 4 additions & 4 deletions dialog/en-us/date.dialog
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{date}}
It is {{date}}
It's {{date}}
{{date}}
{{date}}
It is {{date}}
It's {{date}}
{{date}}
4 changes: 0 additions & 4 deletions dialog/en-us/timezone.value

This file was deleted.

4 changes: 0 additions & 4 deletions dialog/es-es/date.dialog

This file was deleted.

5 changes: 0 additions & 5 deletions dialog/es-es/time.current.dialog

This file was deleted.

1 change: 0 additions & 1 deletion dialog/es-es/time.tz.not.found.dialog

This file was deleted.

4 changes: 0 additions & 4 deletions dialog/fr-fr/date.dialog

This file was deleted.

5 changes: 0 additions & 5 deletions dialog/fr-fr/time.current.dialog

This file was deleted.

1 change: 0 additions & 1 deletion dialog/fr-fr/time.tz.not.found.dialog

This file was deleted.

Loading

0 comments on commit 28c5595

Please sign in to comment.