あどけない話

インターネットに関する技術的な話など

Haskellでの時間の取り扱い

Haskell には、以下のような時間用の型がある。この記事は、どれを使えばいいかの解説。

  • time ライブラリの Data.Time.Clock の UTCTime
  • old-time ライブラリの System.Time の ClockTime
  • base ライブラリの System.Posix.Types の EpochTime

UTCTime

速度を気にしないなら、UTCTime を使う。getCurrentTime で現在の時間を取得できる。

パーサーやプリティプリンタは Data.Time.Format を参照のこと。TimeLocale は、old-locale ライブラリのを使う。old でない locale ライブラリがないのは、Haskell の恥の一つ。

Data.Time.Format は、信じられないぐらい遅い。たまにプリティプリントする用途にはいいが、Web サーバのログ生成などには使ってはいけない。僕の経験では、CPU を 60% ぐらい消費していた。速いライブラリに関しては、後ほど説明。

ClockTime

古いコードを相手にする以外は使用禁止。

Haskell 98 で定義されていたが、Haskell 2010 で削られた型。Haskell 98 での定義は抽象データ型だが、TOD という構成子が公開されている。

data ClockTime = TOD Integer Integer

左が1970年1月1日から数えた秒で、右がピコ秒。なので、以下の EPochTime には簡単に変換できる。

getClockTime で現在の時間を取得できる。

EpochTime

unix ライブラリを利用すると、必然的に使うようになる型。EpochTime は CTime の別名であり、これは C の time_t に対応する。なので、環境によって Int32 だったり、Int64 だったりする。

epochTime で現在の時間を取得できる。

変換

適当に書いた変換関数。間違いの指摘を歓迎。

from\to UTCTime ClockTime EpochTime
UTCTime id uToC uToE
ClockTime cToU id cToE
EpochTime eToU eToC id
import Data.Time (UTCTime)
import Data.Time.Clock.POSIX (posixSecondsToUTCTime, utcTimeToPOSIXSeconds)
import Foreign.C.Types (CTime(..))
import System.Posix.Types (EpochTime)
import System.Time (ClockTime(..))

uToC :: UTCTime -> ClockTime
uToC t = TOD (truncate . utcTimeToPOSIXSeconds $ t) 0

uToE :: UTCTime -> EpochTime
uToE = CTime . truncate . utcTimeToPOSIXSeconds

cToU :: ClockTime -> UTCTime
cToU (TOD t _) = posixSecondsToUTCTime . realToFrac $ t

cToE :: ClockTime -> EpochTime
cToE (TOD t _) = fromInteger t

eToU :: EpochTime -> UTCTime
eToU = posixSecondsToUTCTime . realToFrac

eToC :: EpochTime -> ClockTime
eToC (CTime t) = TOD (fromIntegral t) 0

もっと速く

Unix で速くて汎用的なパーサやプリティプリンタが欲しい場合には、僕が作った unix-time がいいだろう。これは strptime() や strftime() へのラッパーである。

さらに HTTP に特化したパーサやプリティプリンタが欲しい場合には、僕が作った http-date がいいだろう。こちらは書式を決め打つことで、unix-time よりも速くなっている。

これら2つのライブラリの使い方は、マニュアルを見ればすぐに分かると思う。