如何将服务器时间转换为本地时间并处理夏令时
How to get convert server time to local time and deal with daylight saving time
我在 Godaddy 上托管我的网站(asp.net webforms、.Net 4.5、SQL Server 2012),他们(服务器)使用 Mountain Standard Time
(- 7 与 UTC
时间相比) 从未改变 并且 不 遵守夏令时。
所以如果我这样做
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 they use EDT in the summer and EST 在冬天
如何获得正确的用户当前时间?假设用户打开我的网络应用程序并点击 Show my time
按钮,它会显示正确的当前用户时间?
您可以使用 TimeZoneInfo.ConvertTime 将一个时区转换为另一个时区。但是,如果您只是转换为 EST 或 EDT,它将始终显示该值。如果你想始终为客户端显示正确的时间,你需要做一些事情,比如使用 Javascript 将客户端浏览器的本地时区存储在 cookie 中,然后使用该值作为转换为的时区.
从服务器获取 UtcTime 并使用 TimeZoneInfo.ConvertTimeFromUtc 从中转换可能会更简单一些,如果您希望做很多这样的事情。不过基本上是相同的过程。
永远不要依赖服务器的时区设置。因此 DateTime.Now
不应 曾经 在 ASP.NET 应用程序中使用。
还有许多其他原因需要避免 DateTime.Now
。阅读:The case against DateTime.Now.
无论如何,服务器的当地时间永远不能保证是您网站用户的当地时间。如果是,纯属巧合
获取用户所在时区的当前时间的最简单方法是通过 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");
其实检测用户的时区是一个目前没有解决方案的难题。有些人可能会推荐 new Date().getTimezoneOffset()
,但这只会为您提供当前的数字偏移量,而不是时区。 DST 的偏移量可能会发生变化,许多时区使用类似的偏移量。还有 complications for historical dates near DST transitions 对你不利。
像jsTimeZoneDetect这样的脚本可以猜测你的IANA时区ID,比如America/New_York
东部时间,但它们不是100%准确。如果您需要服务器上用户的时区,那么最终应该询问用户在您的应用程序中某处的时区。
在 .NET 中,您可以使用 Noda Time 来处理 IANA 时区。没有 Noda Time,.NET 有 TimeZoneInfo
class,但它只能使用 Windows 时区。
如果您确定用户位于佐治亚州亚特兰大(美国东部时区),那么您可以这样做:
DateTime utc = DateTime.UtcNow;
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime eastern = TimeZoneInfo.ConvertTimeFromUtc(utc, tz);
或者,使用野田时间和 IANA 时区 ID:
Instant now = SystemClock.Instance.Now;
DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/New_York"];
ZonedDateTime eastern = now.InZone(tz);
看看这个例子。这很容易。
[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));
}
我在 Godaddy 上托管我的网站(asp.net webforms、.Net 4.5、SQL Server 2012),他们(服务器)使用 Mountain Standard Time
(- 7 与 UTC
时间相比) 从未改变 并且 不 遵守夏令时。
所以如果我这样做
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 they use EDT in the summer and EST 在冬天
如何获得正确的用户当前时间?假设用户打开我的网络应用程序并点击 Show my time
按钮,它会显示正确的当前用户时间?
您可以使用 TimeZoneInfo.ConvertTime 将一个时区转换为另一个时区。但是,如果您只是转换为 EST 或 EDT,它将始终显示该值。如果你想始终为客户端显示正确的时间,你需要做一些事情,比如使用 Javascript 将客户端浏览器的本地时区存储在 cookie 中,然后使用该值作为转换为的时区.
从服务器获取 UtcTime 并使用 TimeZoneInfo.ConvertTimeFromUtc 从中转换可能会更简单一些,如果您希望做很多这样的事情。不过基本上是相同的过程。
永远不要依赖服务器的时区设置。因此
DateTime.Now
不应 曾经 在 ASP.NET 应用程序中使用。还有许多其他原因需要避免
DateTime.Now
。阅读:The case against DateTime.Now.无论如何,服务器的当地时间永远不能保证是您网站用户的当地时间。如果是,纯属巧合
获取用户所在时区的当前时间的最简单方法是通过 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");
其实检测用户的时区是一个目前没有解决方案的难题。有些人可能会推荐
new Date().getTimezoneOffset()
,但这只会为您提供当前的数字偏移量,而不是时区。 DST 的偏移量可能会发生变化,许多时区使用类似的偏移量。还有 complications for historical dates near DST transitions 对你不利。像jsTimeZoneDetect这样的脚本可以猜测你的IANA时区ID,比如
America/New_York
东部时间,但它们不是100%准确。如果您需要服务器上用户的时区,那么最终应该询问用户在您的应用程序中某处的时区。在 .NET 中,您可以使用 Noda Time 来处理 IANA 时区。没有 Noda Time,.NET 有
TimeZoneInfo
class,但它只能使用 Windows 时区。如果您确定用户位于佐治亚州亚特兰大(美国东部时区),那么您可以这样做:
DateTime utc = DateTime.UtcNow; TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); DateTime eastern = TimeZoneInfo.ConvertTimeFromUtc(utc, tz);
或者,使用野田时间和 IANA 时区 ID:
Instant now = SystemClock.Instance.Now; DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/New_York"]; ZonedDateTime eastern = now.InZone(tz);
看看这个例子。这很容易。
[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));
}