Files
dualfroz 518ab0a093 fix: make Delorean hashable by defining __hash__
Defining __eq__ without __hash__ sets __hash__ to None in Python 3, so
Delorean instances were unhashable and could not be used in sets or as
dict keys (unlike datetime). Hash on self.epoch, the same value __eq__
compares, so equal instances hash equal.
2026-09-04 09:39:40 +02:00

1262 lines
47 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Testing for Delorean
"""
import unittest
from copy import deepcopy
from datetime import date, datetime, timedelta, timezone, tzinfo
from unittest import mock
from zoneinfo import ZoneInfo
from dateutil.parser import UnknownTimezoneWarning
from dateutil.tz import tzlocal, tzoffset
import delorean
def naive_utcnow():
return datetime.now(timezone.utc).replace(tzinfo=None)
class GenericUTC(tzinfo):
"""GenericUTC"""
ZERO = timedelta(0)
def utcoffset(self, dt):
return self.ZERO
def tzname(self, dt):
return "GenericUTC"
def dst(self, dt):
return self.ZERO
UTC = "UTC"
generic_utc = GenericUTC()
est = naive_utcnow().replace(tzinfo=ZoneInfo("US/Eastern")).tzinfo
class DeloreanTests(unittest.TestCase):
def setUp(self):
self.naive_dt = datetime(2013, 1, 3, 4, 31, 14, 148540)
self.do = delorean.Delorean(datetime=self.naive_dt, timezone="UTC")
def test_date_failure(self):
dt = date(2013, 5, 6)
self.assertRaises(ValueError, delorean.Delorean, dt)
def test_hashable(self):
# Delorean defines __eq__, so it must define __hash__ too, otherwise
# Python 3 makes instances unhashable and unusable in sets/dict keys.
self.assertEqual(hash(self.do), hash(self.do))
self.assertIn(self.do, {self.do})
mapping = {self.do: "value"}
self.assertEqual(mapping[self.do], "value")
def test_hash_consistent_with_equality(self):
# Equal objects (same instant, different timezone) must hash equal.
other = self.do.shift("US/Pacific")
self.assertEqual(self.do, other)
self.assertEqual(hash(self.do), hash(other))
self.assertEqual(len({self.do, other}), 1)
def test_initialize_from_datetime_naive(self):
self.assertRaises(
delorean.DeloreanInvalidTimezone, delorean.Delorean, datetime=self.naive_dt
)
def test_initialize_with_tzinfo_generic(self):
aware_dt_generic = datetime(2013, 1, 3, 4, 31, 14, 148540, tzinfo=generic_utc)
do = delorean.Delorean(datetime=aware_dt_generic)
self.assertTrue(isinstance(do, delorean.Delorean))
def test_initialize_with_tzinfo_zoneinfo(self):
aware_dt_zoneinfo = datetime(2013, 1, 3, 4, 31, 14, 148540, tzinfo=delorean.utc)
do = delorean.Delorean(datetime=aware_dt_zoneinfo)
self.assertTrue(isinstance(do, delorean.Delorean))
def test_initialize_with_invalid_datetime(self):
self.assertRaises(ValueError, delorean.Delorean, "2015-01-01")
def test_initialize_with_naive_datetime_with_zoneinfo_timezone(self):
dt = datetime(2015, 1, 1)
do = delorean.Delorean(dt, timezone=delorean.utc)
dt = dt.replace(tzinfo=timezone.utc)
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, delorean.utc)
def test_initialize_with_naive_datetime_with_dateutil_timezone(self):
dt = datetime(2015, 1, 1)
tz = tzoffset(None, -22500)
do = delorean.Delorean(dt, timezone=tz)
utcoffset = tz.utcoffset(None)
total_seconds = (
utcoffset.microseconds
+ (utcoffset.seconds + utcoffset.days * 24 * 3600) * 10**6
) / 10**6
tz = timezone(timedelta(minutes=total_seconds / 60))
dt = dt.replace(tzinfo=tz)
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, tz)
def test_initialize_with_naive_datetime_with_string_timezone(self):
dt = datetime(2015, 1, 1)
tz_str = "US/Pacific"
tz = ZoneInfo(tz_str)
do = delorean.Delorean(dt, timezone=tz_str)
tz = datetime(2015, 1, 1).replace(tzinfo=tz).tzinfo
dt = dt.replace(tzinfo=tz)
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, tz)
def test_initialize_with_naive_datetime_without_timezone(self):
self.assertRaises(
delorean.DeloreanInvalidTimezone, delorean.Delorean, datetime(2015, 1, 1)
)
def test_initialize_with_datetime_with_timezone(self):
dt = datetime(2015, 1, 1).replace(tzinfo=timezone.utc)
do = delorean.Delorean(dt, timezone=ZoneInfo("US/Pacific"))
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, timezone.utc)
def test_initialize_with_datetime_without_timezone(self):
dt = datetime(2015, 1, 1).replace(tzinfo=timezone.utc)
do = delorean.Delorean(dt)
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, timezone.utc)
@mock.patch("delorean.dates.datetime_timezone")
def test_initialize_without_datetime_with_zoneinfo_timezone(
self, mock_datetime_timezone
):
tz = ZoneInfo("US/Pacific")
dt = datetime(2015, 1, 1).replace(tzinfo=tz)
tz = dt.tzinfo
mock_datetime_timezone.return_value = dt
do = delorean.Delorean(timezone=tz)
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, tz)
@mock.patch("delorean.dates.datetime_timezone")
def test_initialize_without_datetime_with_dateutil_timezone(
self, mock_datetime_timezone
):
tz = tzoffset(None, -22500)
dt = datetime(2015, 1, 1, tzinfo=tz)
utcoffset = tz.utcoffset(None)
total_seconds = (
utcoffset.microseconds
+ (utcoffset.seconds + utcoffset.days * 24 * 3600) * 10**6
) / 10**6
tz = timezone(timedelta(minutes=total_seconds / 60))
dt = dt.astimezone(tz)
mock_datetime_timezone.return_value = dt
do = delorean.Delorean(timezone=tz)
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, tz)
@mock.patch("delorean.dates.datetime_timezone")
def test_initialize_without_datetime_with_string_timezone(
self, mock_datetime_timezone
):
tz_str = "US/Pacific"
tz = ZoneInfo(tz_str)
dt = datetime(2015, 1, 1).replace(tzinfo=tz)
tz = dt.tzinfo
mock_datetime_timezone.return_value = dt
do = delorean.Delorean(timezone=tz_str)
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, tz)
@mock.patch("delorean.dates.datetime_timezone")
def test_initialize_without_datetime_without_timezone(self, mock_datetime_timezone):
dt = datetime(2015, 1, 1).replace(tzinfo=timezone.utc)
mock_datetime_timezone.return_value = dt
do = delorean.Delorean()
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, delorean.utc)
def test_truncation_hour(self):
self.do.truncate("hour")
self.assertEqual(self.do.naive, datetime(2013, 1, 3, 4, 0))
def test_midnight(self):
do = self.do.midnight
self.assertIsInstance(do, delorean.Delorean)
self.assertEqual(
do.datetime, datetime(2013, 1, 3, 0, 0, 0, tzinfo=delorean.utc)
)
def test_start_of_day(self):
do = self.do.start_of_day
self.assertIsInstance(do, delorean.Delorean)
self.assertEqual(
do.datetime, datetime(2013, 1, 3, 0, 0, 0, 0, tzinfo=delorean.utc)
)
def test_end_of_day(self):
do = self.do.end_of_day
self.assertIsInstance(do, delorean.Delorean)
self.assertEqual(
do.datetime, datetime(2013, 1, 3, 23, 59, 59, 999999, tzinfo=delorean.utc)
)
def test_day_boundaries_are_chainable(self):
do = self.do.last_month().end_of_day
self.assertIsInstance(do, delorean.Delorean)
self.assertEqual(
do.datetime, datetime(2012, 12, 3, 23, 59, 59, 999999, tzinfo=delorean.utc)
)
# Still a Delorean, so the chain can continue.
self.assertIsInstance(do.shift("US/Eastern"), delorean.Delorean)
def test_start_of_month(self):
do = delorean.Delorean(datetime(2015, 5, 15, 14, 30), timezone="UTC")
self.assertEqual(
do.start_of_month.datetime, datetime(2015, 5, 1, tzinfo=delorean.utc)
)
def test_end_of_month(self):
do = delorean.Delorean(datetime(2015, 5, 15, 14, 30), timezone="UTC")
self.assertEqual(
do.end_of_month.datetime,
datetime(2015, 5, 31, 23, 59, 59, 999999, tzinfo=delorean.utc),
)
def test_end_of_month_short_month(self):
do = delorean.Delorean(datetime(2015, 2, 15), timezone="UTC")
self.assertEqual(do.end_of_month.datetime.day, 28)
def test_end_of_month_leap_year(self):
do = delorean.Delorean(datetime(2024, 2, 15), timezone="UTC")
self.assertEqual(do.end_of_month.datetime.day, 29)
def test_start_of_year(self):
do = delorean.Delorean(datetime(2015, 5, 15, 14, 30), timezone="UTC")
self.assertEqual(
do.start_of_year.datetime, datetime(2015, 1, 1, tzinfo=delorean.utc)
)
def test_end_of_year(self):
do = delorean.Delorean(datetime(2015, 5, 15, 14, 30), timezone="UTC")
self.assertEqual(
do.end_of_year.datetime,
datetime(2015, 12, 31, 23, 59, 59, 999999, tzinfo=delorean.utc),
)
def test_last_day_of_previous_month(self):
# The use case from issue #85.
do = delorean.Delorean(datetime(2013, 5, 15, 14, 30), timezone="US/Eastern")
end = do.last_month().end_of_month
self.assertIsInstance(end, delorean.Delorean)
self.assertEqual(end.datetime.month, 4)
self.assertEqual(end.datetime.day, 30)
def test_month_and_year_boundaries_do_not_mutate(self):
before = self.do.datetime
self.do.start_of_month
self.do.end_of_month
self.do.start_of_year
self.do.end_of_year
self.assertEqual(self.do.datetime, before)
def test_day_boundaries_do_not_mutate(self):
before = self.do.datetime
self.do.midnight
self.do.start_of_day
self.do.end_of_day
self.assertEqual(self.do.datetime, before)
def test_truncation_second(self):
self.do.truncate("second")
self.assertEqual(self.do.naive, datetime(2013, 1, 3, 4, 31, 14, 0))
def test_truncation_minute(self):
self.do.truncate("minute")
self.assertEqual(self.do.naive, datetime(2013, 1, 3, 4, 31, 0, 0))
def test_truncation_day(self):
self.do.truncate("day")
self.assertEqual(self.do.naive, datetime(2013, 1, 3, 0, 0, 0, 0))
def test_truncation_month(self):
self.do.truncate("month")
self.assertEqual(self.do.naive, datetime(2013, 1, 1, 0, 0, 0, 0))
def test_truncation_year(self):
self.do.truncate("year")
self.assertEqual(self.do.naive, datetime(2013, 1, 1, 0, 0, 0, 0))
def test_date(self):
self.assertEqual(self.do.date, date(2013, 1, 3))
def test_datetime(self):
self.assertEqual(self.do.naive, datetime(2013, 1, 3, 4, 31, 14, 148540))
def test_naive(self):
dt1 = delorean.Delorean()
dt_naive = dt1.naive
self.assertEqual(dt_naive.tzinfo, None)
def test_naive_timezone(self):
dt1 = delorean.Delorean(timezone="US/Eastern").truncate("minute").naive
dt2 = delorean.Delorean().truncate("minute").naive
self.assertEqual(dt2, dt1)
self.assertEqual(dt1.tzinfo, None)
def test_localize(self):
dt = datetime.today()
dt = delorean.localize(dt, "UTC")
self.assertEqual(dt.tzinfo, delorean.utc)
def test_failure_truncation(self):
self.assertRaises(ValueError, self.do.truncate, "century")
def test_normalize(self):
dt1 = delorean.Delorean()
dt2 = delorean.Delorean(timezone="US/Eastern")
dt1.truncate("minute")
dt2.truncate("minute")
dt_normalized = delorean.normalize(dt1.datetime, "US/Eastern")
self.assertEqual(dt2.datetime, dt_normalized)
def test_normalize_failure(self):
naive_datetime = datetime.today()
self.assertRaises(ValueError, delorean.normalize, naive_datetime, "US/Eastern")
def test_localize_failure(self):
dt1 = delorean.localize(naive_utcnow(), "UTC")
self.assertRaises(ValueError, delorean.localize, dt1, "UTC")
def test_timezone(self):
do_timezone = delorean.Delorean().timezone
self.assertEqual(delorean.utc, do_timezone)
def test_datetime_timezone_default(self):
do = delorean.Delorean()
do.truncate("minute")
dt1 = delorean.datetime_timezone(UTC)
self.assertEqual(dt1.replace(second=0, microsecond=0), do.datetime)
def test_datetime_timezone(self):
do = delorean.Delorean(timezone="US/Eastern")
do.truncate("minute")
dt1 = delorean.datetime_timezone(tz="US/Eastern")
self.assertEqual(dt1.replace(second=0, microsecond=0), do.datetime)
def test_parse(self):
with self.assertWarns(UnknownTimezoneWarning):
do = delorean.parse("Thu Sep 25 10:36:28 BRST 2003")
dt1 = datetime(2003, 9, 25, 10, 36, 28).replace(tzinfo=timezone.utc)
self.assertEqual(do.datetime, dt1)
def test_parse_iso(self):
do = delorean.parse("2017-05-02T05:38:49Z")
dt1 = datetime(2017, 5, 2, 5, 38, 49).replace(tzinfo=timezone.utc)
self.assertEqual(do.datetime, dt1)
def test_parse_default(self):
do = delorean.parse("2016-07-01T11:00:00+02:00", dayfirst=False)
dt1 = delorean.Delorean(
datetime=datetime(2016, 7, 1, 11, 0),
timezone=timezone(timedelta(minutes=120)),
)
self.assertEqual(do.datetime, dt1.datetime)
def test_parse_with_invalid_datetime_string(self):
self.assertRaises(ValueError, delorean.parse, "asd")
def test_parse_timezone_less_string_assumes_utc_by_default(self):
do = delorean.parse("2015-02-04T16:33:21.247513")
self.assertEqual(
do.datetime,
datetime(2015, 2, 4, 16, 33, 21, 247513, tzinfo=delorean.utc),
)
def test_parse_timezone_less_string_can_require_assumption(self):
with self.assertRaisesRegex(
delorean.DeloreanInvalidDatetime, "assume_timezone"
):
delorean.parse(
"2015-02-04T16:33:21.247513",
assume_timezone=None,
)
def test_parse_with_assumed_utc_timezone(self):
do = delorean.parse("2015-02-04T16:33:21.247513", assume_timezone="UTC")
self.assertIsInstance(do, delorean.Delorean)
self.assertEqual(
do.datetime,
datetime(2015, 2, 4, 16, 33, 21, 247513, tzinfo=delorean.utc),
)
def test_parse_with_assumed_non_utc_timezone(self):
do = delorean.parse(
"2015-02-04T16:33:21.247513",
assume_timezone="America/Toronto",
)
expected = datetime(2015, 2, 4, 16, 33, 21, 247513).replace(
tzinfo=ZoneInfo("America/Toronto")
)
self.assertIsInstance(do, delorean.Delorean)
self.assertEqual(do.datetime, expected)
def test_parse_with_assumed_timezone_object(self):
timezone = ZoneInfo("America/Toronto")
do = delorean.parse(
"2015-02-04T16:33:21.247513",
assume_timezone=timezone,
)
expected = datetime(2015, 2, 4, 16, 33, 21, 247513).replace(tzinfo=timezone)
self.assertEqual(do.datetime, expected)
def test_parse_does_not_apply_assumed_timezone_to_aware_string(self):
do = delorean.parse(
"2015-02-04T16:33:21.247513-05:00",
assume_timezone="US/Pacific",
)
self.assertEqual(do.timezone, timezone(timedelta(minutes=-300)))
def test_parse_timezone_override_takes_precedence_over_assumption(self):
do = delorean.parse(
"2015-02-04T16:33:21.247513-05:00",
timezone="US/Pacific",
assume_timezone="UTC",
)
expected = datetime(2015, 2, 4, 16, 33, 21, 247513).replace(
tzinfo=ZoneInfo("US/Pacific")
)
self.assertEqual(do.datetime, expected)
def test_parse_timezone_override_applies_to_timezone_less_string(self):
do = delorean.parse(
"2015-02-04T16:33:21.247513",
timezone="US/Pacific",
assume_timezone=None,
)
expected = datetime(2015, 2, 4, 16, 33, 21, 247513).replace(
tzinfo=ZoneInfo("US/Pacific")
)
self.assertEqual(do.datetime, expected)
def test_parse_does_not_apply_assumed_timezone_to_utc_designator(self):
do = delorean.parse("2013-09-30T15:34:00.000Z", assume_timezone="US/Pacific")
self.assertEqual(
do.datetime, datetime(2013, 9, 30, 15, 34).replace(tzinfo=timezone.utc)
)
def test_parse_with_assumed_zoneinfo_timezone(self):
tz = ZoneInfo("America/Toronto")
do = delorean.parse("2015-02-04T16:33:21.247513", assume_timezone=tz)
self.assertEqual(
do.datetime,
datetime(2015, 2, 4, 16, 33, 21, 247513, tzinfo=tz),
)
def test_parse_with_assumed_timezone_resolves_nonexistent_local_time(self):
do = delorean.parse("2013-03-10T02:30:00", assume_timezone="US/Eastern")
self.assertEqual(do.datetime.tzname(), "EST")
def test_parse_with_assumed_timezone_takes_the_first_ambiguous_occurrence(self):
do = delorean.parse("2013-11-03T01:30:00", assume_timezone="US/Eastern")
self.assertEqual(do.datetime.tzname(), "EDT")
def test_parse_strict_error_is_a_value_error(self):
with self.assertRaises(ValueError):
delorean.parse("2015-02-04T16:33:21.247513", assume_timezone=None)
def test_parse_with_utc_year_fill(self):
do = delorean.parse("Thu Sep 25 10:36:28")
dt1 = datetime(date.today().year, 9, 25, 10, 36, 28, tzinfo=delorean.utc)
self.assertEqual(do.datetime, dt1)
def test_parse_with_assumed_timezone_year_fill(self):
do = delorean.parse("Thu Sep 25 10:36:28", assume_timezone="UTC")
dt1 = datetime(date.today().year, 9, 25, 10, 36, 28, tzinfo=delorean.utc)
self.assertEqual(do.datetime, dt1)
self.assertEqual(do.timezone.tzname(None), "UTC")
def test_parse_with_fixed_offset_timezone(self):
tz = timezone(timedelta(minutes=-480))
dt = datetime(2015, 1, 1).replace(tzinfo=tz)
dt_str = dt.strftime("%Y-%m-%d %H:%M:%S %z")
do = delorean.parse(dt_str)
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, tz)
@mock.patch("delorean.interface.get_localzone")
def test_parse_with_tzlocal_timezone(self, mock_get_local_zone):
tz = ZoneInfo("US/Eastern")
mock_get_local_zone.return_value = tz
dt = datetime(2015, 1, 1, tzinfo=tzlocal())
dt_str = dt.strftime("%Y-%m-%d %H:%M:%S %Z")
dt = dt.replace(tzinfo=None)
dt = dt.replace(tzinfo=tz)
tz = dt.tzinfo
do = delorean.parse(dt_str)
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, tz)
@mock.patch("delorean.interface.get_localzone")
def test_parse_with_tzutc_timezone(self, mock_get_localzone):
mock_get_localzone.return_value = delorean.utc
dt = datetime(2015, 1, 1).replace(tzinfo=timezone.utc)
dt_str = dt.strftime("%Y-%m-%d %H:%M:%S %Z")
do = delorean.parse(dt_str)
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, delorean.utc)
def test_parse_with_timezone_parameter(self):
tz = ZoneInfo("US/Pacific")
dt = datetime(2015, 1, 1).replace(tzinfo=tz)
tz = dt.tzinfo
dt_str = dt.strftime("%Y-%m-%d %H:%M:%S")
do = delorean.parse(dt_str, timezone="US/Pacific")
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, tz)
def test_parse_with_overriding_timezone_parameter(self):
tz = ZoneInfo("US/Pacific")
dt = datetime(2015, 1, 1).replace(tzinfo=tz)
tz = dt.tzinfo
dt_str = dt.strftime("%Y-%m-%d %H:%M:%S -0500")
do = delorean.parse(dt_str, timezone="US/Pacific")
self.assertEqual(do.datetime, dt)
self.assertEqual(do.timezone, tz)
def test_move_namedday(self):
dt_next = datetime(2013, 1, 4, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_next_2 = datetime(2013, 1, 11, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_last = datetime(2012, 12, 28, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_last_2 = datetime(2012, 12, 21, 4, 31, 14, 148540, tzinfo=delorean.utc)
d_obj_next = self.do.next_friday()
d_obj_next_2 = self.do.next_friday(2)
d_obj_last = self.do.last_friday()
d_obj_last_2 = self.do.last_friday(2)
self.assertEqual(dt_next, d_obj_next.datetime)
self.assertEqual(dt_last, d_obj_last.datetime)
self.assertEqual(dt_next_2, d_obj_next_2.datetime)
self.assertEqual(dt_last_2, d_obj_last_2.datetime)
def test_move_namedday_function(self):
dt_next = datetime(2013, 1, 4, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_last = datetime(2012, 12, 28, 4, 31, 14, 148540, tzinfo=delorean.utc)
d_obj_next = delorean.move_datetime_namedday(self.do.datetime, "next", "friday")
d_obj_last = delorean.move_datetime_namedday(self.do.datetime, "last", "friday")
self.assertEqual(dt_next, d_obj_next)
self.assertEqual(dt_last, d_obj_last)
def test_move_week(self):
dt_next = datetime(2013, 1, 10, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_next_2 = datetime(2013, 1, 17, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_last = datetime(2012, 12, 27, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_last_2 = datetime(2012, 12, 20, 4, 31, 14, 148540, tzinfo=delorean.utc)
d_obj_next = self.do.next_week()
d_obj_next_2 = self.do.next_week(2)
d_obj_last = self.do.last_week()
d_obj_last_2 = self.do.last_week(2)
self.assertEqual(dt_next, d_obj_next.datetime)
self.assertEqual(dt_last, d_obj_last.datetime)
self.assertEqual(dt_next_2, d_obj_next_2.datetime)
self.assertEqual(dt_last_2, d_obj_last_2.datetime)
def test_move_week_function(self):
dt_next = datetime(2013, 1, 10, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_last = datetime(2012, 12, 27, 4, 31, 14, 148540, tzinfo=delorean.utc)
d_obj_next = delorean.move_datetime_week(self.do.datetime, "next", 1)
d_obj_last = delorean.move_datetime_week(self.do.datetime, "last", 1)
self.assertEqual(dt_next, d_obj_next)
self.assertEqual(dt_last, d_obj_last)
def test_move_month(self):
dt_next = datetime(2013, 2, 3, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_next_2 = datetime(2013, 3, 3, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_last = datetime(2012, 12, 3, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_last_2 = datetime(2012, 11, 3, 4, 31, 14, 148540, tzinfo=delorean.utc)
d_obj_next = self.do.next_month()
d_obj_next_2 = self.do.next_month(2)
d_obj_last = self.do.last_month()
d_obj_last_2 = self.do.last_month(2)
self.assertEqual(dt_next, d_obj_next.datetime)
self.assertEqual(dt_last, d_obj_last.datetime)
self.assertEqual(dt_next_2, d_obj_next_2.datetime)
self.assertEqual(dt_last_2, d_obj_last_2.datetime)
def test_move_month_function(self):
dt_next = datetime(2013, 2, 3, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_last = datetime(2012, 12, 3, 4, 31, 14, 148540, tzinfo=delorean.utc)
d_obj_next = delorean.move_datetime_month(self.do.datetime, "next", 1)
d_obj_last = delorean.move_datetime_month(self.do.datetime, "last", 1)
self.assertEqual(dt_next, d_obj_next)
self.assertEqual(dt_last, d_obj_last)
def test_move_day_function(self):
dt_next = datetime(2013, 1, 4, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_last = datetime(2013, 1, 2, 4, 31, 14, 148540, tzinfo=delorean.utc)
d_obj_next = delorean.move_datetime_day(self.do.datetime, "next", 1)
d_obj_last = delorean.move_datetime_day(self.do.datetime, "last", 1)
self.assertEqual(dt_next, d_obj_next)
self.assertEqual(dt_last, d_obj_last)
def test_move_year(self):
dt_next = datetime(2014, 1, 3, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_next_2 = datetime(2015, 1, 3, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_last = datetime(2012, 1, 3, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_last_2 = datetime(2011, 1, 3, 4, 31, 14, 148540, tzinfo=delorean.utc)
d_obj_next = self.do.next_year()
d_obj_next_2 = self.do.next_year(2)
d_obj_last = self.do.last_year()
d_obj_last_2 = self.do.last_year(2)
self.assertEqual(dt_next, d_obj_next.datetime)
self.assertEqual(dt_last, d_obj_last.datetime)
self.assertEqual(dt_next_2, d_obj_next_2.datetime)
self.assertEqual(dt_last_2, d_obj_last_2.datetime)
def test_move_year_function(self):
dt_next = datetime(2014, 1, 3, 4, 31, 14, 148540, tzinfo=delorean.utc)
dt_last = datetime(2012, 1, 3, 4, 31, 14, 148540, tzinfo=delorean.utc)
d_obj_next = delorean.move_datetime_year(self.do.datetime, "next", 1)
d_obj_last = delorean.move_datetime_year(self.do.datetime, "last", 1)
self.assertEqual(dt_next, d_obj_next)
self.assertEqual(dt_last, d_obj_last)
def test_move_hour(self):
dt_next = datetime(2013, 1, 3, 5, 31, 14, 148540, tzinfo=delorean.utc)
dt_next_2 = datetime(2013, 1, 3, 6, 31, 14, 148540, tzinfo=delorean.utc)
dt_last = datetime(2013, 1, 3, 3, 31, 14, 148540, tzinfo=delorean.utc)
dt_last_2 = datetime(2013, 1, 3, 2, 31, 14, 148540, tzinfo=delorean.utc)
d_obj_next = self.do.next_hour()
d_obj_next_2 = self.do.next_hour(2)
d_obj_last = self.do.last_hour()
d_obj_last_2 = self.do.last_hour(2)
self.assertEqual(dt_next, d_obj_next.datetime)
self.assertEqual(dt_last, d_obj_last.datetime)
self.assertEqual(dt_next_2, d_obj_next_2.datetime)
self.assertEqual(dt_last_2, d_obj_last_2.datetime)
def test_move_hour_function(self):
dt_next = datetime(2013, 1, 3, 5, 31, 14, 148540, tzinfo=delorean.utc)
dt_last = datetime(2013, 1, 3, 3, 31, 14, 148540, tzinfo=delorean.utc)
d_obj_next = delorean.move_datetime_hour(self.do.datetime, "next", 1)
d_obj_last = delorean.move_datetime_hour(self.do.datetime, "last", 1)
self.assertEqual(dt_next, d_obj_next)
self.assertEqual(dt_last, d_obj_last)
def test_move_minute(self):
dt_next = datetime(2013, 1, 3, 4, 32, 14, 148540, tzinfo=delorean.utc)
dt_next_2 = datetime(2013, 1, 3, 4, 33, 14, 148540, tzinfo=delorean.utc)
dt_last = datetime(2013, 1, 3, 4, 30, 14, 148540, tzinfo=delorean.utc)
dt_last_2 = datetime(2013, 1, 3, 4, 29, 14, 148540, tzinfo=delorean.utc)
d_obj_next = self.do.next_minute()
d_obj_next_2 = self.do.next_minute(2)
d_obj_last = self.do.last_minute()
d_obj_last_2 = self.do.last_minute(2)
self.assertEqual(dt_next, d_obj_next.datetime)
self.assertEqual(dt_last, d_obj_last.datetime)
self.assertEqual(dt_next_2, d_obj_next_2.datetime)
self.assertEqual(dt_last_2, d_obj_last_2.datetime)
def test_move_minute_function(self):
dt_next = datetime(2013, 1, 3, 4, 32, 14, 148540, tzinfo=delorean.utc)
dt_last = datetime(2013, 1, 3, 4, 30, 14, 148540, tzinfo=delorean.utc)
d_obj_next = delorean.move_datetime_minute(self.do.datetime, "next", 1)
d_obj_last = delorean.move_datetime_minute(self.do.datetime, "last", 1)
self.assertEqual(dt_next, d_obj_next)
self.assertEqual(dt_last, d_obj_last)
def test_move_second(self):
dt_next = datetime(2013, 1, 3, 4, 31, 15, 148540, tzinfo=delorean.utc)
dt_next_2 = datetime(2013, 1, 3, 4, 31, 16, 148540, tzinfo=delorean.utc)
dt_last = datetime(2013, 1, 3, 4, 31, 13, 148540, tzinfo=delorean.utc)
dt_last_2 = datetime(2013, 1, 3, 4, 31, 12, 148540, tzinfo=delorean.utc)
d_obj_next = self.do.next_second()
d_obj_next_2 = self.do.next_second(2)
d_obj_last = self.do.last_second()
d_obj_last_2 = self.do.last_second(2)
self.assertEqual(dt_next, d_obj_next.datetime)
self.assertEqual(dt_last, d_obj_last.datetime)
self.assertEqual(dt_next_2, d_obj_next_2.datetime)
self.assertEqual(dt_last_2, d_obj_last_2.datetime)
def test_move_fractional_seconds(self):
expected_datetimes = {
("next_second", 0.5): datetime(
2013, 1, 3, 4, 31, 14, 648540, tzinfo=delorean.utc
),
("next_second", 1.5): datetime(
2013, 1, 3, 4, 31, 15, 648540, tzinfo=delorean.utc
),
("last_second", 0.5): datetime(
2013, 1, 3, 4, 31, 13, 648540, tzinfo=delorean.utc
),
("last_second", 1.5): datetime(
2013, 1, 3, 4, 31, 12, 648540, tzinfo=delorean.utc
),
}
for (method_name, seconds), expected in expected_datetimes.items():
with self.subTest(method_name=method_name, seconds=seconds):
shifted = getattr(self.do, method_name)(seconds)
self.assertEqual(expected, shifted.datetime)
def test_fractional_shifts_are_rejected_for_non_second_units(self):
non_second_units = set(self.do._VALID_SHIFT_UNITS) - {"second"}
for direction in self.do._VALID_SHIFT_DIRECTIONS:
for unit in non_second_units:
with self.subTest(direction=direction, unit=unit):
shift = getattr(self.do, f"{direction}_{unit}")
with self.assertRaisesRegex(TypeError, "integer"):
shift(0.5)
def test_move_second_function(self):
dt_next = datetime(2013, 1, 3, 4, 31, 15, 148540, tzinfo=delorean.utc)
dt_last = datetime(2013, 1, 3, 4, 31, 13, 148540, tzinfo=delorean.utc)
d_obj_next = delorean.move_datetime_second(self.do.datetime, "next", 1)
d_obj_last = delorean.move_datetime_second(self.do.datetime, "last", 1)
self.assertEqual(dt_next, d_obj_next)
self.assertEqual(dt_last, d_obj_last)
def test_range_count(self):
"""
tests the range method with count used
"""
count = list(delorean.stops(delorean.DAILY, count=5))
self.assertEqual(len(count), 5)
def test_range_with_start(self):
dates1 = []
for do in delorean.stops(delorean.DAILY, count=5, start=naive_utcnow()):
do.truncate("minute")
dates1.append(do)
do = delorean.Delorean().truncate("minute")
dates2 = []
for x in range(5):
dates2.append(do.next_day(x))
self.assertEqual(dates1, dates2)
def test_range_with_start_and_stop(self):
dates1 = []
tomorrow = naive_utcnow() + timedelta(days=1)
for do in delorean.stops(delorean.DAILY, start=naive_utcnow(), stop=tomorrow):
do.truncate("minute")
dates1.append(do)
do = delorean.Delorean().truncate("minute")
dates2 = []
for x in range(2):
dates2.append(do.next_day(x))
self.assertEqual(dates1, dates2)
def test_range_with_interval(self):
dates1 = []
for do in delorean.stops(
delorean.DAILY, interval=2, count=3, start=naive_utcnow()
):
do.truncate("minute")
dates1.append(do)
do = delorean.Delorean().truncate("minute")
dates2 = []
for x in range(6):
if (x % 2) == 0:
dates2.append(do.next_day(x))
self.assertEqual(dates1, dates2)
def test_delorean_with_datetime(self):
dt = naive_utcnow()
d = delorean.Delorean(datetime=dt, timezone=UTC)
dt = dt.replace(tzinfo=timezone.utc)
self.assertEqual(dt, d._dt)
self.assertEqual(delorean.utc, d.timezone)
def test_delorean_with_timezone(self):
dt = naive_utcnow()
d = delorean.Delorean(datetime=dt, timezone=UTC)
d = d.shift("US/Eastern")
dt = dt.replace(tzinfo=timezone.utc).astimezone(est)
dt = dt.astimezone(est)
self.assertEqual(dt, d.datetime)
self.assertEqual(est, d.timezone)
def test_delorean_with_only_timezone(self):
dt = naive_utcnow()
dt = dt.replace(tzinfo=timezone.utc)
dt = dt.astimezone(est)
dt = dt.replace(second=0, microsecond=0)
d = delorean.Delorean(timezone="US/Eastern")
d.truncate("minute")
self.assertEqual(est, d.timezone)
self.assertEqual(dt, d._dt)
def test_shift_failure(self):
self.assertRaises(
delorean.DeloreanInvalidTimezone, self.do.shift, "US/Westerrn"
)
def test_invalid_shift_unit_raises(self):
self.assertRaises(AttributeError, getattr, self.do, "next_bogus")
def test_invalid_shift_direction_raises(self):
self.assertRaises(AttributeError, getattr, self.do, "sideways_day")
def test_invalid_shift_name_is_not_reported_by_hasattr(self):
self.assertFalse(hasattr(self.do, "next_bogus"))
def test_shift_across_dst_keeps_wall_clock(self):
eastern = ZoneInfo("US/Eastern")
do = delorean.Delorean(datetime(2013, 3, 9, 7, 0).replace(tzinfo=eastern))
shifted = do.next_day().datetime
self.assertEqual(shifted.strftime("%Y-%m-%d %H:%M"), "2013-03-10 07:00")
self.assertEqual(shifted.tzname(), "EDT")
def test_shift_into_nonexistent_local_time_resolves_to_standard(self):
# Eastern clocks jump 02:00 EST -> 03:00 EDT on 2013-03-10, so 02:30
# has no local reading at all that day.
eastern = ZoneInfo("US/Eastern")
do = delorean.Delorean(datetime(2013, 3, 9, 2, 30).replace(tzinfo=eastern))
shifted = do.next_day().datetime
self.assertEqual(shifted.strftime("%Y-%m-%d %H:%M"), "2013-03-10 02:30")
self.assertEqual(shifted.tzname(), "EST")
self.assertEqual(shifted.astimezone(delorean.utc).strftime("%H:%M"), "07:30")
def test_shift_into_ambiguous_local_time_takes_the_first_occurrence(self):
# 01:30 happens twice on 2013-11-03, first as EDT and then as EST.
eastern = ZoneInfo("US/Eastern")
do = delorean.Delorean(datetime(2013, 11, 2, 1, 30).replace(tzinfo=eastern))
shifted = do.next_day().datetime
self.assertEqual(shifted.strftime("%Y-%m-%d %H:%M"), "2013-11-03 01:30")
self.assertEqual(shifted.tzname(), "EDT")
def test_localize_nonexistent_local_time_resolves_to_standard(self):
dt = delorean.localize(datetime(2013, 3, 10, 2, 30), "US/Eastern")
self.assertEqual(dt.tzname(), "EST")
def test_localize_ambiguous_local_time_takes_the_first_occurrence(self):
dt = delorean.localize(datetime(2013, 11, 3, 1, 30), "US/Eastern")
self.assertEqual(dt.tzname(), "EDT")
def test_localize_with_zoneinfo_timezone(self):
tz = ZoneInfo("US/Eastern")
dt = delorean.localize(datetime(2013, 1, 1, 12), tz)
self.assertEqual(dt, datetime(2013, 1, 1, 12, tzinfo=tz))
def test_normalize_with_zoneinfo_timezone(self):
tz = ZoneInfo("US/Eastern")
dt = delorean.normalize(
datetime(2013, 1, 1, 12).replace(tzinfo=timezone.utc), tz
)
self.assertEqual(dt, datetime(2013, 1, 1, 7, tzinfo=tz))
def test_now_with_zoneinfo_local_timezone(self):
# tzlocal 5.x hands back a zoneinfo zone rather than a pytz one.
tz = ZoneInfo("America/Toronto")
with mock.patch("delorean.interface.get_localzone", return_value=tz):
do = delorean.now()
self.assertEqual(do.timezone, tz)
def test_datetime_localization(self):
dt1 = self.do.datetime
dt2 = delorean.Delorean(dt1).datetime
self.assertEqual(dt1, dt2)
def test_localize_datetime(self):
dt = naive_utcnow()
tz = ZoneInfo("US/Pacific")
dt = dt.replace(tzinfo=tz)
d = delorean.Delorean(dt)
d2 = d.shift("US/Pacific")
self.assertEqual(str(d.timezone), "US/Pacific")
self.assertEqual(d.datetime, dt)
self.assertEqual(d.datetime, d2.datetime)
def test_lt(self):
dt1 = self.do
dt2 = delorean.Delorean()
self.assertTrue(dt1 < dt2)
def test_gt(self):
dt1 = self.do
dt2 = delorean.Delorean()
self.assertTrue(dt2 > dt1)
def test_ge(self):
dt = naive_utcnow()
dt1 = delorean.Delorean(dt, timezone="UTC")
dt2 = delorean.Delorean(dt, timezone="UTC")
dt3 = self.do
self.assertTrue(dt2 >= dt1)
self.assertTrue(dt1 >= dt3)
def test_le(self):
dt = naive_utcnow()
dt1 = delorean.Delorean(dt, timezone="UTC")
dt2 = delorean.Delorean(dt, timezone="UTC")
dt3 = self.do
self.assertTrue(dt2 <= dt1)
self.assertTrue(dt3 <= dt2)
def test_timestamp(self):
self.assertEqual(self.do.timestamp, 1357187474.148540)
def test_timestamp_matches_stdlib(self):
self.assertEqual(self.do.timestamp, self.do.datetime.timestamp())
def test_from_timestamp(self):
do = delorean.from_timestamp(1357187474.148540)
self.assertEqual(self.do, do)
def test_from_timestamp_round_trips(self):
self.assertEqual(delorean.from_timestamp(self.do.timestamp), self.do)
def test_epoch_is_alias_of_timestamp(self):
self.assertEqual(self.do.epoch, self.do.timestamp)
def test_epoch_creation_is_alias_of_from_timestamp(self):
self.assertEqual(
delorean.epoch(1357187474.148540),
delorean.from_timestamp(1357187474.148540),
)
def test_not_equal(self):
d = delorean.Delorean()
self.assertNotEqual(d, None)
def test_equal(self):
d1 = delorean.Delorean()
d2 = deepcopy(d1)
self.assertEqual(d1, d2)
self.assertFalse(d1 != d2, "Overloaded __ne__ is not correct")
d1 = delorean.Delorean(datetime(2015, 1, 1), timezone="US/Pacific")
d2 = delorean.Delorean(datetime(2015, 1, 1, 8), timezone="UTC")
self.assertEqual(d1, d2)
def test_repr_string_timezone(self):
import datetime
from delorean import Delorean
d1 = Delorean(datetime.datetime(2015, 1, 1), timezone="US/Pacific")
d2 = eval(repr(d1))
self.assertEqual(d1, d2)
d3 = Delorean(d1.datetime, timezone="UTC")
d4 = eval(repr(d3))
self.assertEqual(d1, d4)
def test_repr_named_timezone(self):
import datetime
from delorean import Delorean
d1 = Delorean(datetime.datetime(2015, 1, 1), timezone="US/Pacific")
d2 = eval(repr(d1))
self.assertEqual(d1, d2)
self.assertEqual(d1.datetime, d2.datetime)
self.assertEqual(d1.timezone, d2.timezone)
def test_repr_fixed_offset_timezone(self):
import datetime
# Resolved by the eval(repr(...)) below, so static analysis sees no use.
from delorean import Delorean # noqa: F401
tz = ZoneInfo("US/Pacific")
dt = datetime.datetime(2015, 1, 1).replace(tzinfo=tz)
dt_str = dt.strftime("%Y-%m-%d %H:%M:%S %z")
d1 = delorean.parse(dt_str)
d2 = eval(repr(d1))
self.assertEqual(d1, d2)
self.assertEqual(d1.datetime, d2.datetime)
self.assertEqual(d1.timezone, d2.timezone)
def test_repr_zoneinfo_timezone(self):
d = delorean.Delorean(
datetime(2015, 1, 1), timezone=ZoneInfo("America/Toronto")
)
self.assertEqual(
repr(d),
"Delorean(datetime=datetime.datetime(2015, 1, 1, 0, 0), "
"timezone='America/Toronto')",
)
def test_timezone_delorean_to_datetime_to_delorean_utc(self):
d1 = delorean.Delorean()
d2 = delorean.Delorean(d1.datetime)
# these deloreans should be the same
self.assertEqual(d1.next_day(1), d2.next_day(1))
self.assertEqual(d2.last_week(), d2.last_week())
self.assertEqual(d1.timezone, d2.timezone)
self.assertEqual(d1, d2)
def test_timezone_delorean_to_datetime_to_delorean_non_utc(self):
"""Test if when you create Delorean object from Delorean's datetime
it still behaves the same
"""
d1 = delorean.Delorean(timezone="America/Chicago")
d2 = delorean.Delorean(d1.datetime)
# these deloreans should be the same
self.assertEqual(d1.next_day(1), d2.next_day(1))
self.assertEqual(d2.last_week(), d2.last_week())
self.assertEqual(d1.timezone, d2.timezone)
self.assertEqual(d1, d2)
def test_stops_bymonth(self):
"""Test if create stops, checks bymonth, bymonthday, count
and start parameters work properly
"""
days = list(
delorean.interface.stops(
delorean.MONTHLY,
bymonth=(1, 4, 7, 10),
bymonthday=15,
count=4,
start=datetime(datetime.now().year, 1, 1),
)
)
year = datetime.now().year
day = 15
dt1 = datetime(year, 1, day)
dt4 = datetime(year, 4, day)
dt7 = datetime(year, 7, day)
dt10 = datetime(year, 10, day)
self.assertTrue(len(days) == 4)
dl1 = delorean.Delorean(datetime=dt1, timezone="UTC")
self.assertEqual(days[0], dl1)
dl4 = delorean.Delorean(datetime=dt4, timezone="UTC")
self.assertEqual(days[1], dl4)
dl7 = delorean.Delorean(datetime=dt7, timezone="UTC")
self.assertEqual(days[2], dl7)
dl10 = delorean.Delorean(datetime=dt10, timezone="UTC")
self.assertEqual(days[3], dl10)
def test_timedelta_arithmetic(self):
hour = timedelta(hours=1)
d = delorean.parse("2014/06/02 10:00:00 -0700")
hour_before = delorean.parse("2014/06/02 09:00:00 -0700")
hour_after = delorean.parse("2014/06/02 11:00:00 -0700")
self.assertEqual(d + hour, hour_after)
self.assertEqual(d - hour, hour_before)
self.assertEqual(hour_after - d, hour)
@mock.patch("delorean.Delorean.now")
def test_humanize_past(self, mock_now):
mock_now.return_value = delorean.Delorean(
datetime(2015, 1, 2), timezone="US/Pacific"
)
do = delorean.Delorean(datetime(2015, 1, 1), timezone="US/Pacific")
self.assertEqual(do.humanize(), "a day ago")
@mock.patch("delorean.Delorean.now")
def test_humanize_future(self, mock_now):
mock_now.return_value = delorean.Delorean(
datetime(2014, 12, 31), timezone="US/Pacific"
)
do = delorean.Delorean(datetime(2015, 1, 1), timezone="US/Pacific")
self.assertEqual(do.humanize(), "a day from now")
def test_replace(self):
do = delorean.Delorean(datetime(2015, 1, 1), timezone="US/Pacific")
dt = do.datetime
# Check if parts are okay
self.assertEqual(do.replace(hour=8).datetime.hour, 8)
self.assertEqual(do.replace(minute=23).datetime.minute, 23)
self.assertEqual(do.replace(second=45).datetime.second, 45)
# Asserts on datetimes
self.assertEqual(do.replace(hour=8).datetime, dt.replace(hour=8))
self.assertEqual(do.replace(minute=38).datetime, dt.replace(minute=38))
self.assertEqual(do.replace(second=48).datetime, dt.replace(second=48))
# Test that the timezone does not change
self.assertEqual(do.replace(second=45).timezone, do.timezone)
# Test the datetime
eight_hours_late = dt + timedelta(hours=8)
self.assertEqual(do.replace(hour=8).datetime, eight_hours_late)
class StdlibTimezoneTests(unittest.TestCase):
"""The 2.0 timezone surface: standard library types, no pytz anywhere."""
def test_utc_constant_is_exported(self):
self.assertEqual(delorean.utc, ZoneInfo("UTC"))
def test_timezone_helper_returns_a_named_zone(self):
self.assertEqual(delorean.timezone("US/Eastern"), ZoneInfo("US/Eastern"))
def test_timezone_helper_understands_an_offset_string(self):
self.assertEqual(
delorean.timezone("UTC-08:00").utcoffset(None), timedelta(hours=-8)
)
def test_timezone_helper_understands_a_positive_offset_string(self):
self.assertEqual(
delorean.timezone("UTC+05:30").utcoffset(None),
timedelta(hours=5, minutes=30),
)
def test_timezone_helper_passes_a_tzinfo_through(self):
tz = ZoneInfo("US/Eastern")
self.assertIs(delorean.timezone(tz), tz)
def test_timezone_helper_rejects_an_unknown_name(self):
with self.assertRaises(delorean.DeloreanInvalidTimezone):
delorean.timezone("Not/AZone")
def test_error_base_class_is_exported(self):
self.assertTrue(issubclass(delorean.DeloreanError, ValueError))
def test_named_zone_is_a_zoneinfo(self):
do = delorean.Delorean(datetime(2013, 1, 15, 12), timezone="US/Eastern")
self.assertIsInstance(do.timezone, ZoneInfo)
def test_parsed_offset_is_a_stdlib_timezone(self):
do = delorean.parse("2015-01-01 00:01:02 -0800")
self.assertIsInstance(do.timezone, timezone)
def test_no_third_party_timezone_types_escape(self):
values = [
delorean.Delorean(datetime(2013, 1, 15, 12), timezone="US/Eastern"),
delorean.parse("2015-01-01 00:01:02 -0800"),
delorean.parse("2013-09-30T15:34:00.000Z"),
delorean.utcnow(),
]
for do in values:
with self.subTest(value=repr(do)):
self.assertIn(type(do.timezone).__module__, ("zoneinfo", "datetime"))
def test_constructor_accepts_an_offset_string(self):
do = delorean.Delorean(datetime(2015, 1, 1), timezone="UTC-08:00")
self.assertEqual(do.datetime.utcoffset(), timedelta(hours=-8))
def test_repr_prints_an_offset_as_a_string(self):
do = delorean.parse("2015-01-01 00:01:02 -0800")
self.assertIn("timezone='UTC-08:00'", repr(do))
def test_repr_prints_a_named_zone_as_its_key(self):
do = delorean.Delorean(datetime(2013, 1, 15, 12), timezone="US/Eastern")
self.assertIn("timezone='US/Eastern'", repr(do))
def test_unknown_zone_in_constructor_raises_delorean_error(self):
with self.assertRaises(delorean.DeloreanInvalidTimezone):
delorean.Delorean(datetime(2013, 1, 15, 12), timezone="Not/AZone")
def test_unknown_assumed_zone_in_parse_raises_delorean_error(self):
with self.assertRaises(delorean.DeloreanInvalidTimezone):
delorean.parse("2015-02-04T16:33:21", assume_timezone="Not/AZone")
def test_ambiguous_local_time_takes_the_first_occurrence(self):
# zoneinfo's fold=0 default: 01:30 resolves to the daylight side.
do = delorean.Delorean(datetime(2013, 11, 3, 1, 30), timezone="US/Eastern")
self.assertEqual(do.datetime.tzname(), "EDT")
self.assertEqual(
do.datetime.astimezone(timezone.utc),
datetime(2013, 11, 3, 5, 30, tzinfo=timezone.utc),
)
def test_nonexistent_local_time_still_takes_standard_time(self):
do = delorean.Delorean(datetime(2013, 3, 10, 2, 30), timezone="US/Eastern")
self.assertEqual(do.datetime.tzname(), "EST")
self.assertEqual(
do.datetime.astimezone(timezone.utc),
datetime(2013, 3, 10, 7, 30, tzinfo=timezone.utc),
)
if __name__ == "__main__":
unittest.main()