Files
cell/time.cm
2026-02-10 14:21:49 -06:00

213 lines
5.4 KiB
Plaintext

// epoch = 0000-01-01 00:00:00 +0000
var time = native
var now = time.now
var computer_zone = time.computer_zone
var computer_dst = time.computer_dst
delete time.now
delete time.computer_zone
delete time.computer_dst
time.second = 1
time.minute = 60
time.hour = 3600
time.day = 86400
time.week = 604800
time.weekdays = [
"Sunday", "Monday", "Tuesday",
"Wednesday", "Thursday", "Friday", "Saturday"
]
time.monthstr = [
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
]
time.epoch = 1970
time.hour2minute = function() { return time.hour / time.minute }
time.day2hour = function() { return time.day / time.hour }
time.minute2second = function() { return time.minute / time.second }
time.week2day = function() { return time.week / time.day }
time.yearsize = function yearsize(y) {
if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) return 366
return 365
}
time.isleap = function(y) { return time.yearsize(y) == 366 }
time.timecode = function(t) {
var fps = 24
var s = whole(t)
var frac = t - s
return `${s}:${whole(frac * fps)}`
}
time.monthdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
// convert seconds-since-epoch -> broken-down record
function time_record(_num, _zone, _dst) {
var n = _num
var z = _zone
var d = _dst
if (n == null) n = now()
if (z == null) z = computer_zone()
if (d == null) d = computer_dst()
if (is_object(n)) return n
var monthdays = array(time.monthdays)
var rec = {
second: 0, minute: 0, hour: 0,
yday: 0, year: 0,
weekday: 0, month: 0, day: 0,
zone: z, dst: !!d,
ce: "AD"
}
var offset = z + (d ? 1 : 0)
n = n + offset * time.hour
var hms = n % time.day
var day = floor(n / time.day)
if (hms < 0) { hms = hms + time.day; day = day - 1 }
rec.second = hms % time.minute
var tmp = floor(hms / time.minute)
rec.minute = tmp % time.minute
rec.hour = floor(tmp / time.minute)
rec.weekday = (day + 4503599627370496 + 2) % 7
var y = time.epoch
if (day >= 0) {
y = time.epoch
while (day >= time.yearsize(y)) {
day = day - time.yearsize(y)
y = y + 1
}
} else {
y = time.epoch
while (day < 0) {
y = y - 1
day = day + time.yearsize(y)
}
}
rec.year = y
rec.ce = (y <= 0) ? "BC" : "AD"
rec.yday = day
if (time.yearsize(y) == 366) monthdays[1] = 29
var m = 0
while (day >= monthdays[m]) {
day = day - monthdays[m]
m = m + 1
}
rec.month = m
rec.day = day + 1
return rec
}
function time_number(_rec) {
var r = _rec
if (r == null) r = now()
if (is_number(r)) return r
var c = 0
var year = r.year || 0
var hour = r.hour || 0
var minute = r.minute || 0
var second = r.second || 0
var zone = r.zone || 0
var dst = r.dst ? 1 : 0
var yday = r.yday || 0
var i = 0
if (year > time.epoch) {
i = time.epoch
while (i < year) {
c = c + time.day * time.yearsize(i)
i = i + 1
}
} else if (year < time.epoch) {
i = time.epoch - 1
while (i > year) {
c = c + time.day * time.yearsize(i)
i = i - 1
}
c = c + (time.yearsize(year) - yday - 1) * time.day
c = c + (time.day2hour() - hour - 1) * time.hour
c = c + (time.hour2minute() - minute - 1) * time.minute
c = c + time.minute2second() - second
c = c + (zone + dst) * time.hour
return -c
}
c = second
c = c + minute * time.minute
c = c + hour * time.hour
c = c + yday * time.day
c = c - (zone + dst) * time.hour
return c
}
// text formatting
var default_fmt = "vB mB d hh:nn:ss a z y c"
function time_text(_num, _fmt, _zone, _dst) {
var n = _num
var f = _fmt
var z = _zone
var d = _dst
if (n == null) n = now()
if (f == null) f = default_fmt
if (z == null) z = computer_zone()
if (d == null) d = computer_dst()
var rec = is_number(n) ? time_record(n, z, d) : n
z = rec.zone
d = rec.dst
if (search(f, "a") != null) {
if (rec.hour >= 13) { rec.hour = rec.hour - 12; f = replace(f, "a", "PM") }
else if (rec.hour == 12) { f = replace(f, "a", "PM") }
else if (rec.hour == 0) { rec.hour = 12; f = replace(f, "a", "AM") }
else f = replace(f, "a", "AM")
}
var year = rec.year > 0 ? rec.year : rec.year - 1
if (search(f, "c") != null) {
if (year < 0) { year = abs(year); f = replace(f, "c", "BC") }
else f = replace(f, "c", "AD")
}
var full_offset = z + (d ? 1 : 0)
f = replace(f, "yyyy", text(year, "i4"))
f = replace(f, "y", year)
f = replace(f, "eee", rec.yday + 1)
f = replace(f, "dd", text(rec.day, "i2"))
f = replace(f, "d", rec.day)
f = replace(f, "hh", text(rec.hour, "i2"))
f = replace(f, "h", rec.hour)
f = replace(f, "nn", text(rec.minute, "i2"))
f = replace(f, "n", rec.minute)
f = replace(f, "ss", text(rec.second, "i2"))
f = replace(f, "s", rec.second)
f = replace(f, "x", d ? "DST" : "")
f = replace(f, "z", (full_offset >= 0 ? "+" : "") + text(full_offset))
f = replace(f, /mm[^bB]/g, rec.month + 1)
f = replace(f, /m[^bB]/g, rec.month + 1)
f = replace(f, /v[^bB]/g, rec.weekday)
f = replace(f, "mb", text(time.monthstr[rec.month], 0, 3))
f = replace(f, "mB", time.monthstr[rec.month])
f = replace(f, "vB", time.weekdays[rec.weekday])
f = replace(f, "vb", text(time.weekdays[rec.weekday], 0, 3))
return f
}
return { record: time_record, number: time_number, text: time_text }