Stream: python-questions

Topic: timedelta support for nonstandard calendars


view this post on Zulip Heather Craker (Jul 07 2021 at 17:48):

Hi all. I'm trying to do some timedelta operations on cftime.datetime objects so I can write a computation function that supports non-standard calendars (i.e noleap, all_leap, julian, etc.). All I need to do is be able to add one day to a preexisting cftime.datetime object. The documentation page for cftime.datetime says the following:

This class mimics datetime.datetime but support calendars other than the proleptic Gregorian calendar.

Supports timedelta operations by overloading +/-, and comparisons with other instances using the same calendar.

I don't think the + and - operators are actually overloaded, because I recieve a TypeError when I run the code below. On top of that, there is no way to define one day in cftime since the month must be between 1 and 12.

time = cftime.datetime(year=2000, month=1, day=1, calendar='gregorian')
delta = cftime.datetime(year=0, month=1, day=1, calendar='gregorian', has_year_zero=True)
print(time + delta)
TypeError: unsupported operand type(s) for +: 'cftime._cftime.datetime' and 'cftime._cftime.datetime'

Does anyone now if there is an existing package that supports this kind of operation? Pandas has timedeltas and datetime offsets, but it only supports one kind of calendar. Any help is appreciated! Thanks!

view this post on Zulip Deepak Cherian (Jul 07 2021 at 17:53):

Does https://github.com/pydata/xarray/discussions/4999 help?

view this post on Zulip Deepak Cherian (Jul 07 2021 at 18:09):

delta = cftime.datetime

Ah you're creating a datetime not a timedelta

view this post on Zulip Heather Craker (Jul 07 2021 at 18:11):

Oh I see the problem now. Using datetime.timedelta I can add one day to my cftime.datetime object.

view this post on Zulip Heather Craker (Jul 07 2021 at 18:12):

I just remembered that I have another case where I will need to add a month to a datetime, but datetime.timedelta does not support months. Do you know of something that does? Depending on which month is next, I want to add 28, 29, 30, or 31 days.

view this post on Zulip Rich Neale (Aug 04 2021 at 23:41):

I want to do this too!
I tried this package and couldn't get it to work.
https://stackoverflow.com/questions/12433233/what-is-the-difference-between-datetime-timedelta-and-dateutil-relativedelta

view this post on Zulip Deepak Cherian (Aug 05 2021 at 17:14):

@Rich Neale can you describe what you're trying to do in more detail?

view this post on Zulip Rich Neale (Aug 09 2021 at 17:31):

Just to re-label (FEB) by 1 backwards (JAN) as par of the var.time.dt.strftime("%b")

view this post on Zulip Deepak Cherian (Aug 09 2021 at 20:30):

is the time vector always starting at day 1 of the month? If so, does this work

(var.time - pd.Timedelta("1 day")).dt.strftime("%b")

view this post on Zulip Rich Neale (Aug 09 2021 at 23:06):

Oh sorry, no. Knowing the name of the month from the time object (var.time) I want to realign the time object to be one month earlier. Can I just do pd.timedelta("1 month") ?

view this post on Zulip Deepak Cherian (Aug 10 2021 at 14:44):

Unfortunately not, because pd.timedelta tries to convert that to an absolute number of nanoseconds, which fails ...

But how about this:

time = xr.DataArray(
    xr.cftime_range("1000-01-01", "1000-05-01", freq="MS", calendar="360_day"), dims="time", name="time"
)
time - xr.coding.cftime_offsets.MonthEnd(1)

Does this do what you want? If so, I can open an issue about making those offsets more public


Last updated: Jan 30 2022 at 12:01 UTC