将UTC/GMT时间转换为当地时间

nzp*_*mad 291 .net c# datetime utc

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

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);            
Run Code Online (Sandbox Code Playgroud)

根据这个日期网站:

UTC/GMT抵消

标准时区:UTC/GMT +12小时
夏令时:+ 1小时
当前时区偏移:UTC/GMT +13小时

我们如何调整额外的小时?这可以通过编程方式完成,还是PC上的某种设置?

Dre*_*kes 367

对于字符串,例如2012-09-19 01:27:30.000,DateTime.Parse无法分辨日期和时间来自哪个时区.

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

  • 不明
  • 本地
  • 世界标准时间

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


所以对于你问题中的代码:

DateTime convertedDate = DateTime.Parse(dateStr);

var kind = convertedDate.Kind; // will equal DateTimeKind.Unspecified
Run Code Online (Sandbox Code Playgroud)

你说你知道它是什么类型,所以告诉它.

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

var kind = convertedDate.Kind; // will equal DateTimeKind.Utc
Run Code Online (Sandbox Code Playgroud)

现在,一旦系统知道它在UTC时间,你可以调用ToLocalTime:

DateTime dt = convertedDate.ToLocalTime();
Run Code Online (Sandbox Code Playgroud)

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

  • 另一种指定类型的方法:`DateTime convertedTime = new DateTime(DateTime.Parse(dateStr).Ticks),DateTimeKind.Utc);` (18认同)
  • @ CJ7:是的,但明确对于可能需要维护代码的其他开发人员特别有用. (14认同)
  • 将`DateTime`的`Kind`从`Unspecified`改为`UTC`的步骤是不必要的.为了ToLocalTime的目的,`Unspecified`被假定为`UTC`:http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx (6认同)
  • 此解决方案是否可以解决夏令时问题?当我尝试它时,我已经休息了一个小时. (2认同)

Dan*_*ger 119

如果你在.NET 3.5中,我会考虑使用System.TimeZoneInfo类.请参阅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);
Run Code Online (Sandbox Code Playgroud)

  • +1假设服务器不在新西兰 (37认同)
  • 如果有人需要,这里是我为TimeZoneInfo.FindSystemTimeZoneById找到的时区列表 - http://www.codeproject.com/Messages/3867850/Csharp-NET-List-of-timezones-for-TimeZoneInfo-Find. ASPX (10认同)

cod*_*er1 54

TimeZone.CurrentTimeZone.ToLocalTime(date);
Run Code Online (Sandbox Code Playgroud)

  • 这仅在系统知道转换的日期是UTC时才有效.请看我的答案. (8认同)
  • 但是 UTC 是默认的不是吗?因此,它适用于 CJ7 的回答中的“未指定”。 (3认同)

CJ7*_*CJ7 23

DateTime对象具有KindUnspecified默认,其为以下目的ToLocalTime假定为UTC.

要获取Unspecified DateTime对象的本地时间,您只需要这样做:

convertedDate.ToLocalTime();
Run Code Online (Sandbox Code Playgroud)

改变的步骤KindDateTimeUnspecifiedUTC是不必要的.Unspecified假定是UTC出于以下目的ToLocalTime:http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx

  • 反之亦然:`convertedDate.FromLocalTime();`将转换为`UTC`. (5认同)

Dav*_*vid 16

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

DateTime.Parse()可能很棘手 - 例如,请看这里.

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

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

或者,甚至更好,

DateTime.TryParseExact(...)
Run Code Online (Sandbox Code Playgroud)

AssumeUniversal标志告诉解析器日期/时间已经是UTC; 的组合AssumeUniversal,并AdjustToUniversal告诉它不要结果"本地"的时候,它会尝试在默认情况做转换.(无论如何,我个人尝试在业务/应用程序/服务层专门处理UTC.但绕过转换到本地时间也会加速 - 在我的测试中增加50%或更多,见下文.)

这是我们之前做的事情:

DateTime.Parse(dateString, new CultureInfo("en-US"))
Run Code Online (Sandbox Code Playgroud)

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

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

  • +1用于分析解析方法.很高兴知道! (3认同)

Mar*_*k T 14

我只想补充一点注意事项.

如果你所做的只是从计算机的内部时钟获取当前时间,在显示器或报告上显示日期/时间,那么一切都很顺利.但是,如果您要保存日期/时间信息以供日后参考或计算日期/时间,请注意!

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

  • 实际上,#2并不完全正确.事实上,在每个时区都有关于DST的规则,如果信息已经安装(和更新),您的计算机就会知道.对于许多区域,这些规则是固定的.其他人实施"动态DST".巴西是我的宠儿.总而言之,如果当地时间在12月份是DST,那么你的计算机可以计算出来,假设从现在到现在之间没有任何变化通过法律. (6认同)

Bre*_*itz 5

不要忘记,如果您已经有一个 DateTime 对象并且不确定它是 UTC 还是 Local,直接在对象上使用方法很容易:

DateTime convertedDate = DateTime.Parse(date);
DateTime localDate = convertedDate.ToLocalTime();
Run Code Online (Sandbox Code Playgroud)

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

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

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

DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges( year );
Run Code Online (Sandbox Code Playgroud)

如上所述,请仔细检查您的服务器所在的时区设置。网上有关于如何安全地影响 IIS 中的更改的文章。


Pri*_*sad 5

@TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)
Run Code Online (Sandbox Code Playgroud)