Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #5 from sbuss/sysdate

Sysdate parsing
  • Loading branch information...
commit 3486147721b5c460049993afb04476b4bfad7280 2 parents e66b4a4 + 7af1d5b
Steven Buss authored
28 tests/tests.py
View
@@ -154,11 +154,11 @@ def test_from_local_time(self):
def test_sys_date(self):
#TODO: Make this test pass
- """s = "Mon Dec 10 23:31:50 EST 2012"
- ts_pst = datetime(2012, 12, 10, 23, 31, 50)
+ s = "Mon Dec 10 23:31:50 EST 2012"
+ ts_pst = datetime(2012, 12, 10, 20, 31, 50)
self.assertEqual(ts_pst, wtftz.convert(s, 'pst'))
- ts_utc = datetime(2012, 12, 11, 7, 31, 50)
- self.assertEqual(ts_utc, wtftz.convert(s, 'utc'))"""
+ ts_utc = datetime(2012, 12, 11, 4, 31, 50)
+ self.assertEqual(ts_utc, wtftz.convert(s, 'utc'))
def test_naive(self):
ts = datetime.utcnow()
@@ -223,13 +223,19 @@ def test_naive(self):
self.assertFalse(converted.tzinfo is None)
self.assertEqual(converted.tzinfo, pytz.timezone("US/Pacific"))
+ def test_sysdate_free(self):
+ s = "Mon Dec 10 23:31:50 EST 2012"
+ ts_pst = datetime(2012, 12, 10, 20, 31, 50)
+ query = "%s to pst" % s
+ self.assertEqual(ts_pst, wtftz.convert_free(query))
+
def test_sysdate_tz_doesnt_match(self):
# TODO: Make this test pass
- """s = "Mon Dec 10 23:31:50 EST 2012"
- target = datetime(2012, 12, 10, 23, 31, 50)
+ s = "Mon Dec 10 23:31:50 EST 2012"
+ target = datetime(2012, 12, 10, 20, 31, 50)
query = "{ts} from utc to pst".format(ts=s)
result = wtftz.convert_free(query)
- self.assertEqual(result, target)"""
+ self.assertEqual(result, target)
def _test_extraction(self, query, ts, fromz, toz):
_ts, _fromz, _toz = free_text(query)
@@ -276,6 +282,14 @@ def test_extraction_no_from(self):
self._test_extraction(
query, self.est_ts_str, None, "US/Pacific")
+ def test_extraction_no_from_keyword(self):
+ query_template = "{ts} {fromz} to {toz}"
+ query = query_template.format(ts=self.est_ts_str,
+ fromz="EST",
+ toz="US/Pacific")
+ self._test_extraction(
+ query, self.est_ts_str, "EST", "US/Pacific")
+
class TestTimesWithoutDates(TestCase):
def test_simple_bare_times(self):
2  wtftz/_version.py
View
@@ -1 +1 @@
-__version__ = "0.2.3"
+__version__ = "0.2.4"
31 wtftz/converter.py
View
@@ -5,6 +5,7 @@
from .timezones import common_timezones
from .parser import free_text
+from .parser import _from
def convert(timestamp, to_tz="utc", from_tz="utc", naive=True):
@@ -33,8 +34,8 @@ def convert(timestamp, to_tz="utc", from_tz="utc", naive=True):
to_tz = "utc"
if not from_tz:
from_tz = "utc"
- from_timezone = common_tz_name_to_real_tz(from_tz)
- to_timezone = common_tz_name_to_real_tz(to_tz)
+ from_timezone = common_tz_name_to_real_tz(from_tz) or pytz.UTC
+ to_timezone = common_tz_name_to_real_tz(to_tz) or pytz.UTC
timestamp = parse_timestamp(timestamp)
if not hasattr(timestamp, 'tzinfo') or timestamp.tzinfo is None:
timestamp = from_timezone.localize(timestamp)
@@ -67,7 +68,7 @@ def common_tz_name_to_real_tz(name):
Args:
name: The name of the timezone. eg "est" or "US/Eastern"
- Returns a tzinfo.
+ Returns a tzinfo or None, if the given name is unknown.
"""
if isinstance(name, datetime.tzinfo):
return name
@@ -78,7 +79,7 @@ def common_tz_name_to_real_tz(name):
return pytz.timezone(name)
except Exception:
pass
- return pytz.UTC
+ return None
def parse_timestamp(timestamp):
@@ -89,6 +90,7 @@ def parse_timestamp(timestamp):
isoformat, and anything python-dateutil can handle.
Returns a timestamp.
"""
+ orig_timestamp = timestamp
if isinstance(timestamp, datetime.datetime) or \
isinstance(timestamp, datetime.time):
return timestamp
@@ -104,9 +106,26 @@ def parse_timestamp(timestamp):
pass
timestamp = str(timestamp)
+ # We might have a weird timestamp string with a timezone
+ # eg: "Mon Dec 10 23:31:50 EST 2012"
+ fromz = None
try:
- return date_parser.parse(timestamp)
+ free_ts, free_from = _from(timestamp)
+ if free_from and common_tz_name_to_real_tz(free_from):
+ fromz = common_tz_name_to_real_tz(free_from)
+ timestamp = free_ts
except Exception:
pass
- raise ValueError("Cannot parse timestamp {ts}".format(ts=timestamp))
+ try:
+ parsed_date = date_parser.parse(timestamp)
+ if fromz:
+ if hasattr(parsed_date, 'tzinfo') and parsed_date.tzinfo:
+ parsed_date.replace(tzinfo=fromz)
+ else:
+ parsed_date = fromz.localize(parsed_date)
+ return parsed_date
+ except Exception:
+ pass
+
+ raise ValueError("Cannot parse timestamp {ts}".format(ts=orig_timestamp))
100 wtftz/parser.py
View
@@ -12,62 +12,88 @@ def free_text(query):
Ex:
>>> free_text("2012-12-23T14:23:03.826437-05:00 to pst")
('2012-12-23T14:23:03.826437-05:00', None, 'pst')
+ >>> free_text("2012-12-23T14:23:03.826437 from to pst")
+ ('2012-12-23T14:23:03.826437-05:00', 'est', 'pst')
+ >>> free_text("Mon Dec 10 23:31:50 EST 2012 to UTC")
+ ("Mon Dec 10 23:31:50 2012", "EST", "UTC")
"""
- try:
- return _from_to(query)
- except Exception:
- pass
+ query, toz = _to(query)
+ query, fromz = _from(query)
+ return (query, fromz, toz)
- try:
- return _to(query)
- except Exception:
- pass
- raise MismatchException("%s does not match a known pattern" % query)
+def _to(query):
+ """Try to parse a `to` timezone from the query.
+
+ Args:
+ query - A string with a time, and a source and destination timezone.
+ Returns a tuple (query, to_timezone_string) parsed from the query. The
+ query will be have the `to` timezone removed. If no timezone is found,
+ return (query, None).
+
+ >>> _to("2012-12-23T14:23:03.826437 to pst")
+ ('2012-12-23T14:23:03.826437', 'pst')
+ """
+ pattern = re.compile(r"to ?(.*)")
+ matches = pattern.findall(query)
+ if len(matches) > 0:
+ toz = matches[0]
+ query = pattern.sub("", query, 1)
+ return (query.strip(), toz.strip())
+ else:
+ raise MismatchException()
-def _from_to(query):
- """Try to parse a `from` and `to` timezone from the query.
+def _from(query):
+ """Extract the `from ...` part of a query.
Args:
query - A string with a time, and a source and destination timezone.
- Returns a triplet (timestamp, from_timezone, to_timezone) parsed from
- the query.
+ Returns a tuple (query, from_timezone_string) parsed from the query. The
+ query will be have the from timezone removed. If no timezone is found,
+ return (query, None).
- >>> _from_to("2012-12-23T14:23:03.826437 from est to pst")
- ('2012-12-23T14:23:03.826437', 'est', 'pst')
+ >>> _from("2012-12-23T14:23:03.826437 from est")
+ ('2012-12-23T14:23:03.826437', 'est')
+
+ If no `from` keyword is in this query, we will attempt to find a suitable
+ timezone in the query string.
"""
- template = re.compile(r"(.*)from(.*)to(.*)")
- matches = template.findall(query)
- if len(matches) == 1:
- match = matches[0]
- ts = match[0].strip()
- fromz = match[1].strip()
- toz = match[2].strip()
- return (ts, fromz, toz)
- raise MismatchException()
+ pattern = re.compile(r"from ([A-Za-z/ ]+)")
+ matches = pattern.findall(query)
+ if len(matches) > 0:
+ fromz = matches[0]
+ query = pattern.sub("", query, 1)
+ return (query.strip(), fromz.strip())
+ return _implicit_from(query)
-def _to(query):
- """Try to parse a `to` timezone from the query.
+
+def _implicit_from(query):
+ """There *is* a source timezone in the query, but no from keyword.
Args:
query - A string with a time, and a source and destination timezone.
Returns a triplet (timestamp, from_timezone, to_timezone) parsed from
the query.
- >>> _to("2012-12-23T14:23:03.826437 to pst")
- ('2012-12-23T14:23:03.826437', None, 'pst')
+ >>> _implicit_from("2012-12-23T14:23:03.826437 est")
+ ('2012-12-23T14:23:03.826437', 'est')
+ >>> _implicit_from("Mon Dec 10 23:31:50 EST 2012")
+ ("Mon Dec 10 23:31:50 2012", "EST")
"""
- template = re.compile(r"(.*)to(.*)")
- fromz = None
- matches = template.findall(query)
- if len(matches) == 1:
- match = matches[0]
- ts = match[0].strip()
- toz = match[1].strip()
- return (ts, fromz, toz)
- raise MismatchException()
+ pattern = re.compile(r"^([A-Za-z/]+)$")
+ tokens = query.split(" ")
+ for count, token in enumerate(tokens[::-1]):
+ matches = pattern.findall(token)
+ if len(matches) > 0:
+ fromz = matches[0]
+ if len(fromz) <= 1:
+ continue
+ query = " ".join(tokens[0:len(tokens) - count - 1] +
+ tokens[len(tokens) - count:])
+ return (query.strip(), fromz.strip())
+ return (query.strip(), None)
class MismatchException(Exception):
Please sign in to comment.
Something went wrong with that request. Please try again.