Esempio n. 1
0
def test_cftime_range(start, end, periods, freq, closed, normalize, calendar,
                      expected_date_args):
    date_type = get_date_type(calendar)
    expected_dates = [date_type(*args) for args in expected_date_args]

    if isinstance(start, tuple):
        start = date_type(*start)
    if isinstance(end, tuple):
        end = date_type(*end)

    result = cftime_range(start=start,
                          end=end,
                          periods=periods,
                          freq=freq,
                          closed=closed,
                          normalize=normalize,
                          calendar=calendar)
    resulting_dates = result.values

    assert isinstance(result, CFTimeIndex)

    if freq is not None:
        np.testing.assert_equal(resulting_dates, expected_dates)
    else:
        # If we create a linear range of dates using cftime.num2date
        # we will not get exact round number dates.  This is because
        # datetime arithmetic in cftime is accurate approximately to
        # 1 millisecond (see https://unidata.github.io/cftime/api.html).
        deltas = resulting_dates - expected_dates
        deltas = np.array([delta.total_seconds() for delta in deltas])
        assert np.max(np.abs(deltas)) < 0.001
Esempio n. 2
0
def test_calendar_specific_month_end(freq, calendar, expected_month_day):
    year = 2000  # Use a leap-year to highlight calendar differences
    result = cftime_range(
        start='2000-02', end='2001', freq=freq, calendar=calendar).values
    date_type = get_date_type(calendar)
    expected = [date_type(year, *args) for args in expected_month_day]
    np.testing.assert_equal(result, expected)
Esempio n. 3
0
def test_calendar_year_length(calendar, start, end, expected_number_of_days):
    result = cftime_range(start,
                          end,
                          freq='D',
                          closed='left',
                          calendar=calendar)
    assert len(result) == expected_number_of_days
def test_calendar_specific_month_end(freq, calendar, expected_month_day):
    year = 2000  # Use a leap-year to highlight calendar differences
    result = cftime_range(
        start='2000-02', end='2001', freq=freq, calendar=calendar).values
    date_type = get_date_type(calendar)
    expected = [date_type(year, *args) for args in expected_month_day]
    np.testing.assert_equal(result, expected)
Esempio n. 5
0
def test_cftime_range(
        start, end, periods, freq, closed, normalize, calendar,
        expected_date_args):
    date_type = get_date_type(calendar)
    expected_dates = [date_type(*args) for args in expected_date_args]

    if isinstance(start, tuple):
        start = date_type(*start)
    if isinstance(end, tuple):
        end = date_type(*end)

    result = cftime_range(
        start=start, end=end, periods=periods, freq=freq, closed=closed,
        normalize=normalize, calendar=calendar)
    resulting_dates = result.values

    assert isinstance(result, CFTimeIndex)

    if freq is not None:
        np.testing.assert_equal(resulting_dates, expected_dates)
    else:
        # If we create a linear range of dates using cftime.num2date
        # we will not get exact round number dates.  This is because
        # datetime arithmetic in cftime is accurate approximately to
        # 1 millisecond (see https://unidata.github.io/cftime/api.html).
        deltas = resulting_dates - expected_dates
        deltas = np.array([delta.total_seconds() for delta in deltas])
        assert np.max(np.abs(deltas)) < 0.001
Esempio n. 6
0
def test_cftime_range_name():
    result = cftime_range(start='2000', periods=4, name='foo')
    assert result.name == 'foo'

    result = cftime_range(start='2000', periods=4)
    assert result.name is None
Esempio n. 7
0
def test_dayofyear_after_cftime_range(freq):
    pytest.importorskip('cftime', minversion='1.0.2.1')
    result = cftime_range('2000-02-01', periods=3, freq=freq).dayofyear
    expected = pd.date_range('2000-02-01', periods=3, freq=freq).dayofyear
    np.testing.assert_array_equal(result, expected)
Esempio n. 8
0
def test_dayofyear_after_cftime_range(freq):
    pytest.importorskip('cftime', minversion='1.0.2.1')
    result = cftime_range('2000-02-01', periods=3, freq=freq).dayofyear
    expected = pd.date_range('2000-02-01', periods=3, freq=freq).dayofyear
    np.testing.assert_array_equal(result, expected)
Esempio n. 9
0
def test_calendar_year_length(
        calendar, start, end, expected_number_of_days):
    result = cftime_range(start, end, freq='D', closed='left',
                          calendar=calendar)
    assert len(result) == expected_number_of_days
Esempio n. 10
0
def test_cftime_range_name():
    result = cftime_range(start='2000', periods=4, name='foo')
    assert result.name == 'foo'

    result = cftime_range(start='2000', periods=4)
    assert result.name is None
Esempio n. 11
0
def test_cftime_range_standard_calendar_refers_to_gregorian():
    from cftime import DatetimeGregorian

    (result, ) = cftime_range("2000", periods=1)
    assert isinstance(result, DatetimeGregorian)
Esempio n. 12
0
def test_dayofweek_after_cftime_range(freq):
    pytest.importorskip("cftime", minversion="1.0.2.1")
    result = cftime_range("2000-02-01", periods=3, freq=freq).dayofweek
    expected = pd.date_range("2000-02-01", periods=3, freq=freq).dayofweek
    np.testing.assert_array_equal(result, expected)
