DateTime в UT C в базе данных и не выполняет преобразование часового пояса из контроллера, преобразование обрабатывается только в клиентском браузере - PullRequest
1 голос
/ 06 мая 2020

Я столкнулся с проблемой, о которой много говорят на SO. Я на самом деле читал ТАК вопросы и ответы в течение 2 дней, пытаясь определить хороший способ решения моей проблемы. Проблема заключается в довольно простой концепции c. Даты и время должны быть отправлены в метод контроллера mvc и сохранены в базе данных как UT C. Все ответы, которые я смог найти о topi c, касались обработки преобразования UT C в самом методе контроллера. Я хотел специально обрабатывать все преобразования даты в клиентском коде. Мне также нужно было использовать SQLCommand для моего запроса в таблице, которая содержала даты, а не с помощью Linq / EF. Некоторые из найденных мной решений касаются использования DateTime.SpecifyKind и использования JsonSerializerSettings как DateTimeZoneHandling.Ut c в сериализации Newtonsoft.

Для некоторых примеров ... Моя дата хранится в Sql Серверная база данных как тип данных DateTime, допускающий значение NULL. Я использую военное время и храню его в следующем формате ...

2020-05-04 16: 52: 00.000

Следующий код - это весь клиентский код, написанный на html / jquery / js:

В системе, над которой я работаю, я использую flatpickr для настройки средства выбора даты на входе.

<div class="flatpickrcontainer">
     <input type="text" id="time" class="form-control" placeholder="Select Date..." data-input>
</div>

Затем я создаю экземпляр flatpickr с датой и временем ...

    flatpickr.l10ns.default.firstDayOfWeek = 1; // Monday default is sunday
    const addDateInput = document.querySelector(".flatpickrcontainer");
    flatpickr(addDateInput,
        {
            wrap: true,
            weekNumbers: false,
            defaultDate: new Date(), //set the date to now as the default
            onReady: function () {
                if (this.amPM)
                    this.amPM.textContent = "PM";
            },
            enableTime: true, // enables timepicker default is false    
            time_24hr: false, // set to false for AM PM default is false
            dateFormat: "n/j/yy h:i K"
        });
    flatpickr_for_add = document.querySelector(".flatpickrcontainer")._flatpickr;

flatpickr_for_add теперь является экземпляром, который можно вызывать с помощью методов. Следующее, что я делаю, я получаю данные flatpickr в виде такой строки:

var strInputDate = flatpickr_for_add.selectedDates[0];

Мой вопрос: как мне преобразовать эту дату и время из flatpickr строка в UT C, а затем сохраните ее в базе данных, используя любой / весь AJAX / JSON / JS / JQUERY / C# MVC SqlServer?

Вторая часть у меня вопрос: как мне получить дату и время из базы данных и вернуть его в браузер при преобразовании даты и времени из UT C в часовой пояс локального браузера пользователя?

1 Ответ

1 голос
/ 06 мая 2020

Вот как я справился с этим. Я надеюсь, что это поможет кому-то другому, и я также надеюсь, что я не использую какие-либо сомнительные методы, собирая этот пост.

В моем коде сервера c# mvc мой класс выглядит примерно так. ..

public class GridRecord
{
     public int id { get; set; }
     public DateTime? opened_dt { get; set; }
     public DateTime? closed_dt { get; set; }
}

Обратите внимание, что я использую DateTime? для типа, а не DateTimeOffset?

Предполагая, что ваша SQLCommand отформатирована и готова к go, а ваш класс (в моем случае GridRecord - это имя класса) соответствует результату данные столбца sql, сделайте это в методе контроллера c# mvc:

//...here we would set up the connection string and define a variable typed to the class (GridRecord) 
//that will hold the returned data from the sqlcommand... for this variable I will use var sqlGridData 
//... and we can handle any passed in values from the controller method parameters, 
//like specialdata here in this area before we call the sqlcommand...
using (SqlConnection sqlconn = new SqlConnection(constring))
{
     SqlCommand command = new SqlCommand(sql, sqlconn);
     sqlconn.Open();
     SqlDataReader reader = command.ExecuteReader();
     try
     {
          var dataTable = new DataTable();
          dataTable.Load(reader);
          if (dataTable.Rows.Count > 0)
          {
               var serializedMyObjects = JsonConvert.SerializeObject(dataTable);
               sqlGridData = (List<GridModel.GridRecord>)JsonConvert.DeserializeObject(serializedMyObjects,typeof(List<GridModel.GridRecord>));
          }
     }
     //add catch{} here to handle exception if desired (good practice)
     finally
     {
          reader.Close();
     }
}

