Cypher Sleuthing: Работа с датами, часть 2

В моем предыдущем сообщении Часть 1 по этой теме были представлены даты Cypher и переведены несколько других форматов дат в поддерживаемый Cypher формат ISO 8601. Если вы это читаете, то этот пост станет следующим шагом с датами Cypher, которые охватывают продолжительность и многое другое. Если вы не видели часть 1, не стесняйтесь наверстывать упущенное - хотя для этой части не обязательно читать часть 1. :)

Мы продолжим часть последнего сообщения, показав, как обрезать дату и время. Затем мы рассмотрим следующую область встроенных функций даты Cypher - измерение расстояния по времени и вычисление разницы между датами с длительностями. Мы обсудим и увидим примеры того, как работают длительности в Cypher - вычисление длительностей по отдельным датам, добавление или вычитание длительностей из дат и вычисление расстояния между двумя датами или временем.

Вы можете продолжить, запустив пустую песочницу (бесплатно) и скопировав Cypher в браузер или настроив и запустив запросы для вашего собственного набора данных. Пора окунуться!

Обрезка даты

Если вы читали документацию Cypher по усечению дат, формулировка верна, но у меня кружится голова. Итак, позвольте мне попытаться перевести это.

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

Моя версия: Вы можете обрезать (усечь) временное значение в определенной точке, при этом любые меньшие единицы будут установлены в значения по умолчанию. Например, усечение даты 2021–04–21 до года означает, что значение года будет сохранено, а значения месяца и дня будут по умолчанию равны 01, возвращая результат 2021–01–01.

Это может быть полезно, если вы хотите, чтобы поиск по умолчанию обобщал все даты по годам или месяцам. Обратите внимание: если вы хотите полностью сократить дату до нужного компонента (например, 2021–04–21 до 2021), вы можете сделать это, обратившись к компоненту значения. Об этом вкратце рассказывалось в Части 1 этой серии, а более подробно мы рассмотрим в другом посте. Давайте посмотрим на несколько примеров усечения дат.

Каждый из временных моментов Neo4j (Date, Time, Datetime, LocalDatetime, LocalTime) может использовать .truncate() в конце. Как и в предыдущем посте, мы будем придерживаться более общих значений Date, Time и Datetime. Хотя LocalDatetime и LocalTime действительны и поддерживаются, очень мало случаев, которые действительно требуют использования local, и работать с ними сложнее.

Пример 1: усечение даты и времени в году

WITH datetime.truncate(‘year’,datetime()) as truncatedDatetime
MATCH (b:BlogPost)
WHERE b.publishedDatetime >= truncatedDatetime
RETURN b.publishedDatetime, truncatedDatetime;

В приведенном выше примере выполняется поиск всех сообщений в блогах, опубликованных в 2021 (не ранее 2021–01–01).

Пример 2: усечение даты в месяце

WITH date.truncate(‘month’,date()) as truncatedDate
MATCH (p:Project)
WHERE p.expectedEndDate > truncatedDate
RETURN p.expectedEndDate, truncatedDate;

В приведенном выше примере выполняется поиск проектов, которые еще не завершены - ожидаемая дата окончания которых наступает после 1 апреля 2021 года.

Пример 3: усечение даты по часам

WITH time.truncate(‘hour’,time(‘09:30:52–06:00’)) as truncatedTime
MATCH (p:Presentation)
WHERE time.truncate(‘hour’,p.time) = truncatedTime
RETURN time.truncate(‘hour’,p.time), truncatedTime;

В примере 3 выше запрашиваются любые презентации, которые проводятся в 9 утра. Это может быть полезно во время конференции, если вы хотите увидеть, какие сеансы проходят в течение определенного часа.

Мы видели, как можно обрезать даты, чтобы создать общие даты для таких случаев, как отправные точки при поиске. Теперь перейдем к работе с отрезками времени с помощью длительностей.

Cypher Продолжительность

