Локализация дат

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 1.11.2015

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

public class User
{
    public int Id { get; set; }
    [Display(Name = "Имя")]
    public string Name { get; set; }

    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:dd'/'MM'/'yyyy}", ApplyFormatInEditMode = true)]
    [Display(Name = "Дата рождения")]
    public DateTime Date { get; set; }
}

В данном случае мы ориентированы на формат dd/MM/yyyy, как показывает атрибут DisplayFormat.

В представлении используются скрипты валидации и виджет jQuery DatePicker для выбора дат:

@model DateLocalizationApp.Models.User

@{
    ViewBag.Title = "Create";
}

<h2>Добавление модели</h2>

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>Пользователь</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Date, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Date, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Date, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <link href='@Url.Content("~/Content/themes/base/all.css")' rel="stylesheet" type="text/css" />
    <script src='@Url.Content("~/Scripts/jquery-ui-1.11.4.min.js")' type="text/javascript"></script>
    <script type="text/javascript">
    $(function () {
        $("input[type='date']")
                    .datepicker({ dateFormat: 'dd/mm/yy' })
                    .get(0).setAttribute("type", "text");
        $.datepicker.regional['ru'] = {
            prevText: 'Пред',
            nextText: 'След',
            monthNames: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь',
            'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
            monthNamesShort: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн',
            'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'],
            dayNames: ['воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота'],
            dayNamesShort: ['вск', 'пнд', 'втр', 'срд', 'чтв', 'птн', 'сбт'],
            dayNamesMin: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'],
            weekHeader: 'Не',
            dateFormat: 'dd/mm/yy',
            firstDay: 1,
            isRTL: false,
            showMonthAfterYear: false,
            yearSuffix: ''
        };
        $.datepicker.setDefaults($.datepicker.regional['ru']);
    });
    </script>
}

В контроллере перед сохранением модель проходит валидацию:

[HttpPost]
public ActionResult Create(User user)
{
    if(ModelState.IsValid)
    {
        db.Users.Add(user);
        db.SaveChanges();
    }
    return View(user);
}

И при стандартном ходе событий несмотря на то, что мы введем обычную вроде дату, мы получим ошибку:

Локализация дат в ASP.NET MVC 5

Потому что стандартная библиотека валидации javascript, которую предоставляет Microsoft, ориентируется на формат mm/dd/yy, у нас же datepicker использует формат dd/mm/yy.

Чтобы решить проблему, надо переопределить функцию валидатора. Для этого после определения настроек datepicker переопределим функцию валидатора для выбора даты:

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <link href='@Url.Content("~/Content/themes/base/all.css")' rel="stylesheet" type="text/css" />
    <script src='@Url.Content("~/Scripts/jquery-ui-1.11.4.min.js")' type="text/javascript"></script>
    <script type="text/javascript">
    $(function () {
        $("input[type='date']")
                    .datepicker({ dateFormat: 'dd/mm/yy' })
                    .get(0).setAttribute("type", "text");
        $.datepicker.regional['ru'] = {
            prevText: 'Пред',
            nextText: 'След',
            monthNames: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь',
            'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
            monthNamesShort: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн',
            'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'],
            dayNames: ['воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота'],
            dayNamesShort: ['вск', 'пнд', 'втр', 'срд', 'чтв', 'птн', 'сбт'],
            dayNamesMin: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'],
            weekHeader: 'Не',
            dateFormat: 'dd/mm/yy',
            firstDay: 1,
            isRTL: false,
            showMonthAfterYear: false,
            yearSuffix: ''
        };
        $.datepicker.setDefaults($.datepicker.regional['ru']);
		$.validator.addMethod('date',
            function (value, element) {
                var ok = true;
                try {
                    $.datepicker.parseDate('dd/mm/yy', value);
                }
                catch (err) {
                    ok = false;
                }
                return ok;
        });
    });
    </script>
}

Теперь для проверки используется функция $.datepicker.parseDate. Если виджет сможет распарсить дату, то возвращается true. Если же в процессе парсинга возникнет ошибка, то возвращается false.

После исправления при запуске проекта в Visual Studio все заработает. Но при размещении на зарубежном хостинге, например, на том же somee.com мы можем столкнуться с другой проблемой:

Валидация дат в ASP.NET MVC

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

Рещением в данной ситуации будет явное указание культуры с помощью элемента globalization в файле web.config в узле system.web:

<system.web>
    <globalization culture="ru-RU" uiCulture="ru" />
	<!-- остальное содержимое system.web-->

Теперь на стороне сервера также будет использоваться дата в формате dd/MM/yyyy.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850