Выбор лучшего формата для хранения даты и времени в JSON

Apache CouchDB и IBM Cloudant являются хранилищами документов JSON и поэтому не имеют собственного типа date - только примитивы данных, разрешенные в спецификации JSON.

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

Что касается форматов хранения, обычно используются три варианта.

1. Сохраните дату как одну строку ISO-8601.

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

В JavaScript вы можете создать этот формат с помощью:

Это состоит из:

  • год, месяц и день через дефис.
  • символ «T» для разделения элементов даты и времени.
  • час, минута и секунда (с точностью до микросекунд), разделенные двоеточием.
  • Часовой пояс UTC обозначается знаком Z, который относится к военному часовому поясу Zulu.

Это хороший универсальный формат, который является компактным, сортируется в порядке даты / времени и может быть возвращен объекту даты в конструкторе объекта JavaScript Date, например, при манипулировании датами в представлении MapReduce »:

который при упаковке в Проектный документ со встроенным редуктором можно запросить с помощью:

Это создает упорядоченные по времени, иерархические, сгруппированные агрегаты ваших данных.

Менее очевидно то, что если бы вы выбрали для хранения данных другой формат, например 2018-05-02 15:02:40, то вызов new Date(doc.datetime) завершился бы ошибкой. Это связано с тем, что более старая версия движка SpiderMonkey JavaScript, используемая CouchDB и Cloudant, не может анализировать этот нераспознанный формат даты.

2. Сохраните дату как отметку времени.

Вместо того, чтобы хранить дату и время в виде строки, вы можете сохранить целочисленную метку времени - в частности, количество миллисекунд с 00:00:00 UTC 1 января 1970 года.

Хотя эта строка не так удобочитаема, как строка ISO-8601, она по-прежнему доступна для машинного чтения, сортируется по дате и времени и может быть легко преобразована обратно в объект Date в функции карты:

Этот формат не совсем подходит для хранения дат до 1970 года (хотя отрицательные временные метки действительно работают!), Но он может быть полезен для простой арифметики дат, поскольку одна временная метка может быть вычтена из другой для вычисления разницы во времени.

3. Сохраняйте компоненты даты и времени в отдельных полях.

Третий вариант - хранить каждый компонент даты и времени отдельно:

Это более подробное решение по сравнению с двумя предыдущими решениями, но имеет то преимущество, что данные готовы для запроса и индексации без какой-либо предварительной обработки. Это особенно важно при использовании Cloudant Query - представления MapReduce обычно используются для предварительной обработки данных перед их отправкой в индекс, но при использовании Cloudant Query такой возможности нет. Для Cloudant Query данные должны быть в документе и в правильном формате.

Создайте индекс с помощью конечной точки /db/_index или через панель управления:

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

Если бы данные хранились в формате ISO-8601, было бы невозможно проиндексировать или запросить отдельный компонент (например, год) самостоятельно с помощью Cloudant Query.

Проблемы с датой и временем

  • Помните, что функции JavaScript Date.getMonth() и Date.setMonth() используют числа 0-11 для обозначения месяцев с января по декабрь.
  • При извлечении данных из объекта Javascript Date помните, что это getDate(), getMonth()+1 и getFullYear(), а не имена функций, которые вы могли ожидать!
  • Механизм JavaScript, используемый в механизме MapReduce, не может анализировать многие форматы даты в своем конструкторе. Он может работать с форматом ISO-8601 и миллисекундами с 1970 года, вот и все.
  • Если вы используете строковые манипуляции для разделения даты, вы можете столкнуться с этой загадкой в ​​своей функции карты.

В приведенном выше коде мы решили хранить только дату в виде строки. Мы разбиваем строку символом -, превращаем части года / месяца / дня в целые числа и используем их для создания иерархического индекса. В чем проблема такого подхода?

Возьмем дату 2018-08-09 (9 августа). В этом случае рассчитываются следующие данные:

  • год - 2018
  • месяц - 0
  • 1 день

Почему? Поскольку механизм индексатора SpiderMonkey JavaScript интерпретирует начальный ноль на 08 и 09, чтобы указать, что вы хотите, чтобы дата анализировалась как восьмеричные числа! Это можно исправить с помощью:

Это означает, что ваши строки в десятичном формате.