Продолжительность в Cypher - это промежуток времени между двумя временными моментами. Независимо от того, используем ли мы саму продолжительность для определения отрезка времени или для расчета расстояния между точками времени, эти значения невероятно полезны для измерения времени. Существует 2 различных способа указать продолжительность, перечисленных ниже:

  1. Суммы на основе единиц (буквальный P и / или T + числовое значение + идентификатор компонента) - например, P1Y3M10D или {hours: 24}.
  2. Моменты даты и времени (буквальные P и / или T + значение даты и / или времени) - например, P20210419 или PT090000.

Давайте посмотрим на несколько примеров.

Пример 1. Получение значения продолжительности (с использованием суммы в единицах)

MERGE (p:Person)-[r:BOOKED]->(v:Vacation)
SET v.length = duration(‘P5D’)
RETURN v.length as vacationDuration;

Установка продолжительности отпуска для человека. Мы могли бы использовать этот запрос для планирования проживания, электронных писем об отсутствии на работе, планирования отпусков или других вариантов использования.

Пример 2: Установите продолжительность как частоту для дозировки лекарства

MERGE (d:Dose)-[r:PRESCRIBED_AMOUNT]->(m:Medicine)
SET d.frequency = duration(‘PT4H’)
RETURN d.frequency;

В приведенном выше примере это используется для расчета того, как часто можно принимать прописанные лекарства. Теперь вы можете сказать: «Погодите, а почему это считалось секундами, а не часами и минутами»? Мы объясним это более подробно после еще пары примеров. А пока знайте, что продолжительность часов и минут конвертируется в секунды.

Пример 3. Рассчитать конкретную дату как продолжительность

MATCH (:Employee)-[rel:ASSIGNED]-(:Project)
RETURN rel.startDate as date, duration(‘P’+ rel.startDate) as duration;

ПРИМЕЧАНИЕ. Формат даты не может включать значение часового пояса. Полезный ключ к запоминанию заключается в том, что продолжительность времени не зависит от географического положения - только расстояние между двумя датами или временем. Кроме того, дате должна предшествовать буква «P», а перед временем - буква T.

Если мы разделим полученные 24 254 месяца на 12 (чтобы найти количество лет), мы получим 2021.16667. Это говорит нам количество месяцев от года 0, которое соответствует дате 2021–02–15. Хотя это, вероятно, не очень полезно для этого варианта использования, в научных областях может быть более полезно точная датировка артефактов или география.

Пример 3: Рассчитать конкретное время как продолжительность

MATCH (d:Dose)
MERGE (p:Person)-[r:TAKES]->(d)
SET d.dose1Time = duration(‘PT093000’)
RETURN d.dose1Time;

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

Точность продолжительности

Следует отметить, что существуют очень конкретные правила, которым следует придерживаться при расчетах продолжительности. Продолжительность хранится в месяцах, днях, секундах, наносекундах. Это связано с тем, что некоторые компоненты времени могут различаться - часы в день (из-за перехода на летнее время), дни в месяце (28, 29, 30, 31) и т. Д. Это причина, по которой вы можете заметить, что часовые и минутные вычисления меняются. к более точным и последовательным вторым значениям.

Вот почему наши предыдущие запросы (снова перечисленные ниже) были преобразованы в секунды. В первом запросе частоты приема лекарственного средства 4 часа преобразуются в секунды, поскольку большие значения времени не могут считаться постоянными на 100% во все времена. На самом деле это могло бы стать смертельным исходом, если бы частота доз не была рассчитана должным образом.

Тот же сценарий существует для второго запроса. Если мы приняли дозу в 9:30 в обычный день или в день, который перешел на летнее время или наоборот, это время могло быть отключено. Более точно рассчитывать секунды от полуночи (34 200 секунд / 60 секунд в минуте / 60 минут в часе = 9,5 часа после полуночи). Это гарантирует отсутствие неправильных значений хранения и возможность расчета времени пользователями в зависимости от обстоятельств.

