将日期字符串解析为某个时区(支持夏令时)

好吧,过去几周我一直在努力工作,我遇到了一个小问题。 我认为我的思想现在不能完成任务:)所以我需要一些提示/帮助! 这可能很简单,但我的头还没有点击。

用户将在AEST中输入日期和时间。 还有一个应用程序集“默认”时区(因为它可能需要更改),目前设置为“AUS东部标准时间”

因此,我们在美国的服务器上有一个没有时区和定义的系统时区的用户字符串(因此本地不匹配,无法更改或使用)

现在我需要的是一种方式来说“使用时区X解析此用户输入的字符串”我不能只输入+10或+11作为偏移量,因为日期可以在夏令时之内或之外; 即使对于相同的时区,肯定会在+10和+11之间进行更改!

当前的AEST时间也可能在DST之内或之外,因此我不能只将UTC日期转换为当前的AEST时间并获取“zzz”字符串并附加它,因为日期将在一小时后关闭以输入任何内容当前DST设置。

现在代码实际上就是这样:

TimeZoneInfo ConvTo = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["DefaultTimeZone"]); DateTimeOffset getDate = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, ConvTo); string TimeZoneId = " " + getDate.ToString("zzz"); DateTimeOffset cvStartDate = DateTimeOffset.MinValue; DateTimeOffset.TryParse(StartDate + TimeZoneId, out cvStartDate); 

然后我通过检查它是否仍然== DateTimeOffset.MinValue或将其转换为UTC并添加到数据库来检查日期是否无效,它将在显示时转换回AEST。 然而,有些日期是一小时,其他日期是完美的(如预期的那样):)

解决这个问题最优雅的方法是什么?

编辑:

为了帮助解释这个问题,我写了一些测试代码作为Windows测试应用程序:

 // User entered date string EnteredDate = "2011/01/01 10:00:00 AM"; // Get the timezone we want to use TimeZoneInfo myTimeZone = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time"); // Find the timezone string of the selected timezone to parse the user string // This is the part that is incorrect and what i need help with. DateTimeOffset getDate = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, myTimeZone); string TimeZoneId = " " + getDate.ToString("zzz"); // Parse the string into the date object DateTimeOffset cvEnteredDate = DateTimeOffset.MinValue; DateTimeOffset.TryParse(EnteredDate + TimeZoneId, out cvEnteredDate); // Display textBox1.Text += "Parsed: " + cvEnteredDate.ToString("yyyy/MM/dd HH:mm:ss zzz") + Environment.NewLine; // Convert to UTC and display cvEnteredDate = cvEnteredDate.ToUniversalTime(); textBox1.Text += "UTC: " + cvEnteredDate.ToString("yyyy/MM/dd HH:mm:ss zzz") + Environment.NewLine; // Convert back to AEST and display cvEnteredDate = TimeZoneInfo.ConvertTime(cvEnteredDate, myTimeZone); textBox1.Text += "Changed Back: " + cvEnteredDate.ToString("yyyy/MM/dd HH:mm:ss zzz") + Environment.NewLine; 

这是什么输出?

 Parsed:2011/01/01 10:00:00 +10:00
 UTC:2011/01/01 00:00:00 +00:00
更改回:2011/01/01 11:00:00 +11:00

请注意,小时偏离一个,偏移量不同。 另外,如果我们只是将输入的日期改为:

 string EnteredDate = "2011/04/20 10:00:00 AM"; 

我们得到:

解析:2011/04/20 10:00:00 +10:00
 UTC:2011/04/20 00:00:00 +00:00
更改回:2011/04/20 10:00:00 +10:00

这是非常好和好,使用相同的代码只是一个不同的输入日期。

这是因为当前的DST设置和输入日期的DST设置不同,这就是我想要的解决方案:)

把它想象成鸡和蛋的问题。 在解析之前我需要为输入的字符串提供正确的时区数据,这是我在解析字符串后才能得到的(因此将是一个精心设计的解决方案)

或者我需要.NET使用myTimeZone对象解析字符串,因此它知道将其设置为自身,但我看不到任何执行此操作的函数,它们采用已经解析并设置datetime或datetimeoffset对象

所以我正在寻找别人可能做过的优雅解决方案? 我当然不可能是唯一注意到这一点的人?

EDIT2:

