python中的日期时间差调整为night tim

2024-04-19 14:47:52 发布

您现在位置:Python中文网/ 问答频道 /正文

我在pythond1和d2中有两个datetime对象。我想看看他们之间的时差。我想要比(d1-d2)稍微复杂一点的东西:我希望晚上的时间比白天的时间少一个常数的分数c,例如晚上一个小时只算白天的半小时。在

在python(pandas和/或numpy)中有没有一种简单的方法来实现这一点?在

谢谢!在

从早上7点到晚上9点编辑。但理想情况下,我正在寻找一个解决方案,你可以在一天中的任意时段选择任意权重


Tags: 对象方法numpy编辑pandasdatetime时间常数
3条回答

这里有一个解决方案。在

它做了两件事,首先它计算两个日期之间的完整天数,并且由于我们知道(我们可以近似地)每天是24小时,所以加权“白天”和“晚上时间”(计算以小时为单位)就相当简单了。所以现在我们只需要计算出剩下的不到24小时的间隔。这里的诀窍是“折叠”时间,这样“黎明”就不在一天的中间,而在0时,我们只有一个分隔符来表示“黄昏”,所以我们只有三种情况,都是白天时间,都是夜间,或者晚些的日期是夜间,较早的是白天。在

根据评论更新。在

一百万次函数调用的运行时间是在我的笔记本上4.588s。在

from datetime import datetime,timedelta

def weighteddiff(d2,d1,dawn,dusk,night_weight):

    #if dusk is "before" dawn, switch roles
    day_weight = 1
    if dusk < dawn:
        day_weight = night_weight
        night_weight = 1
        placeholder = dawn
        dawn = dusk
        dusk = placeholder

    nighttime = dawn.total_seconds()/3600 + 24 - dusk.total_seconds()/3600
    daytime = 24-nighttime


    dt = d2-d1

    total_hours = 0
    total_hours += dt.days*daytime*day_weight + dt.days*nighttime*night_weight

    d1 += timedelta(days=dt.days)
    d1 -= dawn
    d2 -= dawn

    dawntime = datetime(d2.year,d2.month,d2.day,0)
    dusktime = dawntime + dusk - dawn

    if d1 < dusktime and d2 < dusktime:
        total_hours += (d2-d1).total_seconds()/3600*day_weight
    elif d1 < dusktime and d2 >= dusktime:
        total_hours += (dusktime - d1).total_seconds()/3600*day_weight
        total_hours += (d2 - dusktime).total_seconds()/3600*night_weight
    elif d1 >= dusktime and d2 >= dusktime:
        total_hours += (d2-d1).total_seconds()/3600*night_weight
    else:
        pass

    return total_hours


weight = 0.5 #weight of nightime hours

#dawn and dusk supplied as timedelta from midnight
dawn = timedelta(hours=5,minutes=0,seconds=0)
dusk = timedelta(hours=19,minutes=4,seconds=0)

d1 = datetime(2017,10,23, 14)
d2 = datetime(2017,10,23, 22)
print("test1",weighteddiff(d2,d1,dawn,dusk,weight))

d1 = datetime(2016,10,22, 20)
d2 = datetime(2016,10,23, 20) 
print("test2",weighteddiff(d2,d1,dawn,dusk,weight))

dawn = timedelta(hours=6,minutes=0,seconds=0)
dusk = timedelta(hours=1,minutes=4,seconds=0)

d1 = datetime(2017,10,22, 2)
d2 = datetime(2017,10,23, 19)
print("test3",weighteddiff(d2,d1,dawn,dusk,weight))

d1 = datetime(2016,10,22, 20)
d2 = datetime(2016,10,23, 20) 
print("test4",weighteddiff(d2,d1,dawn,dusk,weight))

一种解决方案,允许您定义任意多个周期,以及它们各自的权重。在

首先,一个helper函数将日期时间间隔切片:

from datetime import date, time, datetime, timedelta

