在下面的要求中,我遇到了有趣的问题:测试一个进程是否在同一天内运行,如果没有运行该进程。日期以DataTimeOffset形式存储。
我最初的做法是:
大多数情况下,这是可行的,但我遇到了一个情况,即逻辑将失败。如果其中一个值的时间接近上一天/第二天,那么当转换为UTC时,它将更改日期。如果其他值没有时间也转换为前一天/第二天,则日期比较失败。
因此,我得到了下面的逻辑来包含这个场景:
public static bool SameDate(DateTimeOffset first, DateTimeOffset second)
{
bool returnValue = false;
DateTime firstAdjusted = first.ToUniversalTime().Date;
DateTime secondAdjusted = second.ToUniversalTime().Date;
// If date is now a day ahead after conversion, than add/deduct a day to other date if that date hasn't advanced
if (first.Date < firstAdjusted.Date && second.Date == secondAdjusted.Date)
secondAdjusted = secondAdjusted.Date.AddDays(1);
if (first.Date > firstAdjusted.Date && second.Date == secondAdjusted.Date)
secondAdjusted = secondAdjusted.Date.AddDays(-1);
if (second.Date < secondAdjusted.Date && first.Date == firstAdjusted.Date)
firstAdjusted = firstAdjusted.Date.AddDays(1);
if (second.Date > secondAdjusted.Date && first.Date == firstAdjusted.Date)
firstAdjusted = firstAdjusted.Date.AddDays(-1);
if (DateTime.Compare(firstAdjusted, secondAdjusted) == 0)
returnValue = true;
return returnValue;
}以下是未能通过的单元测试:
[TestMethod()]
public void SameDateTest()
{
DateTimeOffset current = DateTimeOffset.Now;
DateTimeOffset first = current;
DateTimeOffset second = current;
// 23 hours later, next day, with negative offset (EST) -- First rolls over
first = new DateTimeOffset(2014, 1, 1, 19, 0, 0, new TimeSpan(-5, 0, 0));
second = new DateTimeOffset(2014, 1, 2, 18, 0, 0, new TimeSpan(-5, 0, 0));
Assert.IsFalse(Common.SameDate(first, second));
// 23 hours earlier, next day, with postive offset -- First rollovers
first = new DateTimeOffset(2014, 1, 1, 4, 0, 0, new TimeSpan(5, 0, 0));
second = new DateTimeOffset(2014, 1, 2, 5, 0, 0, new TimeSpan(5, 0, 0));
Assert.IsFalse(Common.SameDate(first, second));
// 23 hours later, next day, with negative offset (EST) -- Second rolls over
first = new DateTimeOffset(2014, 1, 2, 18, 0, 0, new TimeSpan(-5, 0, 0));
second = new DateTimeOffset(2014, 1, 1, 19, 0, 0, new TimeSpan(-5, 0, 0));
Assert.IsFalse(Common.SameDate(first, second));
// 23 hours earlier, next day, with postive offset -- Second rolls over
first = new DateTimeOffset(2014, 1, 2, 5, 0, 0, new TimeSpan(5, 0, 0));
second = new DateTimeOffset(2014, 1, 1, 4, 0, 0, new TimeSpan(5, 0, 0));
Assert.IsFalse(Common.SameDate(first, second));
}我的直觉是,有一个更清洁的方法,比增加/减少的基础上的其他价值。有没有更好的方法?
主要标准:
发布于 2014-12-01 19:25:57
根据两个日期的差异调整其中一个日期:
public static bool SameDate(DateTimeOffset first, DateTimeOffset second)
{
bool returnValue = false;
DateTime firstAdjusted = first.ToUniversalTime().Date;
DateTime secondAdjusted = second.ToUniversalTime().Date;
// calculate the total diference between the dates
int diff = first.Date.CompareTo(firstAdjusted) - second.Date.CompareTo(secondAdjusted);
// the firstAdjusted date is corected for the difference in BOTH dates.
firstAdjusted = firstAdjusted.AddDays(diff);
if (DateTime.Compare(firstAdjusted, secondAdjusted) == 0)
returnValue = true;
return returnValue;
}在这个函数中,我要指出,抵消时间永远不会超过24小时。一个日期和它的调整日期之间的差额不会是两天或两天以上。如果不是这样,那么您可以使用time span比较。
发布于 2014-11-25 23:58:11
您所描述的一般方法(转换为公共时区,然后比较日期部分)是合理的。这里的问题实际上是一个决定参照系的问题。你随意选择了UTC作为你的参照系。起初,光泽度并不重要,只要它们在同一时区进行比较,但是正如您已经发现的,这可以将它们置于一天边界的任何一边。
我认为你需要改进你的规格。问问自己,以下哪一个是你想要确定的。
也可能是别的东西。已实现的定义(但被您拒绝)是“值是否发生在相同的UTC日历日”。
发布于 2014-12-01 23:10:52
首先,你需要澄清一些混乱的程序应该做什么。对于两个普通时区中的两个通用时间戳(两个没有特定限制的DateTimeOffset实例),不存在“日历日”这样的概念。每个时区都有自己的日历日。例如,我们可以有两个DateTimeOffset实例,名为first和second,它们有不同的偏移量。让我们可视化时间轴,并用DateTimeOffset实例引用的特定时间点( * )和相应时区中的日历日(即特定时区中0:00到23:59之间的间隔)使用|__|标记。看起来可能是这样的:
first: ........|___________________*__|.......
second: ...|______*_______________|............在first的时区中,second事件发生在同一日历日(凌晨2点至3点之间)。在second的时区中,first事件发生在下一个日历日(凌晨1点到2点之间)。
因此,很明显,这个问题需要澄清,而且可能需要一些范围的限制。这些时区是真正的通用时区,还是属于同一地点的时区,仅在夏令时可能有所不同?既然如此,你为什么不直接忽略时区呢?例如,在2014年11月2日00:10到23:50之间,UTC偏移量发生了变化(EDT->ET),这两个瞬间之间的间隔超过24小时:new DateTimeOffset(2014, 11, 02, 00, 10, 00, new TimeSpan(-4, 0, 0)).Date == new DateTimeOffset(2014, 11, 02, 23, 50, 00, new TimeSpan(-5, 0, 0)).Date。基本上,这就是martijn试图做的事情,但方法非常复杂。当你试着
public static bool SameDateSimple(DateTimeOffset first, DateTimeOffset second)
{
return first.Date == second.Date;
}它将适用于所有上述单元测试。而且,这也是大多数人所称的“同一个日历日”,保证这两个实例指的是同一地点的时间。
或者,如果你真的在比较两个“随机”时区,你必须选择你的参考时区。它可能是UTC,正如你最初尝试的那样。或者,从人类的角度来看,使用第一个时区作为参考可能更合乎逻辑(您也可以选择第二个时区,它会给出不同的结果,但这两个变体“同样好”):
public static bool SameDateGeneral(DateTimeOffset first, DateTimeOffset second)
{
DateTime secondAdjusted = second.ToOffset(first.Offset).Date;
return first.Date == secondAdjusted.Date;
}这对于上述一些测试不起作用,但对于两个随机时区来说,它的工作“正确”(在某种意义上)更为普遍:如果您尝试first = new DateTimeOffset(2014, 1, 2, 0, 30, 0, new TimeSpan(5, 0, 0)), second = new DateTimeOffset(2014, 1, 1, 23, 30, 0, new TimeSpan(4, 0, 0)),简单的SameDateSimple返回false (与martijn一样),尽管这两个实例引用的时间完全相同(都是2014-01-01 19:30:00Z)。SameDateGeneral在这里正确地返回true。
https://stackoverflow.com/questions/27093065
复制相似问题