好吧,我已经做了一个“工作”function,解决了我认为的问题,这是一个例子(在ac#windows app中添加一个文本框,并使用下面的代码来测试你自己):

 private void Form1_Load(object sender, EventArgs e) { TimeZoneInfo myTimeZone = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time"); DateTimeOffset get1Date = ReadStringWithTimeZone("2011/01/01 10:00:00 AM", myTimeZone); textBox1.Text += "Read1: " + get1Date.ToString("yyyy/MM/dd HH:mm:ss zzz") + Environment.NewLine; get1Date = get1Date.ToUniversalTime(); textBox1.Text += "Read1 - UTC: " + get1Date.ToString("yyyy/MM/dd HH:mm:ss zzz") + Environment.NewLine; get1Date = TimeZoneInfo.ConvertTime(get1Date, myTimeZone); textBox1.Text += "Changed Back: " + get1Date.ToString("yyyy/MM/dd HH:mm:ss zzz") + Environment.NewLine + Environment.NewLine; DateTimeOffset get2Date = ReadStringWithTimeZone("2011/04/20 10:00:00 AM", myTimeZone); textBox1.Text += "Read2: " + get2Date.ToString("yyyy/MM/dd HH:mm:ss zzz") + Environment.NewLine; get2Date = get2Date.ToUniversalTime(); textBox1.Text += "Read2 - UTC: " + get2Date.ToString("yyyy/MM/dd HH:mm:ss zzz") + Environment.NewLine; get2Date = TimeZoneInfo.ConvertTime(get2Date, myTimeZone); textBox1.Text += "Changed Back: " + get2Date.ToString("yyyy/MM/dd HH:mm:ss zzz") + Environment.NewLine + Environment.NewLine; } public DateTimeOffset ReadStringWithTimeZone(string EnteredDate, TimeZoneInfo tzi) { DateTimeOffset cvUTCToTZI = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, tzi); DateTimeOffset cvParsedDate = DateTimeOffset.MinValue; DateTimeOffset.TryParse(EnteredDate + " " + cvUTCToTZI.ToString("zzz"), out cvParsedDate); if (tzi.SupportsDaylightSavingTime) { TimeSpan getDiff = tzi.GetUtcOffset(cvParsedDate); string MakeFinalOffset = (getDiff.Hours  9 ? "" : "0") + getDiff.Hours + ":" + (getDiff.Minutes > 9 ? "" : "0") + getDiff.Minutes; textBox1.Text += "Diff: " + MakeFinalOffset + Environment.NewLine; DateTimeOffset.TryParse(EnteredDate + " " + MakeFinalOffset, out cvParsedDate); return cvParsedDate; } else { return cvParsedDate; } } 

并输出:

差异:+11:00
阅读时间:2011年1月1日10:00:00 +11:00
 Read1  -  UTC:2010/12/31 23:00:00 +00:00
更改回:2011/01/01 10:00:00 +11:00

差异:+10:00
阅读时间:2011/04/20 10:00:00 +10:00
阅读2  -  UTC:2011/04/20 00:00:00 +00:00
更改回:2011/04/20 10:00:00 +10:00

唯一的问题是如果用户输入日期正好在DST的一小时更改时它仍然可能是一小时关闭,因为它只是读取当前偏移量并使用它,然后检查它应该是夏令时还是不,如果它在那里它会读错。 然而,它比我现在的好几英里。

任何人都可以帮我清理这个function吗? 这是我需要的最佳路线吗? 想法?

这是一个预定义格式的简单解决方案,也可以是动态的。 我个人用它来与javascript交谈:

 public DateTimeOffset ParseDateExactForTimeZone(string dateTime, TimeZoneInfo timezone) { var parsedDateLocal = DateTimeOffset.ParseExact(dateTime, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); var tzOffset = timezone.GetUtcOffset(parsedDateLocal.DateTime); var parsedDateTimeZone = new DateTimeOffset(parsedDateLocal.DateTime, tzOffset); return parsedDateTimeZone; } 

当我需要将已知时区的日期时间字符串解析为本地时区时,这似乎对我有用。 在很多情况下还没有测试过它,但到目前为止它在欧盟某个地方的服务器上解析时间非常有用。

 TimeZoneInfo.ConvertTime(DateTime.Parse(“2012-05-25 23:17:15”,CultureInfo.CreateSpecificCulture(“en-EU”)),TimeZoneInfo.FindSystemTimeZoneById(“W。欧洲标准时间”),TimeZoneInfo.Local)

由于没有人提供任何更好的解决方案(这是非常令人惊讶的!)我接受我自己的function作为答案,虽然我可能会使function更简洁,稍后重新工作:

 public DateTimeOffset ReadStringWithTimeZone(string EnteredDate, TimeZoneInfo tzi) { DateTimeOffset cvUTCToTZI = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, tzi); DateTimeOffset cvParsedDate = DateTimeOffset.MinValue; DateTimeOffset.TryParse(EnteredDate + " " + cvUTCToTZI.ToString("zzz"), out cvParsedDate); if (tzi.SupportsDaylightSavingTime) { TimeSpan getDiff = tzi.GetUtcOffset(cvParsedDate); string MakeFinalOffset = (getDiff.Hours < 0 ? "-" : "+") + (getDiff.Hours > 9 ? "" : "0") + getDiff.Hours + ":" + (getDiff.Minutes > 9 ? "" : "0") + getDiff.Minutes; DateTimeOffset.TryParse(EnteredDate + " " + MakeFinalOffset, out cvParsedDate); return cvParsedDate; } else { return cvParsedDate; } } 

TimeZoneInfo有一个静态方法ConvertTimeToUtc ,它允许您指定日期时间和时区。 这将为您进行时间调整,并返回UTC日期。

MSDN文档是http://msdn.microsoft.com/en-us/library/bb495915.aspx ,完整的示例。

最简单的解决方案:首先将字符串解析为本地DateTime,然后使用任何解析方法调用

 new DateTimeOffset(dateTimeLocal.Ticks, timezone.BaseUtcOffset)