Framework updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2026-01-12 17:25:07 +00:00
parent ee709ae86d
commit f70ca09f78
12 changed files with 1234 additions and 156 deletions

View File

@@ -111,9 +111,18 @@ class Rsx_Date {
// CURRENT DATE
// =========================================================================
/**
* Alias for today()
*
* @returns {string}
*/
static now() {
return this.today();
}
/**
* Get today's date as "YYYY-MM-DD"
* Uses the user's timezone to determine what "today" is
* Uses user → site → default timezone from rsxapp
*
* @returns {string}
*/
@@ -236,4 +245,309 @@ class Rsx_Date {
return Math.round((ms2 - ms1) / (1000 * 60 * 60 * 24));
}
/**
* Format as relative date ("Today", "Yesterday", "3 days ago", "in 5 days")
*
* @param {*} date
* @returns {string}
*/
static relative(date) {
const parsed = this.parse(date);
if (!parsed) {
return '';
}
const days = this.diff_days(this.today(), parsed);
if (days === 0) {
return 'Today';
} else if (days === 1) {
return 'Tomorrow';
} else if (days === -1) {
return 'Yesterday';
} else if (days > 1) {
return `in ${days} days`;
} else {
return `${Math.abs(days)} days ago`;
}
}
// =========================================================================
// ARITHMETIC
// =========================================================================
/**
* Add days to a date
*
* @param {*} date
* @param {number} days Can be negative to subtract
* @returns {string|null} "YYYY-MM-DD" or null if invalid input
*/
static add_days(date, days) {
const parsed = this.parse(date);
if (!parsed) {
return null;
}
const [year, month, day] = parsed.split('-').map(Number);
const d = new Date(year, month - 1, day);
d.setDate(d.getDate() + days);
return d.getFullYear() + '-' +
String(d.getMonth() + 1).padStart(2, '0') + '-' +
String(d.getDate()).padStart(2, '0');
}
// =========================================================================
// WEEK/MONTH BOUNDARIES
// =========================================================================
/**
* Get the Monday of the week containing the date
*
* @param {*} date
* @returns {string|null} "YYYY-MM-DD" or null if invalid input
*/
static start_of_week(date) {
const parsed = this.parse(date);
if (!parsed) {
return null;
}
const [year, month, day] = parsed.split('-').map(Number);
const d = new Date(year, month - 1, day);
const dow = d.getDay();
// Convert to Monday=0 based, then subtract to get Monday
const daysToSubtract = (dow === 0) ? 6 : dow - 1;
d.setDate(d.getDate() - daysToSubtract);
return d.getFullYear() + '-' +
String(d.getMonth() + 1).padStart(2, '0') + '-' +
String(d.getDate()).padStart(2, '0');
}
/**
* Get the Sunday of the week containing the date
*
* @param {*} date
* @returns {string|null} "YYYY-MM-DD" or null if invalid input
*/
static end_of_week(date) {
const parsed = this.parse(date);
if (!parsed) {
return null;
}
const [year, month, day] = parsed.split('-').map(Number);
const d = new Date(year, month - 1, day);
const dow = d.getDay();
// Days to add to get to Sunday
const daysToAdd = (dow === 0) ? 0 : 7 - dow;
d.setDate(d.getDate() + daysToAdd);
return d.getFullYear() + '-' +
String(d.getMonth() + 1).padStart(2, '0') + '-' +
String(d.getDate()).padStart(2, '0');
}
/**
* Get the first day of the month containing the date
*
* @param {*} date
* @returns {string|null} "YYYY-MM-DD" or null if invalid input
*/
static start_of_month(date) {
const parsed = this.parse(date);
if (!parsed) {
return null;
}
const [year, month] = parsed.split('-').map(Number);
return year + '-' + String(month).padStart(2, '0') + '-01';
}
/**
* Get the last day of the month containing the date
*
* @param {*} date
* @returns {string|null} "YYYY-MM-DD" or null if invalid input
*/
static end_of_month(date) {
const parsed = this.parse(date);
if (!parsed) {
return null;
}
const [year, month] = parsed.split('-').map(Number);
// Day 0 of next month = last day of current month
const d = new Date(year, month, 0);
return d.getFullYear() + '-' +
String(d.getMonth() + 1).padStart(2, '0') + '-' +
String(d.getDate()).padStart(2, '0');
}
/**
* Check if date falls on a weekend (Saturday or Sunday)
*
* @param {*} date
* @returns {boolean}
*/
static is_weekend(date) {
const dow = this.dow(date);
if (dow === null) {
return false;
}
return dow === 0 || dow === 6;
}
/**
* Check if date falls on a weekday (Monday-Friday)
*
* @param {*} date
* @returns {boolean}
*/
static is_weekday(date) {
const dow = this.dow(date);
if (dow === null) {
return false;
}
return dow >= 1 && dow <= 5;
}
// =========================================================================
// COMPONENT EXTRACTORS
// =========================================================================
/**
* Get day of month (1-31)
*
* @param {*} date
* @returns {number|null}
*/
static day(date) {
const parsed = this.parse(date);
if (!parsed) {
return null;
}
return parseInt(parsed.split('-')[2], 10);
}
/**
* Get day of week (0=Sunday, 6=Saturday)
*
* @param {*} date
* @returns {number|null}
*/
static dow(date) {
const parsed = this.parse(date);
if (!parsed) {
return null;
}
const [year, month, day] = parsed.split('-').map(Number);
const d = new Date(year, month - 1, day);
return d.getDay();
}
/**
* Get full day name ("Monday", "Tuesday", etc.)
*
* @param {*} date
* @returns {string}
*/
static dow_human(date) {
const parsed = this.parse(date);
if (!parsed) {
return '';
}
const [year, month, day] = parsed.split('-').map(Number);
const d = new Date(year, month - 1, day);
return new Intl.DateTimeFormat('en-US', { weekday: 'long' }).format(d);
}
/**
* Get short day name ("Mon", "Tue", etc.)
*
* @param {*} date
* @returns {string}
*/
static dow_short(date) {
const parsed = this.parse(date);
if (!parsed) {
return '';
}
const [year, month, day] = parsed.split('-').map(Number);
const d = new Date(year, month - 1, day);
return new Intl.DateTimeFormat('en-US', { weekday: 'short' }).format(d);
}
/**
* Get month (1-12)
*
* @param {*} date
* @returns {number|null}
*/
static month(date) {
const parsed = this.parse(date);
if (!parsed) {
return null;
}
return parseInt(parsed.split('-')[1], 10);
}
/**
* Get full month name ("January", "February", etc.)
*
* @param {*} date
* @returns {string}
*/
static month_human(date) {
const parsed = this.parse(date);
if (!parsed) {
return '';
}
const [year, month, day] = parsed.split('-').map(Number);
const d = new Date(year, month - 1, day);
return new Intl.DateTimeFormat('en-US', { month: 'long' }).format(d);
}
/**
* Get short month name ("Jan", "Feb", etc.)
*
* @param {*} date
* @returns {string}
*/
static month_human_short(date) {
const parsed = this.parse(date);
if (!parsed) {
return '';
}
const [year, month, day] = parsed.split('-').map(Number);
const d = new Date(year, month - 1, day);
return new Intl.DateTimeFormat('en-US', { month: 'short' }).format(d);
}
/**
* Get year (e.g., 2025)
*
* @param {*} date
* @returns {number|null}
*/
static year(date) {
const parsed = this.parse(date);
if (!parsed) {
return null;
}
return parseInt(parsed.split('-')[0], 10);
}
}

