LoginSignup
2
2

More than 5 years have passed since last update.

System.Timeを使うときは気をつけよう

Posted at

少なくとも2005年ごろには認識されていることですが、一応メモ。これが理由か分かりませんが、現在ではこのモジュールに代わるData.Timeの利用が推奨されています。

問題点

System.TimeにはTimeDiffという日付の差を表現するデータ型と、それを正規化するnormalizeTimeDiff :: TimeDiff -> TimeDiffという関数があります。TimeDiffの定義は次の通り。

data TimeDiff
 = TimeDiff {
     tdYear    :: Int,
     tdMonth   :: Int,
     tdDay     :: Int,
     tdHour    :: Int,
     tdMin     :: Int,
     tdSec     :: Int,
     tdPicosec :: Integer -- not standard
   }
   deriving (Eq,Ord,Read,Show)

TimeDiffの正規化というのは、可能な限り上位の時間単位を使った表現へ変換することです。(例:13ヶ月→1年1ヶ月)
ここで思うのはTimeDiffの正規化は無理筋なのでは・・・?」ということ。月によって1ヶ月に含まれる日数が異なるからです。

というわけで試してみます。

Prelude> :m + System.Time
Prelude System.Time> let oct1 = toClockTime $ CalendarTime 2016 October 1 0 0 0 0 Saturday 0 "UTC" 0 False
Prelude System.Time> let nov1 = toClockTime $ CalendarTime 2016 November 1 0 0 0 0 Tuesday 0 "UTC" 0 False
Prelude System.Time> let d = nov1 `diffClockTimes` oct1
Prelude System.Time> d `addToClockTime` oct1
Tue Nov  1 09:00:00 JST 2016
Prelude System.Time> (normalizeTimeDiff d) `addToClockTime` oct1
Wed Nov  2 09:00:00 JST 2016

正規化したTimeDiffを足してやると日付が一日ずれてしまいました。
normalizeTimeDiffでは1ヶ月を一律30日として計算しているためこのようなことが起こります。

Prelude System.Time> d
TimeDiff {tdYear = 0, tdMonth = 0, tdDay = 0, tdHour = 0, tdMin = 0, tdSec = 2678400, tdPicosec = 0}
Prelude System.Time> normalizeTimeDiff d
TimeDiff {tdYear = 0, tdMonth = 1, tdDay = 1, tdHour = 0, tdMin = 0, tdSec = 0, tdPicosec = 0}

ちなみに1年の方も一律に365日で計算されます。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2