【问题标题】:How to get convert server time to local time and deal with daylight saving time如何将服务器时间转换为本地时间并处理夏令时
【发布时间】:2015-09-19 02:53:40
【问题描述】:

我在 Godaddy 上托管我的网站(asp.net webforms、.Net 4.5、SQL Server 2012),他们(服务器)使用 Mountain Standard Time-7UTC 时间相比)这是从未改变并且遵守夏令时。

如果我这样做了

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

它会显示这个:

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 按钮,它将显示正确的当前用户时间?

【问题讨论】:

    标签: c# asp.net .net sql-server-2012 timezone


    【解决方案1】:
    1. 您永远不应依赖服务器的时区设置。因此,DateTime.Now 不应在 ASP.NET 应用程序中使用。

      还有很多其他原因可以避免使用DateTime.Now。阅读:The case against 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 的偏移量可以改变,许多时区使用类似的偏移量。还有complications for historical dates near DST transitions对你不利。

      jsTimeZoneDetect 之类的脚本可以猜测您的 IANA 时区 ID,例如东部时间的 America/New_York,但它们并非 100% 准确。如果您需要服务器上的用户时区,那么最终应该询问用户在您的应用程序中的某个地方提供他们的时区。

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

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

      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.ConvertTimeFromUtc 是否照顾 Daylight Saving
    • 是的,确实如此。尽管 ID 中有“标准”一词,但该特定区域同时涵盖 EST 和 EDT。
    • @Awesome Matt,我如何使它成为通用函数/类......所以我可以从应用程序的任何地方访问它?你能编辑你的答案对我有什么帮助吗?
    • 只要放在静态类中的静态方法中即可。见dotnetperls.com/static
    • here 是来自msdnTime Zone Index Values,可能对某人有所帮助。
    【解决方案2】:

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

    如果您希望执行大部分操作,从服务器获取 UtcTime 并使用 TimeZoneInfo.ConvertTimeFromUtc 进行转换可能会更加简化。不过,基本上是相同的过程。

    【讨论】:

      【解决方案3】:

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

      [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));
          }
      

      【讨论】:

      • 不需要LINQ,你可以使用TimeZoneInfo.FindSystemTimeZoneById。此外,您显示的 ID 不是 OP 描述的 ID,如果值是 UTC,则服务器的时区应该是无关紧要的。除非用户的时区总是已知,否则它也无济于事。
      • 马特,你是对的。 FindSystemTimeZoneById 可以在这里使用
      • 小罗,在本例中,我在 TimeZoneInfo 中搜索服务器时间,即山区标准时间。然后我在 TimeZoneInfo 中搜索本地时间,即大西洋标准时间。当我得到它们时,我将日期时间从服务器时间转换为本地时间。清楚了吗?
      • @EvgenyShmanev 是否​​让TimeZoneInfo.ConvertTime 照顾Daylight Saving
      • @RonaldinhoLearnCoding,是的,当然。请查看更新的测试。我已经用 Rissian 标准时间更改了服务器时区,因为没有夏令时。有两种不同的断言。
      猜你喜欢
      • 2010-09-24
      • 2011-02-12
      • 2012-06-08
      • 1970-01-01
      • 1970-01-01
      • 2021-03-09
      • 2017-10-08
      • 1970-01-01
      • 2016-07-08
      相关资源
      最近更新 更多