我有一个应用程序,它从几个数据收集点接收数据,可能部署在世界任何地方。它们发布到Azure服务总线中的队列,控制台应用程序从队列中读取数据,并使用UTC时间戳和表示数据来源的Id存储这些数据。
我有一个服务,它根据输入数据运行反应事件,每20秒刷新一次,因此它会查看的数据窗口
var window = DateTime.UtcNow.AddSeconds(-20);
var events = context.MyTable.Where(x => x.Timestamp >= window).ToList();
//Process the events
由于时间被标准化为UTC,因此这项工作效果良好。
然而,考虑到夏令时(DST),我还需要能够断言与本地时间相关的有关该数据的统计信息,例如:
"此类事件发生的平均时间为09:30:00"。
在本例中,09:30:00
表示本地时间,无论它发生在PST、GMT还是其他时间,也考虑了夏令时。
正如我所说,事件是用位置Id存储的,该位置Id与表示该数据来自的位置的对象相关:
public class Location
{
public int id { get; set; }
public string name { get; set; }
public Organisation organisation { get; set; }
}
一旦设置好,这些位置是永久性的,即它们不会移动到不同的时区,但它们的当地时间可能会随着夏令时的变化而变化。
为了推断UTC标准化事件发生的当地时间,我需要向Location对象添加哪些字段(以及格式),以及如何使用它将UTC转换为事件发生时的当地时间。
例如,如果我有3个事件发生在当地时间下午12点,分别来自西班牙(+1)、格林尼治标准时间(+0)和太平洋标准时间(-8)。它们基本上存储在下午1点、12点和凌晨4点。我需要能够断言平均时间是一天中的上午9点。
您应该在Location
记录中添加一个名为TimeZone
的字符串值。您需要用时区标识符填充它,该标识符可以是Windows时区ID或IANA时区ID。有关差异的解释,请参阅时区标记wiki。然后使用该时区来确定适用于相应UTC时间的本地时间。
我的建议是使用IANA时区,因为它们可以跨平台和语言使用,而不仅仅是锁定在Windows和.NET上。这是时区的事实标准。要在.NET中使用它们,请使用Noda Time库:
using NodaTime;
...
DateTimeZone tz = DateTimeZoneProviders.Tzdb[location.TimeZone];
Instant instant = Instant.FromDateTimeUtc(theUtcDateTime);
LocalTime localTime = instant.InZone(tz).TimeOfDay;
另一种选择是将Windows时区与.NET:附带的TimeZoneInfo
对象一起使用
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById(location.TimeZone);
DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(theUtcDateTime, tz);
TimeSpan localTime = localDateTime.TimeOfDay;
我认为您应该能够将正在收集的日期保存为UTC时间,然后使用DateTime.ToLocalTime()将它们更改为需要显示的本地时间。