将日期字符串解析为特定的时区(支持夏令时)
好吧,过去几周我一直在努力工作,并遇到了一个小问题。 我不认为我的想法现在完全取决于任务:)所以我需要一些提示/帮助! 它可能很简单,但我的头还没有点击。
用户将在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 Changed Back: 2011/01/01 11:00:00 +11:00
请注意,小时关闭一次,偏移量不同。 另外,如果我们只是改变输入的日期:
string EnteredDate = "2011/04/20 10:00:00 AM";
我们得到:
Parsed: 2011/04/20 10:00:00 +10:00 UTC: 2011/04/20 00:00:00 +00:00 Changed Back: 2011/04/20 10:00:00 +10:00
这是非常好的,使用相同的代码只是一个不同的输入日期。
发生这种情况是因为当前的DST设置和输入日期的DST设置不同,这就是我想要的解决方案:)
想想它就像鸡和鸡蛋的问题。 我需要输入的字符串的正确的时区数据之前我解析它,我只能得到后,我已经解析了字符串(这将是一个精心制作的解决方案)
或者我需要.NET来解析字符串使用myTimeZone对象,所以它知道该怎么设置它自己,但我看不到任何这样做的功能,他们都采取了已解析和设置的日期时间或datetimeoffset对象
所以我正在寻找其他人可能已经完成的优雅解决方案? 我当然不能成为唯一注意到这一点的人?
EDIT2:
好吧,我已经创建了一个“工作”函数来解决我认为的问题,下面是一个示例(将文本框添加到ac#windows应用程序并使用下面的代码来测试自己):
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 < 0 ? "-" : "+") + (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;
}
}
输出:
Diff: +11:00 Read1: 2011/01/01 10:00:00 +11:00 Read1 - UTC: 2010/12/31 23:00:00 +00:00 Changed Back: 2011/01/01 10:00:00 +11:00 Diff: +10:00 Read2: 2011/04/20 10:00:00 +10:00 Read2 - UTC: 2011/04/20 00:00:00 +00:00 Changed Back: 2011/04/20 10:00:00 +10:00
唯一的问题是,如果用户输入的日期与DST整个小时的变化是正确的,那么它可能会在一个小时内关闭,因为它只是读取当前的偏移量并使用它,然后检查它是否应该是夏令时或不,如果它在那里它会读错误。 然而,它比我现在拥有的更好。
任何人都可以帮我清理这个功能? 这是最适合我需要的路线吗? 想法?
下面是一个预定义格式的简单解决方案,这也可以是动态的。 我个人使用这个与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. Europe Standard Time"),TimeZoneInfo.Local)
由于没有人提供了更好的解决方案(这是非常令人惊讶的!)我接受我自己的功能作为答案,尽管我可能会使该函数更简洁并稍后重新工作:
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;
}
}
链接地址: http://www.djcxy.com/p/29371.html
上一篇: Parse a date string into a certain timezone (supporting daylight saving time)