关于C#:将UTC/GMT时间转换为本地时间

Convert UTC/GMT time to local time

我们正在为Web服务客户机开发一个C应用程序。这将在Windows XP PC上运行。

Web服务返回的字段之一是日期时间字段。服务器返回一个gmt格式的字段,即末尾带有"z"。

然而,我们发现.NET似乎做了某种隐式转换,而且时间总是12小时。

以下代码示例在某种程度上解决了这一问题,即12小时的时差已经消失,但它不考虑新西兰的日光节约。

1
2
3
CultureInfo ci = new CultureInfo("en-NZ");
string date ="Web service date".ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);

根据此日期站点:

UTC/GMT Offset

Standard time zone: UTC/GMT +12 hours
Daylight saving time: +1 hour
Current time zone offset: UTC/GMT +13 hours

我们如何调整额外的时间?这可以通过编程方式完成,还是在电脑上进行某种设置?


对于像2012-09-19 01:27:30.000这样的字符串,DateTime.Parse无法判断日期和时间来自哪个时区。

DateTime有一个种类属性,可以有三个时区选项之一:

  • 未指定的
  • 局部的
  • UTC

注意:如果您希望表示除UTC或本地时区以外的日期/时间,则应使用DateTimeOffset

因此,对于问题中的代码:

1
2
3
DateTime convertedDate = DateTime.Parse(dateStr);

var kind = convertedDate.Kind; // will equal DateTimeKind.Unspecified

你说你知道它是什么样的,所以说吧。

1
2
3
4
5
DateTime convertedDate = DateTime.SpecifyKind(
    DateTime.Parse(dateStr),
    DateTimeKind.Utc);

var kind = convertedDate.Kind; // will equal DateTimeKind.Utc

现在,一旦系统知道它在UTC时间内,您就可以调用ToLocalTime

1
DateTime dt = convertedDate.ToLocalTime();

这将为您提供所需的结果。


如果您在.NET 3.5中,我将研究使用System.TimeZoneInfo类。请参阅http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx。这应正确考虑日光节约的变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
// Coordinated Universal Time string from
// DateTime.Now.ToUniversalTime().ToString("u");
string date ="2009-02-25 16:13:00Z";
// Local .NET timeZone.
DateTime localDateTime = DateTime.Parse(date);
DateTime utcDateTime = localDateTime.ToUniversalTime();

// ID from:
//"HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zone"
// See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.id.aspx
string nzTimeZoneKey ="New Zealand Standard Time";
TimeZoneInfo nzTimeZone = TimeZoneInfo.FindSystemTimeZoneById(nzTimeZoneKey);
DateTime nzDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, nzTimeZone);


1
TimeZone.CurrentTimeZone.ToLocalTime(date);


DateTime对象默认为UnspecifiedKind,根据ToLocalTime的目的,该对象假定为UTC

要获取UnspecifiedDateTime对象的本地时间,您只需执行以下操作:

1
convertedDate.ToLocalTime();

DateTimeKindUnspecified改为UTC的步骤是不必要的。在ToLocalTime中,Unspecified假定为UTC:http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx


我知道这是一个老问题,但我遇到了类似的情况,我想分享我为未来的搜索者找到的东西,可能包括我自己)。

DateTime.Parse()可能很棘手——例如,请参见此处。

如果DateTime来自Web服务或其他具有已知格式的源,您可能需要考虑

1
2
3
4
DateTime.ParseExact(dateString,
                  "MM/dd/yyyy HH:mm:ss",
                   CultureInfo.InvariantCulture,
                   DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)

或者,更好的是,

1
DateTime.TryParseExact(...)

AssumeUniversal标志告诉解析器日期/时间已经是UTC;AssumeUniversalAdjustToUniversal的组合告诉解析器不要将结果转换为"本地"时间,默认情况下会尝试这样做。(无论如何,我个人都试图在业务/应用程序/服务层中专门与UTC打交道。但是绕过转换到本地时间也会加快速度——在我的测试中提高50%或更多,见下文)。

以下是我们之前所做的:

1
DateTime.Parse(dateString, new CultureInfo("en-US"))

我们对应用程序进行了分析,发现datetime.parse占CPU使用率的很大一部分。(顺便说一下,CultureInfo构造函数对CPU的使用并不是一个重要的贡献者。)

因此,我设置了一个控制台应用程序,以各种方式解析10000次日期/时间字符串。底线:Parse()10秒ParseExact()(转换为本地)20-45 msParseExact()(不转换为本地)10-15 ms…是的,Parse()的结果是以秒为单位的,而其他的结果是以毫秒为单位的。


我只想增加一个一般性的注意事项。

如果您所做的就是从计算机的内部时钟中获取当前时间,以便在显示器或报表上显示日期/时间,那么一切都正常。但是,如果您正在保存日期/时间信息以供以后参考,或者正在计算日期/时间,请注意!

假设您确定一艘游轮于2007年12月20日15:00 UTC抵达檀香山。你想知道当地时间。1。可能至少有三个"当地人"参与其中。本地可能是指檀香山,也可能是指您的计算机所在地,也可能是指您的客户所在地。2。如果使用内置函数进行转换,则可能是错误的。这是因为夏令时(可能)目前在您的计算机上有效,但在12月无效。但Windows不知道…它只有一个标志来确定夏令时当前是否有效。如果它目前有效,那么它将很高兴地为12月的某个日期增加一个小时。三。夏令时在不同的政治部门实施方式不同(或完全不同)。不要因为你的国家在某个特定的日期发生变化而认为其他国家也会改变。


不要忘记,如果您已经有了一个日期时间对象,并且不确定它是UTC还是本地的,那么直接在对象上使用这些方法就足够简单了:

1
2
DateTime convertedDate = DateTime.Parse(date);
DateTime localDate = convertedDate.ToLocalTime();

How do we adjust for the extra hour?

除非指定.NET将使用本地PC设置。我读过:http://msdn.microsoft.com/en-us/library/system.globalization.daylighttime.aspx

从外观上看,代码可能类似于:

1
DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges( year );

如上所述,再次检查服务器的时区设置。网上有一些文章介绍如何安全地影响IIS中的更改。


1
@TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)

作为对达纳建议的回应:

代码示例如下:

1
2
3
string date ="Web service date"..ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);            
DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(convertedDate);

最初的日期是2008年8月20日,类型是UTC。

"converteddate"和"dt"都是相同的:

2008年8月21日10:00:26;类型是本地的


我遇到这个问题的时候,你通过Twitter API返回的UTC日期有问题(在状态字段上创建了);我需要将它们转换为日期时间。本页答案中的所有答案/代码示例都不足以阻止我获取"字符串未被识别为有效的日期时间"错误(但这是我在so上找到正确答案的最接近方法)

在这里发布这个链接,以防对其他人有所帮助-我需要的答案可以在这个博客上找到:http://www.wduffy.co.uk/blog/parsing-dates-when-aspnets-datetime parse-doesnot-work/-基本上使用datetime.parseexact而不是datetime.parse


我有一个问题,它在一个数据集中被推过网络(WebService到客户端),因为DataColumn的日期类型字段设置为本地,所以它会自动更改。确保在推送数据集时检查日期类型是什么。

如果不想更改,请将其设置为"未指定"。