View File

@@ -609,4 +609,157 @@ class Rsx_Time {
stop: () => clearInterval(interval)
};
}
// =========================================================================
// COMPONENT EXTRACTORS
// =========================================================================
/**
* Get day of month (1-31)
* Uses user's timezone
*
* @param {*} time
* @returns {number|null}
*/
static day(time) {
const date = this.parse(time);
if (!date) return null;
return parseInt(this.format_in_timezone(time, { day: 'numeric' }), 10);
}
/**
* Get day of week (0=Sunday, 6=Saturday)
* Uses user's timezone
*
* @param {*} time
* @returns {number|null}
*/
static dow(time) {
const date = this.parse(time);
if (!date) return null;
// Get the day name and map to number
const dayName = this.format_in_timezone(time, { weekday: 'short' });
const dayMap = { 'Sun': 0, 'Mon': 1, 'Tue': 2, 'Wed': 3, 'Thu': 4, 'Fri': 5, 'Sat': 6 };
return dayMap[dayName] ?? null;
}
/**
* Get full day name ("Monday", "Tuesday", etc.)
* Uses user's timezone
*
* @param {*} time
* @returns {string}
*/
static dow_human(time) {
const date = this.parse(time);
if (!date) return '';
return this.format_in_timezone(time, { weekday: 'long' });
}
/**
* Get short day name ("Mon", "Tue", etc.)
* Uses user's timezone
*
* @param {*} time
* @returns {string}
*/
static dow_short(time) {
const date = this.parse(time);
if (!date) return '';
return this.format_in_timezone(time, { weekday: 'short' });
}
/**
* Get month (1-12)
* Uses user's timezone
*
* @param {*} time
* @returns {number|null}
*/
static month(time) {
const date = this.parse(time);
if (!date) return null;
// Use 2-digit to get padded month, then parse
const monthStr = this.format_in_timezone(time, { month: '2-digit' });
return parseInt(monthStr, 10);
}
/**
* Get full month name ("January", "February", etc.)
* Uses user's timezone
*
* @param {*} time
* @returns {string}
*/
static month_human(time) {
const date = this.parse(time);
if (!date) return '';
return this.format_in_timezone(time, { month: 'long' });
}
/**
* Get short month name ("Jan", "Feb", etc.)
* Uses user's timezone
*
* @param {*} time
* @returns {string}
*/
static month_human_short(time) {
const date = this.parse(time);
if (!date) return '';
return this.format_in_timezone(time, { month: 'short' });
}
/**
* Get year (e.g., 2025)
* Uses user's timezone
*
* @param {*} time
* @returns {number|null}
*/
static year(time) {
const date = this.parse(time);
if (!date) return null;
return parseInt(this.format_in_timezone(time, { year: 'numeric' }), 10);
}
/**
* Get hour (0-23)
* Uses user's timezone
*
* @param {*} time
* @returns {number|null}
*/
static hour(time) {
const date = this.parse(time);
if (!date) return null;
// Use hour12: false and 2-digit for consistent 24-hour format
const hourStr = this.format_in_timezone(time, { hour: '2-digit', hour12: false });
// "24" is returned for midnight in some locales, treat as 0
const hour = parseInt(hourStr, 10);
return hour === 24 ? 0 : hour;
}
/**
* Get minute (0-59)
* Uses user's timezone
*
* @param {*} time
* @returns {number|null}
*/
static minute(time) {
const date = this.parse(time);
if (!date) return null;
return parseInt(this.format_in_timezone(time, { minute: '2-digit' }), 10);
}
}