答案可能会让您感到惊讶,但它是 NO。您不能添加天、周、月或年而不影响结果的时区。
原因是并非所有当地日子都有 24 小时。根据时区、该区域的规则以及 DST 是否在相关期间转换,某些“天”可能有 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