Framework updates
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user