[英]How do I detect if two dates straddle a weekend?
给定两个日期时间, dt0
和dt1
(可能是乱序),什么算法可以确定两个日期之间是否至少有24小时的周末(SAT,SUN)?
假设有一个dayofweek()
函数为SUN返回0,为MON返回1,等等...
注意:问题很容易根据线段在几何上进行可视化,但目前我的计算结果不计算在内。
以下解决方案适用于UTC,但DST会失败。
weekdayno()
实现不包括:SUN == 0,MON == 1等... isWeekday()
也没有显示,但微不足道的实施一旦你有dayofweek()
operator-()
实现也没有显示,但我们只是简单地将两个实例转换为UNIX时间(自Epoch以来的秒数)并采用差异来产生两个DateTime
之间的秒数。 hh()
mm()
ss()
只是返回小时,分钟和秒的const访问器 关于夏令时, 詹姆斯麦克尼利斯是正确的。
让这段代码适用于一般的DST案例并非易事:需要添加tz以及在任何地方进行任何类型的日期算法都需要仔细考虑。 将需要额外的单元测试。
目前的解决方案足以满足我的目的(我将使用UTC来避免DST问题)。 我将选择holygeek的答案,因为他建议我画一些ASCII艺术。 在这种情况下,这样做有助于我提出一种易于理解的算法,并且实际上就像我可能做到的那样简单。 感谢所有人为此问题的分析做出贡献。
static const size_t ONEDAYINSECS = (24 * 60 * 60);
DateTime
DateTime::nextSatMorning() const
{
// 0 is SUN, 6 is SAT
return *this + (6 - weekdayno()) * ONEDAYINSECS -
(((hh() * 60) + mm())*60 + ss());
}
DateTime
DateTime::previousSunNight() const
{
return *this - ((weekdayno() - 1 + 7)%7) * ONEDAYINSECS -
(((hh() * 60) + mm())*60 + ss());
}
bool
DateTime::straddles_24HofWeekend_OrMore( const DateTime& newDt ) const
{
const DateTime& t0 = min( *this, newDt );
const DateTime& t1 = max( *this, newDt );
// ------------------------------------
//
// <--+--F--+--S--+--S--+--M--+-->
// t0 ^ ^ t1
// +---->+ +<----|
// | |
// +<--nSecs-->+
// edge0 edge1
//
// ------------------------------------
DateTime edge0 = t0.isWeekday() ? t0.nextSatMorning() : t0;
DateTime edge1 = t1.isWeekday() ? t1.previousSunNight() : t1;
return (edge1 - edge0) > ONEDAYINSECS;
}
John Leidegren要求进行我的单元测试,所以这里有(使用googletest)注意他们通过上面的非DST案例(为UTC运行) - 我希望当前的实现失败的DST案例(没有将它们添加到以下测试用例)。
TEST( Test_DateTime, tryNextSatMorning )
{
DateTime mon{ 20010108, 81315 };
DateTime exp_sat{ 20010113, 0ul };
EXPECT_EQ( exp_sat, mon.nextSatMorning() );
}
TEST( Test_DateTime, tryPrevSunNight )
{
DateTime tue{ 20010109, 81315 };
DateTime exp_sun1{ 20010108, 0ul };
EXPECT_EQ( exp_sun1, tue.previousSunNight() );
DateTime sun{ 20010107, 81315 };
DateTime exp_sun2{ 20010101, 0ul };
EXPECT_EQ( exp_sun2, sun.previousSunNight() );
}
TEST( Test_DateTime, straddlesWeekend )
{
DateTime fri{ 20010105, 163125 };
DateTime sat{ 20010106, 101515 };
DateTime sun{ 20010107, 201521 };
DateTime mon{ 20010108, 81315 };
DateTime tue{ 20010109, 81315 };
EXPECT_FALSE( fri.straddles_24HofWeekend_OrMore( sat ));
EXPECT_TRUE( fri.straddles_24HofWeekend_OrMore( sun ));
EXPECT_TRUE( fri.straddles_24HofWeekend_OrMore( mon ));
EXPECT_TRUE( sat.straddles_24HofWeekend_OrMore( sun ));
EXPECT_TRUE( sat.straddles_24HofWeekend_OrMore( mon ));
EXPECT_FALSE( sun.straddles_24HofWeekend_OrMore( mon ));
EXPECT_TRUE( fri.straddles_24HofWeekend_OrMore( tue ));
EXPECT_FALSE( sun.straddles_24HofWeekend_OrMore( tue ));
}
该图可能有所帮助:
SAT SUN
|---------|---------|
a---------b
a---------b
...
a---------b
我能想到解决这个问题的最简单方法是:复制较小的日期时间值,不断添加,直到它大于其他日期时间值(较大的值)或dayofweek()不再等于0或7。 然后检查您添加的时间总值是否少于24小时。
一个稍微不那么愚蠢的方法是检查一个周末,增加24小时的时间,然后检查一次,以确保它是一个周末,仍然少于第二个日期时间。
只要你的功能找到它的工作日,夏令时就不应真正发挥作用。
以结构化的方式处理它:什么是简单/边缘情况? 平均情况是多少?
简单的情况我可以想到我的头脑(请注意,因为你已经强迫t0
为较低的值,我假设在下面):
t1 - t0
小于1天,则返回false t1 - t0
> = 6天,则返回true(即使您在星期天开始,在任何给定的6天区块中总共会有24小时的周末时间)。 然后我们对t0
和t1
采用dayofweek(),并进行一些检查(这是一般情况)。 我们现在可以在这里特别便宜,因为我们知道 t0
比t1
早5天。
编辑:删除我的条件,因为有一些讨厌的小边缘情况我没有考虑。 无论如何,我推荐的解决方案仍然可行,我不会在这里做。
该网站用C#计算营业日,这有帮助吗? http://www.infopathdev.com/forums/t/7156.aspx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.