2011-08-30 64 views
6

我被困周围解析日期和时间的问题:解析日期时间与已知的而不是定的时区

我试图解析从德国网站提取的日期时间字符串。它的格式为“day.month.year 24小时:分钟”,例如:

01.01.2011 17:00 

它始终在德国时区。但这里谈到的问题:

  • 01 .01.2011 17:00' 应该解释为DateTime结构与'01 .01.2011 16:00' 在UTC(这里,时区CET,没有日光
  • 而01 .06.2011 17:00' 应该解释为DateTime结构与'01 .01.2011 15:00' 在UTC(这里节省时间),时区是CEST,夏令时)

我不知道如何做到这一点。如果我将本地时钟设置为德国时区,并且我使用DateTime.ParseExact和标志DateTimeStyles.AssumeLocalDateTimeStyles.AdjustToUniversal进行解析,则它会被正确解析。但是,我希望任何客户端都能从当地时钟和时区独立解析。另外,我不想自己做时区偏移,因为它取决于日期(夏季:-2 /冬季:-1)。

一旦我有UTC的日期时间,它将很容易将其转换为任何本地时区。

+0

[在c#fx 3.5的特定时区中创建日期时间]的可能重复(http://stackoverflow.com/questions/246498/creating-a-datetime-in-a-specific-time-zone-in -c-fx-3-5) –

+0

@迈克尔哈伦:不,它不是重复的。在我问这个问题之前,我看了一下,并没有帮助解决我的具体问题。 –

+0

可能不是重复的,但我认为它会有帮助 –

回答

1

在看到该任务不能与WP7/Silverlight的框架的帮助下archieved后,这将是Noda Time容易多了,我写了一个小帮手这项工作:

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)); 
    } 
} 

诀窍是要分析它没有的DateTimeStyles.AssumeUniversal标志(这使得TryParseExact假定日期是UTC和返回日期转换的/调整到地方),respecifying它作为UTC和然后手动将其调整至执行器等同于UTC。

它遵循DST规则,可以找到here。我在夏令时开始/结束之前/之后对所有4种边界案例进行了测试。这再次表明了测试的重要性:我必须将DstStart.CompareTo(result) < 0中的<运营商更改为<=,以使其产生正确的结果。

我有这样的感觉,我在这里重新发明轮子(我讨厌这么做),但不想为这个简单的工作使用专用的库。我看了Noda Time这个很棒的项目,但我认为它不是必需的。

我希望我能用这个小帮手救一个人一点时间。对于所有时区而言,它并不是通用的(如果您需要使用像Noda Time这样的库),但是对于这些只有一个固定时区的情况,就像我的情况一样。

+0

我很惊讶你没有使用AssumeUniversal - 我希望*已经用UTC DateTime返回它;如果不是这种情况,请在这方面误导你。 DateTime惹恼了我:( –

+0

@Jon:我以为老老实实地想,为什么它会产生这样奇怪的结果,直到我意识到它做的是正确的事情,但与你期望的不同:如果你让它解析'17 :00'假设UTC时间下午5点如预期的那样,但是在我的情况下(本地时区=德语)返回一个DateTime结构,其中7pm(Kind = local)。如果你调用''SpecifyKind(..,Utc)''一个7pm的Utc结构... –

+0

是的:DateTime确实很烦人:) –

4

这听起来像你知道你应该解析它的时区。假设.NET 3.5(因而TimeZoneInfo),你应该在逻辑:

  • 解析它作为一个 “本地” 时间(具体未时区)
  • 转换本地时间UTC时间

不幸的是DateTime makes that slightly tricky。编辑:我想到你想转换解析它使用DateTimeStyles.AssumeUniversal - 但最终返回本地DateTime,烦人。基本上你想落得一个DateTime与正确的时间,这样就可以使用:

parsed = DateTime.SpecifyKind(parsed, DateTimeKind.Unspecified); 

然后,您可以得到一个UTC值:

DateTime utc = TimeZoneInfo.ConvertTimeToUtc(parsed, germanTimeZone); 

需要注意的是你真正想要的“未指定”日期时间,以便您可以在任意时区将其转换为UTC。您还应该记住,由于DST更改,本地时间可能不明确(发生两次)或不可能发生(完全不会发生)。

是的,当它完成:)

+0

+1很好,ConvertTimeToUtc是某种程度上缺失的部分。但是,我还有最后一个问题:我从哪里得到'germanTimeZone'? –

+0

@Philip:你制定出适当的时区ID,并使用'TimeZoneInfo.FindSystemTimeZoneById'。我认为你想要“欧洲标准时间”(忽略标准时间这个事实;这只是ID--它仍然可以处理夏令时)。 –

+0

我可能应该提到我正在构建一个windows phone 7应用程序,其中TimeZoneInfo只有ConvertTime方法和时区Utc和Local。 –