C# 使用已知但未给定的时区分析DateTime
我遇到了解析日期和时间的问题: 我正在尝试解析从德国网站提取的日期时间字符串。其格式为“日.月.年24小时:分钟”,如:C# 使用已知但未给定的时区分析DateTime,c#,parsing,datetime,windows-phone-7,timezone,C#,Parsing,Datetime,Windows Phone 7,Timezone,我遇到了解析日期和时间的问题: 我正在尝试解析从德国网站提取的日期时间字符串。其格式为“日.月.年24小时:分钟”,如: 01.01.2011 17:00 而且总是在德国时区。但问题来了: 应将“01.01.2011 17:00”解析为一个日期时间结构,其UTC格式为“01.01.2011 16:00”(此处,时区为CET,,不含夏令时) 而'01.06.2011 17:00'应解析为UTC格式的'01.01.2011 15:00'的DateTime结构(此处,时区为CEST,带夏令时)
01.01.2011 17:00
而且总是在德国时区。但问题来了:
- 应将“01.01.2011 17:00”解析为一个日期时间结构,其UTC格式为“01.01.2011 16:00”(此处,时区为CET,,不含夏令时)
- 而'01.06.2011 17:00'应解析为UTC格式的'01.01.2011 15:00'的DateTime结构(此处,时区为CEST,带夏令时)
DateTime.ParseExact
和标志DateTimeStyles.AssumeLocal
和DateTimeStyles.AdjustToUniversal
进行解析,则解析正确。但是,我希望任何客户端都能独立于本地时钟和时区来解析它。另外,我不想自己做时区偏移,因为它取决于日期(夏季:-2/冬季:-1)
一旦我有了UTC的datetime,就可以很容易地将其转换为任何本地时区。听起来你知道应该用哪个时区来解析它。假设.NET 3.5(因此
TimeZoneInfo
),您在逻辑上应该:
- 将其解析为“本地”时间(不特定于时区)
- 将当地时间转换为UTC时间
DateTimeStyles.AssumeUniversal
转换并解析它,但这最终会返回一个本地DateTime
,令人烦恼。基本上,您希望在适当的时间结束一个DateTime
,以便您可以使用:
parsed = DateTime.SpecifyKind(parsed, DateTimeKind.Unspecified);
然后,您可以通过以下方式获得UTC值:
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(parsed, germanTimeZone);
请注意,您确实首先需要一个“未指定”的日期时间,以便可以在任意时区将其转换为UTC。您还应该记住,由于DST更改,本地时间可能不明确(发生两次)或不可能(根本不发生)
是的,当它完成后,这将更容易:)在看到任务无法在WP7/Silverlight框架的帮助下归档后,我编写了一个小助手来完成这项工作:
public static class DateTimeHelper
{
/// <summary>
/// Tries to parse the given datetime string that is not annotated with a timezone
/// information but known to be in the CET/CEST zone and returns a DateTime struct
/// in UTC (so it can be converted to the devices local time). If it could not be
/// parsed, result contains the current date/time in UTC.
/// </summary>
public static bool TryParseCetCest(string s, string format, IFormatProvider provider, DateTimeStyles style, out DateTime result)
{
// Parse datetime, knowing it is in CET/CEST timezone. Parse as universal as we fix it afterwards
if (!DateTime.TryParseExact(s, format, provider, style, out result))
{
result = DateTime.UtcNow;
return false;
}
result = DateTime.SpecifyKind(result, DateTimeKind.Utc);
// The boundaries of the daylight saving time period in CET and CEST (_not_ in UTC!)
// Both DateTime structs are of kind 'Utc', to be able to compare them with the parsing result
DateTime DstStart = LastSundayOf(result.Year, 3).AddHours(2);
DateTime DstEnd = LastSundayOf(result.Year, 10).AddHours(3);
// Are we inside the daylight saving time period?
if (DstStart.CompareTo(result) <= 0 && result.CompareTo(DstEnd) < 0)
result = result.AddHours(-2); // CEST = UTC+2h
else
result = result.AddHours(-1); // CET = UTC+1h
return true;
}
/// <summary>
/// Returns the last sunday of the given month and year in UTC
/// </summary>
private static DateTime LastSundayOf(int year, int month)
{
DateTime firstOfNextMonth = new DateTime(year, month + 1, 1, 0, 0, 0, DateTimeKind.Utc);
return firstOfNextMonth.AddDays(firstOfNextMonth.DayOfWeek == DayOfWeek.Sunday ? -7 :
(-1 * (int)firstOfNextMonth.DayOfWeek));
}
}
公共静态类DateTimeHelper
{
///
///尝试分析未使用时区注释的给定日期时间字符串
///信息,但已知位于CET/CEST区域,并返回DateTime结构
///UTC(因此可以转换为设备本地时间)。如果无法
///解析后,结果包含当前UTC日期/时间。
///
公共静态bool tryparsecetest(字符串s、字符串格式、IFormatProvider提供程序、DateTimeStyles样式、out DateTime结果)
{
//解析datetime,知道它在CET/CEST时区。解析的通用性取决于我们之后对它的修复
if(!DateTime.TryParseExact(s、格式、提供程序、样式、输出结果))
{
结果=DateTime.UtcNow;
返回false;
}
结果=DateTime.SpecifyKind(结果,DateTimeKind.Utc);
//以CET和CEST为单位的夏时制时间段的边界(不是UTC!)
//两个DateTime结构都属于“Utc”类型,以便能够将它们与解析结果进行比较
DateTime DstStart=LastSundayOf(result.Year,3)。AddHours(2);
DateTime DstEnd=LastSundayOf(result.Year,10)。AddHours(3);
//我们是否在夏令时内?
如果(DstStart.CompareTo)(结果)@Michael Haren的可能重复项:不,不是重复项。在我问这个问题之前,我看了一下,它对我的具体问题没有帮助。可能不是重复项,但我认为它会有帮助+1太好了,ConvertTimeToUtc
不知何故是缺少的部分。不过,我还有最后一个问题:我从哪里得到细菌anTimeZone
from?@Philip:您计算出适当的时区ID,然后使用时区信息。FindSystemTimeZoneById
。我想您想要的是“W.Europe标准时间”(忽略它被称为标准时间的事实;这只是ID-它仍然可以处理夏令时)。我可能应该提到我正在构建一个windows phone 7应用程序,TimeZoneInfo
只有ConvertTime
方法和时区Utc
和Local
。@Philip:Ah.是的,你应该提到这一点。所以你不能得到除本地时区以外的任何时区?恩。Noda time不是真的y产品已经准备好了,但是如果你想试试看它是否对你有帮助,我很乐意提供帮助。我们还没有进行LocalDateTime
解析,但是你可以在.NET中进行解析,然后进行转换……感谢你的帮助。如果没有我以前不知道的SpecifyKind
,我会浪费更多的时间:).我写了一个小助手(贴在这里作为答案)这就是诀窍。野田佳彦时间看起来很棒,但我不想为这样一个简单的工作包含整个库。我很惊讶你没有使用AssumeUniversal-我本来希望它已经返回UTC日期时间;如果不是这样的话,我为在这方面误导你道歉。日期时间让我恼火:(@Jon:老实说,我的想法完全一样,我想知道为什么它会产生如此奇怪的结果。直到我意识到它做了正确的事情,但与您可能期望的不同:如果让它解析“17:00”,它假设UTC时间为下午5点,但在我的情况下返回一个DateTime结构,即下午7点(种类=本地)(本地时区=德语)。如果您在此调用SpecifyKind(..,Utc)
,它将返回一个晚上7点的Utc结构…是的:DateTime确实很烦人:)奇怪。啊,谢谢您让我知道。将在这方面编辑我的答案。只需说明为什么能够解析为不同类型很重要:)