Last active
June 8, 2019 18:57
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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