【问题标题】:O(1) way to find the days in a date range, not including weekendsO(1) 在日期范围内查找天数的方法,不包括周末
【发布时间】:2014-02-26 18:07:08
【问题描述】:

所以,我有两个日期,它们来自 UI:

var start = new Date(self.Start()), end = new Date(self.End());

我们需要计算出该范围之间的天数,这很容易:

var days = Math.max(0, Math.floor((end - start) / ticksInDay) || 0);

我们使用这个数字来计算某种总工作估算。然而,现在这项工作的需求估计不再包括周末。我的第一次尝试是这样的:

var days = Math.max(0, Math.floor((5 / 7) * (end - start) / ticksInDay) || 0);

基本上,如果范围有 7 天,我们将其乘以 (5 / 7) 得到 5 个实际天数。 14 将给我们 10 个实际天数。但是,这有一些缺陷。

(5/7)*1  = 0.714285714285714
(5/7)*2  = 1.42857142857143
(5/7)*3  = 2.14285714285714
(5/7)*4  = 2.85714285714286
(5/7)*5  = 3.57142857142857
(5/7)*6  = 4.28571428571429
(5/7)*7  = 5
(5/7)*8  = 5.71428571428571
(5/7)*9  = 6.42857142857143
(5/7)*10 = 7.14285714285714
(5/7)*11 = 7.85714285714286
(5/7)*12 = 8.57142857142857
(5/7)*13 = 9.28571428571429
(5/7)*14 = 10

四舍五入(无论哪种方式)在这里都不起作用,因为 3 或 4 天或 10 或 11 天这样的范围是错误的。我尝试过的任何其他内容都相当于一个丑陋的字符串或 if...thens 或奇怪的条件语句。

我能想到的 100% 准确的唯一方法是循环范围,类似于this answer 推荐的方法。但是,此代码必须在 UI 模型更改时运行,并且需要为可能具有较大日期范围的大量行计算工作估计。我担心O(n) 解决方案会太慢。

是否有一个很好的公式来排除每 7 天中的 2 天的日期范围?

【问题讨论】:

  • 你不能使用.getDay 来确定开始日期和结束日期是一周中的哪一天 - 那么剩下的整周只是days * 5 / 7 然后添加剩余的天数开始和结束的部分星期。
  • 等他们要求你也不要放假...
  • 假设您的整体时间范围被限制在相关的人类时间范围内,只需制作一张按日期 (yyymmdd) 键控的地图,用于几年内的每一天,并将所有工作日设置为单调递增的计数.将周末设置为 -1 或其他值。然后,您可以提取任意一对工作日的值并进行简单的减法。
  • 另外:我担心 O(n) 解决方案会太慢。您不应该先对其进行分析,看看它是否真的是一个问题?
  • @MikeChristensen 我怀疑这只需要几毫秒,您可以在应用程序构建时构建地图,和/或将其保存在本地存储中。这样做的好处是您可以轻松地将其扩展为处理假期。

标签: javascript algorithm date formula


【解决方案1】:
// Count days from d0 to d1 inclusive, excluding weekends
function countWeekDays( d0, d1 )
{
    var ndays = 1 + Math.round((d1.getTime()-d0.getTime())/(24*3600*1000));
    var nsaturdays = Math.floor((ndays + d0.getDay()) / 7);
    return ndays - 2*nsaturdays - (d0.getDay()==0) + (d1.getDay()==6);
}

2014 年 1 月的示例:

    January 2014
Su Mo Tu We Th Fr Sa
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

countWeekDays(new Date(2014,0,1),new Date(2014,0,1)) // 1
countWeekDays(new Date(2014,0,1),new Date(2014,0,2)) // 2
countWeekDays(new Date(2014,0,1),new Date(2014,0,3)) // 3
countWeekDays(new Date(2014,0,1),new Date(2014,0,4)) // 3
countWeekDays(new Date(2014,0,1),new Date(2014,0,5)) // 3
countWeekDays(new Date(2014,0,1),new Date(2014,0,6)) // 4

注意Date 输入应该在一天中的同一时间。如果您在上面的示例中仅基于年、月和日创建Date 对象,那么您应该没问题。举个反例,1 月 1 日凌晨 12:01 到 1 月 2 日晚上 11:59 仅持续 2 天,但如果您使用这些时间,上述函数将计为 3。

【讨论】:

  • 注意夏令时!
  • @Pointy Math.round 负责处理:)
  • 是的,但最好确保将日期实例四舍五入到午夜或中午。
  • startend总是在午夜。我们使用不处理时间的 jQuery 日期选择器控件。
  • @Pointy 公平点,值得一提(猜猜这就是为什么你是 Pointy :)。已添加文本以解决此问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-05
  • 2018-03-15
  • 2011-03-22
  • 1970-01-01
  • 2011-04-06
  • 1970-01-01
相关资源
最近更新 更多