我有一个UTC时间字符串(我从数据库中获取,因此我无法更改格式)DateTime.UtcNow.ToString("s").我想展示一些面向用户的内容,如"上午10点".我在哪里(在英格兰),时钟最近出现了,下面的方法是一小时出来:
var timenowstring = DateTime.UtcNow.ToString("s");
var dateutc = DateTime.Parse(timenowstring).ToShortTimeString();
var datelocal = DateTime.Parse(timenowstring).ToLocalTime().ToShortTimeString();
Console.WriteLine("Utc time string: " + dateutc);
Console.WriteLine("Local time string: " + datelocal);
Run Code Online (Sandbox Code Playgroud)
两者都打印"上午9:02"实际上是10:02 AM.
这是在http://csharppad.com/上重新发布的屏幕截图:
我做错了什么以及获取DateTime对象的最简单方法是.ToShortTimeString()什么?它会在我调用时返回正确的时间?
转换还考虑了适用于当前DateTime对象所表示的时间的夏令时规则.
你说:
我有一个UTC时间字符串(我从数据库中获取,因此我无法更改格式)
DateTime.UtcNow.ToString("s").
蝙蝠,你有一个问题.数据库中的日期(通常)不存储为字符串.它们存储在具有特定数据类型的字段中.在SQL Server(例如)中,您可能正在使用datetime或datetime2字段.这些不是字符串.将它们检索到.NET代码中时,它们会直接转换为DateTime类型.如果你把它当作一个字符串来对待,那你做错了.
例如,您的数据访问代码可能正在执行以下操作:
DateTime dt = Convert.ToDateTime(dataReader["myDateTimeField"].ToString());
Run Code Online (Sandbox Code Playgroud)
这是非常普遍的,完全错误的.你应该这样做:
DateTime dt = (DateTime) dataReader["myDateTimeField"];
Run Code Online (Sandbox Code Playgroud)
或者如果字段可以为空:
DateTime? dt = dataReader["myDateTimeField"] as DateTime;
Run Code Online (Sandbox Code Playgroud)
一旦正确加载值而不是将其解析为字符串,其余的都可以正常工作.该DateTime值将具有DateTimeKind.Unspecified其Kind属性,当您调用ToLocalTime它时,它将假定您希望将未指定的值视为UTC.(参见MSDN上的图表.)
关于你发布的代码,虽然它有点乱(不必要地通过字符串),它实际上会工作得很好 - 假设你在你的时区运行它.在该ToLocalTime方法中,"本地"表示代码恰好在哪里运行的机器的本地时区设置. 对于csharppad.com,时区恰好是UTC.它无法知道你想要使用英格兰的时区规则.

如果您打算在服务器上运行代码,那么您根本不应该使用ToLocalTime- 因为服务器的时区可能不相关.相反,您可以TimeZoneInfo用来转换时间:
// this uses the time zone for England
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTime englandDatetime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, tz);
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用开源Noda Time库,如下所示:
DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/London"];
DateTime englandDateTime = Instant.FromDateTimeUtc(utcDateTime)
.InZone(tz)
.ToDateTimeUnspecified();
Run Code Online (Sandbox Code Playgroud)