def slice_datetimes_interval(start, end):
    """
    Slices the interval between the datetimes start and end.

    If start and end are on different days:
    start time -> midnight | number of full days | midnight -> end time
    ----------------------   -------------------   --------------------
               ^                     ^                      ^
          day_part_1             full_days              day_part_2

    If start and end are on the same day:
    start time -> end time
    ----------------------
              ^
         day_part_1              full_days = 0

    Returns full_days and the list of day_parts (as tuples of time objects).
    """

    if start > end:
        raise ValueError("Start time must be before end time")

    # Number of full days between the end of start day and the beginning of end day
    # If start and end are on the same day, it will be -1
    full_days = (datetime.combine(end, time.min) - 
                 datetime.combine(start, time.max)).days
    if full_days >= 0:
        day_parts = [(start.time(), time.max),
                     (time.min, end.time())]
    else:
        full_days = 0
        day_parts = [(start.time(), end.time())]

    return full_days, day_parts

计算给定期间和权重列表的加权持续时间的类:

^{pr2}$

我们创建一个WeightedDuration实例,定义我们的周期及其权重。 我们可以有任意多个周期,权重小于或大于1。在

wd = WeightedDuration([(time.min, time(7, 0), 0.5),      # from midnight to 7, 50%
                       (time(12, 0), time(13, 0), 0.75), # from 12 to 13, 75%
                       (time(21, 0), time.max, 0.5)])    # from 21 to midnight, 50%

让我们计算日期时间之间的加权持续时间:

# 1 hour at 50%, 1 at 100%: that should be 3600 + 1800 = 5400 s
print(wd.duration(datetime(2017, 1, 3, 6, 0), datetime(2017, 1, 3, 8)))
# 5400

# a few tests
intervals = [
    (datetime(2017, 1, 3, 9, 0), datetime(2017, 1, 3, 10)),  # 1 hour with weight 1
    (datetime(2017, 1, 3, 23, 0), datetime(2017, 1, 4, 1)),  # 2 hours, weight 0.5
    (datetime(2017, 1, 3, 5, 0), datetime(2017, 1, 4, 5)),   # 1 full day
    (datetime(2017, 1, 3, 5, 0), datetime(2017, 1, 3, 23)),  # same day
    (datetime(2017, 1, 3, 5, 0), datetime(2017, 1, 4, 23)),  # next day
    (datetime(2017, 1, 3, 5, 0), datetime(2017, 1, 5, 23)),  # 1 full day in between
            ]
for interval in intervals:
    print(interval)
    print(wd.duration(*interval))  

# (datetime.datetime(2017, 1, 3, 9, 0), datetime.datetime(2017, 1, 3, 10, 0))
# 3600
# (datetime.datetime(2017, 1, 3, 23, 0), datetime.datetime(2017, 1, 4, 1, 0))
# 3600
# (datetime.datetime(2017, 1, 3, 5, 0), datetime.datetime(2017, 1, 4, 5, 0))
# 67500
# (datetime.datetime(2017, 1, 3, 5, 0), datetime.datetime(2017, 1, 3, 23, 0))
# 56700
# (datetime.datetime(2017, 1, 3, 5, 0), datetime.datetime(2017, 1, 4, 23, 0))
# 124200
# (datetime.datetime(2017, 1, 3, 5, 0), datetime.datetime(2017, 1, 5, 23, 0))
# 191700

此解决方案计算完整日期的加权数,然后从第一个日期和最后一个日期中减去或添加任何残差。这并不能解释夏令时的影响。在

import pandas as pd


def timediff(t1, t2):

    DAY_SECS = 24 * 60 * 60
    DUSK = pd.Timedelta("21h")
    # Dawn is chosen as 7 a.m.
    FRAC_NIGHT = 10 / 24
    FRAC_DAY = 14 / 24
    DAY_WEIGHT = 1
    NIGHT_WEIGHT = 0.5

    full_days = ((t2.date() - t1.date()).days * DAY_SECS *
                 (FRAC_NIGHT * NIGHT_WEIGHT + FRAC_DAY * DAY_WEIGHT))

    def time2dusk(t):
        time = (pd.Timestamp(t.date()) + DUSK) - t
        time = time.total_seconds()
        wtime = (min(time * NIGHT_WEIGHT, 0) +
                 min(max(time, 0), FRAC_DAY * DAY_SECS) * DAY_WEIGHT +
                 max(time - DAY_SECS * FRAC_DAY, 0) * NIGHT_WEIGHT)
        return wtime

    t1time2dusk = time2dusk(t1)
    t2time2dusk = time2dusk(t2)
    return full_days + t1time2dusk - t2time2dusk

这在加权秒数内提供了解决方案,但您可以在之后转换为任何方便的方法

^{pr2}$

相关问题 更多 >