我的软件使用本地时间显示日期/时间,然后用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