如果您必须处理来自不同时区的DateTime对象 - 请说是因为您的Web应用程序在东海岸的一台服务器上运行,另一台在西海岸运行 - 并且您想确保比较两个时间戳(例如,客户首先点击的时间戳)时,你没有犯错,那么有一个方法可以为你做到这一点。
典型的测试用例可能如下所示:
namespace ImageServerTest
{
[..]
[TestMethod]
public void TestOrIfLater()
{
var PST = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
var EST = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var t0 = DateTime.UtcNow;
var t0p = TimeZoneInfo.ConvertTimeFromUtc(t0, PST);
var t0e = TimeZoneInfo.ConvertTimeFromUtc(t0, EST);
Thread.Sleep(100);
var t1 = DateTime.UtcNow;
var t1p = TimeZoneInfo.ConvertTimeFromUtc(t1, PST);
var t1e = TimeZoneInfo.ConvertTimeFromUtc(t1, EST);
Assert.AreEqual(t1, t0.OrIfLater(t1));
Assert.AreEqual(t1p, t0p.OrIfLater(t1p));
Assert.AreEqual(t1e, t1e.OrIfLater(t1p));
Assert.AreEqual(t1e, t0p.OrIfLater(t1e));
//Assert.IsTrue(t1p > t0e); //fails
//Assert.IsTrue(t1p.Ticks > t0e.Ticks); //fails
Assert.AreEqual(t1p, t1p.OrIfLater(t0e));
}
}
显然,t1小于t0(意味着t1> t0或t1.Ticks> t0.Ticks),t0p / t0e和t1p / t1e是它们在PST / EST中的表示。因此,从全球的角度来看,我们期待
t1p > t0e
以及
t1p.Ticks > t0e.Ticks
测试用例指定我们要确保名为 OrIfLater 的扩展方法始终返回较年轻的时间戳(时间轴右侧的时间戳)。
答案 0 :(得分:1)
在处理时区和数据比较时,您确实应该使用DateTimeOffset
。为此目的,它被添加到BCL。
您现有的代码断言产生以下值:
True True True True False False False
但如果你改为DateTimeOffset
,就像这样:
TimeZoneInfo PST = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
TimeZoneInfo EST = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTimeOffset t0 = DateTimeOffset.UtcNow;
DateTimeOffset t0p = TimeZoneInfo.ConvertTime(t0, PST);
DateTimeOffset t0e = TimeZoneInfo.ConvertTime(t0, EST);
Thread.Sleep(100);
DateTimeOffset t1 = DateTimeOffset.UtcNow;
DateTimeOffset t1p = TimeZoneInfo.ConvertTime(t1, PST);
DateTimeOffset t1e = TimeZoneInfo.ConvertTime(t1, EST);
Assert.AreEqual(t1, t0.OrIfLater(t1));
Assert.AreEqual(t1p, t0p.OrIfLater(t1p));
Assert.AreEqual(t1e, t1e.OrIfLater(t1p));
Assert.AreEqual(t1e, t0p.OrIfLater(t1e));
Assert.IsTrue(t1p > t0e);
Assert.IsTrue(t1p.Ticks > t0e.Ticks); //still fails
Assert.AreEqual(t1p, t1p.OrIfLater(t0e));
...然后你得到这个结果:
True True True True True False True
当然,您需要将扩展方法从使用DateTime
更改为使用DateTimeOffset
。
Ticks
属性比较仍有一个失败。但这不是一个错误。它是如何运作的。
如果您查看MSDN Documentation,您会看到以下详细信息:
DateTimeOffset对象的时钟时间中的滴答数。 Ticks属性不受Offset属性值的影响。
所以要检查这是我输出new [] { t0, t0p, t0e, t1, t1p, t1e, }.Select(x => x.Ticks)
的结果然后我得到了这个:
635955882954740587 635955630954740587 635955738954740587 635955882955751105 635955630955751105 635955738955751105
Ticks
确实相对于当地时间而不是基础UTC时间。最终失败的Assert
无效。
但是,如果将其更改为Assert.IsTrue(t1p.UtcTicks > t0e.UtcTicks);
,则可以正常使用。
答案 1 :(得分:-1)
namespace Stuff
{
public static class DynamicHelper
{
/// <summary>
/// returns the latest date/time of the two, based on universal time
/// </summary>
/// <param name="a">this timestamp</param>
/// <param name="b">the parameter timestamp to compare with</param>
/// <example>var latest = yesterday.OrIfLater(today);</example>
/// <returns>the most recent of the two timestamps</returns>
public static DateTimeOffset OrIfLater(this DateTimeOffset a, DateTimeOffset b)
{
return a.UtcTicks > b.UtcTicks ? a : b;
}
}
[..]
}