Подтвердить что ты не робот

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

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

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

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

Теперь мне нужен способ сказать "разобрать этот введенный пользователем текст с использованием часового пояса 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. Однако некоторые даты отключены на час, а другие - идеальны (как и ожидалось):)

Какой самый элегантный способ решить эту проблему?

EDIT:

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

Итак, я ищу элегантные решения, которые другие могли бы сделать? Я, конечно, не могу быть единственным, кто это заметил?

EDIT2:

Хорошо, я сделал "рабочую" функцию, которая решает проблему, я думаю, вот пример (добавьте текстовое поле в приложение 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, по-прежнему может быть часами, поскольку он просто считывает текущее смещение и использует это, а затем проверяет, должно ли оно быть дневной свет или нет, и если бы он там, то он читал бы неправильно. Однако он намного лучше, чем у меня сейчас.

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

4b9b3361

Ответ 1

Это простое решение для предопределенного формата, это также может быть динамичным. Я лично использую это для разговора с 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;
}

Ответ 2

Кажется, это работает для меня, когда мне нужно проанализировать строку даты и времени из известного часового пояса на мой локальный. Не проверял его во многих случаях, но до сих пор он отлично поработал для разбора времени на сервере где-то в eu.

TimeZoneInfo.ConvertTime(DateTime.Parse("2012-05-25 23:17:15", CultureInfo.CreateSpecificCulture("en-EU")),TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time"),TimeZoneInfo.Local)

Ответ 3

Поскольку никто не предоставил никаких лучших решений (что очень удивительно!), я принимаю мою собственную функцию в качестве ответа, хотя я мог бы сделать функцию более кратким и переделать ее чуть позже:

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

Ответ 4

TimeZoneInfo имеет статический метод ConvertTimeToUtc, который позволяет вам указывать дату и время. Это позволит вам настроить время и вернуть дату UTC.

Документация MSDN http://msdn.microsoft.com/en-us/library/bb495915.aspx, в комплекте с примером.

Ответ 5

Самое простое решение: Сначала выполните синтаксический анализ локального DateTime, используйте любой метод анализа затем вызовите

new DateTimeOffset(dateTimeLocal.Ticks, timezone.BaseUtcOffset)