Clojureで日時を扱う方法

java.timeパッケージ

Clojureからjava.timeパッケージを利用することでClojureで日時を扱うことができます。

java.timeパッケージはイミュータブルなデータ構造になっているのでClojureからでも安心して使えます。

java.timeパッケージの使い方

java.timeパッケージの基本的な使い方は以下のページに載ってます。

qiita.com

上記のリンクに載ってない使い方を以下に示します。

(ns main
  (:require [clojure.pprint])
  (:import
   (java.time LocalDateTime
              ZonedDateTime
              ZoneId)
   (java.time.format DateTimeFormatter)))

(defn pattern ^DateTimeFormatter [^String p]
  (DateTimeFormatter/ofPattern p))

(defn parse-local
  ^LocalDateTime [^CharSequence text ^DateTimeFormatter formatter]
  (LocalDateTime/parse text formatter))

(defn parse-zoned
  ^ZonedDateTime [^CharSequence text ^DateTimeFormatter formatter]
  (ZonedDateTime/parse text formatter))

(defn format-date ^String [date ^String p]
  (.format date (pattern p)))

(defn change-zone ^ZonedDateTime [^ZonedDateTime date ^ZoneId zone]
  (.withZoneSameInstant date zone))

(def PATTERN_LOCAL "yyyy/MM/dd HH:mm:ss")

(def PATTERN_ZONED "yyyy/MM/dd HH:mm:ss XXX")

(def d-local
  (parse-local "2023/04/22 21:14:00"
               (pattern PATTERN_LOCAL)))

;; 2023/04/22 21:14:00
(printf "%-15s%s\n" "d-local" (format-date d-local PATTERN_LOCAL))

(def d-zoned
  (.atZone d-local (ZoneId/of "Asia/Tokyo")))

(printf "%-15s%s\n" "d-zoned" (format-date d-zoned PATTERN_ZONED))

(def d-utc
  (parse-zoned "2023/04/22 21:14:00 Z"
               (pattern PATTERN_ZONED)))

;; 2023/04/22 21:14:00 Z
(printf "%-15s%s\n" "d-utc" (format-date d-utc PATTERN_ZONED))

(def d-system-zone
  (change-zone d-utc (ZoneId/systemDefault)))

;; 2023/04/23 06:14:00 +09:00
(printf "%-15s%s\n" "d-system-zone" (format-date d-system-zone PATTERN_ZONED))

(def d-jst
  (change-zone d-utc (ZoneId/of "Asia/Tokyo")))

;; 2023/04/23 06:14:00 +09:00
(printf "%-15s%s\n" "d-jst" (format-date d-jst PATTERN_ZONED))

上のコードの実行結果は、以下になります。

$ clojure -M src/main.clj
d-local        2023/04/22 21:14:00
d-zoned        2023/04/22 21:14:00 +09:00
d-utc          2023/04/22 21:14:00 Z
d-system-zone  2023/04/23 06:14:00 +09:00
d-jst          2023/04/23 06:14:00 +09:00

d-zoned.atZoneから作っていますが、タイムゾーン+09:00になっただけで日時は変わっていないことに注意してください。

時差の分日時をずらすには、.withZoneSameInstantを使います。

これによっってchange-zone.withZoneSameInstantした結果、d-utcd-system-zoneに9時間の時差が生じています。

java.timeパッケージのドキュメント

java.timeパッケージのドキュメントは以下のリンクにあります。

docs.oracle.com

DateTimeFormatterのドキュメントにフォーマットに使える記号(yyyyなど)の説明があります。 リンクは以下になります。

docs.oracle.com