parseTimestamp refactor, was broken for non-ms-bearing humanized timestamps

7956dc0b3fa2bba95c3632f1b4334d893f5b9840

Succubyss <87207237+Succubyss@users.noreply.github.com>

1 files changed, +28 -23Ignore whitespace
public/scripts/utils.js+28 -23
@@ -723,42 +723,47 @@ export function timestampToMoment(timestamp) {
723}723}
724724
725function parseTimestamp(timestamp) {725function parseTimestamp(timestamp) {
726 if (!timestamp) {726 if (!timestamp) return moment.invalid();
727 return moment.invalid();
728 }
729727
730 // Unix time (legacy TAI / tags)728 // Unix time (legacy TAI / tags)
731 if (typeof timestamp === 'number' || /^\d+$/.test(timestamp)) {729 if (typeof timestamp === 'number' || /^\d+$/.test(timestamp)) {
732 if (isNaN(timestamp) || !isFinite(timestamp) || timestamp < 0) {730 if (isNaN(timestamp)) return moment.invalid();
733 return moment.invalid();731 if (!isFinite(timestamp)) return moment.invalid();
734 }732 if (timestamp < 0) return moment.invalid();
735 return moment(Number(timestamp));733 return moment(Number(timestamp));
736 }734 }
737735
738 // ST "humanized" format pattern736 let dtFmt = [];
739 const pattern1 = /(\d{4})-(\d{1,2})-(\d{1,2}) @(\d{1,2})h (\d{1,2})m (\d{1,2})s (\d{1,3})ms/;
740 const replacement1 = (match, year, month, day, hour, minute, second, millisecond) => {
741 return `${year.padStart(4, '0')}-${month.padStart(2, '0')}-${day.padStart(2, '0')}T${hour.padStart(2, '0')}:${minute.padStart(2, '0')}:${second.padStart(2, '0')}.${millisecond.padStart(3, '0')}Z`;
742 };
743 const isoTimestamp1 = timestamp.replace(pattern1, replacement1);
744 if (moment(isoTimestamp1).isValid()) {
745 return moment(isoTimestamp1);
746 }
747737
748 // New format pattern: "June 19, 2023 4:13pm"738 // meridiem-based format
749 const pattern2 = /(\w+)\s(\d{1,2}),\s(\d{4})\s(\d{1,2}):(\d{1,2})(am|pm)/i;739 const convertFromMeridiemBased = (_, month, day, year, hour, minute, meridiem) => {
750 const replacement2 = (match, month, day, year, hour, minute, meridiem) => {
751 const monthNum = moment().month(month).format('MM');740 const monthNum = moment().month(month).format('MM');
752 const hour24 = meridiem.toLowerCase() === 'pm' ? (parseInt(hour, 10) % 12) + 12 : parseInt(hour, 10) % 12;741 const hour24 = meridiem.toLowerCase() === 'pm' ? (parseInt(hour, 10) % 12) + 12 : parseInt(hour, 10) % 12;
753 return `${year}-${monthNum}-${day.padStart(2, '0')}T${hour24.toString().padStart(2, '0')}:${minute.padStart(2, '0')}:00`;742 return `${year}-${monthNum}-${day.padStart(2, '0')}T${hour24.toString().padStart(2, '0')}:${minute.padStart(2, '0')}:00`;
754 };743 };
755 const isoTimestamp2 = timestamp.replace(pattern2, replacement2);744 // June 19, 2023 2:20pm
756 if (moment(isoTimestamp2).isValid()) {745 dtFmt.push({ callback: convertFromMeridiemBased, pattern: /(\w+)\s(\d{1,2}),\s(\d{4})\s(\d{1,2}):(\d{1,2})(am|pm)/i });
757 return moment(isoTimestamp2);746
747 // ST "humanized" format patterns
748 const convertFromHumanized = (_, year, month, day, hour, min, sec, ms) => {
749 ms = typeof ms !== 'undefined' ? `.${ms.padStart(3, '0')}` : '';
750 return `${year.padStart(4, '0')}-${month.padStart(2, '0')}-${day.padStart(2, '0')}T${hour.padStart(2, '0')}:${min.padStart(2, '0')}:${sec.padStart(2, '0')}${ms}Z`;
751 };
752 // 2024-7-12@01h31m37s
753 dtFmt.push({ callback: convertFromHumanized, pattern: /(\d{4})-(\d{1,2})-(\d{1,2})@(\d{1,2})h(\d{1,2})m(\d{1,2})s/ });
754 // 2024-6-5 @14h 56m 50s 682ms
755 dtFmt.push({ callback: convertFromHumanized, pattern: /(\d{4})-(\d{1,2})-(\d{1,2}) @(\d{1,2})h (\d{1,2})m (\d{1,2})s (\d{1,3})ms/ });
756
757 let iso8601;
758 for (const x of dtFmt) {
759 let rgxMatch = timestamp.match(x.pattern)
760 if (!rgxMatch) continue;
761 iso8601 = x.callback(...rgxMatch);
762 break;
758 }763 }
759764
760 // If none of the patterns match, return an invalid moment object765 // If one of the patterns matched, return a valid moment object, otherwise return an invalid moment object
761 return moment.invalid();766 return iso8601 ? moment(iso8601) : moment.invalid();
762}767}
763768
764/**769/**