给定日期范围如何计算部分或全部在该范围内的周末数?
(要求的一些定义: 把'周末'表示周六和周日。 日期范围包括在内,即结束日期是范围的一部分 “全部或部分”意味着周末的任何部分都在日期范围内,这意味着整个周末都会被计算在内。)
为了简化,我想你实际上只需要知道持续时间以及一周的哪一天......
我现在很好,它将涉及整数除以7和一些逻辑,根据余数加1,但我不能弄清楚是什么......
Python中答案的额外分数;-)
修改
这是我的最终代码。
周末是星期五和星期六(因为我们正在计算夜晚的数量),从周一开始,天数为0。我使用了onebyone的算法和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
答案 0 :(得分:5)
这种事情的一般方法:
对于一周中的每一天,计算在该日开始的“包含周末”之前需要多少天。例如,如果“包含周末”表示“包含星期六和星期日”,那么我们有下表:
周日:8 星期一:7 星期二:6 星期三:5 星期四:4 星期五:3 星期六:2对于“部分或全部”,我们有:
周日:1 星期一:6 星期二:5 星期三:4 星期四:3 星期五:2 星期六:1显然,不必将其编码为表格,现在看起来很明显。
然后,给定周期开始的星期几,从周期长度(可能是开始结束+ 1,包括两个fenceposts)中减去[*]魔术值。如果结果小于0,则包含0个周末。如果它等于或大于0,则它包含(至少)1个周末。
然后你必须处理余下的日子。在第一种情况下,这很容易,每7天就有一个额外的周末。除了星期天之外,每个开始日的第二种情况也是如此,只需要再过6天就可以包括另一个周末。因此,在周日开始的第二种情况下,您可以在期间开始时计算1个周末,然后从长度中减去1并从周一重新计算。
更一般地说,“全部或部分”周末发生的事情是,我们正在检查是否从有趣的位置(“周末”)中途开始。如果是这样,我们可以:
在周末的情况下,只有一个特殊情况从中途开始,所以(1)看起来不错。但是如果你把日期作为日期+时间而不是白天,或者如果你对5天工作周而不是2天周末感兴趣,那么(2)可能更容易理解。
[*]除非你当然使用无符号类型。
答案 1 :(得分: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.(注意我不是要把这个部分推到之前的列表理解中,因为那很难验证是否正确)。< / p>
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
更短,更清晰,更易于理解意味着您可以对代码更有信心,并可以继续处理更多有趣的问题。
答案 2 :(得分:1)
要计算整个周末,只需调整天数,以便在星期一开始,然后除以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)
如果你想知道部分周末(或周),只需看七分的小数部分。
答案 3 :(得分:0)
在原始数学旁边你需要外部逻辑。您需要有一个日历库(或者如果您有足够的时间自己实施),以定义周末,您开始的一周中的哪一天,结束等等。
如果没有对代码中的天数进行逻辑定义,纯粹的数学方法会在极端情况下失败,例如1天的间隔,或者我相信,任何低于整整一周的任何事情(或者如果允许部分则低于6天) )。