コンテンツにスキップ

英文维基 | 中文维基 | 日文维基 | 草榴社区

モジュール:MJD

モジュールの解説[作成]
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