我有一个UTC时间字符串(我从数据库中获取,因此我无法更改格式)是使用DateTime.UtcNow.ToString("s")
创建的。我希望展示一些面向用户的内容,例如" 10:00 AM"。我在哪里(在英格兰),时钟最近向前推进,以下方法是一小时出发:
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);
印刷" 9:02 AM"实际上它的时间是10:02 AM。
以下是http://csharppad.com/上重新发布的屏幕截图:
我做错了什么以及获取DateTime对象的最简单方法是什么?当我调用.ToShortTimeString()
时,它会返回正确的时间?
NB the docs on ToLocalTime()说:
转换还会考虑适用于当前DateTime对象所代表的时间的夏令时规则。
答案 0 :(得分:7)
你说:
我有一个UTC时间字符串(我从数据库中获取,因此我无法更改格式)是使用
DateTime.UtcNow.ToString("s")
创建的。
马上,你有一个问题。数据库中的日期(通常)不存储为字符串。它们存储在具有特定数据类型的字段中。在SQL Server中(例如),您可能正在使用datetime
或datetime2
字段。这些不是字符串。当您将它们检索到.NET代码中时,它们会直接转换为DateTime
类型。如果你把它当作一个字符串来处理,你就错了。
例如,您的数据访问代码可能正在执行以下操作:
DateTime dt = Convert.ToDateTime(dataReader["myDateTimeField"].ToString());
这很常见,而且完全错误。你应该这样做:
DateTime dt = (DateTime) dataReader["myDateTimeField"];
或者如果字段可以为空:
DateTime? dt = dataReader["myDateTimeField"] as DateTime;
正确加载值而不是将其解析为字符串后,其余的都可以正常工作。 DateTime
属性的DateTimeKind.Unspecified
值为Kind
,当您在其上调用ToLocalTime
时,它会假定您要将未指定的值视为UTC。 (See the chart on MSDN。)
关于您发布的代码,虽然它有点混乱(不必要地浏览字符串),但它实际上可以正常工作 - 假设您在 时区中运行它。在ToLocalTime
方法中," local"表示代码恰好在哪里运行的本地时区设置。 对于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);
或者,您可以使用开源Noda Time库,如下所示:
DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/London"];
DateTime englandDateTime = Instant.FromDateTimeUtc(utcDateTime)
.InZone(tz)
.ToDateTimeUnspecified();
答案 1 :(得分:0)
当我在本地运行代码时,它会给出预期的结果(本地时间对应于我的机器本地时间)。 虽然当我在http://csharppad.com上运行它时,时间是相同的。 Matt Johnson的答案中提到了原因:服务器与本地计算机有不同的时区。
答案 2 :(得分:0)
对于其他认为DateTime.ToLocalTime忽略夏时制时间的人(就像我一样),要意识到的是,您要转换的日期是是否考虑夏时制的基础。
示例:将UTC日期时间'1/1/2020'转换为我的本地(美国中部),我得到:'12 / 31/2019 18:00:00',这是正确的。当我在四月运行此程序并且夏令时生效时,我期望的是UTC-5:00而不是UTC-6:00。但是1月是CST,而不是CDT,因此UTC-6:00是正确的。
您的问题可能是“用户错误”,因为这是我的。