Разобрать строку даты в определенном часовом поясе (с поддержкой летнего времени)

Хорошо, я очень много работал последние несколько недель и столкнулся с небольшой проблемой. Я не думаю, что сейчас мой разум вполне готов к этой задаче :), так что мне нужны советы / помощь! это, вероятно, очень просто, но моя голова еще не щелкает.

Пользователи будут вводить дату и время в AEST. Существует также часовой пояс, установленный в приложении "по умолчанию" (который может потребоваться изменить), в настоящее время он установлен на "Стандартное восточное время Австралии".

Итак, у нас есть строка пользователя без часового пояса и с определенным системным часовым поясом на сервере в США (так что local не совпадает, и его нельзя изменить или использовать)

Теперь мне нужно способ сказать «проанализировать эту введенную пользователем строку, используя часовой пояс X», я не могу просто ввести +10 или +11 в качестве смещения, поскольку даты могут быть как в летнее время, так и вне его; что да, меняет его от +10 до +11 даже для одного и того же часового пояса!

Текущее время AEST также может быть в DST или вне его, поэтому я не могу просто преобразовать дату UTC в текущее время AEST и получить "zzz" и прикрепите ее, так как даты будут отключены на час для всего, что введено вне текущей настройки летнего времени.

На данный момент код действительно делает именно это:

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

Что совершенно нормально, используя тот же код, только другую введенную дату.

Это происходит из-за текущей настройки летнего времени и Установка летнего времени введенной даты отличается, это то, для чего я хочу решение:)

Думайте об этом как о проблеме с курицей и яйцом. Мне нужны правильные данные о часовом поясе для введенной строки, прежде чем я проанализирую ее, что я могу получить только после того, как я проанализирую строку (так что это будет сложное решение)

Или мне нужен .NET для анализа строки с помощью объекта myTimeZone поэтому он знает, что установить для себя, но я не вижу никаких функций, которые это делают, они все берут уже проанализированный и устанавливаемый объект datetime или 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

Единственная проблема в том, что может возникнуть проблема, если введенная пользователем дата совпадает с изменением часового периода летнего времени, это все равно может быть через час, поскольку он просто считывает текущее смещение и использует его, а затем проверяет, должно ли оно быть летнее время или нет, и если он там, он будет читать неправильно. Однако это намного лучше, чем то, что у меня есть сейчас.

Может кто-нибудь помочь мне с очисткой этой функции? Это лучший вариант для того, что мне нужно? идеи?

22
задан White Dragon 11 April 2011 в 02:37
поделиться