我们正在为Web服务客户端开发一个C#应用程序。这将在Windows XP PC上运行。
Web 服务返回的字段之一是"日期时间"字段。服务器返回一个 GMT 格式的字段,即末尾带有"Z"。
但是,我们发现 .NET 似乎进行了某种隐式转换,并且时间始终为 12 小时。
下面的代码示例在某种程度上解决了这个问题,因为 12 小时的差异已经消失,但它不允许新西兰夏令时。
CultureInfo ci = new CultureInfo("en-NZ");
string date = "Web service date".ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
根据此日期网站:
UTC/GMT 偏移量
标准时区:UTC/GMT +12 小时
夏令时:+1 小时
当前时区偏移量:UTC/GMT +13 小时
我们如何调整额外的小时数?这可以通过编程方式完成,还是这是PC上的某种设置?
对于像 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
你说你知道它是什么类型,所以告诉它。
DateTime convertedDate = DateTime.SpecifyKind(
DateTime.Parse(dateStr),
DateTimeKind.Utc);
var kind = convertedDate.Kind; // will equal DateTimeKind.Utc
现在,一旦系统知道它的UTC时间,你只需调用ToLocalTime
:
DateTime dt = convertedDate.ToLocalTime();
这将为您提供所需的结果。
在.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_MACHINESoftwareMicrosoftWindows NTCurrentVersionTime 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);
TimeZone.CurrentTimeZone.ToLocalTime(date);
默认情况下DateTime
对象具有Unspecified
Kind
,出于ToLocalTime
的目的,假定UTC
。
因此,要获取Unspecified
DateTime
对象的本地时间,您只需执行以下操作:
convertedDate.ToLocalTime();
不需要将DateTime
的Kind
从Unspecified
更改为UTC
。 Unspecified
被假定为UTC
ToLocalTime
:http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx
这是一个较老的问题,但我遇到了类似的情况,我想为未来的搜索者分享我的发现,可能包括我自己:)。
DateTime.Parse()
可能很棘手 - 例如,请参阅此处。
如果DateTime
来自 Web 服务或具有已知格式的其他源,则可能需要考虑类似
DateTime.ParseExact(dateString,
"MM/dd/yyyy HH:mm:ss",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)
或者,更好的是,
DateTime.TryParseExact(...)
AssumeUniversal
标志告诉解析器日期/时间已经是 UTC;AssumeUniversal
和 AdjustToUniversal
的组合告诉它不要将结果转换为"本地"时间,默认情况下它会尝试这样做。 (无论如何,我个人都尝试在业务/应用程序/服务层中专门处理UTC。 但是绕过到本地时间的转换也会加快速度 - 在我的测试中增加了 50% 或更多,见下文。
以下是我们之前所做的:
DateTime.Parse(dateString, new CultureInfo("en-US"))
我们已经分析了该应用程序,发现DateTime.Parse代表了CPU使用率的很大一部分。 (顺便说一下,CultureInfo
构造函数并不是 CPU 使用率的重要贡献者。
因此,我设置了一个控制台应用程序,以多种方式解析日期/时间字符串 10000 次。 底线:
Parse()
10 秒
ParseExact()
(转换为本地) 20-45 ms
ParseExact()
(不转换为本地) 10-15 ms
...是的,Parse()
的结果以秒为单位,而其他结果以毫秒为单位。
我只想补充一个一般的注意事项。
如果您所做的只是从计算机的内部时钟中获取当前时间以将日期/时间放在显示屏或报告上,那么一切都很好。 但是,如果您要保存日期/时间信息以供以后参考或正在计算日期/时间,请注意!
假设您确定一艘游轮于 2007 年 12 月 20 日 15:00 UTC 抵达檀香山。 你想知道那是当地时间。
1. 可能至少有三个"当地人"参与其中。 本地可能意味着檀香山,也可能意味着您的计算机所在的位置,或者可能意味着您的客户所在的位置。
2.如果使用内置函数进行转换,则可能是错误的。 这是因为夏令时目前(可能)在您的计算机上生效,但在 12 月未生效。 但是Windows不知道这一点...它只有一个标志来确定夏令时当前是否有效。 如果它目前有效,那么它甚至会很乐意在 12 月的日期增加一个小时。
3. 夏令时在各个政治分区的实施方式不同(或根本不实施)。 不要以为仅仅因为您所在的国家/地区在特定日期发生变化,其他国家/地区也会发生变化。
@TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)
不要忘记,如果您已经有一个 DateTime 对象并且不确定它是 UTC 还是本地,那么直接在对象上使用方法很容易:
DateTime convertedDate = DateTime.Parse(date);
DateTime localDate = convertedDate.ToLocalTime();
我们如何调整额外的小时数?
除非指定,否则 .net 将使用本地电脑设置。我会读到:http://msdn.microsoft.com/en-us/library/system.globalization.daylighttime.aspx
从外观上看,代码可能如下所示:
DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges( year );
如上所述,请仔细检查您的服务器所在的时区设置。网上有关于如何安全地影响 IIS 中的更改的文章。
在回答Dana的建议时:
代码示例现在如下所示:
string date = "Web service date"..ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(convertedDate);
最初的日期是20/08/08;那种是UTC。
"convertedDate"和"dt"都是相同的:
08-08-21 10:00:26;那种是本地的
我遇到了一个问题,它位于一个被推送到线路(网络服务到客户端)的数据集中,它会自动更改,因为 DataColumn 的 DateType 字段设置为本地。确保检查 DateType 是什么,如果你推送数据集。
如果不希望更改,请将其设置为"未指定"
我遇到了这个问题,因为我通过推特 API(状态上的created_at字段)返回的 UTC 日期有问题;我需要将它们转换为日期时间。此页面上答案中的任何答案/代码示例都不足以阻止我收到"字符串未被识别为有效的日期时间"错误(但这是我最接近在 SO 上找到正确答案)
在这里发布此链接以防这对其他人有帮助 - 我需要的答案在这篇博文中找到:http://www.wduffy.co.uk/blog/parsing-date-when-aspnets-datetimeparse-don't-work/- 基本上使用DateTime.ParseExact 与格式字符串而不是DateTime.Parse
此代码块使用通用时间转换当前 DateTime 对象,然后将其转换回本地 DateTime。对我来说效果很好,希望它有所帮助!
CreatedDate.ToUniversalTime().ToLocalTime();
如果您的日期时间字符串被视为在 UTC 时区之外,则可以使用 DateTimeOffset 来仅设置时区信息,而无需更改字符串中的时间,如下所示:
// Input datetime string
string datetimeString = "2023-07-11 12:42:56";
// Specify the timezone as "Europe/Prague"
TimeZoneInfo pragueTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Europe/Prague");
// Parse the datetime string with the specified format
DateTime datetimeObj = DateTime.ParseExact(datetimeString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
// Create a DateTimeOffset with the parsed datetime and the "Europe/Prague" timezone
DateTimeOffset pragueDateTimeOffset = new DateTimeOffset(datetimeObj, pragueTimeZone.GetUtcOffset(datetimeObj));
您还可以像通常使用 DateTime 实例一样设置日期时间偏移量字符串的格式。
// Print the resulting DateTimeOffset object
Console.WriteLine(pragueDateTimeOffset.ToString("O"));
我在ASP.NET Core 7.0 Web API
中遇到了类似的情况,我按如下方式解决了它,
- 安装
NodaTime
Nuget。 - 使用
CultureInfo.CurrentCulture.Name[^2..]
从用户请求中获取国家/地区代码。就我而言,这是IN
,这将返回Asia/Kolkatta
. - 如果它
not null
则使用其他ZoneId
获取TimeZoneInfo
DateTime
将导出为UTC
。 - 现在我们可以使用
TimeZoneInfo.ConvertTimeFromUtc(UTCDateTime, TimeZoneInfo)
将UTC
DateTime
转换为用户的Local
DateTime
。
var timeZone = TzdbDateTimeZoneSource.Default.ZoneLocations!.FirstOrDefault(x => x.CountryCode == CultureInfo.CurrentCulture.Name[^2..]);
if (timeZone is not null)
{
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZone.ZoneId);
foreach (var order in orders)
{
order.OrderDate = TimeZoneInfo.ConvertTimeFromUtc(order.OrderDate.DateTime, timeZoneInfo);
}
}
请注意,我采用的是FirstOrDefault()
这意味着对于拥有单一timezone
的国家来说,这就足够了。但是对于具有多个时区的国家/地区,我们需要将用户timezone
详细信息存储在数据库中以进行转换。