繁体   English   中英

给定日期范围,如何计算部分或全部在该范围内的周末数量?

[英]Given a date range how to calculate the number of weekends partially or wholly within that range?

给定日期范围,如何计算部分或全部在该范围内的周末数量?

(要求提供一些定义:将“周末”表示为星期六和星期日。日期范围包括在内,即结束日期是“全部或部分”范围的一部分,表示周末的任何部分都落在该日期范围内,表示整个周末都算在内。)

为简化起见,我想您实际上只需要知道持续时间以及第一天是星期几...

我现在好多了,它涉及将整数除以7,并根据剩余的逻辑进行一些加1的运算,但我无法完全解决...

Python答案的加分;-)

编辑

这是我的最终代码。

周末是星期五和星期六(因为我们在计算住宿天数),而天数从星期一开始是0索引。 我使用了bybyone的算法和Tom的代码布局。 非常感谢大家。

def calc_weekends(start_day, duration):
    days_until_weekend = [5, 4, 3, 2, 1, 1, 6]
    adjusted_duration = duration - days_until_weekend[start_day]
    if adjusted_duration < 0:
        weekends = 0
    else:
        weekends = (adjusted_duration/7)+1
    if start_day == 5 and duration % 7 == 0: #Saturday to Saturday is an exception
        weekends += 1
    return weekends

if __name__ == "__main__":
    days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
    for start_day in range(0,7):
        for duration in range(1,16):
            print "%s to %s (%s days): %s weekends" % (days[start_day], days[(start_day+duration) % 7], duration, calc_weekends(start_day, duration))
        print

这类事情的一般方法:

对于一周中的每一天,计算出从该天开始的一段“包含一个周末”之前需要多少天。 例如,如果“包含一个周末”的意思是“包含星期六和星期日”,那么我们有下表:

星期日:8星期一:7星期二:6星期三:5星期四:4星期五:3星期六:2

对于“部分或全部”,我们有:

星期日:1星期一:6星期二:5星期三:4星期四:3星期五:2星期六:1

显然,不必将其编码为表格,因为它看起来像什么。

然后,给定周期开始的星期几,从周期的长度(以天为单位)中减去[*]魔术值(可能是start-end + 1,包括两个栅栏)。 如果结果小于0,则包含0个周末。 如果等于或大于0,则它包含(至少)1个周末。

然后,您必须处理剩余的日子。 在第一种情况下,这很容易,每7天额外增加一个周末。 在第二种情况下,对于每个开始日(星期日除外)也是如此,星期日仅需要6天才能包含另一个周末。 因此,在第二种情况下,对于从星期日开始的时间段,您可以在时间段开始时算一个周末,然后从长度中减去1,然后从星期一重新计算。

更一般而言,“整个或部分”周末在这里发生的事情是,我们正在检查是否从有趣的部分(“周末”)开始。 如果是这样,我们可以:

  • 1)数一,将开始日期移动到感兴趣的位的末尾,然后重新计算。
  • 2)将开始日期移回感兴趣的位的开头,然后重新计算。

在周末的情况下,只有一种特殊情况从中途开始,因此(1)看起来不错。 但是,如果您以秒为单位而不是日期来获取日期和日期,或者如果您对工作日为5天而不是周末为2天感兴趣,那么(2)可能更容易理解。

[*]当然,除非您使用无符号类型。

对于这种事情,我的一般做法是:不要开始弄乱尝试重新实现自己的日期逻辑-这很困难。 您会把它固定在边盒上,看起来很糟。 提示:如果您在程序中的任何地方都使用了mod 7算术,或者在程序中的任何地方都将日期视为整数: 则会失败 如果我在代码库中的任何地方(甚至附近)看到“可接受的解决方案”,那么有人将需要重新开始。 让人难以想象的是,任何认为自己是程序员的人都会投票赞成这个答案。

相反,请使用Python随附的内置日期/时间逻辑:

首先,获取您感兴趣的所有日期的列表:

from datetime import date, timedelta    
FRI = 5; SAT = 6

# a couple of random test dates
now = date.today()
start_date = now - timedelta(57)
end_date = now - timedelta(13)
print start_date, '...', end_date    # debug

days = [date.fromordinal(d) for d in  
            range( start_date.toordinal(),
                   end_date.toordinal()+1 )]

接下来,只过滤到周末的日子。 在您的情况下,您对周五和周六晚上分别为5和6感兴趣。(请注意,我不打算将此部分推入先前的列表理解中,因为这很难证明是正确的)。

weekend_days = [d for d in days if d.weekday() in (FRI,SAT)]

for day in weekend_days:      # debug
    print day, day.weekday()  # debug

最后,您想弄清楚列表中有几个周末。 这是棘手的部分,但实际上只需要考虑四种情况,星期五或星期六的每一端都需要考虑。 具体的示例有助于使它更加清晰,此外,这确实是您想要在代码中记录的一类东西:

num_weekends = len(weekend_days) // 2

# if we start on Friday and end on Saturday we're ok,
# otherwise add one weekend
#  
# F,S|F,S|F,S   ==3 and 3we, +0
# F,S|F,S|F     ==2 but 3we, +1
# S|F,S|F,S     ==2 but 3we, +1
# S|F,S|F       ==2 but 3we, +1

ends = (weekend_days[0].weekday(), weekend_days[-1].weekday())
if ends != (FRI, SAT):
    num_weekends += 1

print num_weekends    # your answer

更短,更清晰,更容易理解意味着您可以对代码更有信心,并可以解决更多有趣的问题。

要计算整个周末,只需调整天数,以便从星期一开始,然后除以7。 (请注意,如果开始日期是工作日,请添加天数以移至上一个星期一,如果是周末,则减去天数以移至下周一,因为您已经错过了这个周末。)

days = {"Saturday":-2, "Sunday":-1, "Monday":0, "Tuesday":1, "Wednesday":2, "Thursday":3, "Friday":4}

def n_full_weekends(n_days, start_day):
    n_days += days[start_day]
    if n_days <= 0:
        n_weekends = 0
    else:
        n_weekends = n_days//7
    return n_weekends

if __name__ == "__main__":
    tests = [("Tuesday", 10, 1), ("Monday", 7, 1), ("Wednesday", 21, 3), ("Saturday", 1, 0), ("Friday", 1, 0),
    ("Friday", 3, 1), ("Wednesday", 3, 0), ("Sunday", 8, 1), ("Sunday", 21, 2)]
    for start_day, n_days, expected in tests:
        print start_day, n_days, expected, n_full_weekends(n_days, start_day)

如果您想知道部分周末(或几周),只需看除以7的小数部分即可。

除了原始数学之外,您还需要外部逻辑。 您需要有一个日历库(或者如果您有足够的时间自己实施),以定义一个周末,一周中的哪一天开始,结束等等。

看一下Python的日历类

如果没有在代码中对天数进行逻辑定义,则纯数学方法将在极端情况下失败,例如间隔1天,或者,我相信,任何低于整整一周的时间(或者如果允许分批,则不到6天)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM