答案可能会让您大吃一惊,但事实并非如此。如果时区不影响结果,则无法添加天、周、月或年。
原因是并非所有当地日子都有 24 小时。根据时区、该区域的规则以及 DST 是否在相关期间转换,某些“天”可能有 23、23.5、24、24.5 或 25 小时。(如果您想准确,那么请改用“标准日”一词来表示您的意思是 24 小时。)
例如,首先将您的计算机设置为美国夏令时更改的时区之一,例如太平洋时间或东部时间。然后运行这些示例:
这一篇涵盖了 2013 年的“spring-forward”过渡:
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
使用DateTime
该Local
类型的代码。如果这样做,那么您将介绍服务器的时区- 而不是用户的时区。如果您的用户不在同一个时区,或者您曾经将应用程序部署到其他地方,那么您将遇到问题。
- 如果您想避免此类问题,请查看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