import { Injectable } from '@nestjs/common' import * as _ from 'lodash' import { DateTime, Settings, HourNumbers, MinuteNumbers, SecondNumbers, DayNumbers, WeekdayNumbers, } from 'luxon' Settings.defaultLocale = 'en-US' Settings.defaultZone = 'utc' Settings.defaultWeekSettings = { firstDay: 2, minimalDays: 1, weekend: [6, 7], } export type TimeType = { hour: HourNumbers minute: MinuteNumbers second: SecondNumbers } @Injectable() export class DateTimeUtils { static nowAsJSDate(): Date { return DateTime.now().toJSDate() } static now(): DateTime { return DateTime.now() } static getOverlapRange( startA: DateTime, endA: DateTime, startB: DateTime, endB: DateTime, ): { start: DateTime; end: DateTime } { const overlapStart = DateTime.max(startA, startB) const overlapEnd = DateTime.min(endA, endB) return { start: overlapStart, end: overlapEnd, } } static isExpired(expires: string): boolean { return DateTime.fromISO(expires) < DateTime.now() } static isOverlap( startA: DateTime, endA: DateTime, startB: DateTime, endB: DateTime, ): boolean { return ( this.getOverlapRange(startA, endA, startB, endB).start < this.getOverlapRange(startA, endA, startB, endB).end ) } static isOverlaps( listA: { start: DateTime; end: DateTime }[], listB: { start: DateTime; end: DateTime }[], ): boolean { for (const a of listA) { for (const b of listB) { if (this.isOverlap(a.start, a.end, b.start, b.end)) { return true } } } return false } static fromIsoString(isoString: string): DateTime { const dateTime = DateTime.fromISO(isoString) if (!dateTime.isValid) { throw new Error('Invalid date time') } return dateTime } static fromDate(date: Date): DateTime { const dateTime = DateTime.fromJSDate(date) if (!dateTime.isValid) { throw new Error('Invalid date time') } return dateTime } static toIsoString(dateTime: DateTime): string { const isoString = dateTime.toISO() if (!isoString) { throw new Error('Invalid date time') } return isoString } static getTodayWithTime(date: DateTime) { const today = DateTime.now().set({ hour: date.hour, minute: date.minute, second: date.second, }) return today } static getSpecificDateWithNowTime(date: DateTime) { return date.set({ hour: DateTime.now().hour, minute: DateTime.now().minute, second: DateTime.now().second, }) } static getATimeWithDateB(a: DateTime, b: DateTime) { return a.set({ year: b.year, month: b.month, day: b.day, hour: a.hour, minute: a.minute, second: a.second, }) } // example: 12:00:00 static toTime(time: string): TimeType { const [hour, minute, second] = time.split(':').map(Number) return { hour: hour as HourNumbers, minute: minute as MinuteNumbers, second: second as SecondNumbers, } } static getTimeFromDateTime(dateTime: DateTime): TimeType { return this.toTime(`${dateTime.hour}:${dateTime.minute}:${dateTime.second}`) } static subtractDaysFromTimeframe(timeframe: string): DateTime { // convert timeframe to number of days: 'day' -> 1, 'week' -> 7, 'month' -> 30, 'year' -> 365 const daysMap: Record = { day: 1, week: 7, month: 30, year: 365, } const days = daysMap[timeframe.toLowerCase()] if (days === undefined) { throw new Error(`Invalid timeframe: ${timeframe}`) } return DateTime.now().minus({ days }) } }