diff --git a/components/UptimeExpire.vue b/components/UptimeExpire.vue new file mode 100644 index 000000000..e94918ad2 --- /dev/null +++ b/components/UptimeExpire.vue @@ -0,0 +1,56 @@ + + + diff --git a/helpers/time/buildTimeString.ts b/helpers/time/buildTimeString.ts new file mode 100644 index 000000000..1856b8e15 --- /dev/null +++ b/helpers/time/buildTimeString.ts @@ -0,0 +1,42 @@ +import { TimeStringsObject } from '~/types/time'; + +const buildStringFromValues = ({ + years, months, days, hours, minutes, seconds, firstDateWasLater, displaySeconds, +}: TimeStringsObject) => { + const result = []; + + type DateStrings = { + [key: string]: string; + }; + const dateStrings: DateStrings = { + year: 'year', + years: 'years', + month: 'month', + months: 'months', + day: 'day', + days: 'days', + hour: 'hour', + hours: 'hours', + minute: 'minute', + minutes: 'minutes', + second: 'second', + seconds: 'seconds', + firstDateWasLater: 'ago', + delimiter: ' ', + }; + const pluralize = (num: number, word: string) => { + const index = word + (num === 1 ? '' : 's'); + return `${num} ${dateStrings[index]}`; + }; + + if (years) result.push(pluralize(years, 'year')); + if (months) result.push(pluralize(months, 'month')); + if (days) result.push(pluralize(days, 'day')); + if (hours) result.push(pluralize(hours, 'hour')); + if (minutes) result.push(pluralize(minutes, 'minute')); + if (seconds && ((!years && !months && !days && !hours && !minutes) || displaySeconds)) result.push(pluralize(seconds, 'second')); + if (firstDateWasLater) result.push(dateStrings.firstDateWasLater); + return result.join(dateStrings.delimiter); +} + +export default buildStringFromValues; \ No newline at end of file diff --git a/helpers/time/dateDiff.ts b/helpers/time/dateDiff.ts new file mode 100644 index 000000000..2a2b60af4 --- /dev/null +++ b/helpers/time/dateDiff.ts @@ -0,0 +1,11 @@ +import dayjs from 'dayjs'; +import preciseDateDiff from './preciseDateDiff'; + +const readbleDifference = (a = '', b = '') => { + const x = a ? dayjs(parseInt(a, 10)) : dayjs(); + const y = b ? dayjs(parseInt(b, 10)) : dayjs(); + return preciseDateDiff(x, y); +}; +const dateDiff = (time: string, countUp: boolean) => countUp ? readbleDifference(time, '') : readbleDifference('', time); + +export default dateDiff; diff --git a/helpers/time/dateFormat.ts b/helpers/time/dateFormat.ts new file mode 100644 index 000000000..5c83b7aa6 --- /dev/null +++ b/helpers/time/dateFormat.ts @@ -0,0 +1,5 @@ +import dayjs from 'dayjs'; + +const formatDate = (date: string): string => dayjs(parseInt(date, 10)).format('llll'); + +export default formatDate; diff --git a/helpers/time/preciseDateDiff.ts b/helpers/time/preciseDateDiff.ts new file mode 100644 index 000000000..58b07c2ec --- /dev/null +++ b/helpers/time/preciseDateDiff.ts @@ -0,0 +1,72 @@ +import dayjs from 'dayjs'; +import { TimeStringsObject } from '~/types/time'; + +/** + * Original meat and potatos from: + * @version: 1.0.1 + * @author: huangjinlin + * @repo: https://github.com/huangjinlin/dayjs-precise-range + */ +const buildValueObject = (yDiff: number, mDiff: number, dDiff: number, hourDiff: number, minDiff: number, secDiff: number, firstDateWasLater: boolean): TimeStringsObject => ({ + years: yDiff, + months: mDiff, + days: dDiff, + hours: hourDiff, + minutes: minDiff, + seconds: secDiff, + firstDateWasLater, +}); +const preciseDateDiff = (d1: dayjs.Dayjs, d2: dayjs.Dayjs): TimeStringsObject => { + let m1 = dayjs(d1); + let m2 = dayjs(d2); + let firstDateWasLater; + + if (m1.isSame(m2)) { + return buildValueObject(0, 0, 0, 0, 0, 0, false); + } + if (m1.isAfter(m2)) { + const tmp = m1; + m1 = m2; + m2 = tmp; + firstDateWasLater = true; + } else { + firstDateWasLater = false; + } + + let yDiff = m2.year() - m1.year(); + let mDiff = m2.month() - m1.month(); + let dDiff = m2.date() - m1.date(); + let hourDiff = m2.hour() - m1.hour(); + let minDiff = m2.minute() - m1.minute(); + let secDiff = m2.second() - m1.second(); + + if (secDiff < 0) { + secDiff = 60 + secDiff; + minDiff -= 1; + } + if (minDiff < 0) { + minDiff = 60 + minDiff; + hourDiff -= 1; + } + if (hourDiff < 0) { + hourDiff = 24 + hourDiff; + dDiff -= 1; + } + if (dDiff < 0) { + const daysInLastFullMonth = dayjs(`${m2.year()}-${m2.month() + 1}`).subtract(1, 'M').daysInMonth(); + if (daysInLastFullMonth < m1.date()) { // 31/01 -> 2/03 + dDiff = daysInLastFullMonth + dDiff + (m1.date() - daysInLastFullMonth); + } else { + dDiff = daysInLastFullMonth + dDiff; + } + mDiff -= 1; + } + if (mDiff < 0) { + mDiff = 12 + mDiff; + yDiff -= 1; + } + + return buildValueObject(yDiff, mDiff, dDiff, hourDiff, minDiff, secDiff, firstDateWasLater); +}; + +export default preciseDateDiff; diff --git a/package-lock.json b/package-lock.json index 1ca00e193..4a19ac5a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,8 @@ "hasInstallScript": true, "dependencies": { "@pinia/nuxt": "^0.4.11", - "crypto-js": "^4.1.1" + "crypto-js": "^4.1.1", + "dayjs": "^1.11.7" }, "devDependencies": { "@nuxtjs/tailwindcss": "^6.7.0", @@ -3703,6 +3704,11 @@ "node": ">= 12" } }, + "node_modules/dayjs": { + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", + "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", diff --git a/package.json b/package.json index a42a2382d..afcce6d16 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ }, "dependencies": { "@pinia/nuxt": "^0.4.11", - "crypto-js": "^4.1.1" + "crypto-js": "^4.1.1", + "dayjs": "^1.11.7" }, "overrides": { "vue": "latest" diff --git a/types/time.ts b/types/time.ts new file mode 100644 index 000000000..705d27cff --- /dev/null +++ b/types/time.ts @@ -0,0 +1,10 @@ +export interface TimeStringsObject { + years: number; + months: number; + days: number; + hours: number; + minutes: number; + seconds: number; + firstDateWasLater: boolean; + displaySeconds?: boolean; +}; \ No newline at end of file