Как передать дату UTC от клиента к драйверу и фильтру mongo db c #? - PullRequest
0 голосов
/ 16 октября 2018

Есть ли способ предотвратить преобразование драйвером mongodb c # любой даты, переданной в запросе фильтра, в UTC, но вместо этого принять дату как UTC?

Я использую .net core 2.1 с некоторыми элементами управления telerik для отображениясетка.Внутри заголовка сетки у меня есть элемент управления фильтра для фильтрации диапазона дат.

enter image description here

Внутри события клиента перед фильтрацией я фиксирую датуи преобразование его в utc:

function onGridFilter(e) {
        // check if it is a date field
        if (e.filter && e.field === "created"){
            convertDateToUTC(e.filter);
        }
    }

    function convertDateToUTC(filter) {
        var filters = filter.filters;
        for (var i = 0; i < filters.length; i++) {
            if (filters[i].field === "created") {
                var date = filters[i].value;
                var isoDate = new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());                    
                filter.filters[i].value = isoDate;
            }
        }
    }

В вызове API я конвертирую дату UTC в местное время сервера следующим образом (этот API является микросервисом kubernetes и может иметь другой часовой пояс в зависимости отгде он развернут):

// Update the dates to server times for filtering, mongo will accept dates and convert to UTC based on the server location
        foreach (var f in this.Filters)
        {
            if (f.ConvertedValue.GetType() == typeof(DateTime))
            {
                DateTime dt = (DateTime)f.Value;
                f.Value = dt.ToLocalTime();
            }
        }

Использование фильтра telerik (объект DataSourceRequest) и драйвера mongodb c # (linq to mongo) Я создаю запрос mongo для фильтрации записей в базе данных mongo.

 public DataSourceResult GetCollectionQuery(string organizationId, DataSourceRequest request)
    {
        IMongoCollection<Case> casesCollection = _db.GetCollection<Case>(_collection);
        IMongoCollection<Person> personCollection = _db.GetCollection<Person>(_personCollection);
        IQueryable<CaseListViewModel> query;

        // Setup full results query
        query = (from c in casesCollection.AsQueryable()
                 where c.OrganizationId == organizationId
                 join p in personCollection.AsQueryable() on c.ClientId equals p.Id into p
                 from person in p.DefaultIfEmpty()
                 select new CaseListViewModel()
                 {
                     Id = c.Id,
                     DisplayName = person != null ? person.LastName + ", " + person.FirstName : string.Empty,
                     OrganizationCaseId = c.OrganizationCaseId,
                     ServiceName = c.ServiceName,
                     ClientType = c.ClientType,
                     Addresses = c.ClientTypeValue == ClientTypeValue.Person ? person.Addresses != null ?
                                    person.Addresses.Where(o => !o.End.HasValue).Select(o => o.AddressLine1) : null : null,
                     Worker = string.Empty, //c.Assignments,
                     Created = c.Created,
                     Status = c.Status,
                     OrganizationGeography = person != null ? person.OrganizationGeography != null ? person.OrganizationGeography.Name : string.Empty : string.Empty
                 });

        // Filter/Sort/Page results
        return query.ToDataSourceResult(request);
    }

Причина, по которой я конвертирую клиента в UTC, UTC на сервер, а затем передаю эту дату в запрос на монго, заключается в том, что клиент и сервер могут находиться в разных часовых поясах.

Это похоже наэто много ненужной работы, чтобы отфильтровать дату на сетке.В настоящее время это решение работает, но я ищу альтернативу на стороне драйвера mongodb c #.Я хочу, чтобы запрос mongodb считывал все даты как UTC, а не конвертировал полученные даты в UTC.

Я знаю, что есть способ сообщить свойству, что оно сохраняется как utc с BsonDateTimeOptions DateTimeKind:

[BsonElement(elementName: "created")]
[BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
public DateTime Created { get; set; }

Есть ли что-то похожее для запросов?

Обновление: Решением было указать, какой DateTimeKind был для фильтруемой даты.

foreach (var f in this.Filters)
        {
            if (f.ConvertedValue.GetType() == typeof(DateTime))
            {
                DateTime dt = (DateTime)f.Value;
                dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc);
                f.Value = dt;
            }
        }

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

Вы можете попытаться использовать DateTime.SpecifyKind для своей даты, например:

query = (from c in casesCollection.AsQueryable()
...
select new CaseListViewModel()
{
    ...
    Created = DateTime.SpecifyKind(c.Created, DateTimeKind.Utc)
}

В этом случае драйвер mongodb должен интерпретировать дату как уже в utc, поэтому он не будет выполнять преобразование.

0 голосов
/ 16 октября 2018

Я не совсем уверен, что вы спрашиваете, но в вашем коде я вижу несколько вещей:

  • В вашем коде на стороне клиента у вас есть:

    var isoDate = new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
    

    Это распространенный анти-паттерн, и вы никогда не должны этого делать.Параметры объекта Date ожидают значения по местному времени, а вы передаете значения в формате UTC.Делать это в основном то же самое, что и добавлять величину смещения UTC для местного часового пояса.Другими словами, он не конвертирует объект в другой часовой пояс, он просто выбирает другой момент времени.

    Вместо этого вы, вероятно, захотите сделать date.toISOString().При этом будет выдана строка на основе UTC в формате ISO 8601, которая подходит для отправки на сервер.

  • В вашем коде на стороне сервера у вас есть:

    f.Value = dt.ToLocalTime();
    

    Преобразуется в местный часовой пояс сервера.В подавляющем большинстве случаев вам следует избегать написания кода, который зависит от настройки часового пояса сервера.Вместо этого сохраните время ввода в UTC, как оно было дано вам.Хранить с использованием UTC, запрашивать с использованием UTC и возвращать ответы на основе UTC.В своем клиентском коде, который получает ответ, преобразуйте его в местное время, используя объект Date или библиотеку.

Кроме того, в вашем GetCollectionQuery я неЯ вообще не вижу ничего, связанного с датой или временем, поэтому я не уверен, как это относится к вашему вопросу.

...