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

标签 c# timezone datetimeoffset

好的,过去几周我一直在努力工作,但遇到了一个小问题。我认为我现在无法胜任这项任务 :) 所以我需要一些提示/帮助!这可能非常简单,但我还没有理清头绪。

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

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

现在我需要的是一种“使用时区 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

Please note the hour is off by one and the offset is different. Additionally, what if we JUST change the date entered to:

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

Which is perfectly good and fine, using the same code just a different entered date.

This happens because the current DST setting and the DST setting of the entered date are different, this is what i want a solution for :)

Think of it like the chicken and egg problem. I need the correct timezone data for the entered string before i parse it which i can only get after i've parsed the string (so will be an elaborate solution)

Or i need .NET to parse the string using the myTimeZone object so it knows what to set it to itself, but i can't see any functions that do this, they all take a already parsed and set datetime or datetimeoffset object

So i'm looking for elegant solutions others might have done? I certainly can't be the only one who has noticed this?

EDIT2:

Ok i've made a 'working' function that solves the problem i think, here is an example (add a textbox to a c# windows app and use the code below to test yourself):

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

关于c# - 将日期字符串解析为某个时区(支持夏令时),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5615538/

相关文章:

MySQL 时区 Transaction_type_id

c# - 是否有任何时区实际正确使用 TimeZoneInfo IsFixedDateRule?

c# - 从 SQL 2008 获取 DateTimeOffset 值到 C#

datetime - ColdFusion - 具有 GMT 偏移量的日期时间格式

QuickBooks Web 连接器 TimeModified 偏移量不考虑夏令时

c# 如何创建按钮并稍后通过 ID 删除它们

c# - 添加由多部分命名空间引起的服务引用后 Reference.cs 中的编译错误

c# - 使用 CsvHelper 可以将空格转换为可为 null 吗?

c# - 使用 asp.net listview 删除 SweetAlert 确认对话框?

java - 如何将 GMT 的偏移量转换为本地时区?