2008-10-07 239 views
244

我们正在为Web服务客户端开发C#应用程序。这将在Windows XP PC上运行。将UTC/GMT时间转换为当地时间

Web服务返回的字段之一是DateTime字段。服务器以GMT格式返回一个字段,即最后以“Z”结尾。

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

下面的代码示例在一定程度上解决了这个问题,因为12小时的差异已经消失,但它不允许新西兰夏令时。

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

this date site

UTC/GMT偏移

标准时区:UTC/GMT12小时
夏令时间:1小时
目前时区偏移:UTC/GMT +13小时

我们如何调整额外的小时?这可以通过编程来完成吗?或者这是PC上的某种设置?

+1

了`Z`时间是指UTC,而不是GMT。这两者可以相差最多0.9秒。 – mc0e 2017-02-27 04:30:07

回答

42
TimeZone.CurrentTimeZone.ToLocalTime(date); 
+8

这只有在系统知道正在转换的日期是UTC时才有效。请看我的答案。 – 2009-06-08 07:44:19

+1

但UTC是默认的,不是吗?因此它适用于CJ7的答案中的“未指定”。 – NickG 2013-06-12 14:06:05

2

在回答德纳的建议:

的代码示例现在看起来像:

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

原来的日期是20/08/08;那种是UTC。

两者 “convertedDate” 和 “DT” 是相同的:

21/08/08 10点00分26秒;那种是本地的

+0

请参阅我的答案对此进行解释。 – 2009-06-08 07:46:35

1

我有一个数据集被推送通过线(web服务到客户端),它会自动更改,因为DataColumn的DateType字段设置为本地的问题。确保你检查什么DateType是如果你推动DataSets跨。

如果你不想让它改变,其设置为未指定

13

我只是想补充谨慎的备忘。

如果您所做的只是从计算机的内部时钟获取当前时间以在显示屏或报表上输入日期/时间,则一切正常。但如果你是保存日期/时间信息供以后参考或者计算日期/时间,请注意!

假设您确定一艘邮轮于2007年12月20日15:00 UTC抵达檀香山。你想知道当地时间是什么。
1.可能至少有三个“本地人”参与其中。本地可能意味着檀香山,或者它可能意味着您的计算机所在的位置,或者它可能意味着您的客户所在的位置。
2。如果使用内置函数进行转换,则可能是错误的。这是因为夏令时(可能)目前在您的计算机上生效,但在十二月份不生效。但Windows不知道这一点......它只有一个标志来确定夏令时是否正在生效。如果目前正在实施,那么它甚至会在12月份的某个日期快乐地增加一个小时。
3.夏令时在各个政治分支中的实施方式不同(或根本不同)。不要认为,仅仅因为你的国家在特定的日期发生变化,其他国家也会这样做。

+5

其实#2并不完全正确。事实上,在每个时区都有关于DST的规则,您的计算机将知道信息是否已安装(和更新)。对于许多区域来说,这些规则是固定的。其他人实施“动态DST”。巴西是我的宠儿。总而言之,如果您的当地时间是十二月份的DST,假设现在和之后没有任何变化通过法律,您的计算机可以计算出您的当地时间。 – 2011-06-16 12:04:04

+0

即使你不住在巴西,DST也是“有活力的”,因为政治家可以随时改变它(就像几年前在美国所做的那样)。由于大多数软件都是为了将​​来的使用而编写的,因此意识到没有实用的,可预测的甚至是理论的方式来了解DST规则将会生效。你可以靠近,但通过放弃完美来拯救自己一些挫败感。 – DaveWalley 2014-05-14 20:45:31

4

如果你已经有了一个DateTime对象,不知道这是否是UTC或本地不要忘了,这是很容易使用,直接在物体上的方法:

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

我们如何调整额外的一小时?

除非指定.net将使用本地pc设置。我有一个读:http://msdn.microsoft.com/en-us/library/system.globalization.daylighttime.aspx

通过长相代码可能看起来像:

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

和上面仔细检查所提到什么时区设置您的服务器上。网上有关于如何安全地影响IIS中的更改的文章。

+0

只要你告诉系统你的日期是什么样的(本地/ utc /未指定),系统会为你处理这种情况。 – 2009-06-08 07:47:43

103

我打算使用System.TimeZoneInfo类,如果你在.NET 3.5。见http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx。这应该考虑到夏令时更改正确。

// 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); 
+0

如果你在自己的时区(在这种情况下是en-NZ)工作,那么你不需要处理TimeZoneInfo。这只是不必要的复杂性。看到我的答案更详细。 – 2009-06-08 07:45:20

+32

+1不假设服务器在新西兰 – ajbeaven 2010-09-07 07:02:11

329

字符串,例如2012-09-19 01:27:30.000DateTime.Parse分不清哪个时区的日期和时间是从。

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

  • 不明
  • 本地
  • UTC

注意如果你是希望代表UTC以外的日期/时间或当地时间e区,那么你应该使用DateTimeOffset


所以对于你的问题代码:

DateTime convertedDate = DateTime.Parse(dateStr); 

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

你说你知道它是什么样的,所以告诉它。现在

DateTime convertedDate = DateTime.SpecifyKind(
    DateTime.Parse(dateStr), 
    DateTimeKind.Utc); 

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

,一旦系统知道它的UTC时间,你可以叫ToLocalTime

DateTime dt = convertedDate.ToLocalTime(); 

这会给你所需要的结果。

1

我遇到了这个问题,因为我在通过twitter API(status上的created_at字段)返回的UTC日期有问题;我需要将它们转换为DateTime。本页答案中没有任何答案/代码样本足以阻止我得到“字符串未被识别为有效的DateTime”错误(但它是最接近我必须在SO上找到正确答案)

这里张贴此链接的情况下,这可以帮助别人 - 我所需要的答案在这个博客帖子发现:http://www.wduffy.co.uk/blog/parsing-dates-when-aspnets-datetimeparse-doesnt-work/ - 基本上使用DateTime.ParseExact与格式字符串代替DateTime.Parse

15

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

DateTime.Parse()可能会很棘手 - 例如参见here

如果DateTime从Web服务或一些其它音源与已知的格式来了,你可能要考虑像

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

,或者甚至更好,

DateTime.TryParseExact(...) 

AssumeUniversal标志告诉解析器日期/时间已经是UTC; AssumeUniversalAdjustToUniversal的组合告诉它不要将结果转换为“本地”时间,默认情况下它会尝试执行。 (我个人试图在业务/应用/服务层中专门处理UTC,但绕过本地时间的转换也会加快速度 - 在我的测试中速度增加50%或更多,请参阅下文。)

下面是我们在做什么之前:我们已经成型的应用,发现DateTime.Parse代表CPU的使用显著比例

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

。 (顺便说一句,CultureInfo构造是一个显著贡献者CPU使用率。)

所以我成立了一个控制台应用程序来解析日期/时间字符串10000次各种方式。底线:
Parse() 10秒
ParseExact()(转换为本地)20-45毫秒
ParseExact()(未转换为本地)10-15毫秒
...是,对于Parse()结果是在 ,而其他人在毫秒

15

DateTime对象默认情况下有KindUnspecified,对于ToLocalTime的用途假定为UTC

为了得到一个UnspecifiedDateTime对象的本地时间,所以你只需要做到这一点:

convertedDate.ToLocalTime(); 

改变DateTimeUnspecifiedKindUTC的步骤是不必要的。Unspecified被假定为UTCToLocalTime目的:http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx

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