如何将服务器时间转换为本地时间并处理夏令时

我在Godaddy上托管我的网站(asp.net webforms,.Net 4.5,SQL Server 2012),他们(服务器)使用Mountain Standard Time-7UTC时间比较),这是永远不会改变的不会观察夏令时。

所以,如果我这样做

 Response.Write("UTC Time: " + DateTime.UtcNow.ToString() + "
"); Response.Write("Server Time: " + DateTime.Now.ToString() + "
"); Response.Write("Server DateTimeOffset: " + DateTimeOffset.Now.ToString() + "
");

它会显示:

 UTC Time: 9/18/2015 5:14:09 PM Server Time: 9/18/2015 10:14:09 AM Server DateTimeOffset: 9/18/2015 10:14:09 AM -07:00 

但是我的用户位于乔治亚州亚特兰大,它确实观察夏令时,根据timeanddate.com,他们在夏天使用EDT ,在冬天使用EST

如何获得正确的用户当前时间? 假设用户打开我的网络应用程序并点击Show my time按钮,它会显示当前用户的正确时间吗?

  1. 您永远不应该依赖服务器的时区设置。 因此,不应在ASP.NET应用程序中使用DateTime.Now

    还有许多其他原因可以避免DateTime.Now 。 阅读: 针对DateTime.Now的案例 。

  2. 无论如何,服务器的本地时间永远不会保证是您网站用户的本地时间。 如果是的话,那只是巧合。

  3. 获取用户当前时区的最简单方法是通过JavaScript:

     var now = new Date(); 

    虽然这是基于用户的时钟,可能也可能没有正确设置。 要对时间有任何保证,您必须使用服务器时钟的UTC时间,并应用用户的时区。

    您可能考虑的一种方法是将服务器的UTC时间发送到客户端,然后将其加载到客户端的JavaScript中以将其投影到其时区:

     // C# string serverUtcTime = DateTime.UtcNow.ToString("o"); // "2015-09-18T17:53:15.6988370Z" // JS var now = new Date("2015-09-18T17:53:15.6988370Z"); 
  4. 实际上检测用户的时区是一个当前没有解决方案的难题。 有些人可能会推荐new Date().getTimezoneOffset() ,但这只会给你当前的数字偏移,而不是时区。 DST的偏移量可能会发生变化,许多时区使用类似的偏移量。 DST过渡附近的历史日期也会出现并发症,对您不利。

    像jsTimeZoneDetect这样的脚本可以猜测您的IANA时区ID,例如America/New_York的东部时间,但它们不是100%准确。 如果您需要服务器上的用户时区,那么最终应该询问用户在您的应用程序中的某个时区。

  5. 在.NET中,您可以使用Noda Time来处理IANA时区。 如果没有Noda Time,.NET具有TimeZoneInfo类,但它只能用于Windows时区。

  6. 如果您确定用户位于亚特兰大,GA(位于美国东部时区),那么您可以这样做:

     DateTime utc = DateTime.UtcNow; TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); DateTime eastern = TimeZoneInfo.ConvertTimeFromUtc(utc, tz); 

    或者,使用Noda Time和IANA时区ID:

     Instant now = SystemClock.Instance.Now; DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/New_York"]; ZonedDateTime eastern = now.InZone(tz); 

您可以使用TimeZoneInfo.ConvertTime从一个时区转换为另一个时区。 但是,如果您只是转换为EST或EDT,它将始终显示该值。 如果您希望始终为客户端显示正确的时间,则需要执行诸如使用Javascript将客户端浏览器的本地时区存储在cookie中,然后使用该值作为转换为的时区。

从服务器获取UtcTime并使用TimeZoneInfo.ConvertTimeFromUtc进行转换可能会稍微简化一下,如果你希望做到这一点的话。 但基本上是相同的过程。

看看这个例子。 这很容易。

 [Test, TestCase(1), TestCase(9)] public void Test(int month) { var serverTime = new DateTime(2015, month, 18, 10, 14, 09); // No Daylight saving in Russia var serverTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time"); // Daylight saving in Atlanta var localTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Atlantic Standard Time"); // check if ConvertTime take care of daylight saving var localTime = TimeZoneInfo.ConvertTime(serverTime, serverTimeZone, localTimeZone); // it does if (localTimeZone.IsDaylightSavingTime(localTime)) Assert.AreEqual(string.Format("{0}/18/15 04:14 AM", month), localTime.ToString("M/dd/yy hh:mm tt", System.Globalization.CultureInfo.InvariantCulture)); else Assert.AreEqual(string.Format("{0}/18/15 03:14 AM", month), localTime.ToString("M/dd/yy hh:mm tt", System.Globalization.CultureInfo.InvariantCulture)); }