Module:BENGALIDATE/sandbox
| This is the module sandbox page for Module:BENGALIDATE (diff). |
| This module depends on the following other modules: |
Usage
{{BENGALIDATE}} gives current date based on the revised Bengali calendar (which is officially adopted for use in Bangladesh), and gets automatically updated everyday past mid-night Bangladesh time. Use {{BENGALIYEAR}} also to show Bengali Era (BS).
</noinclude>
local p = {}
local getArgs = require('Module:Arguments').getArgs
local epoch_module = require('Module:Bengali Calendar Epoch Offset')
local timestamp = epoch_module._main
local BENGALI_UNIX_EPOCH = epoch_module.EPOCH
local EPOCH_YEAR = 1432
local SECONDS_PER_DAY = 86400
local DAY_START_OFFSET = 6 * 3600
local DEFAULT_FORMAT = "[[F]] j, Y"
local BN_MONTH = {
{ name = "Boisakh", link = "Boisakh", abbr = "Boi" },
{ name = "Joishtho", link = "Joishtho", abbr = "Joi" },
{ name = "Asharh", link = "Asharh", abbr = "Ash" },
{ name = "Shrabon", link = "Shrabon", abbr = "Shr" },
{ name = "Bhadro", link = "Bhadro", abbr = "Bha" },
{ name = "Ashshin", link = "Ashshin", abbr = "Ash" },
{ name = "Kartik", link = "Kartik (month)", abbr = "Kar" },
{ name = "Ogrohayon", link = "Ogrohayon", abbr = "Ogr" },
{ name = "Poush", link = "Poush", abbr = "Pou" },
{ name = "Magh", link = "Magh (Bengali calendar)", abbr = "Mag" },
{ name = "Falgun", link = "Falgun", abbr = "Fal" },
{ name = "Chaitro", link = "Chaitro", abbr = "Cha" },
}
local BN_WEEKDAY = {
{ name = "Robibar", abbr = "Rob" },
{ name = "Sombar", abbr = "Som" },
{ name = "Mongolbar", abbr = "Mon" },
{ name = "Budhbar", abbr = "Bud" },
{ name = "Brihoshpotibar", abbr = "Bri" },
{ name = "Shukrobar", abbr = "Shu" },
{ name = "Shonibar", abbr = "Sho" },
}
local MONTH_LENGTHS_NORMAL = { 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 }
local MONTH_LENGTHS_LEAP = { 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30 }
local function isLeapYear(year)
local n = year - 593
return (n % 400 == 0) or (n % 100 ~= 0 and n % 4 == 0)
end
local function getMonthLengths(year)
return isLeapYear(year) and MONTH_LENGTHS_LEAP or MONTH_LENGTHS_NORMAL
end
local function daysToDate(days)
local year = EPOCH_YEAR
if days >= 0 then
while true do
local year_len = isLeapYear(year) and 366 or 365
if days < year_len then break end
days = days - year_len
year = year + 1
end
else
repeat
year = year - 1
local year_len = isLeapYear(year) and 366 or 365
days = days + year_len
until days >= 0
end
local lengths = getMonthLengths(year)
local month = 1
local day_of_year = days
while month < 12 and days >= lengths[month] do
days = days - lengths[month]
month = month + 1
end
return year, month, days + 1, day_of_year
end
local function tsToWeekday(ts)
local day_index = math.floor(ts / SECONDS_PER_DAY)
return ((day_index + 4) % 7) + 1
end
local function isoWeekNumber(ts)
local day_index = math.floor(ts / SECONDS_PER_DAY)
local dow = (day_index + 3) % 7
return math.floor((day_index - dow + 10) / 7)
end
-- ISO week year: if week 1 belongs to next year or week belongs to prev year, adjust
local function isoWeekYear(year, month_idx, day, week)
if week >= 52 and month_idx == 1 and day <= 3 then
return year - 1
elseif week == 1 and month_idx == 12 and day >= 29 then
return year + 1
end
return year
end
local function tsToTime(ts)
local secs = ts % SECONDS_PER_DAY
if secs < 0 then secs = secs + SECONDS_PER_DAY end
return math.floor(secs / 3600), math.floor((secs % 3600) / 60), secs % 60
end
local function buildCtx(ts)
local date_ts = ts - DAY_START_OFFSET
local days = math.floor(date_ts / SECONDS_PER_DAY)
local year, month_idx, day, day_of_year = daysToDate(days)
local hour, min, sec = tsToTime(ts)
local lengths = getMonthLengths(year)
local week = isoWeekNumber(date_ts)
return {
day = day,
month_idx = month_idx,
month_entry = BN_MONTH[month_idx],
year = year,
hour = hour,
min = min,
sec = sec,
weekday = tsToWeekday(date_ts),
week = week,
week_year = isoWeekYear(year, month_idx, day, week),
day_of_year = day_of_year,
month_days = lengths[month_idx],
is_leap = isLeapYear(year),
ts = ts,
}
end
local TOKEN = {
-- year
Y = function(c) return tostring(c.year) end,
y = function(c) return string.format("%02d", c.year % 100) end,
L = function(c) return c.is_leap and "1" or "0" end,
o = function(c) return tostring(c.week_year) end,
-- month
n = function(c) return tostring(c.month_idx) end,
m = function(c) return string.format("%02d", c.month_idx) end,
M = function(c) return c.month_entry.abbr end,
F = function(c) return c.month_entry.name end,
t = function(c) return tostring(c.month_days) end,
-- day
j = function(c) return tostring(c.day) end,
d = function(c) return string.format("%02d", c.day) end,
z = function(c) return tostring(c.day_of_year) end,
-- week / weekday
W = function(c) return string.format("%02d", c.week) end,
N = function(c)
-- ISO: Mon=1 Sun=7; our table Sun=1 Sat=7
return tostring(c.weekday == 1 and 7 or c.weekday - 1)
end,
w = function(c)
-- Sun=0 Sat=6
return tostring(c.weekday - 1)
end,
D = function(c) return BN_WEEKDAY[c.weekday].abbr end,
l = function(c) return BN_WEEKDAY[c.weekday].name end,
-- hour
a = function(c) return c.hour < 12 and "am" or "pm" end,
A = function(c) return c.hour < 12 and "AM" or "PM" end,
g = function(c) return tostring(c.hour % 12 == 0 and 12 or c.hour % 12) end,
h = function(c) return string.format("%02d", c.hour % 12 == 0 and 12 or c.hour % 12) end,
G = function(c) return tostring(c.hour) end,
H = function(c) return string.format("%02d", c.hour) end,
-- minutes and seconds
i = function(c) return string.format("%02d", c.min) end,
s = function(c) return string.format("%02d", c.sec) end,
-- unix
U = function(c) return tostring(c.ts + BENGALI_UNIX_EPOCH) end,
u = function(c) return tostring(c.ts) end,
-- timezone (static, always Bangladesh)
e = function(_) return "Asia/Dhaka" end,
I = function(_) return "0" end,
O = function(_) return "+0600" end,
P = function(_) return "+06:00" end,
T = function(_) return "BST" end,
Z = function(_) return "21600" end,
}
local function expandToken(char, ctx)
local fn = TOKEN[char]
return fn and fn(ctx) or char
end
local function wrapInLink(char, expanded, month_entry)
if (char == "F" or char == "M") and month_entry.link ~= month_entry.name then
return "[[" .. month_entry.link .. "|" .. month_entry.name .. "]]"
else
return "[[" .. expanded .. "]]"
end
end
local function formatDate(ctx, format)
local result = {}
local i = 1
while i <= #format do
local two = format:sub(i, i + 1)
if two == "''" then
i = i + 2
while i <= #format do
if format:sub(i, i + 1) == "''" then i = i + 2; break end
table.insert(result, format:sub(i, i))
i = i + 1
end
elseif format:sub(i, i) == '"' then
i = i + 1
while i <= #format do
if format:sub(i, i) == '"' then i = i + 1; break end
table.insert(result, format:sub(i, i))
i = i + 1
end
elseif two == "[[" then
i = i + 2
local linked = {}
while i <= #format and format:sub(i, i + 1) ~= "]]" do
local char = format:sub(i, i)
table.insert(linked, { char = char, expanded = expandToken(char, ctx) })
i = i + 1
end
i = i + 2
if #linked == 1 then
table.insert(result, wrapInLink(linked[1].char, linked[1].expanded, ctx.month_entry))
else
local inner = {}
for _, t in ipairs(linked) do table.insert(inner, t.expanded) end
table.insert(result, "[[" .. table.concat(inner) .. "]]")
end
else
table.insert(result, expandToken(format:sub(i, i), ctx))
i = i + 1
end
end
return table.concat(result)
end
local function isDateString(s)
return s:match("^%d+%-%d+%-%d+$") or s:match("^%d+%s+%a+%s+%d+$")
end
local function resolveTimestamp(date_str)
local raw, err = date_str and timestamp(date_str) or timestamp()
if not raw then
return nil, err or "Invalid date: " .. tostring(date_str)
end
return tonumber(raw), nil
end
local function parseArgs(args)
local first = args[1] or ""
if first == "" then
return { date_str = nil, format = DEFAULT_FORMAT }
elseif isDateString(first) then
return { date_str = first, format = args[2] or DEFAULT_FORMAT }
else
return { date_str = args[2], format = first }
end
end
function p.main(frame)
local args = getArgs(frame)
local parsed = parseArgs(args)
local ts, err = resolveTimestamp(parsed.date_str)
if err then
return '<span class="error">' .. err .. '</span>'
end
return formatDate(buildCtx(ts), parsed.format)
end
return p
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.
- 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:
- 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.
- 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.
- 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.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.