Module:Sandbox/HenryLi

local getArgs = require('Module:Arguments').getArgs
local dateUtils = {}

local year = {
											--1  2   3   4   5   6   7   8   9  10  11  12  13
	--[2460351] = { name = "甲辰", months = { 29, 30, 29, 29, 30, 29, 30, 30, 29, 30, 30, 29 }, intercalary = 0 },
	[2460705] = { name = "乙巳", months = { 30, 29, 30, 29, 29, 30, 29, 30, 29, 30, 30, 30, 29 }, intercalary = 6 },
	[2461089] = { name = "丙午", months = { 30, 29, 30, 29, 29, 30, 29, 29, 30, 30, 30, 29 }, intercalary = 0 },
}

local sb60 = {
    "甲子", "乙丑", "丙寅", "丁卯", "戊辰", "己巳", "庚午", "辛未", "壬申", "癸酉",
    "甲戌", "乙亥", "丙子", "丁丑", "戊寅", "己卯", "庚辰", "辛巳", "壬午", "癸未",
    "甲申", "乙酉", "丙戌", "丁亥", "戊子", "己丑", "庚寅", "辛卯", "壬辰", "癸巳",
    "甲午", "乙未", "丙申", "丁酉", "戊戌", "己亥", "庚子", "辛丑", "壬寅", "癸卯",
    "甲辰", "乙巳", "丙午", "丁未", "戊申", "己酉", "庚戌", "辛亥", "壬子", "癸丑",
    "甲寅", "乙卯", "丙辰", "丁巳", "戊午", "己未", "庚申", "辛酉", "壬戌", "癸亥"
}

local m12 = {
    "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"
}

local d30 = {
	"初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十",
	"十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十", 
	"廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十", "卅一"
}

local makeNow = function()
	local d = os.date("*t", os.time())
	return os.time {year = d.year, month = d.month, day = d.day} -- + 8 * 60 * 60 -- data based on UTC+8
end

local makeTime = function(Y, M, D)
	return os.time {year = Y, month = M, day = D}
end

local makeAjd = function(t)
	return math.floor((t / 86400) + 2440587.5)
end

dateUtils.cdate = function(frame)
	local Y = tonumber(frame.args.y) or 2025
	local M = tonumber(frame.args.m) or 3
	local D = tonumber(frame.args.d) or 1
	local today = frame.args.today
	local t
	if today then
		t = makeNow()
	else
		t = makeTime(Y, M, D)
	end
	local ajd_int = makeAjd(t)
	local year_name = ''
	local month_name = ''
	local day_name = ''
	local day_sb_name = ''
	
	for i, year_data in pairs(year) do
		local days = 0
		for i,v in pairs(year_data.months) do
			days = days + v
		end
		local year_start = i
		local year_end = year_start + days
		if ajd_int >= year_start and year_start < year_end then
			local month_start = year_start
			local month_end = 0
			local month = 0
			--local yy = (os.date("*t", os.date((year_start - 2440587.5 ) * 86400)).year - 4) % 60 + 1

			for i, v in pairs(year_data.months) do
				month = i
				
				month_end = month_start + v
				if ajd_int >= month_start and ajd_int < month_end then
					year_name = year_data.name .. '年'
					if month == year_data.intercalary + 1 then
						month_name = "閏" .. m12[month - 1]
					else
						if month > year_data.intercalary + 1 then
							month_name = m12[month - 1]
						else
							month_name = m12[month]
						end
					end
					month_name = month_name .. '月'
					local day = ajd_int - month_start + 1
					day_name = d30[day]
					local day_sb = ( ajd_int - 11) % 60 + 1
					day_sb_name = sb60[day_sb]

					break
				else
					month_start = month_start + v
				end
			end
			break
		else
		end
	end
	local d = os.date("%Y-%m-%d ", t)
	-- local d = os.date("%Y-%m-%d %H:%M:%S", t)
	return d .. year_name  .. month_name  .. day_name .. day_sb_name
end

dateUtils.d60 = function(text)
	local jd = tonumber(text.args[1])
	local ajd = jd - 0.5
	local ajd_int = math.floor(ajd)
	local sb = ( ajd_int - 9 ) % 60
	local sb60_x = sb60[sb]
	return sb60_x
end

-- date_utils.lua
--[[
    Lua Date & Calendar Utilities Module
    ------------------------------------
    Provides:
      - getJD(yyyy, mm, dd)            → Julian Day at midnight UT
      - NdaysGregJul(y)                → Number of days in year (Julian/Gregorian)
      - get_Western_calendar_name(y)   → Calendar name by year
      - langConstant(lang)             → Language constants (0=English, 1=Traditional, 2=Simplified Chinese)

    Usage:
        local dateUtils = require("date_utils")

        local jd = dateUtils.getJD(2025, 8, 16)
        local days = dateUtils.NdaysGregJul(2024)
        local calName = dateUtils.get_Western_calendar_name(2025)
        local langData = dateUtils.langConstant(1) -- Traditional Chinese
--]]

--local dateUtils = {}

-------------------------------------------------
-- Julian Day Number Calculation
-------------------------------------------------
function dateUtils.getJD(yyyy, mm, dd)
    local yy, m = yyyy, mm
    if m <= 2 then
        m = m + 12
        yy = yy - 1
    end

    local ymd = 10000 * yy + 100 * m + dd
    local B
    if ymd <= 15821004 then
        B = -2 + math.floor((yy + 4716) / 4) - 1179
    else
        B = math.floor(yy / 400) - math.floor(yy / 100) + math.floor(yy / 4)
    end

    return 365 * yy - 679004 + B + math.floor(30.6001 * (m + 1)) + dd + 2400000.5
end

