Add initial project files
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
import { parse, add, sub, type Locale } from 'date-fns';
|
||||
import { toZonedTime, fromZonedTime, formatInTimeZone } from 'date-fns-tz';
|
||||
import { SYSTEM_TZ, UNITS_MAP, type IntlDateDisplayFormatEnum, type IntlDateSourceFormatEnum } from './constants';
|
||||
import { getLocale, createConfig } from './lib';
|
||||
import type {
|
||||
IntlDateConfig,
|
||||
IntlDateInstanceInterface,
|
||||
IntlDateMethods,
|
||||
IntlDateLocaleMap,
|
||||
IntlDateLanguage,
|
||||
InitIntlDateServiceConfig,
|
||||
} from './lib';
|
||||
|
||||
class IntlDateService {
|
||||
private _locale: Locale | undefined;
|
||||
private _date: Date;
|
||||
private _config: IntlDateConfig;
|
||||
private _logger?: Console;
|
||||
|
||||
constructor(config: IntlDateConfig, date: Date, logger?: Console) {
|
||||
this._config = config;
|
||||
this._logger = logger;
|
||||
|
||||
const initialLang = config.localeMap[config.language];
|
||||
|
||||
this._locale = initialLang?.locale || (initialLang ? getLocale(initialLang.code) : undefined);
|
||||
this._date = fromZonedTime(date, 'UTC');
|
||||
}
|
||||
|
||||
_call(date: Date): this {
|
||||
this._date = fromZonedTime(date, 'UTC');
|
||||
return this;
|
||||
}
|
||||
|
||||
public setSupportedLanguages(supportedLanguages: IntlDateLocaleMap): void {
|
||||
this._logger?.log('Set supported languages: ', supportedLanguages);
|
||||
this._config.localeMap = supportedLanguages;
|
||||
}
|
||||
|
||||
public setLocaleGlobally(lang: IntlDateLanguage): void {
|
||||
const language = this._config.localeMap[lang];
|
||||
|
||||
if (!language) {
|
||||
this._logger?.error('Language is not supported. Add it to the supported list.');
|
||||
return;
|
||||
}
|
||||
|
||||
this._locale = language.locale ?? getLocale(language.code);
|
||||
this._config.language = lang;
|
||||
this._logger?.log('Set global language: ', lang);
|
||||
}
|
||||
private _getSourceFormat(fmt: IntlDateSourceFormatEnum): string {
|
||||
return this._config.sourceFormat[fmt];
|
||||
}
|
||||
private _getDisplayFormat(fmt: IntlDateDisplayFormatEnum): string {
|
||||
const localeFormat = this._config.localeMap[this._config.language]?.displayFormats?.[fmt];
|
||||
if (localeFormat) return localeFormat;
|
||||
return this._config.displayFormat[fmt];
|
||||
}
|
||||
private _parseDate(dateStr: string, formatStr: string, options?: { strict?: boolean; lang?: IntlDateLanguage }): Date {
|
||||
if (formatStr === 'UNIVERSAL_ISO') {
|
||||
return new Date(dateStr);
|
||||
}
|
||||
|
||||
const locale = this._config.localeMap[options?.lang ?? this._config.language]?.locale;
|
||||
|
||||
const parsedLocal = parse(dateStr, formatStr, new Date(), {
|
||||
locale: locale,
|
||||
});
|
||||
|
||||
return fromZonedTime(parsedLocal, SYSTEM_TZ);
|
||||
}
|
||||
private _formatDate(date: Date, pattern: string, displayLocal?: boolean): string {
|
||||
if (pattern === 'UNIVERSAL_ISO') {
|
||||
return displayLocal ? toZonedTime(date, SYSTEM_TZ).toISOString() : date.toISOString();
|
||||
}
|
||||
|
||||
if (!displayLocal) {
|
||||
return formatInTimeZone(date, 'UTC', pattern, {
|
||||
locale: this._locale,
|
||||
});
|
||||
}
|
||||
|
||||
return formatInTimeZone(date, SYSTEM_TZ, pattern, {
|
||||
locale: this._locale,
|
||||
});
|
||||
}
|
||||
|
||||
public parseSource: IntlDateMethods['parseSource'] = (date, fmt, options) => {
|
||||
this._date = this._parseDate(date, this._getSourceFormat(fmt), options);
|
||||
return this;
|
||||
};
|
||||
|
||||
public parseDisplay: IntlDateMethods['parseDisplay'] = (date, fmt, options) => {
|
||||
this._date = this._parseDate(date, this._getDisplayFormat(fmt), options);
|
||||
return this;
|
||||
};
|
||||
|
||||
public formatToDisplay: IntlDateMethods['formatToDisplay'] = (fmt, options) => {
|
||||
try {
|
||||
const pattern = this._getDisplayFormat(fmt);
|
||||
return this._formatDate(this._date, pattern, options?.displayLocal);
|
||||
} catch {
|
||||
return 'Invalid date';
|
||||
}
|
||||
};
|
||||
|
||||
public formatToSource: IntlDateMethods['formatToSource'] = (fmt, options) => {
|
||||
try {
|
||||
const pattern = this._getSourceFormat(fmt);
|
||||
return this._formatDate(this._date, pattern, options?.displayLocal);
|
||||
} catch {
|
||||
return 'Invalid date';
|
||||
}
|
||||
};
|
||||
|
||||
public add: IntlDateMethods['add'] = (value, unit) => {
|
||||
const duration = Object.assign(UNITS_MAP, { [unit]: value });
|
||||
const result = add(this._date, duration);
|
||||
this._date = fromZonedTime(result, 'UTC');
|
||||
return this;
|
||||
};
|
||||
|
||||
public subtract: IntlDateMethods['subtract'] = (value, unit) => {
|
||||
const duration = Object.assign(UNITS_MAP, { [unit]: value });
|
||||
const result = sub(this._date, duration);
|
||||
this._date = fromZonedTime(result, 'UTC');
|
||||
return this;
|
||||
};
|
||||
|
||||
public toDate = () => this._date;
|
||||
|
||||
public setNow = () => {
|
||||
this._date = fromZonedTime(new Date(), 'UTC');
|
||||
return this;
|
||||
};
|
||||
|
||||
public getMonthShort = (index: number): string => {
|
||||
const d = new Date(Date.UTC(2020, index, 1));
|
||||
return formatInTimeZone(d, 'UTC', 'MMM', { locale: this._locale });
|
||||
};
|
||||
|
||||
public getMonthLong = (index: number): string => {
|
||||
const d = new Date(Date.UTC(2020, index, 1));
|
||||
return formatInTimeZone(d, 'UTC', 'MMMM', { locale: this._locale });
|
||||
};
|
||||
}
|
||||
|
||||
export const intlDateService = (config?: InitIntlDateServiceConfig, logger?: Console): IntlDateInstanceInterface => {
|
||||
const instance = new IntlDateService(createConfig(config), new Date(), logger);
|
||||
|
||||
const methods: IntlDateMethods = {
|
||||
parseSource: instance.parseSource.bind(instance),
|
||||
parseDisplay: instance.parseDisplay.bind(instance),
|
||||
formatToDisplay: instance.formatToDisplay.bind(instance),
|
||||
formatToSource: instance.formatToSource.bind(instance),
|
||||
toDate: instance.toDate.bind(instance),
|
||||
subtract: instance.subtract.bind(instance),
|
||||
add: instance.add.bind(instance),
|
||||
setNow: instance.setNow.bind(instance),
|
||||
setSupportedLanguages: instance.setSupportedLanguages.bind(instance),
|
||||
setLocaleGlobally: instance.setLocaleGlobally.bind(instance),
|
||||
getMonthShort: instance.getMonthShort.bind(instance),
|
||||
getMonthLong: instance.getMonthLong.bind(instance),
|
||||
};
|
||||
|
||||
return Object.assign((date: Date) => instance._call(date), methods);
|
||||
};
|
||||
Reference in New Issue
Block a user