スキマハコ

わすれがちなスキマな事を詰め込んでいます。ITの他に暮らしについても書いています。

UnixTime⇔グレゴリオ暦の計算をAPIを使わずにやってみる[※未解決※]

※できてません。助けて!

そもそもUnixTimeって?

UNIX時間またはUNIX時刻(UNIX time or POSIX time)とはコンピューターシステム上で日時を表す単位。UTCでの1970年1月1日真夜中(0時0分0秒)からの経過秒数(閏秒を加味しない)で表される。
UNIX時間 - Wikipedia

1970年1月1日からの累計秒ですね!なるほど!
うるう年とかも考慮しつつ…むむむ。

先人たちの知恵を借りる。

フェアフィールドの公式
1年1月1日(0年13月1日) 〜 y 年 m 月 d の日数を求める
ツェラーの公式 - Wikipedia

よーし!これをプログラミングしたらいいんだよね!

近代の先人たちの知恵をさらに借りる

参考:
すでにプログラミングっぽく成立してる!
よーしやるぞー!と思ってそのまま実装。ほとんど式がまんまなのでコピペですね。

手近にあったrubyでやってみました。

    # グレゴリオ暦元年から現在までの経過日数を計算
    sum_day = (365.0 * year + (year / 4.0).floor  - (year / 100.0).floor   + (year / 400.0).floor   + ((306.0 * (month + 1)) / 10.0).floor + day - 428) - epoc_time
    # floorをかまさなかったらなんだか値が大幅にずれた。
    #sum_day = (365 * year + (year / 4) - (year / 100)   + (year / 400)   + (306 * ((month + 1) / 10))   - 428 + day) -  epoc_time
    # 経過日数を秒変換し、時分秒を加算
    sum_time = sum_day * 86400.0 + (hour * 3600.0) + (minute * 60.0) + second
    p "----------------------------------------"
    p "a_経過日数(1970から):" + sum_day.to_s
    p "a_経過秒(1970から):" + sum_time.to_s
    p Time.at(sum_time).utc;
    p Time.utc(year , month , day ,hour , minute , second).to_i
    p (Time.utc(year , month , day ,hour , minute , second).to_i - sum_time) / 3600
    p "----------------------------------------"

#=>
#"----------------------------------------"
#"a_経過日数(1970から):12841.0"
#"a_経過秒(1970から):1109502671.0"
#Sun Feb 27 11:11:11 UTC 2005
#1109589071
#24.0
#"----------------------------------------"

なんかずれる…。
場合によっては一致したり、1日2日のずれが発生します。
これはだめだ…orz

逆変換は月日の扱いに弱い…

   # グレゴリオ暦元年から現在までの経過秒から年月日時分秒を取得
    h = (( sum_time % 86400 ) / 3600.0).floor
    mm = ((( sum_time % 86400 ) - h * 3600.0 ) / 60.0).floor
    s = (( sum_time % 86400 ) - h * 3600 ) - mm * 60
    times = (h * 3600) + (mm * 60) + s
    # 割り切れない値をそれぞれ分配
    p h.to_s + ":" + mm.to_s + ":" + s.to_s
    days = (sum_time - times) / 86400.0
    # 1970/1/1以降の累積日数を追加する。
    days = days + epoc_time
    y = (days / 365.0).floor
    # 1年で割り切れない値を月と日のために算出(当年以外のうるう日は除く)
    uruu =  (((y-1) / 4.0).floor  - ((y-1) / 100.0).floor   + ((y-1) / 400.0).floor)
    samedays = ((days + 365 - uruu)% 365).floor 

    # 当年がうるう年の場合に備える
    jan = (y % 4 == 0 || y % 100 != 0 && y % 400 == 0) ? 29 : 28

    # 計算式が思いつかないので、地道に足していきます
    months = [31,jan,31,30,31,30,31,31,30,31,30,31]
    m = 0
    d = 0
    for i in 0...12
      if m + months[i] > samedays
        d = samedays - m
        m = i + 1
        break
      end
      m = m + months[i]
    end
    p y.to_s + "/" + m.to_s + "/" + d.to_s

うーん、一日二日ずれる…計算どっかで違うのかなー