Convert.ToDateTime вызывает форматированиеException во время дня/времени дня

У нас есть синтаксический анализ даты/времени приложения в следующем формате:

2009-10-10 09:19:12.124
2009-10-10 12:13:14.852
2009-10-10 13:00:00
2009-10-10 15:23:32.022

Один конкретный сервер внезапно (сегодня) начал не разбираться с 13:00:00 или позже. У этого конкретного клиента пять серверов, и только одна проблема. У нас есть десятки других клиентов с общим количеством сотен серверов без проблем.

System.FormatException: String was not recognized as a valid DateTime.
at System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
at System.DateTime.Parse(String s, IFormatProvider provider)
at System.Convert.ToDateTime(String value, IFormatProvider provider)
at System.String.System.IConvertible.ToDateTime(IFormatProvider provider)
at System.Convert.ToDateTime(Object value)

Я провел тест, используя DateTime.Parse(s, CultureInfo.CurrentCulture), который был добавлен в DateTime.Parse(s, CultureInfo.InvariantCulture), и проблема возникает только с CurrentCulture. Тем не менее, CurrentCulture является "en-US", как и все другие серверы, и нет ничего другого, что я могу найти в региональных или языковых настройках.

Кто-нибудь видел это раньше? Предложения, связанные с тем, что я могу изучить?

EDIT: Спасибо за ответы до сих пор. Тем не менее, я ищу предложения о том, какую конфигурацию нужно искать, что могло привести к внезапному изменению поведения и прекращению работы, когда он работал годами и работает на сотнях других серверов. Я уже изменил его для следующей версии, но я ищу изменение конфигурации, чтобы исправить это в промежуточный момент для текущей установки.

Ответ 1

Мы также столкнулись с той же проблемой. Просто переработайте пул приложений.

Ответ 2

Если вы точно знаете формат, скажите приложению, что это такое - используйте DateTime.ParseExact вместо DateTime.Parse. (И, как говорили другие, укажите также инвариантную культуру, чтобы убрать больше вариаций.) Это дает вам гораздо больше контроля:

using System;
using System.Globalization;

class Test
{
    static void Main()
    {
        Parse("2009-10-10 09:19:12.124");
        Parse("2009-10-10 12:13:14.852");
        Parse("2009-10-10 13:00:00");
        Parse("2009-10-10 15:23:32.022");
    }

    static readonly string ShortFormat = "yyyy-MM-dd HH:mm:ss";
    static readonly string LongFormat = "yyyy-MM-dd HH:mm:ss.fff";

    static readonly string[] Formats = { ShortFormat, LongFormat };

    static void Parse(string text)
    {
        // Adjust styles as per requirements
        DateTime result = DateTime.ParseExact(text, Formats, 
                                              CultureInfo.InvariantCulture,
                                              DateTimeStyles.AssumeUniversal);
        Console.WriteLine(result);
    }
}

Ответ 3

У нас есть веб-служба С#.NET 2.0, работающая на сервере Windows 2003. Эта служба работает уже более двух лет. Недавно мы обнаружили ошибки в этом приложении. Сообщение об ошибке: "String не был признан допустимым DateTime". Другой веб-сервис возвращает дату, и эта функция должна возвращать значение, подобное

"5/10/2010 12:00:00 AM"

При возникновении ошибок функция возвращает

"5/10/2010 12:00:00"

Неверный возврат имеет пробел в конце и без AM.

Эта проблема появилась и исчезла несколько раз в течение следующих нескольких недель. После изучения журналов Windows мы заметили, что время начала и окончания ошибок совпало (в течение одной минуты или двух) с повторной загрузкой пула приложений, которая устанавливается (по умолчанию) каждые 29 часов. Эта проблема возникла только на веб-сервере производства, а не на серверах разработки или тестирования. Мы попытались заменить сервер, и ошибок не было в течение месяца. Теперь ошибки снова начались. Мы вручную reset пул, и проблема сразу исчезла. Мы бы предпочли не рассматривать это как приемлемое решение, так как пул регулярно перерабатывается. Мы не знаем, нужна ли нам утилизация пула, но мы понимаем, что регулярные переработчики помогают в производительности приложений.

Веб-приложение уже использует ParseExact(), но строка формата выглядит так:

"YYYY-MM-DDHH: мм: ss.0Z"

вместо

"yyyy-MM-dd HH: mm: ss"

предложенный Джоном Скитом в этой теме. Я не знаю, будет ли это иметь большое значение.

Мы также проверили настройки культуры.

Кажется очевидным, что проблема начинается с утилизации пула приложений, но я понятия не имею, что происходит под капотом во время этой утилизации. В большинстве случаев рециркуляция не имеет отрицательного эффекта, и когда происходят ошибки, следующий рецикл всегда останавливал ошибки.

Ответ 4

Решение очень простое, используйте CultureInfo.InvariantCulture. Для выборочных данных это единственная разумная вещь.

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

