Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backport TZ fixes from downstream #209

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions lingua_franca/lang/parse_fa.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import re
import json
from lingua_franca.internal import resolve_resource_file
from lingua_franca.time import now_local


def _is_number(s):
Expand Down Expand Up @@ -215,7 +216,7 @@ def extract_datetime_fa(text, anchorDate=None, default_time=None):


if not anchorDate:
anchorDate = datetime.now()
anchorDate = now_local()
today = anchorDate.replace(hour=0, minute=0, second=0, microsecond=0)
today_weekday = int(anchorDate.strftime("%w"))
weekday_names = [
Expand Down Expand Up @@ -383,11 +384,11 @@ def extract_number_fa(text, ordinals=False):
return False
return x[0]

class EnglishNormalizer(Normalizer):
with open(resolve_resource_file("text/en-us/normalize.json")) as f:
class FarsiNormalizer(Normalizer):
with open(resolve_resource_file("text/fa-ir/normalize.json")) as f:
_default_config = json.load(f)


def normalize_fa(text, remove_articles=True):
""" English string normalization """
return EnglishNormalizer().normalize(text, remove_articles)
""" Farsi string normalization """
return FarsiNormalizer().normalize(text, remove_articles)
3 changes: 1 addition & 2 deletions lingua_franca/lang/parse_fr.py
Original file line number Diff line number Diff line change
Expand Up @@ -944,8 +944,7 @@ def date_found():
if not hasYear:
temp = datetime.strptime(datestr, "%B %d")
if extractedDate.tzinfo:
temp = temp.replace(tzinfo=gettz("UTC"))
temp = temp.astimezone(extractedDate.tzinfo)
temp = temp.replace(tzinfo=extractedDate.tzinfo)
temp = temp.replace(year=extractedDate.year)
if extractedDate < temp:
extractedDate = extractedDate.replace(year=int(currentYear),
Expand Down
22 changes: 15 additions & 7 deletions lingua_franca/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def now_utc():
Returns:
(datetime): The current time in Universal Time, aka GMT
"""
return to_utc(datetime.utcnow())
return datetime.now(gettz("UTC"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much nicer 👍



def now_local(tz=None):
Expand All @@ -62,7 +62,6 @@ def now_local(tz=None):
tz = default_timezone()
return datetime.now(tz)


def to_utc(dt):
""" Convert a datetime with timezone info to a UTC datetime

Expand All @@ -71,11 +70,16 @@ def to_utc(dt):
Returns:
(datetime): time converted to UTC
"""
tzUTC = gettz("UTC")
tz = gettz("UTC")
if dt.tzinfo:
return dt.astimezone(tzUTC)
return dt.astimezone(tz)
else:
return dt.replace(tzinfo=gettz("UTC")).astimezone(tzUTC)
# naive datetimes assumed to be in default timezone already!
# in the case of datetime.now this corresponds to tzlocal()
# otherwise timezone is undefined and can not be guessed, we assume
# the user means "my timezone" and that LN was configured to use it
# beforehand, if unconfigured default == tzlocal()
Comment on lines +77 to +81
Copy link
Contributor

@krisgesling krisgesling Oct 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to update these comments

return dt.replace(tzinfo=default_timezone()).astimezone(tz)


def to_local(dt):
Expand All @@ -90,5 +94,9 @@ def to_local(dt):
if dt.tzinfo:
return dt.astimezone(tz)
else:
return dt.replace(tzinfo=gettz("UTC")).astimezone(tz)

# naive datetimes assumed to be in default timezone already!
# in the case of datetime.now this corresponds to tzlocal()
# otherwise timezone is undefined and can not be guessed, we assume
# the user means "my timezone" and that LN was configured to use it
# beforehand, if unconfigured default == tzlocal()
return dt.replace(tzinfo=tz)
35 changes: 32 additions & 3 deletions test/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import ast
import warnings
import sys
from dateutil import tz
from pathlib import Path

# TODO either write a getter for lingua_franca.internal._SUPPORTED_LANGUAGES,
Expand All @@ -35,7 +36,9 @@
from lingua_franca.format import pronounce_number
from lingua_franca.format import date_time_format
from lingua_franca.format import join_list
from lingua_franca.time import default_timezone
from lingua_franca.time import default_timezone, set_default_tz, now_local, \
to_local



def setUpModule():
Expand Down Expand Up @@ -385,8 +388,34 @@ def test_ordinals(self):
short_scale=False), "eighteen "
"trillionth")

# def nice_time(dt, lang="en-us", speech=True, use_24hour=False,
# use_ampm=False):
class TestTimezones(unittest.TestCase):
def test_default_tz(self):
set_default_tz("America/Chicago")

local_time = now_local()
local_tz = default_timezone()
us_time = datetime.datetime.now(tz=tz.gettz("America/Chicago"))
self.assertEqual(nice_date_time(local_time),
nice_date_time(us_time))
self.assertEqual(local_time.tzinfo, local_tz)

# naive datetimes assumed to be in default timezone already!
# in the case of datetime.now this corresponds to tzlocal()
# otherwise timezone is undefined and can not be guessed, we assume
# the user means "my timezone" and that LN was configured to use it
# beforehand, if unconfigured default == tzlocal()
dt = datetime.datetime(2021, 6, 23, 00, 43, 39)
dt_local = to_local(dt)
self.assertEqual(nice_time(dt), nice_time(dt_local))

def test_tz_conversion(self):
naive = datetime.datetime.now()
system_time = datetime.datetime.now(tz.tzlocal())
# naive == datetime.now() == tzlocal() internally
# NOTE nice_date_time is not a localized function, it just formats
# the datetime object directly
self.assertEqual(nice_date_time(naive),
nice_date_time(system_time))


class TestNiceDateFormat(unittest.TestCase):
Expand Down
39 changes: 38 additions & 1 deletion test/test_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from lingua_franca import load_language, unload_language, set_default_lang
from lingua_franca.internal import FunctionNotLocalizedError
from lingua_franca.time import default_timezone
from lingua_franca.time import default_timezone, now_local, set_default_tz
from lingua_franca.parse import extract_datetime
from lingua_franca.parse import extract_duration
from lingua_franca.parse import extract_number, extract_numbers
Expand All @@ -38,6 +38,43 @@ def setUpModule():
def tearDownModule():
unload_language('en')

class TestTimezones(unittest.TestCase):
def test_default_tz(self):
naive = datetime.now()

# convert to default tz
set_default_tz("Europe/London")
dt = extract_datetime("tomorrow", anchorDate=naive)[0]
self.assertEqual(dt.tzinfo, tz.gettz("Europe/London"))

set_default_tz("America/Chicago")
dt = extract_datetime("tomorrow", anchorDate=naive)[0]
self.assertEqual(dt.tzinfo, tz.gettz("America/Chicago"))

def test_convert_to_anchorTZ(self):
naive = datetime.now()
local = now_local()
london_time = datetime.now(tz=tz.gettz("Europe/London"))
us_time = datetime.now(tz=tz.gettz("America/Chicago"))

# convert to anchor date
dt = extract_datetime("tomorrow", anchorDate=naive)[0]
self.assertEqual(dt.tzinfo, default_timezone())
dt = extract_datetime("tomorrow", anchorDate=local)[0]
self.assertEqual(dt.tzinfo, local.tzinfo)
dt = extract_datetime("tomorrow", anchorDate=london_time)[0]
self.assertEqual(dt.tzinfo, london_time.tzinfo)
dt = extract_datetime("tomorrow", anchorDate=us_time)[0]
self.assertEqual(dt.tzinfo, us_time.tzinfo)

# test naive == default tz
set_default_tz("America/Chicago")
dt = extract_datetime("tomorrow", anchorDate=naive)[0]
self.assertEqual(dt.tzinfo, default_timezone())
set_default_tz("Europe/London")
dt = extract_datetime("tomorrow", anchorDate=naive)[0]
self.assertEqual(dt.tzinfo, default_timezone())


class TestFuzzyMatch(unittest.TestCase):
def test_matches(self):
Expand Down