none
RUSSIAN VALIDATION DateTime в ASP.NET MVC

    Вопрос

  • Есть такое поле:

        <Required>
        <ScaffoldColumn(False)>
        <Display(Name:="Дата изменения")>
        Public Property ModifiedDate As DateTime

    При Get-запросе значение этого поля (#5/16/2014 1:42:17 PM#) приходит в View.
    При POST-отправке значение этого поля становится таким: #12:00:00 AM#.
    Но я его не менял.
    Естественно при сохранении получаю ошибку:
    "The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value."

    Почему так?




Ответы

  • Разобрался!
    Клиентская валидация (jquery.validate.js) по умолчанию не воспринимает дату в формате с точками (30.05.2014). Это довольно странно, когда у тебя Windows и Visual Studio на русском языке. Удивляет, что никто не сказал мне: «Да, это известная особенность, дата с точками не проходит». Коллеги, вы даты вообще отображаете пользователям в своих MVC приложениях?
    Решение проблемы - установить в проект NuGet пакет jQuery.Validation.Globalize.
    В папку Scripts будут добавлены:
    - jquery.validate.globalize.js
    - папка globalize, которая содержит в себе файл globalize.js и папку cultures (в ней находятся файлы с настройками для различных культур, например: globalize.culture.ru-RU.js).
     
    Но не все так просто, здесь важен порядок подключения скриптов:
    <script src="/Scripts/jquery.validate.js"></script>
    <script src="/Scripts/globalize/globalize.js"></script>
    <script src="/Scripts/globalize/cultures/globalize.culture.ru-RU.js"></script>
    <script src="/Scripts/jquery.validate.globalize.js"></script>

    Удобнее всего это сделать в App_Start/BundleConfig.vb:

    ' Комментируем это:
    'bundles.Add(New ScriptBundle("~/bundles/jqueryval").Include(
    '            "~/Scripts/jquery.validate*"))

    ' Добавляем:
            bundles.Add(New ScriptBundle("~/bundles/jqueryval").Include(
                        "~/Scripts/jquery.validate.js",
                        "~/Scripts/jquery.validate.min.js",
                        "~/Scripts/jquery.validate.unobtrusive.js",
                        "~/Scripts/jquery.validate.unobtrusive.min.js"))


            bundles.Add(New ScriptBundle("~/bundles/global").Include(
                        "~/Scripts/globalize/globalize.js",
    "~/Scripts/globalize/cultures/globalize.culture.ru-RU.js"))

            bundles.Add(New ScriptBundle("~/bundles/globalLastFile").Include(
             "~/Scripts/jquery.validate.globalize*"))

    Если вы планируете использовать разные культуры и хотите, чтобы формат даты, времени, валюты и т.п. соответствовал культуре пользователя, то вместо скрипта с конкретной культурой подключите автоматическое определение культуры:
    "~/Scripts/globalize/cultures/globalize.culture." & System.Threading.Thread.CurrentThread.CurrentCulture.ToString & ".js"

    В View, где необходимы региональные настройки, добавляем:

    @Section Scripts
        @Scripts.Render("~/bundles/jqueryval")
        @Scripts.Render("~/bundles/global")
        @Scripts.Render("~/bundles/globalLastFile")

    <script>
        Globalize.culture("ru-RU");
        // автоматическое определение культуры:
        //Globalize.culture('@System.Threading.Thread.CurrentThread.CurrentCulture');
    </script>

    End Section

    Теперь дата в формате русского будет успешно проходить проверку!
    Но если вам требуется в полном смысле DateTime (30.05.2014 1:03:52), то придется еще потрудиться ))

    Открываем Scripts/cultures/globalize.culture.ru-RU.js.
    Находим patterns: {….
    Видим d: "dd.MM.yyyy" и T: "H:mm:ss" по отдельности, но не d+T.
    Добавляем G: "dd.MM.yyyy HH:mm:ss"
    Теперь можно вводить дату + время в русском формате.

    Но… ))) Таким образом можно указать дату, время, дату + время, а если нам нужно запретить возможность ввода даты без времени?
    Открываем /Scripts/jquery.validate.globalize.js, находим функцию $.validator.methods.date = function (value, element) {…
    и вместо var val = Globalize.parseDate(value);
    делаем так: var val = Globalize.parseDate(value, "G");

    • Помечено в качестве ответа Universe Element 26 мая 2014 г. 9:02

Все ответы

  • Ощущение, что дата передается в не том формате. Может быть?
  • Может кто объяснить? Пожалуйста.

    Если я через GET передаю во вьюшку модель, но во View не отображаю какое-то поле, значит в POST запросе это поле передано не будет? А при сохранении в базу это поле превратится в пустое? Я думал оно просто не будет обновляться...

    Как тогда можно отобразить пользователю информацию из поля DateTime (без редактирования), но чтобы оно не было перезаписано при сохранении (если я его значение не поменяю в коде)?

  • "Ощущение, что дата передается в не том формате. Может быть?" - посмотрите сюда.

    Сделаем содержимое сообщества лучше, вместе!

    • Изменено YatajgaMVP, Editor 22 мая 2014 г. 5:38 Исправил ссылку
    Модератор
  • Yatajga, спасибо за ссылку, почитал, сделал, но ничего не изменилось.

    Даже если дату вывожу в EditorFor, при сохранении все равно валидация пишет "Поле должно содержать дату". ((

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

    Сделаем содержимое сообщества лучше, вместе!

    Модератор
  • Сделал поле HiddenInput(DisplayValue=False) и модель стала приходить в контроллер с нормальным значением.
    Значит просто валидация EditorFor не хочет принимать такое значение: 16.05.2014 0:48:44.
    Ну и ладно, EditorFor мне и не нужен. Я хочу просто отобразить значение и получить его обратно с моделью.
    Но HiddenInput меня не устраивает, т.к. значение этого поля перестает отображаться во всех вьюшках.
    Убрал HiddenInput, попробовал отобразить поле с DisplayFor - опять в модель значение этого поля не пришло.
    Делаю вывод, что в модель значение отправляется только через input с value...
    Но мне не нужен input )))))
    Как же мне правильно поступить, чтобы отобразить это значение и чтобы оно вернулось вместе с моделью? HiddenInput ведь как-то делает это o_O
  • Попробуйте установить этот атрибут на свойство содержащее дату в вашей модели.

    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]


    Сделаем содержимое сообщества лучше, вместе!

    Модератор
  • Прошла дата в таком формате через EditorFor, правда без времени.

    Но мне не нужен EditorFor, а с DisplayFor значение не передаётся ((.

  • Сделал обычное свойство:

    <Required>
    <Display(Name:="Дата изменения")>
    Public Property ModifiedDate As DateTime

    Ввел дату так: 30/05/2014 1:03:52

    Прошло!

    Получается это клиентская валидация не пропускает 30.05.2014?

  • Возможно, все зависит от настроек локали и глобализации.

    Сделаем содержимое сообщества лучше, вместе!

    Модератор
  • Разобрался!
    Клиентская валидация (jquery.validate.js) по умолчанию не воспринимает дату в формате с точками (30.05.2014). Это довольно странно, когда у тебя Windows и Visual Studio на русском языке. Удивляет, что никто не сказал мне: «Да, это известная особенность, дата с точками не проходит». Коллеги, вы даты вообще отображаете пользователям в своих MVC приложениях?
    Решение проблемы - установить в проект NuGet пакет jQuery.Validation.Globalize.
    В папку Scripts будут добавлены:
    - jquery.validate.globalize.js
    - папка globalize, которая содержит в себе файл globalize.js и папку cultures (в ней находятся файлы с настройками для различных культур, например: globalize.culture.ru-RU.js).
     
    Но не все так просто, здесь важен порядок подключения скриптов:
    <script src="/Scripts/jquery.validate.js"></script>
    <script src="/Scripts/globalize/globalize.js"></script>
    <script src="/Scripts/globalize/cultures/globalize.culture.ru-RU.js"></script>
    <script src="/Scripts/jquery.validate.globalize.js"></script>

    Удобнее всего это сделать в App_Start/BundleConfig.vb:

    ' Комментируем это:
    'bundles.Add(New ScriptBundle("~/bundles/jqueryval").Include(
    '            "~/Scripts/jquery.validate*"))

    ' Добавляем:
            bundles.Add(New ScriptBundle("~/bundles/jqueryval").Include(
                        "~/Scripts/jquery.validate.js",
                        "~/Scripts/jquery.validate.min.js",
                        "~/Scripts/jquery.validate.unobtrusive.js",
                        "~/Scripts/jquery.validate.unobtrusive.min.js"))


            bundles.Add(New ScriptBundle("~/bundles/global").Include(
                        "~/Scripts/globalize/globalize.js",
    "~/Scripts/globalize/cultures/globalize.culture.ru-RU.js"))

            bundles.Add(New ScriptBundle("~/bundles/globalLastFile").Include(
             "~/Scripts/jquery.validate.globalize*"))

    Если вы планируете использовать разные культуры и хотите, чтобы формат даты, времени, валюты и т.п. соответствовал культуре пользователя, то вместо скрипта с конкретной культурой подключите автоматическое определение культуры:
    "~/Scripts/globalize/cultures/globalize.culture." & System.Threading.Thread.CurrentThread.CurrentCulture.ToString & ".js"

    В View, где необходимы региональные настройки, добавляем:

    @Section Scripts
        @Scripts.Render("~/bundles/jqueryval")
        @Scripts.Render("~/bundles/global")
        @Scripts.Render("~/bundles/globalLastFile")

    <script>
        Globalize.culture("ru-RU");
        // автоматическое определение культуры:
        //Globalize.culture('@System.Threading.Thread.CurrentThread.CurrentCulture');
    </script>

    End Section

    Теперь дата в формате русского будет успешно проходить проверку!
    Но если вам требуется в полном смысле DateTime (30.05.2014 1:03:52), то придется еще потрудиться ))

    Открываем Scripts/cultures/globalize.culture.ru-RU.js.
    Находим patterns: {….
    Видим d: "dd.MM.yyyy" и T: "H:mm:ss" по отдельности, но не d+T.
    Добавляем G: "dd.MM.yyyy HH:mm:ss"
    Теперь можно вводить дату + время в русском формате.

    Но… ))) Таким образом можно указать дату, время, дату + время, а если нам нужно запретить возможность ввода даты без времени?
    Открываем /Scripts/jquery.validate.globalize.js, находим функцию $.validator.methods.date = function (value, element) {…
    и вместо var val = Globalize.parseDate(value);
    делаем так: var val = Globalize.parseDate(value, "G");

    • Помечено в качестве ответа Universe Element 26 мая 2014 г. 9:02
  • Добавляю, что для отображения даты изменения я использовал DisplayFor:

    @Html.DisplayNameFor(Function(model) model.ModifiedDate)
    @Html.DisplayFor(Function(model) model.ModifiedDate)

    А EditorFor, через который дата изменения передается обратно на сервер, я спрятал:
    <div class="hidden">
      @Html.EditorFor(Function(model) model.ModifiedDate)
    </div>


  • "Это довольно странно, когда у тебя Windows и Visual Studio на русском языке. Удивляет, что никто не сказал мне: «Да, это известная особенность, дата с точками не проходит». Коллеги, вы даты вообще отображаете пользователям в своих MVC приложениях?" -  мы создаём приложения преимущественно для рынка США, а там локализация стандартная и с подобными проблемами сталкиваться не приходится. Спасибо, что не забыли и выложили решение проблемы.

    Сделаем содержимое сообщества лучше, вместе!

    Модератор
  • Понятно. Я когда измучился и каким-то чудом разобрался, представил, что еще кто-нибудь пройдет через все это и мне совесть не позволила не поделиться))

  • Очень простое решение без сторонних пакетов и прочего. Взято от сюда: 

    http://codearticles.ru/articles/2254

    http://codearticles.ru/articles/2257

    $.validator.addMethod(
                'date',
                function (value, element, params) {
                    if (this.optional(element)) {
                        return true;
                    };
                    var result = false;
                    try {
                        $.datepicker.parseDate('dd.mm.yy', value);
                        result = true;
                    } catch (err) {
                        result = false;
                    }
                    return result;
                },
                ''
    );
  • В версии 1.1.0  jQuery.Validation.Globalize при установке в проекте папки Culture уже нет. По разному пробовал, но валидация не проходит. Формат проверяемой даты остался mm/dd/yyyy, как выйти из этой ситуации?
    20 марта 2017 г. 21:10