improve time

This commit is contained in:
2025-05-29 02:56:30 -05:00
parent 4e118dd8e9
commit b4371ba3e0
5 changed files with 248 additions and 221 deletions

View File

@@ -22,12 +22,10 @@ function caller_data(depth = 0)
function console_rec(line, file, msg) {
return `[${prosperon.id.slice(0,5)}] [${file}:${line}]: ${msg}\n`
var now = time.now()
var id = prosperon.name ? prosperon.name : prosperon.id
id = id.substring(0,6)
return `[${id}] [${time.text(now, "mb d yyyy h:nn:ss")}] ${file}:${line}: ${msg}\n`
return `[${id}] [${time.text("mb d yyyy h:nn:ss")}] ${file}:${line}: ${msg}\n`
}
var console_mod = prosperon.hidden.console

View File

@@ -27,7 +27,7 @@ graphics.Image = function(surfaceData) {
this[CPU] = surfaceData || undefined;
this[GPU] = undefined;
this[LOADING] = false;
this[LASTUSE] = time.now();
this[LASTUSE] = time.number();
this.rect = {x:0, y:0, width:1, height:1};
}
@@ -35,7 +35,7 @@ graphics.Image = function(surfaceData) {
Object.defineProperties(graphics.Image.prototype, {
gpu: {
get: function() {
this[LASTUSE] = time.now();
this[LASTUSE] = time.number();
if (!this[GPU] && !this[LOADING]) {
this[LOADING] = true;
var self = this;
@@ -69,7 +69,7 @@ Object.defineProperties(graphics.Image.prototype, {
cpu: {
get: function() {
this[LASTUSE] = time.now();
this[LASTUSE] = time.number();
// Note: Reading texture back from GPU requires async operation
// For now, return the CPU data if available
return this[CPU]

View File

@@ -1,183 +1,191 @@
/* time.js exports: {record, number, text} */
var time = this;
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"];
/* -------- host helpers -------------------------------------------------- */
var now = time.now; // seconds since Misty epoch (C stub)
var computer_zone = time.computer_zone; // integral hours, no DST
var computer_dst = time.computer_dst; // true ↔ DST in effect
delete time.now;
delete time.computer_zone;
delete time.computer_dst;
/* -------- units & static tables ----------------------------------------- */
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.hour2minute = function() {
return this.hour / this.minute;
};
/* ratios (kept K&R-style) */
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.day2hour = function() {
return this.day / this.hour;
};
time.minute2second = function() {
return this.minute / this.second;
};
time.week2day = function() {
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.isleap = function isleap(year) {
return this.yearsize(year) === 366;
};
time.yearsize = function yearsize(y) {
/* leap-year helpers */
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 timecode(t, fps = 24) {
/* timecode utility */
time.timecode = function(t, fps = 24)
{
var s = Math.trunc(t);
t -= s;
return `${s}:${Math.trunc(fps * s)}`;
var frac = t - s;
return `${s}:${Math.trunc(frac * fps)}`;
};
/* per-month day counts (non-leap) */
time.monthdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
time.zones = { "-12": "IDLW" };
time.record = function record(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 = Math.floor(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);
rec.weekday = (day + 4503599627370496 + 2) % 7;
var yIter = this.epoch;
if (day >= 0) {
for (yIter = this.epoch; day >= this.yearsize(yIter); yIter++) {
day -= this.yearsize(yIter);
}
} else {
for (yIter = this.epoch; day < 0; yIter--) {
day += this.yearsize(yIter - 1);
}
}
rec.year = yIter;
rec.ce = (rec.year <= 0) ? "BC" : "AD";
rec.yday = day;
if (this.yearsize(yIter) === 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;
/* -------- core converters ----------------------------------------------- */
function record(num = now(),
zone = computer_zone(),
dst = computer_dst())
{
/* caller passed an existing record → return it verbatim */
if (typeof num === "object") return num;
/* -------------------------------------------------------------------- */
/* convert seconds-since-epoch → broken-down record */
var monthdays = time.monthdays.slice();
var rec = {
second : 0, minute : 0, hour : 0,
yday : 0, year : 0,
weekday: 0, month : 0, day : 0,
zone : zone, dst : !!dst,
ce : "AD"
};
/* include DST in the effective offset */
var offset = zone + (dst ? 1 : 0);
num += offset * time.hour;
/* split into day + seconds-of-day */
var hms = num % time.day;
var day = Math.floor(num / time.day);
if (hms < 0) { hms += time.day; day--; }
rec.second = hms % time.minute;
var tmp = Math.floor(hms / time.minute);
rec.minute = tmp % time.minute;
rec.hour = Math.floor(tmp / time.minute);
rec.weekday = (day + 4_503_599_627_370_496 + 2) % 7; /* 2 → 1970-01-01 was Thursday */
/* year & day-of-year */
var y = time.epoch;
if (day >= 0) {
for (y = time.epoch; day >= time.yearsize(y); y++)
day -= time.yearsize(y);
} else {
for (y = time.epoch; day < 0; y--)
day += time.yearsize(y - 1);
}
};
rec.year = y;
rec.ce = (y <= 0) ? "BC" : "AD";
rec.yday = day;
time.number = function number(rec) {
if (typeof rec === "number") {
return rec;
} else if (typeof rec === "object") {
var c = 0;
var year = rec.year || 0;
var hour = rec.hour || 0;
var minute = rec.minute || 0;
var second = rec.second || 0;
var zone = rec.zone || 0;
var yday = rec.yday || 0;
/* month & month-day */
if (time.yearsize(y) === 366) monthdays[1] = 29;
var m = 0;
for (; day >= monthdays[m]; m++) day -= monthdays[m];
rec.month = m;
rec.day = day + 1;
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;
}
return rec;
}
c += second;
c += minute * this.minute;
c += hour * this.hour;
c += yday * this.day;
c -= zone * this.hour;
return c;
function number(rec = now())
{
/* fall through for numeric input or implicit “now” */
if (typeof rec === "number") return rec;
/* -------------------------------------------------------------------- */
/* record → seconds-since-epoch */
var c = 0;
var year = rec.year || 0;
var hour = rec.hour || 0;
var minute = rec.minute || 0;
var second = rec.second || 0;
var zone = rec.zone || 0;
var dst = rec.dst ? 1 : 0;
var yday = rec.yday || 0;
if (year > time.epoch) {
for (var i = time.epoch; i < year; i++)
c += time.day * time.yearsize(i);
} else if (year < time.epoch) {
for (var i = time.epoch - 1; i > year; i--)
c += time.day * time.yearsize(i);
c += (time.yearsize(year) - yday - 1) * time.day;
c += (time.day2hour() - hour - 1) * time.hour;
c += (time.hour2minute() - minute - 1) * time.minute;
c += time.minute2second() - second;
c += (zone + dst) * time.hour;
return -c; /* BCE */
}
};
time.fmt = "vB mB d h:nn:ss TZz a y c";
c = second;
c += minute * time.minute;
c += hour * time.hour;
c += yday * time.day;
c -= (zone + dst) * time.hour;
time.text = function text(num, fmt = this.fmt, zone) {
var rec = (typeof num === "number") ? time.record(num, zone) : num;
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");
}
return c;
}
/* -------- text formatting ----------------------------------------------- */
var default_fmt = "vB mB d hh:nn:ss a z y c"; /* includes new DST token */
function text(num = now(),
fmt = default_fmt,
zone = computer_zone(),
dst = computer_dst())
{
var rec = (typeof num === "number") ? record(num, zone, dst) : num;
zone = rec.zone;
dst = rec.dst;
/* am/pm */
if (fmt.includes("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");
}
/* BCE/CE */
var year = rec.year > 0 ? rec.year : rec.year - 1;
if (fmt.includes("c")) {
if (year < 0) { year = Math.abs(year); fmt = fmt.replaceAll("c", "BC"); }
else fmt = fmt.replaceAll("c", "AD");
}
/* substitutions */
var full_offset = zone + (dst ? 1 : 0);
fmt = fmt.replaceAll("yyyy", year.toString().padStart(4, "0"));
fmt = fmt.replaceAll("y", year);
fmt = fmt.replaceAll("eee", rec.yday + 1);
@@ -189,44 +197,28 @@ time.text = function text(num, fmt = this.fmt, zone) {
fmt = fmt.replaceAll("n", rec.minute);
fmt = fmt.replaceAll("ss", rec.second.toFixed(2).padStart(2, "0"));
fmt = fmt.replaceAll("s", rec.second);
fmt = fmt.replaceAll("z", zone >= 0 ? "+" + zone : zone);
fmt = fmt.replaceAll("x", dst ? "DST" : ""); /* new */
fmt = fmt.replaceAll("z", (full_offset >= 0 ? "+" : "") + full_offset);
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));
fmt = fmt.replaceAll("mb", time.monthstr[rec.month].slice(0, 3));
fmt = fmt.replaceAll("mB", time.monthstr[rec.month]);
fmt = fmt.replaceAll("vB", time.weekdays[rec.weekday]);
fmt = fmt.replaceAll("vb", time.weekdays[rec.weekday].slice(0, 3));
return fmt;
};
}
/* -------- docs ---------------------------------------------------------- */
time[prosperon.DOC] = {
doc: `The main time object, handling date/time utilities in earth-seconds.`,
second: `Number of seconds in a (real) second (always 1).`,
minute: `Number of seconds in a minute (60).`,
hour: `Number of seconds in an hour (3600).`,
day: `Number of seconds in a day (86400).`,
week: `Number of seconds in a week (604800).`,
weekdays: `Names of the days of the week, Sunday through Saturday.`,
monthstr: `Full names of the months of the year, January through December.`,
epoch: `Base epoch year, from which day 0 is calculated (default 1970).`,
hour2minute: `Return the ratio of hour to minute in seconds, e.g. 3600 / 60 => 60.`,
day2hour: `Return the ratio of day to hour in seconds, e.g. 86400 / 3600 => 24.`,
minute2second: `Return the ratio of minute to second in seconds, e.g. 60 / 1 => 60.`,
week2day: `Return the ratio of week to day in seconds, e.g. 604800 / 86400 => 7.`,
strparse: `Mapping of format tokens (yyyy, mm, dd, etc.) to time fields (year, month, day...).`,
isleap: `Return true if a given year is leap, based on whether it has 366 days.`,
yearsize: `Given a year, return 365 or 366 depending on leap-year rules.`,
timecode: `Convert seconds into a "S:frames" timecode string, with optional FPS (default 24).`,
monthdays: `An array of days in each month for a non-leap year.`,
zones: `Table of recognized time zone abbreviations, with offsets (e.g., "-12" -> "IDLW").`,
record: `Convert a timestamp (in seconds) into a record with fields like day, month, year, etc.`,
number: `Convert a record back into a numeric timestamp (seconds).`,
fmt: `Default format string for time.text(), containing tokens like 'yyyy', 'dd', 'hh', etc.`,
text: `Format a numeric or record time into a string using a format pattern, e.g. 'hh:nn:ss'.`,
now: `Return the current system time in seconds (implemented in C extension).`,
computer_dst: `Return true if local system time is currently in DST (implemented in C extension).`,
computer_zone: `Return local time zone offset from UTC in hours (implemented in C extension).`
doc : "Time utilities; epoch = 0000-01-01 00:00:00 +0000.",
record : "time.record([num | rec], [zone], [dst]) → detailed record (adds .dst).",
number : "time.number([rec]) → numeric seconds since epoch.",
text : "time.text([val], [fmt], [zone], [dst]) → formatted string (token Z = DST)."
};
return time;
/* -------- public exports ------------------------------------------------ */
return { record, number, text };

View File

@@ -1,45 +1,81 @@
#include "qjs_time.h"
#include "quickjs.h"
#include <time.h> // For time() calls, localtime, etc.
#include <sys/time.h> // For gettimeofday, if needed
#include <time.h>
#include <sys/time.h>
// Example stubs for your time-related calls
/* ---------------------------------------------------------------- *\
Helpers
\* ---------------------------------------------------------------- */
static JSValue js_time_now(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) {
// time_now
/* Seconds from Misty epoch (year-0) so JS “number()” stays consistent.
62167219200 = seconds between 0000-01-01 00:00 UTC and 1970-01-01 00:00 UTC. */
static inline double misty_now(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
double now = (double)tv.tv_sec + (tv.tv_usec / 1000000.0);
return JS_NewFloat64(ctx, now);
return (double)tv.tv_sec + tv.tv_usec / 1000000.0;
}
static JSValue js_time_computer_dst(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) {
/* ---------------------------------------------------------------- *\
JS bindings
\* ---------------------------------------------------------------- */
static JSValue
js_time_now(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
return JS_NewFloat64(ctx, misty_now());
}
static JSValue
js_time_computer_dst(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
time_t t = time(NULL);
struct tm *lt = localtime(&t);
int is_dst = (lt ? lt->tm_isdst : -1);
return JS_NewBool(ctx, (is_dst > 0));
return JS_NewBool(ctx, lt && lt->tm_isdst > 0);
}
static JSValue js_time_computer_zone(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) {
static JSValue
js_time_computer_zone(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
time_t t = time(NULL);
time_t local_t = mktime(localtime(&t));
double diff = difftime(t, local_t); // difference in seconds from local time
return JS_NewFloat64(ctx, diff / 3600.0);
#ifdef __USE_BSD /* tm_gmtoff / tm_zone available */
struct tm lt = *localtime(&t);
long offset_sec = lt.tm_gmtoff; /* seconds east of UTC */
#else /* portable fallback */
struct tm gmt = *gmtime(&t);
/* Trick: encode the *same* calendar fields as “local” and see
how many seconds they represent. */
gmt.tm_isdst = 0; /* mktime expects valid flag */
time_t local_view = mktime(&gmt); /* same Y-M-D H:M:S but local */
long offset_sec = t - local_view; /* negative west of UTC */
#endif
return JS_NewFloat64(ctx, (double)offset_sec / 3600.0);
}
/* ---------------------------------------------------------------- *\
registration
\* ---------------------------------------------------------------- */
static const JSCFunctionListEntry js_time_funcs[] = {
// name, prop flags, #args, etc.
JS_CFUNC_DEF("now", 0, js_time_now),
JS_CFUNC_DEF("computer_dst", 0, js_time_computer_dst),
JS_CFUNC_DEF("computer_zone", 0, js_time_computer_zone),
JS_CFUNC_DEF("now", 0, js_time_now),
JS_CFUNC_DEF("computer_dst", 0, js_time_computer_dst),
JS_CFUNC_DEF("computer_zone", 0, js_time_computer_zone),
};
JSValue js_time_use(JSContext *ctx) {
JSValue
js_time_use(JSContext *ctx)
{
JSValue obj = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, obj, js_time_funcs,
sizeof(js_time_funcs)/sizeof(js_time_funcs[0]));
JS_SetPropertyFunctionList(ctx, obj,
js_time_funcs,
sizeof(js_time_funcs) /
sizeof(js_time_funcs[0]));
return obj;
}

View File

@@ -1,4 +1,5 @@
var parseq = use('parseq', $_.delay)
var time = use('time')
function load_comment_from_api_requestor(id) {
return function(cb) {
@@ -23,6 +24,6 @@ $_.receiver(tree => {
send(tree, reason)
}
send(tree, { ...result.comment, children: result.children })
send(tree, { ...result.comment, children: result.children, time: time.text() })
})
})