我一直在为此苦苦挣扎,所以我会坚持下去。
我有一个应用程序,需要在其中将字符串解析为日期时间。字符串如下所示:
"201503131557"
(它们始终为“ yyyyMMddHHmm”格式),即使未指定,也始终处于“中央标准时间”(或中央夏令时,具体取决于日期)。
当我解析它们时,我了解它会将它们解析为本地时间。我在Azure PaaS上运行,并且不想为了支持此操作而将其更改为在CST中运行。
我如何编写可在本地和Azure PaaS中使用的代码,以将这些日期正确解析为DateTimes并将其时区设置为CST?
这是我为证明马特·约翰逊的答案而编写的快速单元测试。
[TestMethod]
public void DateTests()
{
var unSpecDt = DateTime.ParseExact("201503131557", "yyyyMMddHHmm", CultureInfo.InvariantCulture);
var tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var utcDt = TimeZoneInfo.ConvertTimeToUtc(unSpecDt, tz);
var offset = tz.GetUtcOffset(unSpecDt);
var dto =new DateTimeOffset(unSpecDt, offset);
var cstDt = dto.DateTime;
Assert.IsTrue(cstDt.Hour - utcDt.Hour == offset.Hours);
}
答案 0 :(得分:3)
要解析字符串,因为您只有日期和时间,并且知道字符串将采用的特定格式,请执行以下操作:
DateTime dt = DateTime.ParseExact("201503131557", "yyyyMMddHHmm", CultureInfo.InvariantCulture);
结果值会将其Kind
属性设置为DateTimeKind.Unspecified
(不是您所想的本地时间)。这是意料之中的,因为您未提供有关此时间戳记与UTC或本地时间之间的关系的信息。
您说的值代表中央标准时间的时间。您将需要一个了解该时区的TimeZoneInfo
对象。
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
请注意,此标识符表示在美国观察到的中部时间,包括CST或CDT,这取决于给定值的生效时间(尽管名称中带有“标准”字样)。还要注意,它仅在Windows操作系统上有效。如果要在其他操作系统上使用.NET Core,则需要传递IANA标识符"America/Chicago"
(或使用我的TimeZoneConverter库在任何平台上使用任一标识符)。>
下一步是找出要使用此值进行 的操作。您可能会用它做一些不同的事情:
如果要将其转换为等效的UTC值(表示为DateTime
),则可以执行以下操作:
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(dt, tz);
如果您想要一个DateTimeOffset
表示形式来保存您提供的输入以及与美国中部时间相关的UTC偏移量,则可以执行以下操作:
TimeSpan offset = tz.GetUtcOffset(dt);
DateTimeOffset dto = new DateTimeOffset(dt, offset);
请记住,如果输入时间接近DST转换,则输入时间可能无效或含糊。在这种情况下,GetUtcOffset
方法将返回 standard 偏移量。如果您想要不同的行为,则可以编写更多代码(超出本文范围)。
您还可以做其他事情,所有这些工作都由TimeZoneInfo
类提供。
请注意,“ Azure PaaS”可能指的是一些不同的东西,尽管Azure App Service中有一个名为WEBSITE_TIME_ZONE
的设置-我不建议您依靠它。认为只有在无法控制代码时才可以使用它。在大多数情况下,最好不要编写代码来完全不依赖于运行它的系统的时区设置。这意味着永远不要调用DateTime.Now
,TimeZoneInfo.Local
,DateTime.ToLocalTime
甚至DateTime.ToUniversalTime
(因为它会转换 from 本地时区),等等。而是依赖与UTC或特定时区或偏移量显式兼容的方法。这样一来,您就不必担心应用程序的托管位置。
最后,请了解DateTime
或DateTimeOffset
类型都不具有将值绑定到特定时区的能力。为此,您需要编写自己的类,或者查看其ZonedDateTime
类提供此类功能的Noda Time库。
答案 1 :(得分:0)
您可以使用:
public static DateTime ParseExact (string s, string format, IFormatProvider provider);
此日期时间没有有关时区的任何元数据。您可以转换为UTC,然后确保可以转换为所有时区。
答案 2 :(得分:0)
将DateTime.TryParseExact(...)方法与DateTimeStyles.RoundtripKind
一起使用以避免转换。
DateTime dt;
DateTime.TryParseExact("201503131557", "yyyyMMddHHmm", null, System.Globalization.DateTimeStyles.RoundtripKind, out dt);
如果需要进行转换,则需要转到UTC,然后将TimeZoneInfo
与TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
一起使用转换方法。