正在为独立于时区的日期/时间添加周、月或年

本文关键字:添加 时间 独立 于时区 日期 | 更新日期: 2023-09-27 18:26:26

我的软件使用本地时间显示日期/时间,然后用UTC将其发送到服务器。在服务器端,我想将月、年、周、天等添加到此日期/时间。然而,问题是,如果我将这种方法与UTC日期/时间一起使用,然后将其转换回本地时间,结果会总是一样的吗?

这是C#中的一个例子:

// #1
var utc = DateTime.Now.ToUtcTime();
utc = utc.AddWeeks(2); // or AddDays, AddYears, AddMonths...
var localtime = utc.ToLocalTime();
// #2
var localtime = DateTime.Now;
localtime = localtime.AddWeeks(2); // or AddDays, AddYears, AddMonths...

#1和#2的结果总是一样吗?或者时区会影响结果?

正在为独立于时区的日期/时间添加周、月或年

答案可能会让您感到惊讶,但它是。您不能将天、周、月或年添加到UTC时间戳,也不能将其转换为本地时区,也不能期望得到与直接添加到本地时间相同的结果。

原因是并非所有当地的日子都有24小时。根据时区、该时区的规则以及夏令时是否在所述时段内转换;天";可以具有23、23.5、24、24.5或25小时。(如果你想精确一点,那就用"标准日"来表示你的意思是24小时。)

例如,首先将您的计算机设置为更改为夏令时的美国时区之一,如太平洋时间或东部时间。然后运行以下示例:

这篇文章涵盖了2013年的";弹簧向前";转换:

DateTime local1 = new DateTime(2013, 3, 10, 0, 0, 0, DateTimeKind.Local);
DateTime local2 = local1.AddDays(1);
DateTime utc1 = local1.ToUniversalTime();
DateTime utc2 = utc1.AddDays(1);
DateTime local3 = utc2.ToLocalTime();
Debug.WriteLine(local2); //  3/11/2013 12:00:00 AM
Debug.WriteLine(local3); //  3/11/2013 1:00:00 AM

这一次涵盖了2013年的";后退";转换:

DateTime local1 = new DateTime(2013, 11, 3, 0, 0, 0, DateTimeKind.Local);
DateTime local2 = local1.AddDays(1);
DateTime utc1 = local1.ToUniversalTime();
DateTime utc2 = utc1.AddDays(1);
DateTime local3 = utc2.ToLocalTime();
Debug.WriteLine(local2); //  11/4/2013 12:00:00 AM
Debug.WriteLine(local3); //  11/3/2013 11:00:00 PM

正如你在两个例子中看到的那样,结果是一个小时的休息时间,无论是一个方向还是另一个方向。

其他几点:

  • 没有AddWeeks方法。乘以7,再加上天
  • 没有ToUtcTime方法。我想你在找ToUniversalTime
  • 不要呼叫DateTime.Now.ToUniversalTime()。这是多余的,因为在.Now中,它必须使用UTC时间并转换为本地时间。相反,请使用DateTime.UtcNow
  • 如果此代码在服务器上运行,则不应该调用.Now.ToLocalTime,也不应该使用具有Local类型的DateTime。如果您这样做了,那么您引入的是服务器的时区,而不是用户的时区。如果您的用户不在同一时区,或者您将应用程序部署到其他地方,则会出现问题
  • 如果你想避免这类问题,那么看看NodaTime。它的API将防止您犯常见的错误

以下是你应该做的:

// on the client
DateTime local = new DateTime(2013, 3, 10, 0, 0, 0, DateTimeKind.Local);
DateTime utc = local.ToUniversalTime();
string zoneId = TimeZoneInfo.Local.Id;
// send both utc time and zone to the server
// ...
// on the server
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(zoneId);
DateTime theirTime = TimeZoneInfo.ConvertTimeFromUtc(utc, tzi);
DateTime newDate = theirTime.AddDays(1);
Debug.WriteLine(newDate); //   3/11/2013 12:00:00 AM

为了更好地衡量,如果你使用Noda Time,它会是什么样子:

// on the client
LocalDateTime local = new LocalDateTime(2013, 3, 10, 0, 0, 0);
DateTimeZone zone = DateTimeZoneProviders.Tzdb.GetSystemDefault();
ZonedDateTime zdt = local.InZoneStrictly(zone);
// send zdt to server
// ...
// on the server
LocalDateTime newDate = zdt.LocalDateTime.PlusDays(1);
Debug.WriteLine(newDate); // 3/11/2013 12:00:00 AM