import { Injectable } from '@angular/core'; import { TimeZoneState } from '@core/states/time-zone.state'; import timeZones from '@core/static-assets/time-zones'; import { ClientSettingsService } from '@features/client-settings/client-settings.service'; import { AttachYCState, BaseYCService } from '@yourcause/common/state'; import moment from 'moment'; import momenttz from 'moment-timezone'; @AttachYCState(TimeZoneState) @Injectable({ providedIn: 'root'}) export class TimeZoneService extends BaseYCService { constructor ( private clientSettingsService: ClientSettingsService ) { super(); } get timeZones () { return this.get('timeZones'); } setTimeZones () { this.set('timeZones', timeZones); } getTimeZones () { return this.get('timeZones'); } returnTimeZoneFromID (timezoneId: string) { return this.timeZones.find((tz) => { return (tz.id === timezoneId); }) || { id: 'UTC', displayName: 'UTC', offset: 0 }; } getTimezoneOptions () { return this.timeZones.map((zone) => { return { label: zone.displayName, value: zone.id }; }); } private adaptDates (offset: number, date: string, save = false) { let dateTime; const timezoneIsUTC = offset === 0; const tzOffset = (offset || timezoneIsUTC) ? offset : this.returnTimeZoneFromID( this.clientSettingsService.clientSettings.defaultTimezone ).offset; const dateWithoutTheZ = date.replace(/Z$/, ''); const todayIsDST = moment().isDST(); const dateSelectedIsDST = moment(date).isDST(); if (timezoneIsUTC) { dateTime = moment(dateWithoutTheZ); } else if (dateSelectedIsDST && !todayIsDST) { dateTime = moment(dateWithoutTheZ).add(save ? -1 : 1, 'hour'); } else if (!dateSelectedIsDST && todayIsDST) { dateTime = moment(dateWithoutTheZ).add(save ? 1 : -1, 'hour'); } else { // or, in this case we don't adapt because DST doesn't apply dateTime = moment(dateWithoutTheZ); } return { dateTime, tzOffset }; } adaptDateForDisplayIfDST (date: string, offset?: number, format = 'lll') { const { dateTime, tzOffset } = this.adaptDates(offset, date, false); return this.returnDateForMgmtDisplay(dateTime.format(), tzOffset, format); } adaptDateForEditIfDST (date: string, offset?: number) { const { dateTime, tzOffset } = this.adaptDates(offset, date, false); return this.returnDateForMgmtDisplay(dateTime.format('YYYY-MM-DDTHH:mm:ss'), tzOffset); } adaptDateForSaveIfDST (date: string, offset?: number) { const { dateTime, tzOffset } = this.adaptDates(offset, date, true); return this.returnDateForSave(dateTime.format('YYYY-MM-DDTHH:mm:ss'), tzOffset); } // Helpers returnDateForSave (date: string, offset: number) { // this is subtracting a negative number (adding) // 12 EST - (-5 hours) = 5AM UTC const x = date ? moment(date.replace(/Z$/, '')).subtract(offset, 'hours').format('YYYY-MM-DDTHH:mm:ss') : ''; return x; } returnDateForMgmtDisplay (date: string, offset: number, format?: string) { // this is adding a negative number (subtracting) // 5AM UTC + (-5 hours) = 12 EST const x = date ? moment(date.replace(/Z$/, '')).add(offset, 'hours').format(format) : ''; return x; } returnMidnightUTCDate (date?: string|moment.Moment) { return moment(date).startOf('day').format('YYYY-MM-DDTHH:mm:ss'); } returnMidnightUTCDateShort (date: string, format = 'll') { if (date) { return moment(date.replace(/Z$/, '')).startOf('day').format(format); } return ''; } returnEndOfDayUTCDate (date: moment.Moment) { return date.endOf('day').format('YYYY-MM-DDTHH:mm:ss'); } displayFormattedTimeInTimezone ( date: string, timezoneId = 'UTC', useClientDefaultTimezone = false, format = 'll' ) { if (date) { const clientSettings = this.clientSettingsService.clientSettings; if (useClientDefaultTimezone) { timezoneId = clientSettings ? clientSettings.defaultTimezone : 'UTC'; } const timezone = this.returnTimeZoneFromID(timezoneId); return this.adaptDateForDisplayIfDST(date, timezone.offset, format); } else { return ''; } } formatDueDate (date: string) { if (date) { return moment(date).endOf('day').format('ll'); } return ''; } returnDateTimeAndTZ (date: string, format: string) { const timeZone = momenttz().tz(momenttz.tz.guess()).format('z'); const utcDate = moment.utc(date).format('lll'); return momenttz(utcDate).format(format) + ' ' + timeZone; } returnLocalDateTimeAndTZ (date: string, format: string) { const timeZone = momenttz().tz(momenttz.tz.guess()).format('z'); return momenttz(date).format(format) + ' ' + timeZone; } }