DateTime.TryParse中的奇怪行为
本文关键字:TryParse DateTime | 更新日期: 2023-09-27 18:00:23
我正在尝试用解析DateTime字符串"5-5-5-5"
DateTime.TryParse("5-5-5-5", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out result);
我希望这个能转换成
5/5/2005 5:00:00 AM
但相反,它被转换为
5/5/2005 10:30:00 AM.
看起来它将提供的日期时间解释为GMT。这有点违反直觉,因为我已经指定了AssumeLocal
标志。这是DateTime
类中的错误吗?
我理解您的观点,并调试dot-net框架代码以了解后台发生了什么。
TryParse
方法忽略DateTimeStyles.AssumeLocal
标志,只处理AdjustToUniversal
标志。
if ((styles & DateTimeStyles.AdjustToUniversal) != 0) {
return (AdjustTimeZoneToUniversal(ref result));
}
return (AdjustTimeZoneToLocal(ref result, bTimeOnly));
另一方面,
TryParseExact
方法得到了正确的实现,并且它具有处理DateTimeStyles.AssumeLocal
标志所需的所有逻辑。查看此实现中如何处理其他案例。
// If AssumeLocal or AssumeLocal is used, there will always be a kind specified. As in the
// case when a time zone is present, it will default to being local unless AdjustToUniversal
// is present. These comparisons determine whether setting the kind is sufficient, or if a
// time zone adjustment is required. For consistentcy with the rest of parsing, it is desirable
// to fall through to the Adjust methods below, so that there is consist handling of boundary
// cases like wrapping around on time-only dates and temporarily allowing an adjusted date
// to exceed DateTime.MaxValue
if ((styles & DateTimeStyles.AssumeLocal) != 0) {
if ((styles & DateTimeStyles.AdjustToUniversal) != 0) {
result.flags |= ParseFlags.TimeZoneUsed;
result.timeZoneOffset = TimeZoneInfo.GetLocalUtcOffset(result.parsedDate, TimeZoneInfoOptions.NoThrowOnInvalidTime);
}
else {
result.parsedDate = DateTime.SpecifyKind(result.parsedDate, DateTimeKind.Local);
return true;
}
}
else if ((styles & DateTimeStyles.AssumeUniversal) != 0) {
if ((styles & DateTimeStyles.AdjustToUniversal) != 0) {
result.parsedDate = DateTime.SpecifyKind(result.parsedDate, DateTimeKind.Utc);
return true;
}
else {
result.flags |= ParseFlags.TimeZoneUsed;
result.timeZoneOffset = TimeSpan.Zero;
}
}
else {
// No time zone and no Assume flags, so DateTimeKind.Unspecified is fine
Contract.Assert(result.parsedDate.Kind == DateTimeKind.Unspecified, "result.parsedDate.Kind == DateTimeKind.Unspecified");
return true;
}
顺便说一下,调试Dot-Net框架代码很有趣。如果您感兴趣,请按照以下步骤操作。
如果未指定时区,则必须使用AssumeLocal
或AssumeUniversal
显式指示时区,然后使用AdjustToUniversal
:将其转换为UTC
DateTimeStyles.AssumeLocal | DateTimeStyles.AdjustToUniversal
或
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal
在MSDN上阅读更多信息,并关注最后一句话:
调整为通用:
如果输入字符串表示本地时间,则通过时区说明符或
AssumeLocal
将日期和时间从本地时间转换为UTC。如果输入字符串通过时区说明符或
AssumeUniversal
表示UTC时间,则不会发生转换。如果输入字符串不表示本地或UTC时间,则不会发生任何转换,并且生成的Kind属性为Unspecified。
如果您想要的结果是:
2005年5月5日上午5:00:00
调整到通用:
日期和时间返回为协调世界时(UTC)。如果输入字符串表示本地时间,则通过时区说明符或AssuumeLocal将日期和时间从本地时间转换为UTC。如果输入字符串通过时区说明符或AssuumeUniversal表示UTC时间,则不会发生转换。如果输入字符串不表示本地时间或UTC时间,则不会发生转换,并且生成的Kind属性为Unspecified。此值不能与RoundtripKind一起使用。
使用以下代码作为AdjustToUniversal
:
DateTime result;
dt= DateTime.TryParse("5-5-5-5" , CultureInfo.InvariantCulture,DateTimeStyles.AdjustToUniversal , out result);
DateTimeStyles.AdjustToUniversal
就是您想要的。