MERGE (d:Dose)-[r:PRESCRIBED_AMOUNT]->(m:Medicine)
SET d.frequency = duration(‘PT4H’)
RETURN d.frequency;
MERGE (p:Person)-[r:TAKES]->(d:Dose)
SET d.dose1Time = duration(‘PT093000’)
RETURN d.dose1Time;

В следующем посте мы увидим, как преобразовать эти небольшие точные значения в более значимые суммы (например, часы). А пока мы просто разберемся с математикой преобразования длительности в точные суммы и нахождения разницы между двумя значениями даты.

Расчеты с указанием дат и продолжительности

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

Пример 1. Вычтите 2,5 месяца из даты окончания, чтобы рассчитать дату начала.

MATCH (p:Project)
SET p.expectedStartDate = p.expectedEndDate — duration(‘P2.5M’)
RETURN p.expectedEndDate, p.expectedStartDate;

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

Пример 2. Добавьте 30 часов к дате начала и времени, чтобы рассчитать дату и время окончания.

MATCH (c:Conference)
SET c.endDatetime = c.startDatetime + duration({hours: 30})
RETURN c.startDatetime, c.endDatetime;

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

Пример 3: Рассчитайте, когда принимать следующую дозу лекарства.

MATCH (d:Dose)
SET d.dose2Time = d.dose1Time + d.frequency
RETURN d.dose2Time;

ПРИМЕЧАНИЕ: мы могли бы быстро произвести расчет вручную (48 600/60 секунд в минуте / 60 минут в часе = 13,5 часов после полуночи), что будет примерно в 13:30 в стандартный день. Однако мы увидим, как это сделать с помощью Cypher, в другой публикации.

На основе дозы, принятой в предыдущем запросе, и частоты приема лекарства, в приведенном выше запросе вычисляется время (в секундах) нашей следующей дозы.

Вычислить разницу между двумя датами с продолжительностью.

Теперь давайте посчитаем разницу между двумя датами. Нам нужно будет использовать duration.between, чтобы сравнить две даты и найти разницу.

Пример 1. Расчет продолжительности между датами начала и окончания проекта.

MATCH (:Employee)-[rel:ASSIGNED]-(p:Project)
RETURN rel.startDate as assigned, p.expectedEndDate as expectedCompletion, duration.between(rel.startDate, p.expectedEndDate) as lengthAssigned;

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

Пример 2: Рассчитать количество времени, которое в настоящее время затрачивается на проект

MATCH (:Employee)-[rel:ASSIGNED]-(p:Project)
RETURN rel.startDate as assigned, duration.between(rel.startDate, date()) as timeSpent;

Используя запрос выше, мы можем узнать, как долго продолжается наш проект. Это говорит нам, сколько времени прошло, и, как и в предыдущем запросе, может помочь нам понять, сколько ресурсов было использовано в проекте в определенный момент времени. Мы сделаем этот расчет в следующем посте! :)

Пример 3. Расчет продолжительности между разными значениями даты и времени.

MATCH (b:BlogPost)
RETURN date(‘2021–03–22’) as started, b.publishedDatetime as published, duration.between(date(‘2021–03–22’), b.publishedDatetime) as amountOfTimeSpent;

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

Подведение итогов!

Мы увидели, как использовать продолжительность Cypher для измерения расстояния во времени - начиная с длины, такой как 2 days, прибавляя или вычитая сумму из даты или времени, или находя разницу между двумя датами / временем. Хотя некоторые из возвращенных сумм преобразованы в более точные (и, возможно, менее значимые) значения, мы обнаружили, что это происходит специально, чтобы обеспечить согласованные суммы, на которые можно положиться независимо от времени года, географического положения или наблюдаемых временных изменений.

В следующем посте мы более подробно рассмотрим компоненты форматирования и даты. Мы увидим, как преобразовать эти точные значения в более значимые значения, а также как получить доступ к компонентам полных значений даты / времени и преобразовать другие временные величины в другие единицы (например, 120 секунд в 2 минуты или 72 часа в 3 дня) . Настройтесь в следующий раз и удачного кодирования!

Ресурсы