Esempio n. 13
0
def test_cftime_range_name():
    result = cftime_range(start="2000", periods=4, name="foo")
    assert result.name == "foo"

    result = cftime_range(start="2000", periods=4)
    assert result.name is None
Esempio n. 14
0
def generate_range(
    start: cftime.datetime,
    end: cftime.datetime,
    offset: cftime_offsets.BaseCFTimeOffset,
) -> Iterable[cftime.datetime]:
    """
    Generate a range of datetime objects between start and end, using offset to
    determine the steps.

    The range will extend both ends of the span to the next valid timestep, see
    examples.

    Parameters
    ----------
    start: :class:`cftime.datetime`
        Starting datetime from which to generate the range (noting roll backward
        mentioned above and illustrated in the examples).

    end: :class:`cftime.datetime`
        Last datetime from which to generate the range (noting roll forward mentioned
        above and illustrated in the examples).

    offset:
        Offset object for determining the timesteps.

    Yields
    ------
    :class:`cftime.datetime`
        Next datetime in the range

    Raises
    ------
    ValueError
        Offset does not result in increasing :class:`cftime.datetime`'s

    Examples
    --------
    The range is extended at either end to the nearest timestep. In the example below,
    the first timestep is rolled back to 1st Jan 2001 whilst the last is extended to 1st
    Jan 2006.

    >>> import datetime as dt
    >>> from pprint import pprint
    >>> from scmdata.offsets import to_offset, generate_range
    >>> g = generate_range(
    ...     dt.datetime(2001, 4, 1),
    ...     dt.datetime(2005, 6, 3),
    ...     to_offset("AS"),
    ... )

    >>> pprint([d for d in g])
    [cftime.datetime(2001, 1, 1, 0, 0),
     cftime.datetime(2002, 1, 1, 0, 0),
     cftime.datetime(2003, 1, 1, 0, 0),
     cftime.datetime(2004, 1, 1, 0, 0),
     cftime.datetime(2005, 1, 1, 0, 0),
     cftime.datetime(2006, 1, 1, 0, 0)]

    In this example the first timestep is rolled back to 31st Dec 2000 whilst the last
    is extended to 31st Dec 2005.

    >>> g = generate_range(
    ...     dt.datetime(2001, 4, 1),
    ...     dt.datetime(2005, 6, 3),
    ...     to_offset("A"),
    ... )
    >>> pprint([d for d in g])
    [cftime.datetime(2000, 12, 31, 0, 0),
     cftime.datetime(2001, 12, 31, 0, 0),
     cftime.datetime(2002, 12, 31, 0, 0),
     cftime.datetime(2003, 12, 31, 0, 0),
     cftime.datetime(2004, 12, 31, 0, 0),
     cftime.datetime(2005, 12, 31, 0, 0)]

    In this example the first timestep is already on the offset so stays there, the last
    timestep is to 1st Sep 2005.

    >>> g = generate_range(
    ...     dt.datetime(2001, 4, 1),
    ...     dt.datetime(2005, 6, 3),
    ...     to_offset("QS"),
    ... )
    >>> pprint([d for d in g])
    [cftime.datetime(2001, 4, 1, 0, 0),
     cftime.datetime(2001, 7, 1, 0, 0),
     cftime.datetime(2001, 10, 1, 0, 0),
     cftime.datetime(2002, 1, 1, 0, 0),
     cftime.datetime(2002, 4, 1, 0, 0),
     cftime.datetime(2002, 7, 1, 0, 0),
     cftime.datetime(2002, 10, 1, 0, 0),
     cftime.datetime(2003, 1, 1, 0, 0),
     cftime.datetime(2003, 4, 1, 0, 0),
     cftime.datetime(2003, 7, 1, 0, 0),
     cftime.datetime(2003, 10, 1, 0, 0),
     cftime.datetime(2004, 1, 1, 0, 0),
     cftime.datetime(2004, 4, 1, 0, 0),
     cftime.datetime(2004, 7, 1, 0, 0),
     cftime.datetime(2004, 10, 1, 0, 0),
     cftime.datetime(2005, 1, 1, 0, 0),
     cftime.datetime(2005, 4, 1, 0, 0),
     cftime.datetime(2005, 7, 1, 0, 0)]
    """
    # Uses the Gregorian calendar - allows for adding/subtracting datetime.timedelta in range calc
    start_cf = cftime.DatetimeGregorian(*start.timetuple()[:6])
    end_cf = cftime.DatetimeGregorian(*end.timetuple()[:6])

    res = cftime_offsets.cftime_range(offset.rollback(start_cf),
                                      offset.rollforward(end_cf),
                                      freq=offset)

    return [cftime.datetime(*dt.timetuple()[:6]) for dt in res]
Esempio n. 15
0
def test_invalid_cftime_range_inputs(start, end, periods, freq, closed):
    with pytest.raises(ValueError):
        cftime_range(start, end, periods, freq, closed=closed)
Esempio n. 16
0
def test_invalid_cftime_range_inputs(start, end, periods, freq, closed):
    with pytest.raises(ValueError):
        cftime_range(start, end, periods, freq, closed=closed)
Esempio n. 17
0
def test_dayofyear_after_cftime_range(freq):
    result = cftime_range("2000-02-01", periods=3, freq=freq).dayofyear
    expected = pd.date_range("2000-02-01", periods=3, freq=freq).dayofyear
    np.testing.assert_array_equal(result, expected)