123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 |
- from datetime import datetime, timedelta
- import pytest
- import pytz
- import isodate
- from flexmeasures.data.schemas.times import DurationField, DurationValidationError
- @pytest.mark.parametrize(
- "duration_input, exp_deserialization",
- [
- ("PT1H", timedelta(hours=1)),
- ("PT6M", timedelta(minutes=6)),
- ("PT6H", timedelta(hours=6)),
- ("P2DT1H", timedelta(hours=49)), # https://github.com/gweis/isodate/issues/74
- ],
- )
- def test_duration_field_straightforward(duration_input, exp_deserialization):
- """Testing straightforward cases"""
- df = DurationField()
- deser = df.deserialize(duration_input, None, None)
- assert deser == exp_deserialization
- assert df.serialize("duration", {"duration": deser}) == duration_input
- @pytest.mark.parametrize(
- "duration_input, exp_deserialization, grounded_timedelta",
- [
- ("P1M", isodate.Duration(months=1), timedelta(days=29)),
- ("PT24H", isodate.Duration(hours=24), timedelta(hours=24)),
- ("P2D", isodate.Duration(hours=48), timedelta(hours=48)),
- # following are calendar periods including a transition to daylight saving time (DST)
- ("P2M", isodate.Duration(months=2), timedelta(days=60) - timedelta(hours=1)),
- # ("P8W", isodate.Duration(days=7*8), timedelta(weeks=8) - timedelta(hours=1)),
- # ("P100D", isodate.Duration(days=100), timedelta(days=100) - timedelta(hours=1)),
- # following is a calendar period with transitions to DST and back again
- ("P1Y", isodate.Duration(years=1), timedelta(days=366)),
- ],
- )
- def test_duration_field_nominal_grounded(
- duration_input, exp_deserialization, grounded_timedelta
- ):
- """Nominal durations are tricky:
- https://en.wikipedia.org/wiki/Talk:ISO_8601/Archive_2#Definition_of_Duration_is_incorrect
- We want to test if we can ground them as expected.
- We use a particular datetime to ground, in a leap year February.
- For the Europe/Amsterdam timezone, daylight saving time started on March 29th 2020.
- # todo: the commented out tests would work if isodate.parse_duration would have the option to stop coercing ISO 8601 days into datetime.timedelta days
- """
- df = DurationField()
- deser = df.deserialize(duration_input, None, None)
- assert deser == exp_deserialization
- dummy_time = pytz.timezone("Europe/Amsterdam").localize(
- datetime(2020, 2, 22, 18, 7)
- )
- grounded = DurationField.ground_from(deser, dummy_time)
- assert grounded == grounded_timedelta
- @pytest.mark.parametrize(
- "duration_input, error_msg",
- [
- ("", "Unable to parse duration string"),
- ("1H", "Unable to parse duration string"),
- ("PP1M", "time designator 'T' missing"),
- ("PT2D", "Unrecognised ISO 8601 date format"),
- ("PT40S", "FlexMeasures only support multiples of 1 minute."),
- ],
- )
- def test_duration_field_invalid(duration_input, error_msg):
- df = DurationField()
- with pytest.raises(DurationValidationError) as ve:
- df.deserialize(duration_input, None, None)
- assert error_msg in str(ve)
|