-------------------------------------------------
-- Number of days in a Gregorian/Julian year
-------------------------------------------------
function dateUtils.NdaysGregJul(y)
    local ndays = (y == 1582) and 355 or 365

    if y % 4 == 0 then
        ndays = ndays + 1
    end
    if y > 1582 then
        if y % 100 == 0 then ndays = ndays - 1 end
        if y % 400 == 0 then ndays = ndays + 1 end
    end

    return ndays
end

-------------------------------------------------
-- Calendar name by year
-------------------------------------------------
function dateUtils.get_Western_calendar_name(y)
    if y > 1582 then
        return {"額曆"}
    elseif y == 1582 then
        return {"儒曆額曆"}
    elseif y > 7 then
        return {"儒曆"}
    else
        return {"逆推儒曆"}
    end
end

-------------------------------------------------
-- Language constants for calendar rendering
-------------------------------------------------
function dateUtils.langConstant(lang)
    -- Chinese data
    local gMonthChi = {"壹月","貳月","叄月","肆月","伍月","陸月","柒月","捌月","久月","拾月","拾壹月","拾貳月"}
    local weeksChi = {"日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"}
    local heavenChi = {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"}
    local earthChi  = {"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"}
    local animalChi = {"鼠","牛","虎","兔","龍","蛇","馬","羊","猴","雞","狗","豬"}
    local animalSim = {"鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"}
    local month_numChi = {"正","二","三","四","五","六","七","八","九","十","十一","十二"}

    -- Generate Chinese lunar dates 初一..三十
    local date_numChi = {"初一"}
    for i=2,10 do table.insert(date_numChi,"初"..month_numChi[i]) end
    table.insert(date_numChi,"十一")
    for i=12,19 do table.insert(date_numChi,"十"..month_numChi[i-11]) end
    table.insert(date_numChi,"二十")
    table.insert(date_numChi,"廿一")
    for i=22,29 do table.insert(date_numChi,"廿"..month_numChi[i-21]) end
    table.insert(date_numChi,"三十")

    local monthLChi = {"小","大"}
    local QnamesChi = {"朔","上弦","望","下弦"}
    local soltermNamesChi = {"小寒","大寒","立春","雨水","驚蟄","春分",
                             "清明","穀雨","立夏","小滿","芒種","夏至",
                             "小暑","大暑","立秋","處暑","白露","秋分",
                             "寒露","霜降","立冬","小雪","大雪","冬至","小寒"}

    local note_earlyChi = "朔的時刻接近午夜零時,初一或會提早一天。"
    local note_lateChi  = "朔的時刻接近午夜零時,初一或會推遲一天。"
    local note1929Chi   = "注意。一九二九年以前朔日以北京時計算,遲東經百二度遲十四分鐘,因此列出朔時過了初二零時。"
    local note1914Chi   = "注意。一九一四年前朔計算方法不準確,且一九二九年前用北京時,遲東經百二度遲約十四分鐘。"

    return {
        gMonth = gMonthChi, weeks = weeksChi, lang = lang,
        heaven = heavenChi, earth = earthChi, animal = animalChi,
        region = "default", cmonth = month_numChi, monthL = monthLChi,
        Qnames = QnamesChi, soltermNames = soltermNamesChi,
        julian = false, li_ancient = nil,
        date_numChi = date_numChi,
        note_early = note_earlyChi, note_late = note_lateChi,
        note1929 = note1929Chi, note1914 = note1914Chi
    }
end

--------------------------------------------------
-- Convert kin number to month number & year offset
--------------------------------------------------
function dateUtils.kinToMonthYearoffset(kinIn, y, region)
    local kin = math.abs(kinIn)
    local yearOffset, monNum = 0, kin

    -- Hon dynasty
    if y < -103 and kin > 9 then
        yearOffset = 1
    end

    -- Sun dynasty
    if y == 8 and kin == 12 then
        monNum, yearOffset = 1, 1
    elseif y > 8 and y < 23 then
        monNum = (kin == 12) and 1 or (kin + 1)
        if kin == 12 then yearOffset = 1 end
    elseif y == 23 and kin < 12 then
        monNum = kin + 1
    end

    -- Ngai dynasty
    if ((y == 237 and kin > 2) or (y == 238) or (y == 239 and kin < 12)) and region == "default" then
        monNum = (kin == 12) and 1 or (kin + 1)
        if kin == 12 then yearOffset = 1 end
    end

    -- Tang dynasty
    if y > 688 and y < 700 then
        if kin > 10 then yearOffset = 1 end
    elseif y == 761 and kin > 10 then
        monNum, yearOffset = kin - 10, 1
    elseif y == 762 and kin < 4 then
        monNum = kin + 2
    end

    if kinIn < 0 then
        monNum = -monNum
    end

    return { monNum = monNum, yearOffset = yearOffset }
end

-- ===========================================================================
-- Determine first month number for a year
-- ===========================================================================
function dateUtils.firstMonthNum(y)
    local firstMonth = 1
    if y < -102 then
        firstMonth = 10
    elseif y > 689 and y < 701 then
        firstMonth = 11
    end
    return firstMonth
end

-- ===========================================================================
-- Decompress time values encoded with compression algorithm
-- Compression: t = floor(x) * 1441 + m
-- Inverse: x ≈ floor(t/1441) + (t - floor(t/1441)*1441)/1440
-- ===========================================================================
function dateUtils.decompress_time(t)
    local x = {}
    for i = 1, #t do
        local y = math.floor(t[i] / 1441)
        local m = t[i] - 1441 * y
        if m > 1439.5 then
            m = 1439.9
        end
        table.insert(x, y + m / 1440.0)
    end
    return x
end

-- Returns offsets for solar and lunar calculations
function dateUtils.offset_sunMoon()
    return {solar = 5, lunar = 5}
end

return dateUtils

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.