//replace js with ts in the url to get the typescript equivalent "use strict"; const daynames: string[] = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; const monthnames: string[] = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; const daynamesFull: string[] = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; const monthnamesFull: string[] = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; /** * tests is the function is strict */ function isStrict() { return (function (this: any): any { return !this; })(); } /** * internal use only * @param format * @param date * @param utc */ function _replaceDate(format: string, date: Date | UDate, utc: boolean = false): string { if (!(date instanceof UDate)) { date = new Date(date); } let local: string = format; let year4: number = date.getFullYear(); let month: number = (date.getMonth() + 1); let dayOfMonth: number = date.getDate(); let dayOfWeek: number = date.getDay(); let hour24: number = date.getHours(); let minutes: number = date.getMinutes(); let seconds: number = date.getSeconds(); if (utc && date.constructor === Date) { year4 = date.getUTCFullYear(); month = (date.getUTCMonth() + 1); dayOfMonth = date.getUTCDate(); dayOfWeek = date.getUTCDay(); hour24 = date.getUTCHours(); minutes = date.getUTCMinutes(); seconds = date.getUTCSeconds(); } let time: number = date.getTime(); const year2: string = year4.toString().slice(-2); const hour12: number = ((hour24 % 12) || 12); const dayOfYear: string = Math.floor((time - (new Date(year4, 0, 0)).getTime()) / (24 * 60 * 60 * 1000)).toString(); local = local // predefined Timetags .replace(/\[DateTimeString]/ig, '[DateString] [TimeString]') .replace(/\[DateString]/ig, '[3dayName] [3MonthName] [pre0-dayNumber] [year4]') .replace(/\[TimeString]/ig, '[pre0-hour24]:[pre0-minutes]:[pre0-seconds]') .replace(/\[tojavascript]/ig, '[year4]-[pre0-monthNumber]-[pre0-dayNumber]T[pre0-hour24]:[pre0-minutes]:[pre0-seconds]Z') .replace(/\[toHeader]/ig, '[3dayname], [pre0-daynumber] [3monthname] [year4] [pre0-hour24]:[pre0-minutes]:[pre0-seconds]') .replace(/\[toMYSQLi]/ig, '[year4]-[pre0-monthNumber]-[pre0-dayNumber] [pre0-hour24]:[pre0-minutes]:[pre0-seconds]') // Years .replace(/\[Year4]|\[Y4]/ig, year4.toString()) .replace(/\[Year2]|\[Y2]/ig, year2) // Hours .replace(/\[Hours?]/ig, hour24.toString()) .replace(/\[Hour24]|\[H2]/ig, hour24.toString()) .replace(/\[Hour12]|\[H1]/ig, hour12.toString()) .replace(/\[pre0-Hour12]|\[0H1]/ig, hour12.toString().padStart(2, '0')) .replace(/\[pre0-Hour24]|\[0H2]/ig, hour24.toString().padStart(2, '0')) .replace(/\[AM]/ig, (hour24 < 12) ? 'AM' : 'PM') .replace(/\[pm]/ig, (hour24 < 12) ? 'am' : 'pm') // Minutes and Seconds .replace(/\[Minutes?]|\[m]/ig, minutes.toString()) .replace(/\[seconds?]|\[s]/ig, seconds.toString()) .replace(/\[pre0-Minutes?]|\[0m]/ig, minutes.toString().padStart(2, '0')) .replace(/\[pre0-seconds?]|\[0s]/ig, seconds.toString().padStart(2, '0')) // DayNumbers .replace(/\[DayNumberWeek]|\[dnw]/ig, dayOfWeek.toString()) .replace(/\[DayNumberMonth]|\[dnm]|\[DayNumber]/ig, dayOfMonth.toString()) .replace(/\[pre0-DayNumberWeek]|\[0dnw]/ig, dayOfWeek.toString().padStart(2, '0')) .replace(/\[pre0-DayNumberMonth]|\[0dnm]|\[pre0-DayNumber]/ig, dayOfMonth.toString().padStart(2, '0')) .replace(/\[DayNumberYear]|\[DNY]/ig, dayOfYear) .replace(/\[pre0-DayNumberYear]|\[0DNY]/ig, dayOfYear.padStart(3, '0')) //Months .replace(/\[DayName]|\[dn]/ig, daynamesFull[(dayOfWeek)]) .replace(/\[3DayName]|\[3dn]/ig, daynames[(dayOfWeek)]) .replace(/\[MonthName]|\[mn]/ig, monthnamesFull[month - 1]) .replace(/\[3MonthName]|\[3mn]/ig, monthnames[month - 1]) .replace(/\[MonthNumber]|\[mu]/ig, month.toString()) .replace(/\[pre0-MonthNumber]|\[0mu]/ig, month.toString().padStart(2, '0')) .replace(/\[timestamp]|\[time]|\[ts?]/i, Math.floor(time / 1000).toString()) .replace(/\[iso]/ig, date.toISOString()); return (local); } /** * constructs a Date object from the following parameters * @param year The year, if its a Date Object it will create a new one with the same timestamp. * if its a string it gets parsed into a date format. if none of the params are specified it is assumed to be now. * if its the sole param and a number its a unix timestamp in seconds (if NaN its 2024) * @param month The month if specified and year isnt a date object or string, this is zero indexed. DEFAULT=0 * @param dayte The day of the month, starting from 1. DEFAULT=1 * @param hour The hour, starting from 0. DEFAULT=0 * @param minutes The minute, starting from 0. DEFAULT=0 * @param seconds The second, starting from 0. DEFAULT=0 */ function createDate(year?: number | string | Date, month?: number, dayte?: number, hour?: number, minutes?: number, seconds?: number): Date { if (year === undefined || year === null) { const d: Date = new Date(); return new Date(d.setMilliseconds(0)); } else if (year.constructor === Date) { return new Date(year); } else if ((typeof year) === 'number' && [month, dayte, hour, minutes, seconds].some( value => value !== null && value !== undefined)) { year = Number(year) ?? 2024; if (year !== year) year = 2024; if (year >= 0 && year < 70) { year += 2000; } month = month ?? 0; dayte = dayte ?? 1; hour = hour ?? 0; minutes = minutes ?? 0; seconds = seconds ?? 0; return new Date(Date.UTC(year, month, dayte, hour, minutes, seconds)); } else { return (new Date((new Date(year)).setMilliseconds(0))); } } const His = '[pre0-hour24]:[pre0-minutes]:[pre0-seconds]'; class UDate { private readonly date!: Date /** * constructs a Date object from the following parameters * @param year The year, if its a Date Object it will create a new one with the same timestamp. * if its a string it gets parsed into a date format. if none of the params are specified it is assumed to be now. * if its the sole param and a number its a unix timestamp in seconds (if NaN its 2024) * @param month The month if specified and year isnt a date object or string, this is zero indexed. DEFAULT=0 * @param dayte The day of the month, starting from 1. DEFAULT=1 * @param hour The hour, starting from 0. DEFAULT=0 * @param minutes The minute, starting from 0. DEFAULT=0 * @param seconds The second, starting from 0. DEFAULT=0 */ constructor(year?: number | string | Date, month?: number, dayte?: number, hour?: number, minutes?: number, seconds?: number) { this.date = createDate(year, month, dayte, hour, minutes, seconds); } /** * get the Milliseconds since 1970 */ getTime(): number { return this.date.getTime(); } /** * get the DayNumberWeek in UTC */ getDayNumberWeek() { return this.date.getUTCDay(); } /** * get the DayNumberWeek in UTC * @see getDayNumberWeek */ getDay() { return this.getDayNumberWeek(); } /** * get the DayNumberMonth in UTC */ getDayNumberMonth() { return this.getDayNumber(); } /** * get the DayNumberMonth in UTC * @see getDayNumberMonth */ getDayNumber() { return this.date.getUTCDate(); } /** * get the DayNumberMonth in UTC * @see getDayNumberMonth */ getDate() { return this.getDayNumberMonth(); } /** * returns the Current Year minus 1900 in UTC * @see getFullYear for the real current year */ getYear() { return this.date.getUTCFullYear() - 1900; } /** * returns the Current Year */ getFullYear() { return this.date.getUTCFullYear(); } /** * returns Month of the Year minus 1 for zero index in UTC */ getMonth() { return this.date.getUTCMonth(); } /** * returns the full day name in UTC */ getDayName() { return this.formatDate('[dayName]'); } /** * returns the full month name in UTC */ getMonthName() { return this.formatDate('[MonthName]'); } /** * returns the hour 24 */ getHours() { return this.date.getUTCHours(); } /** * returns the minute */ getMinutes(): number { return this.date.getUTCMinutes(); } /** * returns the seconds */ getSeconds(): number { return this.date.getUTCSeconds(); } /** * converts this to a promitive * @param hint */ [Symbol.toPrimitive](hint: 'default' | 'number' | 'string'): string | number { switch (hint) { case 'string': return this.formatDate(`[3dayName], [pre0-dayNumber] [3monthName] [year4] ${His}`); case'default': case'number': return this.date.getTime(); default: } throw new Error(`Expected: 'default' | 'number' | 'string': got "${hint}" instead`); } toString() { return this[Symbol.toPrimitive]('string'); } valueOf() { return this[Symbol.toPrimitive]('number'); } /** * formats the date * @param format * @alias formatDate */ toFormat(format: string = '[tojavascript]'): string { return this.formatDate(format); } /** * formats the date in UTC * @param format */ formatDate(format: string = '[tojavascript]'): string { const date: Date = this.date; return _replaceDate(format, date, true); } toISOString() { return this.date.toISOString(); } } /** * formats a Date Object in localTime * @param date Date Object * @param format format */ function formatDate(date: Date, format: string = '[year4]-[pre0-monthNumber]-[pre0-dayNumber]T[pre0-hour24]:[pre0-minutes]:[pre0-seconds]'): string { return _replaceDate(format, date); } /** * returns '+' if the number is positive or 0, and '-' if its negative, 'NaN' if Number(num) is NaN * @param num the number (or BigInt) * @param plusIfZero if true returns '+' if num equals to 0, if false it returns '0', if anything else its truthy value * is checked */ function Mathsign(num: number | BigInt, plusIfZero: boolean = false): string { switch (Math.sign(Number(num)).toString()) { case'1': return '+'; case'-1': return '-'; case'0': return Boolean(plusIfZero) ? '+' : '0'; case'NaN': return 'NaN'; } throw new Error('Math.sign did not return either -1 0 or 1'); } const tin_s: number = 1; const tin_m: number = 60; const tin_h: number = 60 * 60; const tin_d: number = (60 * 60) * 24; /** * calculates a human time thing from seconds */ function timeDecode(seconds: number): any { const else_d: number = seconds % tin_d; const else_h: number = else_d % tin_h; return { 'ResultS': Math.floor(else_h % tin_m), 'Minutes': Math.floor(else_h / tin_m), 'Hours': Math.floor(else_d / tin_h), 'Days': Math.floor(seconds / tin_d), }; } /** * adds these values and returns seconds * @param seconds * @param minutes * @param hours__ * @param days_24 */ function timeEncode(seconds: number, minutes: number, hours__: number, days_24: number): number { let result: number = 0; result += (seconds * tin_s); result += (minutes * tin_m); result += (hours__ * tin_h); result += (days_24 * tin_d); return result; } /** * formats * @param seconds * @param format */ function timeDecode_formatted(seconds: number, format: string = '[0day]:[0hours]:[0minute]:[0seconds]s'): string { return (Mathsign(seconds) + time_decode_formatted(Math.abs(seconds), format)).replace(/^\+/, ' '); } function time_decode_formatted(seconds: number, format: string = '[0day]:[0hours]:[0minute]:[0seconds]s'): string { const array = timeDecode(seconds); let result: string = format; const secondsStr: string = `${array['ResultS']}`.replace(/-/, ''); const Minutes: string = `${array['Minutes']}`.replace(/-/, ''); const Hours: string = `${array['Hours']}`.replace(/-/, ''); const Days: string = `${array['Days']}`.replace(/-/, ''); result = result.replace(/\[0Seconds?]/gi, secondsStr.padStart(2, '0')); result = result.replace(/\[0Minutes?]/gi, Minutes.padStart(2, '0')); result = result.replace(/\[0Hours?]/gi, Hours.padStart(2, '0')); result = result.replace(/\[0Days?]/gi, Days.padStart(2, '0')); result = result.replace(/\[Seconds?]/gi, secondsStr); result = result.replace(/\[Minutes?]/gi, Minutes); result = result.replace(/\[Hours?]/gi, Hours); result = result.replace(/\[Days?]/gi, Days); return [result][+![]]; } function mktime( hour: number, minute: number | null = null, second: number | null = null, month: number | null = null, day: number | null = null, year: number | null = null): Date { const today: Date = new Date(); year = year !== null ? +year : today.getFullYear(); if (year >= 0 && year <= 100) { year += (year < 70) ? 2000 : 1900; } month = (month ?? (today.getMonth() + 1)) - 1; day = day ?? today.getDate(); minute = minute ?? today.getMinutes(); second = second ?? today.getSeconds(); return new Date(year, month, day, hour, minute, second); } function mktime_array( hour: number, minute: number | null = null, second: number | null = null, month: number | null = null, day: number | null = null, year: number | null = null): number { return mktime(hour, minute, second, month, day, year).getTime() / 1000; } function days_since_2000(date?: Date): number { const now: Date = new Date(); return ((date ?? now).getTime() - (new Date(2000, 0)).getTime()) / (1000 * 60 * 60 * 24) } function is_nightmare(date?: Date): boolean { const days_since2000: number = Math.floor(days_since_2000(date)); const num: number = days_since2000 % 30; return num === 1 || num === 2 || num === 3; } function addToDate(date: any, years: number = 0, months: number = 0, days: number = 0, hours: number = 0, minutes: number = 0, seconds: number = 0): Date { if (!(date instanceof Date)) date = new Date(date); return new Date(date.getFullYear() + years, date.getMonth() + months, date.getDate() + days, date.getHours() + hours, date.getMinutes() + minutes, date.getSeconds() + seconds, date.getMilliseconds()); } function addToTime(date: any, hours: number = 0, minutes: number = 0, seconds: number = 0, months: number = 0, days: number = 0, years: number = 0): Date { return addToDate(date, years, months, days, hours, minutes, seconds); } function offsetDate(years: number = 0, months: number = 0, days: number = 0, hours: number = 0, minutes: number = 0, seconds: number = 0): Date { return addToDate(new Date(), years, months, days, hours, minutes, seconds); } function getTimeZoneLetter(date: Date): string { // Get the UTC offset in minutes const utcOffsetMinutes = date.getTimezoneOffset(); // Calculate the UTC offset in hours (rounded to the nearest hour) const utcOffsetHours = Math.round(-utcOffsetMinutes / 60); // Determine the letter based on the offset const letters: string[] = [ 'Y', // UTC-12 'X', // UTC-11 'W', // UTC-10 'V', // UTC-9 'U', // UTC-8 'T', // UTC-7 'S', // UTC-6 'R', // UTC-5 'Q', // UTC-4 'P', // UTC-3 'O', // UTC-2 'N', // UTC-1 'Z', // UTC=0 'A', // UTC+1 'B', // UTC+2 'C', // UTC+3 'D', // UTC+4 'E', // UTC+5 'F', // UTC+6 'G', // UTC+7 'H', // UTC+8 'I', // UTC+9 'K', // UTC+10 'L', // UTC+11 'M', // UTC+12 ]; // Ensure the offset is within the range -12 to +12 if (utcOffsetHours < -12 || utcOffsetHours > 12) { throw new Error('UTC offset out of range.'); } // Return the corresponding letter return letters[utcOffsetHours + 12]; // Offset by 12 for correct indexing } function generateTimeTag(date: Date): string { const currentTimestamp = (new Date((new Date()).setMilliseconds(0))).getTime(); if (date.getTime() > currentTimestamp) { throw new Error("The date cannot be in the future."); } const diffInSeconds = Math.floor((currentTimestamp - Math.floor(date.getTime())) / 1000); let output = ''; if (diffInSeconds < 30) { output = "now"; } else if (diffInSeconds < 3600) { // Less than an hour const minutes = Math.floor(diffInSeconds / 60); output = `${minutes} minutes ago`; } else if (diffInSeconds < 86400) { // Less than a day const hours = Math.floor(diffInSeconds / 3600); output = `${hours} hours ago`; } else if (diffInSeconds < 2592000) { // Less than a month const days = Math.floor(diffInSeconds / 86400); output = `${days} days ago`; } else if (diffInSeconds < 31536000) { // Less than a year const months = Math.floor(diffInSeconds / 2592000); output = `${months} months ago`; } else { const years = Math.floor(diffInSeconds / 31536000); const months = Math.floor((diffInSeconds % 31536000) / 2592000); if (years >= 10) { output = "more than 10 years ago"; } else if (years >= 1) { output = `${years} years and ${months} months ago`; } } return ``; } function totimetagHTML(date: Date, $TimeTags: string = '[DateTimeString]') { const html: string = htmlencode(formatDate(date, $TimeTags)); return ``; } function _Math_abs(var_: number | null = null): number | null { if (var_ === null) { return null; } else { return Math.abs(var_); } } function _Math_abs_zroIfNULL(var_: any): number { return Math.abs(Number(var_)); } const THE_START: Date = (new Date(2024, 5, 19));