Browse Source

Add Luxon library and create TimeService for centralized date handling

pull/22619/head
erdemcaygor 10 months ago
parent
commit
14bb8a6887
  1. 1
      npm/ng-packs/package.json
  2. 26
      npm/ng-packs/packages/core/src/lib/pipes/utc-to-local.pipe.ts
  3. 1
      npm/ng-packs/packages/core/src/lib/services/index.ts
  4. 107
      npm/ng-packs/packages/core/src/lib/services/time.service.ts
  5. 31
      npm/ng-packs/packages/core/src/lib/services/timezone.service.ts

1
npm/ng-packs/package.json

@ -111,6 +111,7 @@
"just-compare": "^2.0.0",
"lerna": "^4.0.0",
"lint-staged": "^13.0.0",
"luxon": "^3.6.1",
"ng-packagr": "~19.1.0",
"ng-zorro-antd": "~19.0.0",
"nx": "~20.3.0",

26
npm/ng-packs/packages/core/src/lib/pipes/utc-to-local.pipe.ts

@ -1,7 +1,6 @@
import { Pipe, PipeTransform, Injectable, inject, LOCALE_ID } from '@angular/core';
import { ConfigStateService, LocalizationService, TimezoneService } from '../services';
import { ConfigStateService, LocalizationService, TimeService, TimezoneService } from '../services';
import { getShortDateFormat, getShortDateShortTimeFormat, getShortTimeFormat } from '../utils';
import { formatDate } from '@angular/common';
@Injectable()
@Pipe({
@ -9,6 +8,7 @@ import { formatDate } from '@angular/common';
})
export class UtcToLocalPipe implements PipeTransform {
protected readonly timezoneService = inject(TimezoneService);
protected readonly timeService = inject(TimeService);
protected readonly configState = inject(ConfigStateService);
protected readonly localizationService = inject(LocalizationService);
protected readonly locale = inject(LOCALE_ID);
@ -27,11 +27,9 @@ export class UtcToLocalPipe implements PipeTransform {
try {
if (this.timezoneService.isUtcClockEnabled) {
const timeZone = this.timezoneService.timezone;
const options: Intl.DateTimeFormatOptions = { timeZone };
const localeStr = this.formatWithIntl(date, type, options);
return formatDate(localeStr, format, this.locale);
return this.timeService.formatDateWithStandardOffset(date, format, timeZone);
} else {
return formatDate(value, format, this.locale, format);
return this.timeService.formatWithoutTimeZone(date, format);
}
} catch (err) {
return value;
@ -49,20 +47,4 @@ export class UtcToLocalPipe implements PipeTransform {
return getShortDateShortTimeFormat(this.configState);
}
}
private formatWithIntl(
date: Date,
propType: 'date' | 'datetime' | 'time',
options: Intl.DateTimeFormatOptions,
): string {
switch (propType) {
case 'date':
return date.toLocaleDateString(this.locale, options);
case 'time':
return date.toLocaleTimeString(this.locale, options);
case 'datetime':
default:
return date.toLocaleString(this.locale, options);
}
}
}

1
npm/ng-packs/packages/core/src/lib/services/index.ts

@ -24,3 +24,4 @@ export * from './internet-connection-service';
export * from './local-storage-listener.service';
export * from './title-strategy.service';
export * from './timezone.service';
export * from './time.service';

107
npm/ng-packs/packages/core/src/lib/services/time.service.ts

@ -0,0 +1,107 @@
import { inject, Injectable, LOCALE_ID } from '@angular/core';
import { DateTime } from 'luxon';
@Injectable({
providedIn: 'root',
})
export class TimeService {
private locale = inject(LOCALE_ID);
/**
* Returns the current date and time in the specified timezone.
*
* @param zone - An IANA timezone name (e.g., 'Europe/Istanbul', 'UTC'); defaults to the system's local timezone.
* @returns A Luxon DateTime instance representing the current time in the given timezone.
*/
now(zone = 'local'): DateTime {
return DateTime.now().setZone(zone);
}
/**
* Converts the input date to the specified timezone, applying any timezone and daylight saving time (DST) adjustments.
*
* This method:
* 1. Parses the input value into a Luxon DateTime object.
* 2. Applies the specified IANA timezone, including any DST shifts based on the given date.
*
* @param value - The ISO string or Date object to convert.
* @param zone - An IANA timezone name (e.g., 'America/New_York').
* @returns A Luxon DateTime instance adjusted to the specified timezone and DST rules.
*/
toZone(value: string | Date, zone: string): DateTime {
return DateTime.fromISO(value instanceof Date ? value.toISOString() : value, {
zone,
});
}
/**
* Formats the input date by applying timezone and daylight saving time (DST) adjustments.
*
* This method:
* 1. Converts the input date to the specified timezone.
* 2. Formats the result using the given format and locale, reflecting any timezone or DST shifts.
*
* @param value - The ISO string or Date object to format.
* @param format - The format string (default: 'ff').
* @param zone - Optional IANA timezone name (e.g., 'America/New_York'); defaults to the system's local timezone.
* @returns A formatted date string adjusted for the given timezone and DST rules.
*/
format(value: string | Date, format = 'ff', zone = 'local'): string {
return this.toZone(value, zone).setLocale(this.locale).toFormat(format);
}
/**
* Formats a date using the standard time offset (ignoring daylight saving time) for the specified timezone.
*
* This method:
* 1. Converts the input date to UTC.
* 2. Calculates the standard UTC offset for the given timezone (based on January 1st to avoid DST).
* 3. Applies the standard offset manually to the UTC time.
* 4. Formats the result using the specified format and locale, without applying additional timezone shifts.
*
* @param value - The ISO string or Date object to format.
* @param format - The Luxon format string (default: 'ff').
* @param zone - Optional IANA timezone name (e.g., 'America/New_York'); if omitted, system local timezone is used.
* @returns A formatted date string adjusted by standard time (non-DST).
*/
formatDateWithStandardOffset(value: string | Date, format = 'ff', zone?: string): string {
const utcDate =
typeof value === 'string'
? DateTime.fromISO(value, { zone: 'UTC' })
: DateTime.fromJSDate(value, { zone: 'UTC' });
if (!utcDate.isValid) return '';
const targetZone = zone ?? DateTime.local().zoneName;
const januaryDate = DateTime.fromObject(
{ year: utcDate.year, month: 1, day: 1 },
{ zone: targetZone },
);
const standardOffset = januaryDate.offset;
const dateWithStandardOffset = utcDate.plus({ minutes: standardOffset });
return dateWithStandardOffset.setZone('UTC').setLocale(this.locale).toFormat(format);
}
/**
* Formats the input date using its original clock time, without converting based on timezone or DST
*
* This method:
* 1. Converts the input date to ISO string.
* 2. Calculates the date time in UTC, keeping the local time.
* 3. Formats the result using the specified format and locale, without shifting timezones.
*
* @param value - The ISO string or Date object to format.
* @param format - The format string (default: 'ff').
* @returns A formatted date string without applying timezone.
*/
formatWithoutTimeZone(value: string | Date, format = 'ff'): string {
const isoString = value instanceof Date ? value.toISOString() : value;
const dateTime = DateTime.fromISO(isoString)
.setZone('utc', { keepLocalTime: true })
.setLocale(this.locale);
return dateTime.toFormat(format);
}
}

31
npm/ng-packs/packages/core/src/lib/services/timezone.service.ts

@ -21,10 +21,16 @@ export class TimezoneService {
});
}
getBrowserTimezone(): string {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
}
/**
* Returns the effective timezone to be used across the application.
*
* This value is determined based on the clock kind setting in the configuration:
* - If clock kind is not equal to Utc, the browser's local timezone is returned.
* - If clock kind is equal to Utc, the configured timezone (`timeZoneNameFromSettings`) is returned if available;
* otherwise, the browser's timezone is used as a fallback.
*
* @returns The IANA timezone name (e.g., 'Europe/Istanbul', 'America/New_York').
*/
get timezone(): string {
if (!this.isUtcClockEnabled) {
return this.getBrowserTimezone();
@ -32,6 +38,23 @@ export class TimezoneService {
return this.timeZoneNameFromSettings || this.getBrowserTimezone();
}
/**
* Retrieves the browser's local timezone based on the user's system settings.
*
* @returns The IANA timezone name (e.g., 'Europe/Istanbul', 'America/New_York').
*/
getBrowserTimezone(): string {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
}
/**
* Sets the application's timezone in a cookie to persist the user's selected timezone.
*
* This method sets the cookie only if the clock kind setting is set to UTC.
* The cookie is stored using the key defined by `this.cookieKey` and applied to the root path (`/`).
*
* @param timezone - The IANA timezone name to be stored (e.g., 'Europe/Istanbul').
*/
setTimezone(timezone: string): void {
if (this.isUtcClockEnabled) {
this.document.cookie = `${this.cookieKey}=${timezone}; path=/`;

Loading…
Cancel
Save