Programmer's Note

コード読み書きの備忘録。

Clojureで日付の計算をする

引き続き「プログラマ脳を鍛える数学パズル」の問題を解いて遊んでいる。 第7問は日付を扱う。 問題自体は簡単なのだが、Clojureでの日付の扱い方がよく分からなくて、調べるのに時間がかかった。

clj-timeというライブラリがあるようだが、わざわざな・・・。

結局javaライブラリを生でたたくのが一番で、しかしまあオブジェクト指向APIは何かするのにいちいち面倒いこと。 もう一度面倒くさいことをしなくて済むようにメモを残しておこう。

動くコードを残しておくのが一番手っ取り早い。

処理

"19991225" から10日分の年月日を出力する

コード
(ns prog-math-puzzle.test-date
  (import (java.util Calendar)
          (java.text SimpleDateFormat)))

(def date-format (SimpleDateFormat. "yyyyMMdd"))

(defn date [dstr]
  (let [cal (Calendar/getInstance)]
    (.setTime cal (.parse date-format dstr))
    cal))

(defn to-str [cal]
  (.format date-format (.getTime cal)))

(defn next-day [cal]
  (let [nc (.clone cal)]
    (.add nc Calendar/DATE 1)
    nc))

(defn date-seq [cal]
  (lazy-seq (cons cal (date-seq (next-day cal)))))

(println 
  (map to-str (take 10 (date-seq (date "19991225")))))
出力

(19991225 19991226 19991227 19991228 19991229 19991230 19991231 20000101 20000102 20000103)

メモ

必要なライブラリ

java.util.Calendarjava.text SimpleDateFormat

日付のフォーマット

(def date-format (SimpleDateFormat. "yyyyMMdd")) の部分で、"yyyy-mm-dd"とかでもOK。

日付オブジェクトの生成

java.util.Calendarオブジェクトを作る。

(defn date [dstr]
  (let [cal (Calendar/getInstance)]
    (.setTime cal (.parse date-format dstr))
    cal))

.setTimejavaのメソッド呼び出しなので、返り値にデータを返す訳ではなくて、calを書き換えちゃうんだな。 なので、最後にcalを返している。

また、javaのメソッドで日付データを変える場合は、データをコピーしてから、やらないといけない。 元のデータが書き換わっちゃうから。

next-day関数ではCalendarインスタンスcloneしてから、日にちを1つ足している。

(defn next-day [cal]
  (let [nc (.clone cal)]
    (.add nc Calendar/DATE 1)
    nc))

以上。