10

Is there an elegant was to convert between relativedelta and timedelta?

The use case is getting user input ISO date. Python's isodate will return either isodate.duration.Duration or datetime.timedelta.

We need the features of relativedelta (per What is the difference between "datetime.timedelta" and "dateutil.relativedelta.relativedelta" when working only with days? -- it does more) so need to convert both these types to a relativedata.

4

3 回答 3

9

seconds只需取and的总数microseconds,这就是一个timedelta对象存储:

def to_relativedelta(tdelta):
    return relativedelta(seconds=int(tdelta.total_seconds()),
                         microseconds=tdelta.microseconds)

>>> to_relativedelta(timedelta(seconds=0.3))
relativedelta(microseconds=+300000)
>>> to_relativedelta(timedelta(seconds=3))
relativedelta(seconds=+3)
>>> to_relativedelta(timedelta(seconds=300))
relativedelta(minutes=+5)
>>> to_relativedelta(timedelta(seconds=3000000))
relativedelta(days=+34, hours=+17, minutes=+20)
于 2013-06-07T06:51:00.063 回答
2
d = datetime.timedelta(...)
dateutil.relativedelta.relativedelta(seconds=d.total_seconds())
于 2013-06-07T06:45:07.873 回答
0

在 relativedelta 中直接使用秒不会填充月份和年份字段,当然,我们不知道它是闰年还是 31 天的月份是有原因的。

所以是这样的:

[In]:  tdelta = datetime.now() - datetime(1971, 1, 1)
[In]:  relativedelta(seconds=tdelta.total_seconds())
[Out]: relativedelta(days=+16958, hours=+13, minutes=+19, seconds=+49)

给出有很多天没有月的相对增量。虽然这在某些情况下是可以的,但在某些情况下,我们可能需要数年和数月。所以:

def timedelta_to_relativedelta(tdelta):
    assert isinstance(tdelta, timedelta)

    seconds_in = {
        'year'  : 365 * 24 * 60 * 60,
        'month' : 30 * 24 * 60 * 60,
        'day'   : 24 * 60 * 60,
        'hour'  : 60 * 60,
        'minute': 60
    }

    years, rem = divmod(tdelta.total_seconds(), seconds_in['year'])
    months, rem = divmod(rem, seconds_in['month'])
    days, rem = divmod(rem, seconds_in['day'])
    hours, rem = divmod(rem, seconds_in['hour'])
    minutes, rem = divmod(rem, seconds_in['minute'])
    seconds = rem

    return relativedelta(years=years, months=months, days=days, hours=hours, minutes=minutes, seconds=seconds)

这可能不是一个非常 Pythonic 的解决方案,但它确实有效。

注意:这假设一年有 365 天(忽略闰非闰年),月份有 30 天。

于 2017-06-06T07:56:10.787 回答