Clojure Datetime Арифметика с # инст - PullRequest
0 голосов
/ 23 января 2019

У меня есть много дат в формате #inst, например

(list #inst "2016-04-30T10:29:17.000-00:00" 
      #inst "2016-03-24T12:13:12.000-00:00" 
      #inst "2016-03-24T12:09:43.000-00:00" 
      #inst "2016-03-23T13:19:03.000-00:00" 
      #inst "2016-02-26T14:51:37.000-00:00" 
      #inst "2016-01-20T16:55:24.000-00:00")

Мне нужно рассчитать разницу во времени между ними как целые числа минут.

Я искал библиотеки времени Clojure, но могуя не вижу много о # inst, кроме как конвертировать в их.

Как я могу сделать арифметику времени с последовательностями # inst для получения различий и преобразования разностей в целые числаминут?

Спасибо за помощь.

Ответы [ 4 ]

0 голосов
/ 24 января 2019

Еще одно решение с использованием нативного java.time:

(ns tst.tupelo.java-time
  (:import [ java.time Duration ZoneId ZonedDateTime ]))

  ; note that instants are in DESCENDING order
  (let [instants         ["2016-04-30T10:29:17.000-00:00"
                          "2016-03-24T12:13:12.000-00:00"
                          "2016-03-24T12:09:43.000-00:00"
                          "2016-03-23T13:19:03.000-00:00"
                          "2016-02-26T14:51:37.000-00:00"
                          "2016-01-20T16:55:24.000-00:00"]

        zoned-date-times (mapv #(ZonedDateTime/parse %) instants)
        zdt-pairs        (partition 2 1 zoned-date-times)
        durations        (vec (for [[interval-stop interval-start] zdt-pairs]
                                (.toMinutes ; *** truncates ***
                                  (Duration/between interval-start interval-stop))))]

с результатом:

durations => [53176 3 1370 37347 53156]

ОБРАТИТЕ ВНИМАНИЕ: эти значения обрезаны до целых минут, как указывалось в исходной проблеме.


Обсуждение:

Поскольку первые 2 ответа были неправильными, это показывает ценность использования встроенных утилит времени java.time вместо попытки быстро написать собственное решение. В большинстве случаев мне проще использовать собственные классы и функции Java по сравнению с оболочкой Clojure, такой как clj-time, которая оборачивает устаревшую библиотеку Joda-Time.

Внимание:

Начиная с Java 8, clj-time (и библиотеку Joda Time, которую он оборачивает) следует считать устаревшим. От clj-time домашней страницы :

Библиотека даты и времени для Clojure, упаковывающая библиотеку Joda Time. На сайте Joda Time написано:

Обратите внимание, что начиная с Java SE 8 и далее пользователям предлагается перейти на java.time (JSR-310) - основная часть JDK, которая заменяет эту проект.

Также обратите внимание, что автор Joda-Time также является автором пакета java.time, который расширяет Joda-Time и исправляет некоторые недостатки, которые были очевидны только с возрастом. Домашняя страница Joda-Time сама говорит:

Обратите внимание, что начиная с Java SE 8 и далее пользователям предлагается перейти на java.time (JSR-310) - основная часть JDK, которая заменяет эту проект.


Обновление

Поскольку исходные метки времени были (в основном) строками, я подумал, что OP может лучше подойти к этому решению. Если вы хотите использовать синтаксис Clojure #inst, ответ будет еще проще:

  ; note that instants are in DESCENDING order
  (let [instants  [  #inst "2016-04-30T10:29:17.000-00:00"
                     #inst "2016-03-24T12:13:12.000-00:00"
                     #inst "2016-03-24T12:09:43.000-00:00"
                     #inst "2016-03-23T13:19:03.000-00:00"
                     #inst "2016-02-26T14:51:37.000-00:00"
                     #inst "2016-01-20T16:55:24.000-00:00"]

        instants         (mapv #(.toInstant %) instants)
        inst-pairs       (partition 2 1 instants)
        durations        (vec (for [[interval-stop interval-start] inst-pairs]
                                (.toMinutes ; *** truncates ***
                                  (Duration/between interval-start interval-stop))))]

Обратите внимание, что новая функция отображения #(.toInstant %) - единственное, что нужно изменить.

0 голосов
/ 23 января 2019

чтобы немного улучшить ответ @akond (и не использовать внешние библиотеки):

(defn diff-minutes [[x y]]
  (quot (- x y) 60000))

(def l (list #inst "2016-04-30T10:29:17.000-00:00"
             #inst "2016-03-24T12:13:12.000-00:00"
             #inst "2016-03-24T12:09:43.000-00:00"
             #inst "2016-03-23T13:19:03.000-00:00"
             #inst "2016-02-26T14:51:37.000-00:00"
             #inst "2016-01-20T16:55:24.000-00:00"))

(->> l (map #(.getTime %))
       (partition 2 1)
       (map diff-minutes))

;; or, an anonymous version
(->> l (map #(.getTime %))
       (partition 2 1)
       (map (fn [[x y]] (quot (- x y) 60000))))

(53176 3 1370 37347 53156)
0 голосов
/ 23 января 2019

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

Обратите внимание, что для этого требуется Java 8 +.

(def l (list #inst "2016-04-30T10:29:17.000-00:00"
             #inst "2016-03-24T12:13:12.000-00:00"
             #inst "2016-03-24T12:09:43.000-00:00"
             #inst "2016-03-23T13:19:03.000-00:00"
             #inst "2016-02-26T14:51:37.000-00:00"
             #inst "2016-01-20T16:55:24.000-00:00"))

(import 'java.time.temporal.ChronoUnit)

(->> l
     (map #(.toInstant %))
     (partition 2 1)
     (map (fn [[a b]] (Math/abs (.between ChronoUnit/MINUTES b a)))))

вернет список:

(53176 3 1370 37347 53156)

Используя пару библиотек clojure.math.numeric-tower и Clojure.Java-Time , мы можем сделать следующее

(require '[java-time])
(require '[clojure.math.numeric-tower :refer [abs]])

(->> l 
     (map java-time/instant)
     (partition 2 1)
     (map (comp abs (partial apply java-time/time-between :minutes))))

, которое вернет тот же список.

Введение xforms позволит нам использовать преобразователи.

(require '[java-time])
(require '[clojure.math.numeric-tower :refer [abs]])
(require '[net.cgrand.xforms :as x])

(sequence
 (comp
  (map java-time/instant)
  (x/partition 2 1)
  (map (partial apply java-time/time-between :minutes))
  (map abs))
 l)

и достичь того же конечного результата.

0 голосов
/ 23 января 2019

#inst "..." - это просто java.util.Date объект, так что вы можете получить его количество миллисекунд с начала эпохи:

(->> (list #inst "2016-04-30T10:29:17.000-00:00"
           #inst "2016-03-24T12:13:12.000-00:00"
           #inst "2016-03-24T12:09:43.000-00:00"
           #inst "2016-03-23T13:19:03.000-00:00"
           #inst "2016-02-26T14:51:37.000-00:00"
           #inst "2016-01-20T16:55:24.000-00:00")
     (map #(.. %
               toInstant
               (atZone (ZoneId/systemDefault))
               toLocalDateTime))
     (partition 2 1)
     (map (fn [[a b]] (Math/abs (.until a b ChronoUnit/MINUTES)))))    
=>  (53236 3 1370 37347 53156)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...