モジュール:MJD

出典: 謎の百科事典もどき『エンペディア(Enpedia)』
ナビゲーションに移動 検索に移動

この説明文は 『 モジュール:MJD/doc 』 から呼び出されています。
MJD(修正ユリウス日 () / Modified Julian Date)と年月日との相互変換モジュールです。MJDは1858年11月17日を0とした連番で、日数計算などに使用できます。

ymd2mjd[編集]

年月日 から MJD への変換を行います。

require('Module:MJD').ymd2mjd({2020, 7, 24})

実行結果 → 59054

curmjd[編集]

今日の MJD を返します。

require('Module:MJD').curmjd()

mjd2ymd[編集]

MJD から 年月日 への変換を行います。

require('Module:MJD').mjd2ymd({59054})

結果は {2020, 7, 24} 形式のテーブルで返されます。モジュールの外側(テンプレートなど)では、年・月・日を個別に取り出せる{{Date}}を使用してください。

curymd[編集]

今日の 年月日 をテーブルで返します。

require('Module:MJD').curymd()

暦法選択[編集]

"mode" 引数を指定すると、以下のように動作します。

  • 未指定 - 1582年10月15日以降はグレゴリオ暦、紀元前45年1月1日から1582年10月4日はユリウス暦 ()の日付を返します。紀元前1年以前の日付は C. J. Bennett による最新の説を反映しています[1]
  • "pj" - 1582年10月15日以降はグレゴリオ暦、1582年10月4日以前はユリウス暦の日付を返します。ユリウス暦初期の閏日挿入の混乱は無視し、西暦4年以前の日付はユリウス暦を遡及して適用したものとみなしています(ユリウス暦が制定された紀元前45年より前の日付も同様に遡及します)。
  • "pg" - 1582年10月14日以前も含め、グレゴリオ暦の日付を返します。
require('Module:MJD').ymd2mjd({1582, 10, 4}) -- -100841
require('Module:MJD').ymd2mjd({1582, 10, 15}) -- -100840

require('Module:MJD').ymd2mjd({1582, 10, 4, mode="pg"}) -- -100851
require('Module:MJD').ymd2mjd({1582, 10, 14, mode="pg"}) -- -100841
require('Module:MJD').ymd2mjd({1582, 10, 15, mode="pg"}) -- -100840

脚注[編集]

local p = {}

-- os.date() が UTC で返されるので UTC+9 に変換
function p.curmjd()
	return math.floor((os.time() / 3600 + 9) / 24) + 40587
end

function p.curymd()
	return p.mjd2ymd({p.curmjd()})
end

function p.ymd2mjd(args)
	local y = tonumber(args[1])
	local m = tonumber(args[2])
	local d = tonumber(args[3])
	local mode = args.mode
	
	-- グレゴリオ暦→修正ユリウス日(MJD)
	y = y + math.floor((m - 3) / 12) -- 1月と2月は前年扱い
	m = (m - 3) % 12 + 3 -- 1月→13月、2月→14月
	-- 1年ごとに365日ずつずらす。ただし閏日が4年に1度挿入され、100年に1度挿入されず、400年に1度挿入される
	-- 1か月を30.6日として整数倍し小数切り捨てて、3月からの日数[31,30,31,30,31][31,30,31,30,31][31]を生成。2月は最後なので処理不要
	local n = 365 * y + math.floor(y / 4) - math.floor(y / 100) + math.floor(y / 400) + math.floor(30.6 * m + 0.7) + d - 678974
	
	repeat
		-- -100840 = 1582年10月15日, pg: 遡及グレゴリオ暦
		if n >= -100840 or mode == 'pg' then break end
		-- 1582年10月4日以前はユリウス暦を適用(1582年10月5日 - 14日は存在しない)
		n = n + math.floor(y / 100) - math.floor(y / 400) - 2
		
		-- pj: 遡及ユリウス暦
		if y >= 0 or mode == 'pj' then break end
		-- 紀元前1年2月28日以前は閏日を挿入しない(紀元前1年2月29日は存在しない)
		n = n - math.floor(y / 4)
		
		--
		if y >= -7 then break end
		-- 紀元前8年2月29日以前は3年に1度閏日を挿入する
		n = n + math.floor((y + 1) / 3) + 2
		
		-- -695015 = 紀元前45年1月1日
		if n >= -695015 or mode == 'pg' then break end
		-- 紀元前46年以前はユリウス暦未実施
		n = nil
	until true -- ループ強制脱出(breakを使用するため)
	return n
end


function p.mjd2ymd(args)
	local n = tonumber(args[1])
	local mode = args.mode or 'b'
	local y
	
	-- -100840 = 1582年10月15日, pg: 遡及グレゴリオ暦
	if n >= -100840 or mode == 'pg' then
		-- 修正ユリウス日(MJD)→グレゴリオ暦
		n = n + 678881 -- グレゴリオ暦0年3月1日を0とする
		
		-- 100年ずつ[36524,36524,36524,36525][36524,36524,36524,36525]...と分解
		local y100 = math.floor((n + 0.9) / 36524.25) -- 年の100の位以上
		n = n - math.floor(36524.25 * y100) -- (100*y100)年3月1日を0とする
		
		-- 1年ずつ[365,365,365,366][365,365,365,366]...と分解
		-- 最後の1年は3/4の確率で365日だが、最後なので処理不要
		y = math.floor((n + 0.9) / 365.25) -- 年の1の位と10の位
		n = n - math.floor(365.25 * y) -- 各年3月1日を0とする
		y = 100*y100 + y
		
	-- -678883 = 紀元前1年3月1日, pj: 遡及ユリウス暦
	elseif n >= -678883 or mode == 'pj' then
		-- 修正ユリウス日(MJD)→ユリウス暦
		n = n + 678883 -- ユリウス暦0年3月1日を0とする
		
		-- 1年ずつ[365,365,365,366][365,365,365,366]...と分解
		y = math.floor((n + 0.9) / 365.25) -- 年の全桁
		n = n - math.floor(365.25 * y) -- 各年3月1日を0とする
		
	-- -681438 = 紀元前8年3月1日
	elseif n >= -681438 then
		-- 修正ユリウス日(MJD)→閏日なしの暦
		n = n + 678883 -- 閏日なしの暦0年3月1日を0とする
		
		-- 1年ずつ[365][365][365][365]...と分解
		y = math.floor((n + 0.9) / 365) -- 年の全桁
		n = n - math.floor(365 * y) -- 各年3月1日を0とする
		
	-- -695015 = 紀元前45年1月1日
	elseif n >= -695015 then
		-- 修正ユリウス日(MJD)→3年に1度閏日を挿入した暦
		n = n + 679246 -- 3年に1度閏日を挿入した暦"-1年"3月1日を0とする
		
		-- 1年ずつ[365,365,366][365,365,366]...と分解
		y = math.floor((n + 0.9) / (365 + 1/3)) -- 年の全桁
		n = n - math.floor((365 + 1/3) * y) -- 各年3月1日を0とする
		y = y - 1 -- 基準を0年に戻す
	else
		n = nil
	end
	
	if n then
		-- 1か月ずつ[31,30,31,30,31][31,30,31,30,31][31]と分解。2月は最後なので処理不要
		local m = math.floor((n + 92.3) / 30.6)
		local d = math.floor(n + 93.3 - 30.6 * m)
		y = y + math.floor((m - 1) / 12) -- 前年扱いの1月と2月を元に戻す
		m = (m - 1) % 12 + 1 -- 1月←13月、2月←14月
		return {y, m, d}
	else
		return nil
	end
end

return p