Ответ 5

Я только что нашел некоторую информацию о том, что вызывает эту проблему. Наш клиент С# отправляет бизнес-дату (только дату) в качестве строкового значения в веб-службу. Веб-служба передает эту строку в SqlParameter в SqlCommand в хранимую процедуру, которая принимает параметр datetime для бизнес-даты.

Потребительская система внезапно начала плохо себя вести. Я использовал профилировщик SQL Server для просмотра вызовов RPC и заметил, что параметр даты внезапно имел компонент времени. Предполагается, что это значение только для даты - т.е. 10/27/2012 12:00:00 утра.

Я изменил хранимую процедуру, чтобы добавить WAITFOR DELAY '00:01:00'. Затем я приобрел дамп памяти веб-службы, когда он вызывал эту хранимую процедуру.

Изучив дамп памяти, я обнаружил, что клиент прошел правильную строку даты "2012-10-25 00:00:00" в DataSet параметров. Веб-сервис каким-то образом испортил преобразование этих дат, когда он назвал хранимую процедуру. Я нашел SqlCommand в дампе и рассмотрел SqlParameter, соответствующий параметру даты хранимой процедуры. Значение было "10/25/2012 12:00:00 PM".

Посмотрев на все объекты CultureInfo, я нашел, что locale 1033 для "en-US" имеет длинную строку "h: mm: ss tt". AMDsignator был "AM", но PMDesignator был пустой строкой! Я подтвердил, что это послужило причиной плохой даты на С#, выполнив следующую команду:

// clear the PM designator
System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.PMDesignator = ""
// this will yield "12/25/2012 12:00:00 " (note the extra space at the end)
Convert.ToDateTime("10/25/2012").ToString()

Результат был "10/22/2012 12:00:00", что соответствует тому, что Брайан Бегли в своем ответе. Использование инвариантного формата дает очень похожий результат:

// clear the PM designator
System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.PMDesignator = ""
// this will yield "10/25/2012 12:00:00"
Convert.ToDateTime("10/25/2012").ToString(System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat)
// restore the PM designator to "PM"
System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.PMDesignator = "PM"
// this will yield "10/25/2012 00:00:00"
Convert.ToDateTime("10/25/2012").ToString(System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat)

Мне еще предстоит определить, что вызывает повреждение CultureInfo.

Обратите внимание, что Microsoft знает об этой проблеме. Связанная статья говорит, что она применяется только к Windows Server 2003, и доступно исправление.

Ответ 6

Похоже, что объект культуры не понимает военное обозначение времени. Я честно не знаю, куда идти оттуда, но это может дать вам отправную точку.

Ответ 7

Какое значение свойства CultureInfo.DateTimeFormat? Согласно MSDN:

"Пользователь может выбрать переопределение некоторые из значений, связанных с текущая культура Windows через региональные и языковые варианты панели управления. Например, пользователь может выбрать отображение даты в другом формате или использовать валюта, отличная от культура.

Если UseUserOverride истинно, и указанная культура соответствует текущему культура Windows, CultureInfo использует эти переопределения, включая пользователя настройки для свойств Возвращен экземпляр DateTimeFormatInfo по свойству DateTimeFormat и свойства NumberFormatInfo экземпляр, возвращаемый NumberFormat имущество. Если пользовательские настройки несовместимый с культурой связанных с CultureInfo, для Например, если выбранный календарь а не один из необязательных календарей, результаты методов и значений свойств undefined.

Значение параметра DateTimeFormat свойство и свойство NumberFormat не рассчитывается до приложение получает доступ к свойству. Если пользователь может изменить текущий культуры в новую культуру, в то время как приложение работает, а затем приложение обращается к DateTimeFormat или NumberFormat свойство, приложение извлекает по умолчанию для новой культуры вместо переопределений для оригинальная культура. Чтобы сохранить переопределяет исходный ток культуре, приложение должно получить доступ DateTimeFormat и NumberFormat свойств перед изменением тока культура".

Не может ли это быть какая-то пользовательская настройка?

Ответ 8

Это дикая догадка, но, возможно, что-то вроде этой последовательности событий могло вызвать проблему:

  • Администратор переходит к международным настройкам панели управления на всех серверах и изменяет формат времени с "HH: mm: ss" на "hh: mm: ss tt".
  • Администратор перерабатывает пул приложений (или службу IIS или машину) только на одном из серверов.

Все новые рабочие потоки ASP.NET на рециклированном сервере теперь будут видеть измененный формат времени, и методы DateTime.Parse не будут выполнены. Однако, если другие серверы все еще используют исходные рабочие потоки, они еще не обнаружили изменения текущей культуры DateTimeFormatInfo.

Это очень маловероятный сценарий, но опять же, у вас очень маловероятная ситуация. Вы можете попробовать переработать соответствующий пул приложений на всех серверах и посмотреть, что-нибудь изменится.