Приведенный выше код действительно является довольно простой концепцией. Мы получаем результат от SQLCommand, сохраняем его в таблице данных и затем используем Newtonsoft Json. NET для сериализации / десериализации его в список, введенный в класс (мой класс - GridRecord).

Следующее, что я сделал, - это настроил метод контроллера для возврата результата. Я использовал ActionResult вместо JsonResult, потому что JsonResult фактически изменяет дату и время во время сериализации. В моем случае метод контроллера называется GetGridData.

public ActionResult GetGridData(string specialData = default(string))
{
     //...perform some controller method actions here, like handling specialdata
     //parameter and include the SqlCommand code with proper connectionstring info...
     return Content(JsonConvert.SerializeObject(sqlGridData, new JsonSerializerSettings { DateTimeZoneHandling = DateTimeZoneHandling.Unspecified }));
}

Обратите внимание, что мы должны использовать JsonSerializerSettings, чтобы определить DateTimeZoneHandling как Unspecified. Это причина использования ActionResult, а не JsonResult.

Для клиентского кода у нас намного больше гибкости в отношении формата, который мы передаем методу контроллера. Я действительно предлагаю вам использовать военное время при хранении данных в базе данных. Я не собираюсь вдаваться в подробности с вызовом ajax здесь, чтобы отправить дату на сервер и сохранить ее в базе данных, потому что вам решать, хотите ли вы выполнить GET или POST для вызова метода, и это также зависит от вас, как вы хотите настроить свой AJAX объект данных.

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

[HttpPost]
public JsonResult Add(string opened_dt = default(string))
{
     result = 0; //you could use this to handle some error like opened_dt = ""
     using (var dbContext = new entities())
     {
          TBL_special rowToAdd = new TBL_special(); //TBL_special is in the database and imported into your edmx model
          rowToAdd = new TBL_special{ opened_dt = Convert.ToDateTime(opened_dt)};
          try
          {
               dbContext.SaveChanges();
          }
          catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
          {
               Exception raise = dbEx;
               foreach (var validationErrors in dbEx.EntityValidationErrors)
               {
                    foreach (var validationError in validationErrors.ValidationErrors)
                    {
                         string message = string.Format("{0}:{1}",validationErrors.Entry.Entity.ToString(),validationError.ErrorMessage);
                         // raise a new exception nesting
                         // the current instance as InnerException
                         raise = new InvalidOperationException(message, raise);
                    }
                }
                throw raise;
          }

     }
     return Json(result, JsonRequestBehavior.AllowGet);
}

Обратите внимание, что в приведенном выше коде я получаю параметр метода контроллера в виде строки, а затем использую Convert.ToDateTime () для обработки строки даты преобразование для типа данных DateTime в базе данных.

Чтобы отформатировать дату в браузере конечного пользователя в UT C перед отправкой в ​​метод контроллера, в коде javascript / jquery я использую момент. js:

moment.utc(moment(dateStringVariableFromInput).utc().format('YYYY-MM-DD HH:mm:ssZ')).format('MM/DD/YYYY HH:mm');

Или вы можете отправить текущую дату и время из браузера пользователя, используя:

moment.utc(new Date()).format("MM/DD/YYYY HH:mm")

Формат очень гибкий с этим решением, если вы хотите go с чем-то другим, кроме MM / ДД / ГГГГ ЧЧ: мм, если вы используете формат момент. js удобный. Как я уже сказал, вы можете придерживаться военного времени, чтобы вам не приходилось иметь дело с AM / PM. Проверьте момент . js документацию для получения дополнительной информации о допустимом форматировании.

Как только вы получите данные обратно от метода контроллера, и вы будете готовы преобразовать дату / время из UT C обратно к дате и времени в браузере пользователя, затем вы используете момент. js такой оператор ...

moment.utc(moment(dateStringFromController).format('YYYY-MM-DD HH:mm:SS')).local().format('MM/DD/YYYY h:mm A');
...