import { TrUtils } from './tr-utils'; import { Add } from '../shared/math-operations'; // One file per function: shareneus is CommonJS, so the 'date-fns' root would // put all of date-fns in every app's first page. import { add } from 'date-fns/add'; import { addDays } from 'date-fns/addDays'; import { addMinutes } from 'date-fns/addMinutes'; import { addMonths } from 'date-fns/addMonths'; import { addWeeks } from 'date-fns/addWeeks'; import { differenceInCalendarMonths } from 'date-fns/differenceInCalendarMonths'; import { differenceInDays } from 'date-fns/differenceInDays'; import { differenceInHours } from 'date-fns/differenceInHours'; import { differenceInMilliseconds } from 'date-fns/differenceInMilliseconds'; import { differenceInMinutes } from 'date-fns/differenceInMinutes'; import { differenceInYears } from 'date-fns/differenceInYears'; import { endOfDay } from 'date-fns/endOfDay'; import { endOfMonth } from 'date-fns/endOfMonth'; import { endOfQuarter } from 'date-fns/endOfQuarter'; import { endOfWeek } from 'date-fns/endOfWeek'; import { endOfYear } from 'date-fns/endOfYear'; import { format } from 'date-fns/format'; import { getHours } from 'date-fns/getHours'; import { getMinutes } from 'date-fns/getMinutes'; import { getMonth } from 'date-fns/getMonth'; import { getYear } from 'date-fns/getYear'; import { isBefore } from 'date-fns/isBefore'; import { isEqual } from 'date-fns/isEqual'; import { set } from 'date-fns/set'; import { setDay } from 'date-fns/setDay'; import { setMonth } from 'date-fns/setMonth'; import { setQuarter } from 'date-fns/setQuarter'; import { setYear } from 'date-fns/setYear'; import { startOfDay } from 'date-fns/startOfDay'; import { startOfMonth } from 'date-fns/startOfMonth'; import { startOfQuarter } from 'date-fns/startOfQuarter'; import { startOfWeek } from 'date-fns/startOfWeek'; import { startOfYear } from 'date-fns/startOfYear'; import { sub } from 'date-fns/sub'; import { subDays } from 'date-fns/subDays'; import { subMonths } from 'date-fns/subMonths'; import { subQuarters } from 'date-fns/subQuarters'; import { subWeeks } from 'date-fns/subWeeks'; import { subYears } from 'date-fns/subYears'; import { TZDate } from '@date-fns/tz'; type Day = 0 | 1 | 2 | 3 | 4 | 5 | 6; // The only date API for the API and the UI: neither imports date-fns directly. // // Every calendar question (which day, start of month, ...) is answered in the // user's zone, never the process zone, so the API (UTC) and the UI (browser // zone) agree. The zone is the optional last argument of each method; when it // is left out, the zone registered with UseTimeZone is used. The UI registers // the logged-in user's zone once; the API always passes it, since one process // serves many users. A missing or unknown zone means UTC. // // Inputs are instants (Date, ISO string with Z or an offset, epoch millis), // read in the user's zone, or text with no offset ('2026-03-10', '2026-03-10T14:30'), // which is that wall-clock time in the user's zone. A date picker's Date is // browser-local midnight: pass GetPickedDay(it), not the Date. // Instants come back as plain Dates or 'Z' ISO strings, as before. date-fns // works in the zone of the TZDate it is given, so At/Now carry the zone through. export class MyDate { private static ZoneSource: () => any = () => undefined; // ------------------------------------------------------------------ zone static UseTimeZone(GetTimeZone: () => any) { this.ZoneSource = GetTimeZone; } static IsValidTimeZone(TimeZone: any) { return typeof TimeZone === 'string' && TimeZone.trim() !== '' && !isNaN(new TZDate(0, TimeZone).getTime()); } // The zone the code runs in: the browser's in the UI, the server's in the API. // Only for libraries that work in local time, such as a calendar widget. static GetBrowserTimeZone() { return Intl.DateTimeFormat().resolvedOptions().timeZone; } static GetUserTimeZone(UserTimeZone?: any) { const zone = TrUtils.IsEmpty(UserTimeZone) ? this.ZoneSource() : UserTimeZone; return this.IsValidTimeZone(zone) ? zone : 'UTC'; } // The instant (or date-only calendar day) as a date in the user's zone. private static At(Value: any, UserTimeZone?: any): TZDate { const zone = this.GetUserTimeZone(UserTimeZone); if (typeof Value === 'string') { // Text with no offset ('2026', '2026-03', '2026-03-10', '2026-03-10T14:30[:00[.000]]') // is wall-clock time in the zone, as date and time pickers give it. const wall = /^(\d{4})(?:-(\d{2})(?:-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3}))?)?)?)?)?$/.exec(Value.trim()); if (wall) { const [, year, month = '1', day = '1', hours = '0', minutes = '0', seconds = '0', ms = '0'] = wall; return new TZDate(Number(year), Number(month) - 1, Number(day), Number(hours), Number(minutes), Number(seconds), Number(ms.padEnd(3, '0')), zone); } } return new TZDate(new Date(Value).getTime(), zone); } private static Now(UserTimeZone?: any): TZDate { return new TZDate(Date.now(), this.GetUserTimeZone(UserTimeZone)); } // Plain Date / 'Z' ISO string, never a TZDate (whose ISO carries an offset). private static Plain(Value: Date) { return new Date(Value.getTime()); } private static Iso(Value: Date) { return new Date(Value.getTime()).toISOString(); } private static Format(Value: any, Pattern: string, UserTimeZone?: any) { return format(this.At(Value, UserTimeZone), Pattern); } private static IsNull(Value: any) { return Value === null || Value === 'null' || typeof Value === 'undefined'; } // ------------------------------------------------------------------ now // An instant has no zone: these are all now. static GetDateTimeNowInUTC(UserTimeZone?: any) { return new Date(); } static GetDateTimeNowInUserTZ(UserTimeZone?: any) { return new Date(); } static GetDateTimeNowInUser(UserTimeZone?: any) { return new Date().toISOString(); } static GetDateInUTC(date: any, UserTimeZone?: any) { return new Date(date).toISOString(); } static GetCurrentYear(UserTimeZone?: any) { return getYear(this.Now(UserTimeZone)); } static GetHourNow(UserTimeZone?: any) { return getHours(this.Now(UserTimeZone)); } // ------------------------------------------------------------------ formatting // Today's date in the user's zone, 'dd-MMM-yyyy'. static GetTodayReadable(UserTimeZone?: any) { return this.ConvertUTCDateToReadable(new Date(), UserTimeZone); } // The calendar day a date picker showed, 'yyyy-MM-dd'. Pickers hand back local // midnight in the browser's zone, which is another day in a zone behind it, so // read the picked Date there and pass the day on, never the Date itself. static GetPickedDay(PickerDate: any) { if (TrUtils.IsEmpty(PickerDate)) { return null; } return this.Format(PickerDate, 'yyyy-MM-dd', this.GetBrowserTimeZone()); } // The date and time a picker or calendar widget showed (it works in browser-local // time), taken as the user's wall time, as a UTC ISO string. static ConvertPickedDateTimeToUTC(PickerDate: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(PickerDate)) { return null; } const shown = this.Format(PickerDate, "yyyy-MM-dd'T'HH:mm:ss.SSS", this.GetBrowserTimeZone()); return this.Iso(this.At(shown, UserTimeZone)); } static ConvertUTCDateToReadable(UTCDateTime: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return this.Format(UTCDateTime, 'dd-MMM-yyyy', UserTimeZone); } static ConvertUTCDateToReadableExDate(UTCDateTime: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return this.Format(UTCDateTime, 'MM/yy', UserTimeZone); } static ConvertUTCDateToReadableExDateTxt(UTCDateTime: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return this.Format(UTCDateTime, 'MMM/yy', UserTimeZone); } static ConvertUTCDateTimeToReadable(UTCDateTime: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return this.Format(UTCDateTime, 'dd-MMM-yyyy, hh:mm a', UserTimeZone); } static ConvertUTCToReadable(UTCDateTime: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return this.Format(UTCDateTime, 'dd-MMM-yyyy , hh:mm:ss a', UserTimeZone); } static ConvertUTCDateTimeToTime(UTCDateTime: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return this.Format(UTCDateTime, 'hh:mm a', UserTimeZone); } static ConvertUTCtoUserDateTime(UTCDateTime: any, UserTimeZone?: any) { return this.Format(UTCDateTime, 'dd-MM-yyyy h:mm a', UserTimeZone); } // 'yyyy-MM-dd' in the user's zone, for date inputs. static ConvertUTCDateToUserTZ(UTCDateTime: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return this.Format(UTCDateTime, 'yyyy-MM-dd', UserTimeZone); } static ConvertUTCDateToUserTZCalendar(UTCDateTime: any, UserTimeZone?: any) { return this.ConvertUTCDateToUserTZ(UTCDateTime, UserTimeZone); } // The user's wall time as 'yyyy-MM-ddTHH:mm:ss' with no offset, which a // calendar widget working in local time shows as that same wall time. static ConvertUTCDateTimeToUserTZCalendar(UTCDateTime: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return this.Format(UTCDateTime, "yyyy-MM-dd'T'HH:mm:ss", UserTimeZone); } // 'HH:mm', 24-hour. static ConvertUTCDateTimeToTime24(UTCDateTime: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return this.Format(UTCDateTime, 'HH:mm', UserTimeZone); } static ConvertUTCtoZonedDate(UTCDateTime: any, userTZ?: string) { return this.Format(UTCDateTime, 'yyyy-MM-dd', userTZ); } static GetTime(argDate: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(argDate)) { return null; } return this.Format(argDate, 'hh:mm a', UserTimeZone); } static GetTimeForCalendar(argDate: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(argDate)) { return null; } return this.Format(argDate, 'HH:mm:ss', UserTimeZone); } static GetTodaysDayName(UTCDateTime: any, UserTimeZone?: any) { return this.Format(UTCDateTime, 'EEEE', UserTimeZone); } static GetMonthName(MonthNumber: number, UserTimeZone?: any) { return format(new Date(2000, MonthNumber - 1, 1), 'MMMM'); } static GetWeekDateAndTime(UTCDateTime: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } if (getYear(this.At(UTCDateTime, UserTimeZone)) === this.GetCurrentYear(UserTimeZone)) { return this.Format(UTCDateTime, 'E, MMM do, h:mm a', UserTimeZone); } return this.ConvertUTCDateTimeToReadable(UTCDateTime, UserTimeZone); } static GetWeekAndDate(UTCDateTime: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } if (getYear(this.At(UTCDateTime, UserTimeZone)) === this.GetCurrentYear(UserTimeZone)) { return this.Format(UTCDateTime, 'E, MMM do', UserTimeZone); } return this.ConvertUTCDateToReadable(UTCDateTime, UserTimeZone); } // ------------------------------------------------------------------ parts static GetYearFromUTCDate(UTCDateTime: any, UserTimeZone?: any) { return getYear(this.At(UTCDateTime, UserTimeZone)); } static GetMonthAndYear(argDate: any, UserTimeZone?: any) { const date = this.At(argDate, UserTimeZone); return { month: getMonth(date), year: getYear(date) }; } // 0-based month (January is 0), in the user's zone; now when no date is given. static GetMonth(argDate?: any, UserTimeZone?: any) { return getMonth(TrUtils.IsEmpty(argDate) ? this.Now(UserTimeZone) : this.At(argDate, UserTimeZone)); } static GetHourFromUTCDateTime(UTCDateTime: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return getHours(this.At(UTCDateTime, UserTimeZone)); } static GetMinutesFromUTCDateTime(UTCDateTime: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return getMinutes(this.At(UTCDateTime, UserTimeZone)); } // ------------------------------------------------------------------ comparisons and differences static CheckUTCDiff(arg1UTC: any, arg2UTC: any) { return differenceInMilliseconds(new Date(arg1UTC), new Date(arg2UTC)); } // Is arg1's calendar day before arg2's, in the user's zone. static IsArg1DateBeforeArg2Date(arg1UTCDate: any, arg2UTCDate: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(arg1UTCDate) || TrUtils.IsEmpty(arg2UTCDate)) { return false; } return isBefore(new Date(this.GetEndOfArgDay(arg1UTCDate, UserTimeZone)), new Date(this.GetEndOfArgDay(arg2UTCDate, UserTimeZone))); } static IsArg1DateBeforeArg2Month(arg1UTCDate: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(arg1UTCDate)) { return false; } return isBefore(this.At(arg1UTCDate, UserTimeZone), new Date(this.GetStartOfMonth(UserTimeZone))); } static IsArg1DateAndArg2DateSame(arg1UTCDate: any, arg2UTCDate: any) { if (TrUtils.IsEmpty(arg1UTCDate) || TrUtils.IsEmpty(arg2UTCDate)) { return false; } return isEqual(new Date(arg1UTCDate), new Date(arg2UTCDate)); } static IsMonthAndYearSame(arg1Date: any, arg2Date: any, UserTimeZone?: any) { const first = this.At(arg1Date, UserTimeZone); const second = this.At(arg2Date, UserTimeZone); return getMonth(first) === getMonth(second) && getYear(first) === getYear(second); } // Is arg1 strictly earlier than arg2, as instants (to the millisecond). static IsBefore(arg1Date: any, arg2Date: any) { return isBefore(new Date(arg1Date), new Date(arg2Date)); } static GetMinutesDiffBetween(startutcdate: any, endutcdate: any) { if (TrUtils.IsEmpty(startutcdate) || TrUtils.IsEmpty(endutcdate)) { return 0; } return differenceInMinutes(new Date(endutcdate), new Date(startutcdate)); } // Whole days from start to end, counted on the user's calendar. static GetDaysDiffBetween(startutcdate: any, endutcdate: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(startutcdate) || TrUtils.IsEmpty(endutcdate)) { return 0; } return differenceInDays(this.At(endutcdate, UserTimeZone), this.At(startutcdate, UserTimeZone)); } // Calendar months from start to end in the user's zone (Jan 31 -> Feb 1 is 1). static GetMonthsDiffBetween(startutcdate: any, endutcdate: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(startutcdate) || TrUtils.IsEmpty(endutcdate)) { return 0; } return differenceInCalendarMonths(this.At(endutcdate, UserTimeZone), this.At(startutcdate, UserTimeZone)); } // Completed years from start to end, e.g. age from a date of birth. static GetYearsDiffBetween(startutcdate: any, endutcdate: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(startutcdate) || TrUtils.IsEmpty(endutcdate)) { return 0; } return differenceInYears(this.At(endutcdate, UserTimeZone), this.At(startutcdate, UserTimeZone)); } // Completed years from DOB to today, in the user's zone. static GetAgeInYears(DOB: any, UserTimeZone?: any) { return this.GetYearsDiffBetween(DOB, this.Now(UserTimeZone), UserTimeZone); } static GetTimeDifferencesInMinutes(startDateTime: any, endDateTime: any) { return differenceInMinutes(new Date(endDateTime), new Date(startDateTime)); } static GetTimeDifferencesInHours(startDateTime: any, endDateTime: any) { return differenceInHours(new Date(endDateTime), new Date(startDateTime)); } // ------------------------------------------------------------------ arithmetic // IncrementType is a duration unit: 'years' | 'months' | 'weeks' | 'days' | 'hours' | 'minutes' | 'seconds'. static AddToGivenDate(UTCDateTime: any, IncrementCount: any, IncrementType: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return this.Plain(add(this.At(UTCDateTime, UserTimeZone), { [IncrementType]: Number(IncrementCount) })); } static SubtractToGivenDate(UTCDateTime: any, DecrementCount: any, DecrementType: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return this.Plain(sub(this.At(UTCDateTime, UserTimeZone), { [DecrementType]: Number(DecrementCount) })); } static AddMinutesToGivenTime(argDate: any, mint: number, UserTimeZone?: any) { return this.Iso(addMinutes(new Date(argDate), mint)); } // The same instant with the wall-clock hour and minutes set, in the user's zone. static SetHourAndMinutes(UTCDateTime: any, Hours: any, Minutes: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(UTCDateTime)) { return null; } return this.Plain(set(this.At(UTCDateTime, UserTimeZone), { hours: Number(Hours), minutes: Number(Minutes) })); } // The user's calendar day of selectedDate at wall time `time` ('HH:mm[:ss[.SSS]]', // now's time when empty), as a UTC ISO string. static ConvertUserTZToUTC(selectedDate: any, time: any, UserTimeZone?: any) { if (TrUtils.IsEmpty(selectedDate)) { return null; } const day = this.At(selectedDate, UserTimeZone); const clock = TrUtils.IsEmpty(time) ? this.Now(UserTimeZone) : null; const parts = clock ? null : /^\s*(\d{1,2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3}))?)?\s*$/.exec(String(time)); if (!clock && !parts) { throw new RangeError('Invalid time value'); } const result = set(day, clock ? { hours: clock.getHours(), minutes: clock.getMinutes(), seconds: clock.getSeconds(), milliseconds: clock.getMilliseconds() } : { hours: Number(parts![1]), minutes: Number(parts![2]), seconds: Number(parts![3] ?? 0), milliseconds: Number((parts![4] ?? '0').padEnd(3, '0')) }); return this.Iso(result); } // ------------------------------------------------------------------ days static GetStartOfDay(UserTimeZone?: any) { return this.Iso(startOfDay(this.Now(UserTimeZone))); } static GetStartOfDayUTC(UserTimeZone?: any) { return this.GetStartOfDay(UserTimeZone); } static GetEndOfDay(UserTimeZone?: any) { return this.Iso(endOfDay(this.Now(UserTimeZone))); } static GetEndOfDayUTC(UserTimeZone?: any) { return this.GetEndOfDay(UserTimeZone); } static GetStartOfArgDay(argDate: any, UserTimeZone?: any) { return this.Iso(startOfDay(this.At(argDate, UserTimeZone))); } static GetEndOfArgDay(argDate: any, UserTimeZone?: any) { return this.Iso(endOfDay(this.At(argDate, UserTimeZone))); } static GetStartOfGivenDate(UTCDate: any, UserTimeZone?: any) { return this.GetStartOfArgDay(UTCDate, UserTimeZone); } static GetEndOfGivenDate(UTCDate: any, UserTimeZone?: any) { return this.GetEndOfArgDay(UTCDate, UserTimeZone); } // The user's calendar day as UTC midnight, e.g. '2026-03-10T00:00:00.000Z'. static GetStart(argDate: any, UserTimeZone?: any) { return this.Format(argDate, "yyyy-MM-dd'T'00:00:00.000'Z'", UserTimeZone); } static GetStartOfPrvDate(Days: number, UserTimeZone?: any) { if (this.IsNull(Days)) { return this.GetStartOfDayUTC(UserTimeZone); } return this.Iso(startOfDay(subDays(this.Now(UserTimeZone), Days))); } static GetEndOfPrvDate(Days: number, UserTimeZone?: any) { if (this.IsNull(Days)) { return this.GetEndOfDayUTC(UserTimeZone); } return this.Iso(endOfDay(subDays(this.Now(UserTimeZone), Days))); } static GetStartOfNextDate(Days: number, UserTimeZone?: any) { if (this.IsNull(Days)) { return this.GetStartOfDayUTC(UserTimeZone); } return this.Iso(startOfDay(addDays(this.Now(UserTimeZone), Days))); } static GetEndOfNextDate(Days: number, UserTimeZone?: any) { return this.Iso(endOfDay(addDays(this.Now(UserTimeZone), this.IsNull(Days) ? 0 : Days))); } static GetStartOfArgNextDay(argDate: any, UserTimeZone?: any) { return this.Iso(startOfDay(addDays(this.At(argDate, UserTimeZone), 1))); } static GetEndOfArgNextDay(argDate: any, UserTimeZone?: any) { return this.Iso(endOfDay(addDays(this.At(argDate, UserTimeZone), 1))); } static GetStartOfArgPrevDay(argDate: any, UserTimeZone?: any) { return this.Iso(startOfDay(subDays(this.At(argDate, UserTimeZone), 1))); } static GetEndOfArgPrevDay(argDate: any, UserTimeZone?: any) { return this.Iso(endOfDay(subDays(this.At(argDate, UserTimeZone), 1))); } // ------------------------------------------------------------------ weeks (Day: 0 = Sunday) static GetUTCDateOfWeekStart(UserTimeZone?: any) { return this.Iso(startOfWeek(this.Now(UserTimeZone))); } static GetWeekStart(Day: any, UserTimeZone?: any) { return this.Iso(startOfWeek(this.Now(UserTimeZone), { weekStartsOn: Day as Day })); } static GetStarOfWeek(Day: number, UserTimeZone?: any) { return this.Iso(setDay(startOfDay(this.Now(UserTimeZone)), this.IsNull(Day) ? 0 : Day)); } static GetEndOfWeek(Day: number, UserTimeZone?: any) { return this.Iso(setDay(endOfDay(this.Now(UserTimeZone)), 6 + (this.IsNull(Day) ? 0 : Day))); } static GetStartOfArgWeek(argDate: any, UserTimeZone?: any) { return this.Iso(startOfWeek(this.At(argDate, UserTimeZone))); } static GetEndOfArgWeek(argDate: any, UserTimeZone?: any) { return this.Iso(endOfWeek(this.At(argDate, UserTimeZone))); } static GetStartOfArgNextWeek(argDate: any, Day: any, UserTimeZone?: any) { return this.Iso(startOfWeek(addWeeks(this.At(argDate, UserTimeZone), 1), { weekStartsOn: Day as Day })); } static GetEndOfArgNextWeek(argDate: any, Day: any, UserTimeZone?: any) { return this.Iso(endOfWeek(addWeeks(this.At(argDate, UserTimeZone), 1), { weekStartsOn: Day as Day })); } static GetStartOfArgPrevWeek(argDate: any, Day: any, UserTimeZone?: any) { return this.Iso(startOfWeek(subWeeks(this.At(argDate, UserTimeZone), 1), { weekStartsOn: Day as Day })); } static GetEndOfArgPrevWeek(argDate: any, Day: any, UserTimeZone?: any) { return this.Iso(endOfWeek(subWeeks(this.At(argDate, UserTimeZone), 1), { weekStartsOn: Day as Day })); } // ------------------------------------------------------------------ months (month: 0 = January) static GetUTCDateOfMonthStart(UserTimeZone?: any) { return this.Plain(startOfMonth(this.Now(UserTimeZone))); } static GetStartOfMonth(UserTimeZone?: any) { return this.Iso(startOfMonth(this.Now(UserTimeZone))); } static GetEndOfMonth(UserTimeZone?: any) { return this.Iso(endOfMonth(this.Now(UserTimeZone))); } static GetLastDayOfMonth(UserTimeZone?: any) { return this.Plain(endOfMonth(this.Now(UserTimeZone))); } static GetEndOfMonthArgDate(argDate: any, UserTimeZone?: any) { return this.Iso(endOfMonth(this.At(argDate, UserTimeZone))); } static GetStartOfArgMonth(month: any, year: any, UserTimeZone?: any) { return this.Iso(this.MonthStart(year, month, UserTimeZone)); } static GetEndOfArgMonth(month: any, year: any, UserTimeZone?: any) { return this.Iso(endOfMonth(this.MonthStart(year, month, UserTimeZone))); } static GetStartAndEndDateMonthAndYear(year: any, month: any, UserTimeZone?: any) { const start = this.MonthStart(year, month, UserTimeZone); return [this.Plain(start), this.Plain(endOfMonth(start))]; } static GetStartOfArgNextMonth(argDate: any, UserTimeZone?: any) { return this.GetStartOfArgaddMonths(argDate, 1, UserTimeZone); } static GetEndOfArgNextMonth(argDate: any, UserTimeZone?: any) { return this.GetEndOfArgaddMonths(argDate, 1, UserTimeZone); } static GetStartOfArgPrevMonth(argDate: any, UserTimeZone?: any) { return this.Iso(startOfMonth(subMonths(this.At(argDate, UserTimeZone), 1))); } static GetEndOfArgPrevMonth(argDate: any, UserTimeZone?: any) { return this.Iso(endOfMonth(subMonths(this.At(argDate, UserTimeZone), 1))); } static GetStartOfArgaddMonths(argDate: any, addmonths: number, UserTimeZone?: any) { return this.Iso(startOfMonth(addMonths(this.At(argDate, UserTimeZone), Number(addmonths)))); } static GetEndOfArgaddMonths(argDate: any, addmonths: any, UserTimeZone?: any) { return this.Iso(endOfMonth(addMonths(this.At(argDate, UserTimeZone), Number(addmonths)))); } private static MonthStart(year: any, month: any, UserTimeZone?: any) { return new TZDate(Number(year), Number(month), 1, this.GetUserTimeZone(UserTimeZone)); } // ------------------------------------------------------------------ quarters (Quarter: 1-4) static GetStartDateOfQuarter(Quarter: number, UserTimeZone?: any) { return this.Iso(startOfQuarter(setQuarter(this.Now(UserTimeZone), Quarter))); } static GetStartDateOfCurrentQuarter(UserTimeZone?: any) { return this.Iso(startOfQuarter(this.Now(UserTimeZone))); } static GetEndDateOfCurrentQuarter(UserTimeZone?: any) { return this.Iso(endOfQuarter(this.Now(UserTimeZone))); } static GetStartOfArgPrevQuarter(argDate: any, UserTimeZone?: any) { return this.Iso(startOfQuarter(subQuarters(this.At(argDate, UserTimeZone), 1))); } static GetEndOfArgPrevQuarter(argDate: any, UserTimeZone?: any) { return this.Iso(endOfQuarter(subQuarters(this.At(argDate, UserTimeZone), 1))); } // ------------------------------------------------------------------ years static GetUTCDateOfYearStart(UserTimeZone?: any) { return this.Plain(startOfYear(this.Now(UserTimeZone))); } static GetStartDateOfYear(UserTimeZone?: any) { return this.Iso(startOfYear(this.Now(UserTimeZone))); } static GetStartOfYear(UserTimeZone?: any) { return this.Iso(startOfYear(this.Now(UserTimeZone))); } static GetEndOfYear(UserTimeZone?: any) { return this.Iso(endOfYear(this.Now(UserTimeZone))); } static GetStartOfArgYear(year: any, UserTimeZone?: any) { return this.Iso(startOfYear(setYear(this.Now(UserTimeZone), Number(year)))); } static GetEndOfArgYear(year: any, UserTimeZone?: any) { return this.Iso(endOfYear(setYear(this.Now(UserTimeZone), Number(year)))); } static GetStartDateOfArgYear(utcDate: any, UserTimeZone?: any) { return this.Iso(startOfYear(this.At(utcDate, UserTimeZone))); } static GetStartOfArgPrevYear(argDate: any, UserTimeZone?: any) { return this.Iso(startOfYear(subYears(this.At(argDate, UserTimeZone), 1))); } static GetEndOfArgPrevYear(argDate: any, UserTimeZone?: any) { return this.Iso(endOfYear(subYears(this.At(argDate, UserTimeZone), 1))); } // Financial year starting in month Month (0 = January) of this calendar year. static GetStartOfYearFromSelectedMonth(Month: number, UserTimeZone?: any) { return this.Iso(setMonth(startOfMonth(this.Now(UserTimeZone)), this.IsNull(Month) ? 0 : Month)); } static GetEndOfYearFromSelectedMonth(Month: number, UserTimeZone?: any) { return this.Iso(setMonth(endOfYear(this.Now(UserTimeZone)), 11 + (this.IsNull(Month) ? 0 : Month))); } static GetStartOfPrevYearFromSelectedMonth(argDate: any, Month: number, UserTimeZone?: any) { return this.FinancialYearStart(argDate, 1, Month, UserTimeZone); } static GetStartOfPrevYearFromSelectedMonthYear(argDate: any, Month: number, UserTimeZone?: any) { return this.FinancialYearStart(argDate, 2, Month, UserTimeZone); } static GetEndOfPrevYearFromSelectedMonth(argDate: any, Month: number, UserTimeZone?: any) { return this.FinancialYearEnd(argDate, 1, Month, UserTimeZone); } static GetEndOfPrevYearFromSelectedMonthYear(argDate: any, Month: number, UserTimeZone?: any) { return this.FinancialYearEnd(argDate, 2, Month, UserTimeZone); } private static FinancialYearStart(argDate: any, YearsBack: number, Month: number, UserTimeZone?: any) { const back = subYears(this.At(argDate, UserTimeZone), YearsBack); return this.Iso(setMonth(startOfMonth(back), this.IsNull(Month) ? 0 : Month)); } private static FinancialYearEnd(argDate: any, YearsBack: number, Month: number, UserTimeZone?: any) { const back = subYears(this.At(argDate, UserTimeZone), YearsBack); return this.Iso(endOfMonth(setMonth(endOfMonth(back), 11 + (this.IsNull(Month) ? 0 : Month)))); } // ------------------------------------------------------------------ time slots static getTimesInInterval(startDateTime: any, endDateTime: any, count: any, UserTimeZone?: any) { let diff = MyDate.GetTimeDifferencesInMinutes(startDateTime, endDateTime); let StartTime = this.GetTimeDifferencesInHours(startDateTime, endDateTime); let StartMin = this.GetTimeDifferencesInMinutes(startDateTime, endDateTime); let ampm: any = this.Format(startDateTime, 'a', UserTimeZone); let Hours: any = []; let totalSlots: number = diff / count; for (let slot = 0; slot < totalSlots; slot++) { if (StartMin === 30) { let time = '{' + StartTime + ':' + StartMin + ' ' + ampm + '}'; let TimeObj: any = {}; TimeObj.Time = time; Hours.push(TimeObj); StartTime++; StartMin = 0; } else { let time = '{' + StartTime + ' ' + ampm + '}'; let TimeObj: any = {}; TimeObj.Time = time; Hours.push(TimeObj); StartMin = 30; } } return Hours; } // '9:30 PM' -> '21:30', '09:30 AM' -> '09:30'. static TimeConversion(val: any) { val = val.trim(); let last2: any = val.slice(-2); if (last2.toUpperCase() == 'AM') { let time: any = val.split(':'); if (this.IsNull(time[1])) { time[0] = time[0].slice(0, 2); time[1] = '00'; } return time[0] + ':' + time[1].slice(0, 2); } else if (last2.toUpperCase() == 'PM') { let time: any = val.split(':'); if (this.IsNull(time[1])) { time[0] = time[0].slice(0, 2); time[1] = '00'; } if (Number(time[0]) < 12) { time[0] = Add(Number(time[0]), 12); } return time[0] + ':' + time[1].slice(0, 2); } else { return last2 + ':' + '00'; } } }