Skip to content

Instantly share code, notes, and snippets.

@pganssle
Last active June 8, 2019 18:57
Show Gist options
  • Save pganssle/719ab711a082e10cb07455c4cb2385f0 to your computer and use it in GitHub Desktop.
Save pganssle/719ab711a082e10cb07455c4cb2385f0 to your computer and use it in GitHub Desktop.
Demo code written to help @Zac-HD develop improved datetime strategies for Hypothesis.
# Released under MPL 2.0 per https://github.com/HypothesisWorks/hypothesis/blob/master/LICENSE.txt
# and CC-0: https://creativecommons.org/publicdomain/zero/1.0/legalcode
#
# Feel free to contact Paul Ganssle if you'd like this released under other terms.
from datetime import datetime, timedelta, timezone
from dateutil import tz
ZERO = timedelta(0)
def _weird_offset(offset, otype):
weirdnesses = set()
if offset is not None and offset % timedelta(hours=1) != timedelta(0):
weirdnesses.add(f"Non-integer {otype} hours")
if offset % timedelta(minutes=1) != timedelta(0):
weirdnesses.add(f"Non-integer {otype} minutes")
if offset % timedelta(seconds=1) != timedelta(0):
weirdnesses.add(f"Non-integer {otype} seconds")
return weirdnesses
def datetime_weird(dt):
weirdnesses = set()
if tz.datetime_ambiguous(dt):
weirdnesses.add("Ambiguous")
if not tz.datetime_exists(dt):
weirdnesses.add("Imaginary")
weirdnesses |= _weird_offset(dt.utcoffset(), "utcoffset")
weirdnesses |= _weird_offset(dt.dst(), "dst")
tzname = dt.tzname()
if tzname is not None:
if len(tzname) != 3:
weirdnesses.add("tzname length != 3")
if not tzname.isalpha():
weirdnesses.add("Non-alphabetic tzname")
if not tzname.isascii():
weirdnesses.add("Non-ASCII tzname")
return weirdnesses
def transition_occurred(dt1, dt2):
if dt1.utcoffset() != dt2.utcoffset():
return True
if dt1.dst() != dt2.dst():
return True
if dt1.tzname() != dt2.tzname():
return True
return False
NYC = tz.gettz("America/New_York")
def test_transitions():
occurred = [
(datetime(2019, 3, 9, tzinfo=NYC), datetime(2019, 3, 11, tzinfo=NYC)),
(datetime(2019, 11, 2, tzinfo=NYC), datetime(2019, 11, 4, tzinfo=NYC)),
]
for dt1, dt2 in occurred:
assert transition_occurred(dt1, dt2), (dt1, dt2)
didnt_occur = [
(datetime(2019, 3, 1, tzinfo=NYC), datetime(2019, 3, 2, tzinfo=NYC)),
(datetime(2019, 10, 1, tzinfo=NYC), datetime(2019, 10, 30, tzinfo=NYC)),
]
for dt1, dt2 in didnt_occur:
assert not transition_occurred(dt1, dt2), (dt1, dt2)
print("Passed!")
def test_weirdness():
cases = [
(datetime(2019, 11, 3, 1, 30, tzinfo=NYC),
{"Ambiguous"}),
(datetime(2019, 3, 10, 2, 30, tzinfo=NYC),
{"Imaginary"}),
(datetime(1969, 1, 1, tzinfo=tz.gettz("Africa/Monrovia")),
{"Non-integer utcoffset hours", "Non-integer utcoffset minutes"}),
(datetime(2014, 1, 1, tzinfo=tz.gettz("America/Sao_Paulo")),
{"Non-alphabetic tzname"}),
(datetime(2014, 1, 1, tzinfo=tz.gettz("America/Sao_Paulo")),
{"Non-alphabetic tzname"}),
(datetime(2014, 1, 1, tzinfo=tz.gettz("Australia/Sydney")),
{"tzname length != 3"}),
(datetime(2014, 1, 1, tzinfo=timezone(timedelta(hours=1), "🐼")),
{"Non-alphabetic tzname", "tzname length != 3", "Non-ASCII tzname"}),
]
for dt, exp in cases:
act = datetime_weird(dt)
assert act == exp, f"{act} != {exp}"
print("Passed")
print("Test weirdness:")
test_weirdness()
print("Test transitions:")
test_transitions()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment