From f32b4841c8e607f068825b6f88746ef783fdbd0b Mon Sep 17 00:00:00 2001 From: Valexr Date: Sun, 5 May 2024 21:25:13 +0200 Subject: [PATCH] cleanup --- package.json | 1 - src/lib/counters.ts | 74 +-------- src/lib/jsDate.js | 368 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 375 insertions(+), 68 deletions(-) create mode 100644 src/lib/jsDate.js diff --git a/package.json b/package.json index 3602331..8d00854 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,6 @@ "devDependencies": { "@types/luxon": "^3.4.2", "@types/node": "^20.12.8", - "dayjs": "^1.11.11", "esbuild": "^0.20.2", "esbuild-svelte": "^0.8.0", "luxon": "^3.4.4", diff --git a/src/lib/counters.ts b/src/lib/counters.ts index a7678c2..e6bfef0 100644 --- a/src/lib/counters.ts +++ b/src/lib/counters.ts @@ -1,7 +1,7 @@ import { Writable, derived } from 'svelte/store'; import { dates } from './dates'; import { quotes } from './quotes'; -import { DateTime, Interval, Duration } from "luxon"; +import { DateTime, Interval } from "luxon"; export const counters = derived<[Writable, Writable], Counter[]>(([dates, quotes]), ([$dates, $quotes], set) => { @@ -9,48 +9,21 @@ export const counters = derived<[Writable, Writable], Coun set($dates.map(({ start, title, quote }, id) => count(id, start, title, quote))) function count(id: number, start: string, title: string, quote: Quote) { - const elapsed = elapse(start) - - // console.log(title, convert(elapsed.ms)) + const { years, months, weeks, days, interval } = elapse(start) return { id, title, quote: quote || quotes.random(id), start: start, - years: elapsed.years, - months: elapsed.months, - days: elapsed.days, - weeks: elapsed.weeks, + years, months, days, weeks, full: { - months: Math.trunc(elapsed.interval.length('months')), - weeks: Math.trunc(elapsed.interval.length('weeks')), - days: Math.trunc(elapsed.interval.length('days')), - hours: Math.trunc(elapsed.interval.length('hours')), - // months: Math.trunc(elapsed.duration.as('months')), - // weeks: Math.trunc(elapsed.duration.as('weeks')), - // days: Math.trunc(elapsed.duration.as('days')), - // hours: Math.trunc(elapsed.duration.as('hours')), - // months: elapsed.years * 12 + elapsed.months, - // weeks: Math.trunc(elapsed.ms / (3600000 * 24 * 7)), - // days: Math.trunc(elapsed.ms / (3600000 * 24)), - // hours: Math.trunc(elapsed.ms / 3600000) + months: Math.trunc(interval.length('months')), + weeks: Math.trunc(interval.length('weeks')), + days: Math.trunc(interval.length('days')), + hours: Math.trunc(interval.length('hours')), } } } }, []) function elapse(start: string) { - // const FROM = new Date(start) - // const TO = new Date() - - // const DATE = new Date(TO.getTime() - FROM.getTime()); - - // DATE.setDate(FROM.getUTCDate()) - // console.log(FROM, TO, DATE) - - // const leap = new Date(year, 1, 29).getDate() === 29; - - // const years = DATE.getUTCFullYear() - 1970 - // const months = DATE.getUTCMonth() - // const days = DATE.getUTCDate() - 1 - const TO = DateTime.now(); const FROM = DateTime.fromISO(start); @@ -64,40 +37,7 @@ function elapse(start: string) { months: DIFF.months || 0, days: DIFF.days || 0, weeks: DIFF.weeks || 0, - // ms: DIFF.milliseconds || 0, - duration: Duration.fromObject(DIFF), interval: Interval.fromDateTimes(FROM, TO) - // days: days % 7, - // weeks: Math.floor(days / 7), - // hours: DATE.getUTCHours(), - // minutes: DATE.getUTCMinutes(), - // seconds: DATE.getUTCSeconds(), - // ms: DATE.getTime() } }; - -function convert(ms: number) { - let Y, M, W, D, h, m, s; - s = Math.floor(ms / 1000); - m = Math.floor(s / 60); - s = s % 60; - h = Math.floor(m / 60); - m = m % 60; - - D = Math.floor(h / 24); - h = h % 24; - - W = Math.floor(D / 7); - D = W % 7; - - M = Math.floor(W / 4); - W = M % 4; - - Y = Math.floor(M / 12); - M = M % 12 - - // Y = Y; - return { Y, M, W, D }; -} - diff --git a/src/lib/jsDate.js b/src/lib/jsDate.js new file mode 100644 index 0000000..cd0107d --- /dev/null +++ b/src/lib/jsDate.js @@ -0,0 +1,368 @@ +/* +Name: jsDate +Desc: VBScript native Date functions emulated for Javascript +Author: Rob Eberhardt, Slingshot Solutions - http://slingfive.com/ +Note: see jsDate.txt for more info +*/ + +// constants +var vbGeneralDate = 0, vbLongDate = 1, vbShortDate = 2, vbLongTime = 3, vbShortTime = 4, // NamedFormat + vbUseSystemDayOfWeek = 0, vbSunday = 1, vbMonday = 2, vbTuesday = 3, vbWednesday = 4, vbThursday = 5, vbFriday = 6, vbSaturday = 7, // FirstDayOfWeek + vbUseSystem = 0, vbFirstJan1 = 1, vbFirstFourDays = 2, vbFirstFullWeek = 3; // FirstWeekOfYear + +// arrays (1-based) +Date.MonthNames = [null, 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; +Date.WeekdayNames = [null, 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + + + + +Date.IsDate = function (p_Expression) { + if (p_Expression === null) { return false; } + return !isNaN(new Date(p_Expression)); // <-- review further +}; + +Date.CDate = function (p_Date) { + if (Date.IsDate(p_Date)) { return new Date(p_Date); } + + var strTry = p_Date.replace(/\-/g, '/').replace(/\./g, '/').replace(/ /g, '/'); // fix separators + strTry = strTry.replace(/pm$/i, " pm").replace(/am$/i, " am"); // and meridian spacing + if (Date.IsDate(strTry)) { return new Date(strTry); } + + var strTryYear = strTry + '/' + new Date().getFullYear(); // append year + if (Date.IsDate(strTryYear)) { return new Date(strTryYear); } + + + if (strTry.indexOf(":")) { // if appears to have time + var strTryYear2 = strTry.replace(/ /, '/' + new Date().getFullYear() + ' '); // insert year + if (Date.IsDate(strTryYear2)) { return new Date(strTryYear2); } + + var strTryDate = new Date().toDateString() + ' ' + p_Date; // pre-pend current date + if (Date.IsDate(strTryDate)) { return new Date(strTryDate); } + } + + return false; // double as looser IsDate + //throw("Error #13 - Type mismatch"); // or is this better? +}; + + + +Date.DateAdd = function (p_Interval, p_Number, p_Date) { + if (!Date.CDate(p_Date)) { return "invalid date: '" + p_Date + "'"; } + if (isNaN(p_Number)) { return "invalid number: '" + p_Number + "'"; } + + p_Number = new Number(p_Number); + var dt = Date.CDate(p_Date); + + switch (p_Interval.toLowerCase()) { + case "yyyy": { + dt.setFullYear(dt.getFullYear() + p_Number); + break; + } + case "q": { + dt.setMonth(dt.getMonth() + (p_Number * 3)); + break; + } + case "m": { + dt.setMonth(dt.getMonth() + p_Number); + break; + } + case "y": // day of year + case "d": // day + case "w": { // weekday + dt.setDate(dt.getDate() + p_Number); + break; + } + case "ww": { // week of year + dt.setDate(dt.getDate() + (p_Number * 7)); + break; + } + case "h": { + dt.setHours(dt.getHours() + p_Number); + break; + } + case "n": { // minute + dt.setMinutes(dt.getMinutes() + p_Number); + break; + } + case "s": { + dt.setSeconds(dt.getSeconds() + p_Number); + break; + } + case "ms": { // JS extension + dt.setMilliseconds(dt.getMilliseconds() + p_Number); + break; + } + default: { + return "invalid interval: '" + p_Interval + "'"; + } + } + return dt; +}; + + + +Date.DateDiff = function (p_Interval, p_Date1, p_Date2, p_FirstDayOfWeek) { + if (!Date.CDate(p_Date1)) { return "invalid date: '" + p_Date1 + "'"; } + if (!Date.CDate(p_Date2)) { return "invalid date: '" + p_Date2 + "'"; } + p_FirstDayOfWeek = (isNaN(p_FirstDayOfWeek) || p_FirstDayOfWeek == 0) ? vbSunday : parseInt(p_FirstDayOfWeek); // set default & cast + + var dt1 = Date.CDate(p_Date1); + var dt2 = Date.CDate(p_Date2); + + // correct DST-affected intervals ("d" & bigger) + if ("h,n,s,ms".indexOf(p_Interval.toLowerCase()) == -1) { + if (p_Date1.toString().indexOf(":") == -1) { dt1.setUTCHours(0, 0, 0, 0); }; // no time, assume 12am + if (p_Date2.toString().indexOf(":") == -1) { dt2.setUTCHours(0, 0, 0, 0); }; // no time, assume 12am + } + + + // get ms between UTC dates and make into "difference" date + var iDiffMS = dt2.valueOf() - dt1.valueOf(); + var dtDiff = new Date(iDiffMS); + + // calc various diffs + var nYears = dt2.getUTCFullYear() - dt1.getUTCFullYear(); + var nMonths = dt2.getUTCMonth() - dt1.getUTCMonth() + (nYears != 0 ? nYears * 12 : 0); + var nQuarters = parseInt(nMonths / 3); //<<-- different than VBScript, which watches rollover not completion + + var nMilliseconds = iDiffMS; + var nSeconds = parseInt(iDiffMS / 1000); + var nMinutes = parseInt(nSeconds / 60); + var nHours = parseInt(nMinutes / 60); + var nDays = parseInt(nHours / 24); // <-- now fixed for DST switch days + var nWeeks = parseInt(nDays / 7); + + + if (p_Interval.toLowerCase() == 'ww') { + // set dates to 1st & last FirstDayOfWeek + var offset = Date.DatePart("w", dt1, p_FirstDayOfWeek) - 1; + if (offset) { dt1.setDate(dt1.getDate() + 7 - offset); } + var offset = Date.DatePart("w", dt2, p_FirstDayOfWeek) - 1; + if (offset) { dt2.setDate(dt2.getDate() - offset); } + // recurse to "w" with adjusted dates + var nCalWeeks = Date.DateDiff("w", dt1, dt2) + 1; + } + // TODO: similar for 'w'? + + + // return difference + switch (p_Interval.toLowerCase()) { + case "yyyy": return nYears; + case "q": return nQuarters; + case "m": return nMonths; + case "y": // day of year + case "d": return nDays; + case "w": return nWeeks; + case "ww": return nCalWeeks; // week of year + case "h": return nHours; + case "n": return nMinutes; + case "s": return nSeconds; + case "ms": return nMilliseconds; // not in VBScript + default: return "invalid interval: '" + p_Interval + "'"; + } +}; + + + + +Date.DatePart = function (p_Interval, p_Date, p_FirstDayOfWeek) { + if (!Date.CDate(p_Date)) { return "invalid date: '" + p_Date + "'"; } + + var dtPart = Date.CDate(p_Date); + + switch (p_Interval.toLowerCase()) { + case "yyyy": return dtPart.getFullYear(); + case "q": return parseInt(dtPart.getMonth() / 3) + 1; + case "m": return dtPart.getMonth() + 1; + case "y": return Date.DateDiff("y", "1/1/" + dtPart.getFullYear(), dtPart) + 1; // day of year + case "d": return dtPart.getDate(); + case "w": return Date.Weekday(dtPart.getDay() + 1, p_FirstDayOfWeek); // weekday + case "ww": return Date.DateDiff("ww", "1/1/" + dtPart.getFullYear(), dtPart, p_FirstDayOfWeek) + 1; // week of year + case "h": return dtPart.getHours(); + case "n": return dtPart.getMinutes(); + case "s": return dtPart.getSeconds(); + case "ms": return dtPart.getMilliseconds(); // <-- JS extension, NOT in VBScript + default: return "invalid interval: '" + p_Interval + "'"; + } +}; + + + +Date.MonthName = function (p_Month, p_Abbreviate) { + if (isNaN(p_Month)) { // v0.94- compat: extract real param from passed date + if (!Date.CDate(p_Month)) { return "invalid month: '" + p_Month + "'"; } + p_Month = DatePart("m", Date.CDate(p_Month)); + } + + var retVal = Date.MonthNames[p_Month]; + if (p_Abbreviate == true) { retVal = retVal.substring(0, 3); } // abbr to 3 chars + return retVal; +}; + + +Date.WeekdayName = function (p_Weekday, p_Abbreviate, p_FirstDayOfWeek) { + if (isNaN(p_Weekday)) { // v0.94- compat: extract real param from passed date + if (!Date.CDate(p_Weekday)) { return "invalid weekday: '" + p_Weekday + "'"; } + p_Weekday = DatePart("w", Date.CDate(p_Weekday)); + } + p_FirstDayOfWeek = (isNaN(p_FirstDayOfWeek) || p_FirstDayOfWeek == 0) ? vbSunday : parseInt(p_FirstDayOfWeek); // set default & cast + + var nWeekdayNameIdx = ((p_FirstDayOfWeek - 1 + parseInt(p_Weekday) - 1 + 7) % 7) + 1; // compensate nWeekdayNameIdx for p_FirstDayOfWeek + var retVal = Date.WeekdayNames[nWeekdayNameIdx]; + if (p_Abbreviate == true) { retVal = retVal.substring(0, 3); } // abbr to 3 chars + return retVal; +}; + + +// adjusts weekday for week starting on p_FirstDayOfWeek +Date.Weekday = function (p_Weekday, p_FirstDayOfWeek) { + p_FirstDayOfWeek = (isNaN(p_FirstDayOfWeek) || p_FirstDayOfWeek == 0) ? vbSunday : parseInt(p_FirstDayOfWeek); // set default & cast + + return ((parseInt(p_Weekday) - p_FirstDayOfWeek + 7) % 7) + 1; +}; + + + + + +Date.FormatDateTime = function (p_Date, p_NamedFormat) { + if (p_Date.toUpperCase().substring(0, 3) == "NOW") { p_Date = new Date(); }; + if (!Date.CDate(p_Date)) { return "invalid date: '" + p_Date + "'"; } + if (isNaN(p_NamedFormat)) { p_NamedFormat = vbGeneralDate; }; + + var dt = Date.CDate(p_Date); + + switch (parseInt(p_NamedFormat)) { + case vbGeneralDate: return dt.toString(); + case vbLongDate: return Format(p_Date, 'DDDD, MMMM D, YYYY'); + case vbShortDate: return Format(p_Date, 'MM/DD/YYYY'); + case vbLongTime: return dt.toLocaleTimeString(); + case vbShortTime: return Format(p_Date, 'HH:MM:SS'); + default: return "invalid NamedFormat: '" + p_NamedFormat + "'"; + } +}; + + +Date.Format = function (p_Date, p_Format, p_FirstDayOfWeek, p_firstweekofyear) { + if (!Date.CDate(p_Date)) { return "invalid date: '" + p_Date + "'"; } + if (!p_Format || p_Format == '') { return dt.toString(); }; + + var dt = Date.CDate(p_Date); + + // Zero-padding formatter + this.pad = function (p_str) { + if (p_str.toString().length == 1) { p_str = '0' + p_str; } + return p_str; + }; + + var ampm = dt.getHours() >= 12 ? 'PM' : 'AM'; + var hr = dt.getHours(); + if (hr == 0) { hr = 12; }; + if (hr > 12) { hr -= 12; }; + var strShortTime = hr + ':' + this.pad(dt.getMinutes()) + ':' + this.pad(dt.getSeconds()) + ' ' + ampm; + var strShortDate = (dt.getMonth() + 1) + '/' + dt.getDate() + '/' + new String(dt.getFullYear()).substring(2, 4); + var strLongDate = Date.MonthName(dt.getMonth() + 1) + ' ' + dt.getDate() + ', ' + dt.getFullYear(); // + + var retVal = p_Format; + + // switch tokens whose alpha replacements could be accidentally captured + retVal = retVal.replace(new RegExp('C', 'gi'), 'CCCC'); + retVal = retVal.replace(new RegExp('mmmm', 'gi'), 'XXXX'); + retVal = retVal.replace(new RegExp('mmm', 'gi'), 'XXX'); + retVal = retVal.replace(new RegExp('dddddd', 'gi'), 'AAAAAA'); + retVal = retVal.replace(new RegExp('ddddd', 'gi'), 'AAAAA'); + retVal = retVal.replace(new RegExp('dddd', 'gi'), 'AAAA'); + retVal = retVal.replace(new RegExp('ddd', 'gi'), 'AAA'); + retVal = retVal.replace(new RegExp('timezone', 'gi'), 'ZZZZ'); + retVal = retVal.replace(new RegExp('time24', 'gi'), 'TTTT'); + retVal = retVal.replace(new RegExp('time', 'gi'), 'TTT'); + + // now do simple token replacements + retVal = retVal.replace(new RegExp('yyyy', 'gi'), dt.getFullYear()); + retVal = retVal.replace(new RegExp('yy', 'gi'), new String(dt.getFullYear()).substring(2, 4)); + retVal = retVal.replace(new RegExp('y', 'gi'), Date.DatePart("y", dt)); + retVal = retVal.replace(new RegExp('q', 'gi'), Date.DatePart("q", dt)); + retVal = retVal.replace(new RegExp('mm', 'gi'), this.pad(dt.getMonth() + 1)); + retVal = retVal.replace(new RegExp('m', 'gi'), (dt.getMonth() + 1)); + retVal = retVal.replace(new RegExp('dd', 'gi'), this.pad(dt.getDate())); + retVal = retVal.replace(new RegExp('d', 'gi'), dt.getDate()); + retVal = retVal.replace(new RegExp('hh', 'gi'), this.pad(dt.getHours())); + retVal = retVal.replace(new RegExp('h', 'gi'), dt.getHours()); + retVal = retVal.replace(new RegExp('nn', 'gi'), this.pad(dt.getMinutes())); + retVal = retVal.replace(new RegExp('n', 'gi'), dt.getMinutes()); + retVal = retVal.replace(new RegExp('ss', 'gi'), this.pad(dt.getSeconds())); + retVal = retVal.replace(new RegExp('s', 'gi'), dt.getSeconds()); + retVal = retVal.replace(new RegExp('t t t t t', 'gi'), strShortTime); + retVal = retVal.replace(new RegExp('am/pm', 'g'), dt.getHours() >= 12 ? 'pm' : 'am'); + retVal = retVal.replace(new RegExp('AM/PM', 'g'), dt.getHours() >= 12 ? 'PM' : 'AM'); + retVal = retVal.replace(new RegExp('a/p', 'g'), dt.getHours() >= 12 ? 'p' : 'a'); + retVal = retVal.replace(new RegExp('A/P', 'g'), dt.getHours() >= 12 ? 'P' : 'A'); + retVal = retVal.replace(new RegExp('AMPM', 'g'), dt.getHours() >= 12 ? 'pm' : 'am'); + // (always proceed largest same-lettered token to smallest) + + // now finish the previously set-aside tokens + retVal = retVal.replace(new RegExp('XXXX', 'gi'), Date.MonthName(dt.getMonth() + 1, false)); // + retVal = retVal.replace(new RegExp('XXX', 'gi'), Date.MonthName(dt.getMonth() + 1, true)); // + retVal = retVal.replace(new RegExp('AAAAAA', 'gi'), strLongDate); + retVal = retVal.replace(new RegExp('AAAAA', 'gi'), strShortDate); + retVal = retVal.replace(new RegExp('AAAA', 'gi'), Date.WeekdayName(dt.getDay() + 1, false, p_FirstDayOfWeek)); // + retVal = retVal.replace(new RegExp('AAA', 'gi'), Date.WeekdayName(dt.getDay() + 1, true, p_FirstDayOfWeek)); // + retVal = retVal.replace(new RegExp('TTTT', 'gi'), dt.getHours() + ':' + this.pad(dt.getMinutes())); + retVal = retVal.replace(new RegExp('TTT', 'gi'), hr + ':' + this.pad(dt.getMinutes()) + ' ' + ampm); + retVal = retVal.replace(new RegExp('CCCC', 'gi'), strShortDate + ' ' + strShortTime); + + // finally timezone + tz = dt.getTimezoneOffset(); + timezone = (tz < 0) ? ('GMT-' + tz / 60) : (tz == 0) ? ('GMT') : ('GMT+' + tz / 60); + retVal = retVal.replace(new RegExp('ZZZZ', 'gi'), timezone); + + return retVal; +}; + + + +// ==================================== + +/* if desired, map new methods to direct functions +*/ +var IsDate = Date.IsDate; +var CDate = Date.CDate; +var DateAdd = Date.DateAdd; +var DateDiff = Date.DateDiff; +var DatePart = Date.DatePart; +var MonthName = Date.MonthName; +var WeekdayName = Date.WeekdayName; +var Weekday = Date.Weekday; +var FormatDateTime = Date.FormatDateTime; +var Format = Date.Format; + + + +/* and other capitalizations for easier porting +isDate = IsDate; +dateAdd = DateAdd; +dateDiff = DateDiff; +datePart = DatePart; +monthName = MonthName; +weekdayName = WeekdayName; +formatDateTime = FormatDateTime; +format = Format; + +isdate = IsDate; +dateadd = DateAdd; +datediff = DateDiff; +datepart = DatePart; +monthname = MonthName; +weekdayname = WeekdayName; +formatdatetime = FormatDateTime; + +ISDATE = IsDate; +DATEADD = DateAdd; +DATEDIFF = DateDiff; +DATEPART = DatePart; +MONTHNAME = MonthName; +WEEKDAYNAME = WeekdayName; +FORMATDATETIME = FormatDateTime; +FORMAT = Format; +*/