Skip to content

Instantly share code, notes, and snippets.

@komasaru
Last active April 19, 2018 06:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save komasaru/e3532e2eabb9fdc724c4926e2b7eacd8 to your computer and use it in GitHub Desktop.
Save komasaru/e3532e2eabb9fdc724c4926e2b7eacd8 to your computer and use it in GitHub Desktop.
Ruby script to verify of converting Julian Day to Gregorian Calendar.
#! /usr/local/bin/ruby
# coding: utf-8
#=ユリウス日 -> グレゴリオ暦 変換の検証(UTC ベース)
#
# 1. 一旦、グレゴリオ暦 -> ユリウス日 の変換。(by フリーゲルの公式
# 2. そのユリウス日を2種の計算式でグレゴリオ暦に変換。
# 3. 2種の計算式で算出した結果が等しいかチェック。
#
# date name version
# 2016.06.14 mk-mode.com 1.00 新規作成
#
# Copyright(C) 2016 mk-mode.com All Rights Reserved.
#---------------------------------------------------------------------------------
class ExConvJdGc
CHECKS = [
[1999, 12, 31, 23, 59, 59],
[2000, 1, 1, 0, 0, 0],
[2016, 6, 14, 0, 0, 0],
[2016, 6, 14, 11, 59, 59],
[2016, 6, 14, 12, 0, 0],
[2016, 6, 14, 23, 59, 59],
[2016, 2, 28, 0, 0, 0],
[2016, 2, 28, 11, 59, 59],
[2016, 2, 28, 12, 0, 0],
[2016, 2, 28, 23, 59, 59],
[2016, 2, 29, 0, 0, 0],
[2016, 2, 29, 11, 59, 59],
[2016, 2, 29, 12, 0, 0],
[2016, 2, 29, 23, 59, 59],
[2016, 3, 1, 0, 0, 0]
]
def run
begin
CHECKS.each do |dt|
str = sprintf("* GC: %04d-%02d-%02d %02d:%02d:%02dUTC\n", *dt)
jd = gc2jd(*dt)
str << " -> JD: #{jd}\n"
gc_1, gc_2 = jd2gc1(jd), jd2gc2(jd)
str << " -> GC: #{gc_1}, #{gc_2}"
str << " (NOT MATCH!)" unless gc_1 == gc_2
puts str
end
rescue => e
end
end
#=========================================================================
# グレゴリオ暦 -> ユリウス日(JD)
#
# * フリーゲルの公式を使用する
# JD = int(365.25 * year)
# + int(year / 400)
# - int(year / 100)
# + int(30.59 * (month - 2))
# + day
# + 1721088.5
# ※上記の int(x) は厳密には、x を超えない最大の整数
# ※正子を整数とする JDN を求めるなら、 1721088.5 を 1721089 に置き換える
# ※修正ユリウス日 MJDを求めるなら + 1721088.5 を - 678912 に置き換える。
#
# @param: year
# @param: month
# @param: day
# @param: hour
# @param: minute
# @param: second
# @return: JD(Julian Day)
#=========================================================================
def gc2jd(year, month, day, hour = 0, min = 0, sec = 0)
# 1月,2月は前年の13月,14月とする
if month < 3
year -= 1
month += 12
end
# 日付(整数)部分計算
jd = (365.25 * year).truncate \
+ (year / 400.0).truncate \
- (year / 100.0).truncate \
+ (30.59 * (month - 2)).truncate \
+ day \
+ 1721088.5
# 時間(小数)部分計算
t = (hour + min / 60.0 + sec / 3600.0) / 24.0
return jd + t
rescue => e
raise
end
#=========================================================================
# ユリウス日(JD) -> グレゴリオ暦 (Ver.1)
#
# * JD = JD + 0.5
# a = int(jd + 68569)
# b = int(a / 36524.25)
# c = a - int(36524.25 * b + 0.75)
# d = int((c + 1) / 365.2425)
# e = c - int(365.25 * d) + 31
# f = int(int(e) / 30.59)
# g = int(f.truncate / 11.0)
# year = 100 * (b - 49) + d + g
# month = f - 12 * g + 2
# day = e - (30.59 * f).truncate
# (hour, min, sec は 小数点以下の端数を処理するだけ)
#
# @param: JD
# @return: "YYYY-MM-DD HH:MM:SS"
#=========================================================================
def jd2gc1(jd)
# 年月日
jd += 0.5
a = (jd + 68569).truncate
b = (a / 36524.25).truncate
c = a - (36524.25 * b + 0.75).truncate
d = ((c + 1) / 365.2425).truncate
e = c - (365.25 * d).truncate + 31
f = (e.truncate / 30.59).truncate
g = (f.truncate / 11.0).truncate
year = 100 * (b - 49) + d + g
month = f - 12 * g + 2
day = e - (30.59 * f).truncate
# 2月30日の補正
if month == 2 && day > 28
if year % 4 == 0 && year % 100 != 0 || year % 400 == 0
day = 29
else
day = 28
end
end
# 時分秒
tm = 86400 * (jd - jd.truncate)
hour = (tm / 3600.0).truncate
min = ((tm - 3600 * hour) / 60.0).truncate
sec = (tm - 3600 * hour - 60 * min).truncate
return Time.new(year, month, day, hour, min, sec).strftime("%Y-%m-%d %H:%M:%SUTC")
rescue => e
raise
end
#=========================================================================
# ユリウス日(JD) -> グレゴリオ暦 (Ver.2)
#
# * JD = JD + 0.5
# a = JD + 32044
# b = int((4 * a + 3) / 146097)
# c = a - int(146097 * b / 4)
# d = int((4 * c + 3) / 1461)
# e = c - int(1461 * d / 4)
# m = int((5 * e + 2) / 153)
# year = 100 * b + d - 4800 + int(m / 10)
# month = m + 3 - 12 * int(m / 10)
# day = e - int((153 * m + 2) / 5) + 1
# (hour, min, sec は 小数点以下の端数を処理するだけ)
#
# @param: JD
# @return: "YYYY-MM-DD HH:MM:SS"
#=========================================================================
def jd2gc2(jd)
jd += 0.5
# 年月日
a = (jd + 32044).truncate
b = ((4 * a + 3) / 146097.0).truncate
c = a - (146097 * b / 4.0).truncate
d = ((4 * c + 3) / 1461.0).truncate
e = c - (1461 * d / 4.0).truncate
m = ((5 * e + 2) / 153.0).truncate
year = 100 * b + d - 4800 + (m / 10.0).truncate
month = m + 3 - 12 * (m / 10.0).truncate
day = e - ((153 * m + 2) / 5.0).truncate + 1
# 2月30日の補正
if month == 2 && day > 28
if year % 4 == 0 && year % 100 != 0 || year % 400 == 0
day = 29
else
day = 28
end
end
# 時分秒
t = 86400 * (jd - jd.truncate)
hour = (t / 3600.0).truncate
min = ((t - 3600 * hour) / 60.0).truncate
sec = (t - 3600 * hour - 60 * min).truncate
return Time.new(year, month, day, hour, min, sec).strftime("%Y-%m-%d %H:%M:%SUTC")
rescue => e
raise
end
end
ExConvJdGc.new.run if __FILE__ == $0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment