244 lines
6.6 KiB
JavaScript
244 lines
6.6 KiB
JavaScript
var time = this
|
|
|
|
/* Time values are always expressed in terms of real earth-seconds */
|
|
Object.assign(time, {
|
|
hour2minute() {
|
|
return this.hour / this.minute;
|
|
},
|
|
day2hour() {
|
|
return this.day / this.hour;
|
|
},
|
|
minute2second() {
|
|
return this.minute / this.second;
|
|
},
|
|
week2day() {
|
|
return this.week / this.day;
|
|
},
|
|
});
|
|
|
|
time.strparse = {
|
|
yyyy: "year",
|
|
mm: "month",
|
|
m: "month",
|
|
eee: "yday",
|
|
dd: "day",
|
|
d: "day",
|
|
v: "weekday",
|
|
hh: "hour",
|
|
h: "hour",
|
|
nn: "minute",
|
|
n: "minute",
|
|
ss: "second",
|
|
s: "second",
|
|
};
|
|
|
|
time.doc = {
|
|
doc: "Functions for manipulating time.",
|
|
second: "Earth-seconds in a second.",
|
|
minute: "Seconds in a minute.",
|
|
hour: "Seconds in an hour.",
|
|
day: "Seconds in a day.",
|
|
week: "Seconds in a week.",
|
|
weekdays: "Names of the days of the week.",
|
|
monthstr: "Full names of the months of the year.",
|
|
epoch: "Times are expressed in terms of day 0 at hms 0 of this year.",
|
|
now: "Get the time now.",
|
|
computer_zone: "Get the time zone of the running computer.",
|
|
computer_dst: "Return true if the computer is in daylight savings.",
|
|
yearsize: "Given a year, return the number of days in that year.",
|
|
monthdays: "Number of days in each month.",
|
|
fmt: "Default format for time.",
|
|
record: "Given a time, return an object with time fields.",
|
|
number: "Return the number representation of a given time.",
|
|
text: "Return a text formatted time.",
|
|
};
|
|
|
|
time.second = 1;
|
|
time.minute = 60;
|
|
time.hour = 3_600;
|
|
time.day = 86_400;
|
|
time.week = 604_800;
|
|
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.isleap = function (year) {
|
|
return this.yearsize(year) === 366;
|
|
};
|
|
time.isleap.doc = "Return true if the given year is a leapyear.";
|
|
|
|
time.yearsize = function (y) {
|
|
if (y % 4 === 0 && (y % 100 != 0 || y % 400 === 0)) return 366;
|
|
return 365;
|
|
};
|
|
|
|
time.timecode = function (t, fps = 24) {
|
|
var s = Math.trunc(t);
|
|
t -= s;
|
|
return `${s}:${Math.trunc(fps * s)}`;
|
|
};
|
|
|
|
time.monthdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
time.zones = {};
|
|
time.zones["-12"] = "IDLW";
|
|
time.record = function (num, zone = this.computer_zone()) {
|
|
if (typeof num === "object") return num;
|
|
else if (typeof num === "number") {
|
|
var monthdays = this.monthdays.slice();
|
|
var rec = {
|
|
second: 0,
|
|
minute: 0,
|
|
hour: 0,
|
|
yday: 0,
|
|
year: 0,
|
|
zone: 0,
|
|
};
|
|
rec.zone = zone;
|
|
num += zone * this.hour;
|
|
|
|
var hms = num % this.day;
|
|
var day = parseInt(num / this.day);
|
|
|
|
if (hms < 0) {
|
|
hms += this.day;
|
|
day--;
|
|
}
|
|
rec.second = hms % this.minute;
|
|
var d1 = Math.floor(hms / this.minute);
|
|
rec.minute = d1 % this.minute;
|
|
rec.hour = Math.floor(d1 / this.minute);
|
|
|
|
/* addend%7 is 4 */
|
|
rec.weekday = (day + 4503599627370496 + 2) % 7;
|
|
|
|
var d1 = this.epoch;
|
|
if (day >= 0) for (d1 = this.epoch; day >= this.yearsize(d1); d1++) day -= this.yearsize(d1);
|
|
else for (d1 = this.epoch; day < 0; d1--) day += this.yearsize(d1 - 1);
|
|
|
|
rec.year = d1;
|
|
if (rec.year <= 0) rec.ce = "BC";
|
|
else rec.ce = "AD";
|
|
|
|
rec.yday = day;
|
|
|
|
if (this.yearsize(d1) === 366) monthdays[1] = 29;
|
|
|
|
var d0 = day;
|
|
for (d1 = 0; d0 >= monthdays[d1]; d1++) d0 -= monthdays[d1];
|
|
|
|
monthdays[1] = 28;
|
|
rec.day = d0 + 1;
|
|
|
|
rec.month = d1;
|
|
return rec;
|
|
}
|
|
};
|
|
|
|
time.number = function (rec) {
|
|
if (typeof rec === "number") return rec;
|
|
else if (typeof rec === "object") {
|
|
var c = 0;
|
|
var year = rec.year ? rec.year : 0;
|
|
var hour = rec.hour ? rec.hour : 0;
|
|
var minute = rec.minute ? rec.minute : 0;
|
|
var second = rec.second ? rec.second : 0;
|
|
var zone = rec.zone ? rec.zone : 0;
|
|
|
|
if (year > this.epoch) for (var i = this.epoch; i < year; i++) c += this.day * this.yearsize(i);
|
|
else if (year < this.epoch) {
|
|
for (var i = this.epoch - 1; i > year; i--) c += this.day * this.yearsize(i);
|
|
|
|
c += (this.yearsize(year) - yday - 1) * this.day;
|
|
c += (this.day2hour() - hour - 1) * this.hour;
|
|
c += (this.hour2minute() - minute - 1) * this.minute;
|
|
c += this.minute2second() - second;
|
|
c += zone * this.hour;
|
|
c *= -1;
|
|
return c;
|
|
}
|
|
|
|
c += second;
|
|
c += minute * this.minute;
|
|
c += hour * this.hour;
|
|
c += yday * this.day;
|
|
c -= zone * this.hour;
|
|
|
|
return c;
|
|
}
|
|
};
|
|
|
|
/* Time formatting
|
|
yyyy - year in a 4 digit field
|
|
y - as many digits as necessary
|
|
mm - month (1-12)
|
|
mB - month name
|
|
mb - abbreviated month name
|
|
dd - day (1-31)
|
|
d
|
|
c - if the year is <= 0, BC. Otherwise, AD.
|
|
hh - hour
|
|
h
|
|
nn - minutes
|
|
n
|
|
ss - seconds
|
|
s
|
|
v - day of the week (0-6)
|
|
vB - weekday name
|
|
vb - abbreviated weekday name
|
|
a - am/pm
|
|
z - zone, -12 to +11
|
|
*/
|
|
|
|
time.fmt = "vB mB d h:nn:ss TZz a y c";
|
|
|
|
/* If num is a number, converts to a rec first. */
|
|
time.text = function (num, fmt = this.fmt, zone) {
|
|
var rec = num;
|
|
|
|
if (typeof rec === "number") rec = time.record(num, zone);
|
|
|
|
zone = rec.zone;
|
|
|
|
if (fmt.match("a")) {
|
|
if (rec.hour >= 13) {
|
|
rec.hour -= 12;
|
|
fmt = fmt.replaceAll("a", "PM");
|
|
} else if (rec.hour === 12) fmt = fmt.replaceAll("a", "PM");
|
|
else if (rec.hour === 0) {
|
|
rec.hour = 12;
|
|
fmt = fmt.replaceAll("a", "AM");
|
|
} else fmt = fmt.replaceAll("a", "AM");
|
|
}
|
|
var year = rec.year > 0 ? rec.year : rec.year - 1;
|
|
if (fmt.match("c")) {
|
|
if (year < 0) {
|
|
year = Math.abs(year);
|
|
fmt = fmt.replaceAll("c", "BC");
|
|
} else fmt = fmt.replaceAll("c", "AD");
|
|
}
|
|
|
|
fmt = fmt.replaceAll("yyyy", year.toString().padStart(4, "0"));
|
|
fmt = fmt.replaceAll("y", year);
|
|
fmt = fmt.replaceAll("eee", rec.yday + 1);
|
|
fmt = fmt.replaceAll("dd", rec.day.toString().padStart(2, "0"));
|
|
fmt = fmt.replaceAll("d", rec.day);
|
|
fmt = fmt.replaceAll("hh", rec.hour.toString().padStart(2, "0"));
|
|
fmt = fmt.replaceAll("h", rec.hour);
|
|
fmt = fmt.replaceAll("nn", rec.minute.toString().padStart(2, "0"));
|
|
fmt = fmt.replaceAll("n", rec.minute);
|
|
fmt = fmt.replaceAll("ss", rec.second.toString().padStart(2, "0"));
|
|
fmt = fmt.replaceAll("s", rec.second);
|
|
fmt = fmt.replaceAll("z", zone >= 0 ? "+" + zone : zone);
|
|
fmt = fmt.replaceAll(/mm[^bB]/g, rec.month + 1);
|
|
fmt = fmt.replaceAll(/m[^bB]/g, rec.month + 1);
|
|
fmt = fmt.replaceAll(/v[^bB]/g, rec.weekday);
|
|
fmt = fmt.replaceAll("mb", this.monthstr[rec.month].slice(0, 3));
|
|
fmt = fmt.replaceAll("mB", this.monthstr[rec.month]);
|
|
fmt = fmt.replaceAll("vB", this.weekdays[rec.weekday]);
|
|
fmt = fmt.replaceAll("vb", this.weekdays[rec.weekday].slice(0, 3));
|
|
|
|
return fmt;
|
|
};
|
|
|
|
return time
|