From 8590a10d859df2609e3646a4f1a63e272be74fe8 Mon Sep 17 00:00:00 2001 From: MKirova Date: Tue, 23 Sep 2025 16:30:35 +0300 Subject: [PATCH 1/8] fix(date-editor): Use default display format based on locale. --- .../lib/date-common/util/date-time.util.ts | 21 +++---------------- .../date-time-editor.directive.ts | 2 +- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts index 18b3bc6b8a4..0b37597f9b4 100644 --- a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts +++ b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts @@ -1,7 +1,7 @@ import { DatePart, DatePartInfo } from '../../directives/date-time-editor/date-time-editor.common'; -import { formatDate, FormatWidth, getLocaleDateFormat } from '@angular/common'; +import { formatDate } from '@angular/common'; import { ValidationErrors } from '@angular/forms'; -import { isDate } from '../../core/utils'; +import { getLocaleDateFormat, isDate } from '../../core/utils'; import { DataType } from '../../data-operations/data-util'; /** @hidden */ @@ -283,22 +283,7 @@ export abstract class DateTimeUtil { * Supports Angular's DatePipe format options such as `shortDate`, `longDate`. */ public static getLocaleDateFormat(locale: string, displayFormat?: string): string { - const formatKeys = Object.keys(FormatWidth) as (keyof FormatWidth)[]; - const targetKey = formatKeys.find(k => k.toLowerCase() === displayFormat?.toLowerCase().replace('date', '')); - if (!targetKey) { - // if displayFormat is not shortDate, longDate, etc. - // or if it is not set by the user - return displayFormat; - } - let format: string; - try { - format = getLocaleDateFormat(locale, FormatWidth[targetKey]); - } catch { - DateTimeUtil.logMissingLocaleSettings(locale); - format = DateTimeUtil.getDefaultInputFormat(locale); - } - - return format; + return getLocaleDateFormat(locale, displayFormat); } /** Determines if a given character is `d/M/y` or `h/m/s`. */ diff --git a/projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts b/projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts index d758e0d3c64..7254b3296da 100644 --- a/projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts @@ -139,7 +139,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh } public get displayFormat(): string { - return this._displayFormat || this.inputFormat; + return this._displayFormat || this._inputFormat || DateTimeUtil.getLocaleDateFormat(this.locale, 'short'); } /** From 823d44fff9df121584dca4c9692e9a399b24dd38 Mon Sep 17 00:00:00 2001 From: MKirova Date: Wed, 24 Sep 2025 11:19:32 +0300 Subject: [PATCH 2/8] chore(*): Replace angular's format date with the new core lib one. --- .../src/lib/date-common/util/date-time.util.ts | 16 +--------------- .../date-range-picker-inputs.common.ts | 6 +++--- .../date-time-editor.directive.ts | 4 ++-- 3 files changed, 6 insertions(+), 20 deletions(-) diff --git a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts index 0b37597f9b4..71de5871c35 100644 --- a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts +++ b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts @@ -1,7 +1,6 @@ import { DatePart, DatePartInfo } from '../../directives/date-time-editor/date-time-editor.common'; -import { formatDate } from '@angular/common'; import { ValidationErrors } from '@angular/forms'; -import { getLocaleDateFormat, isDate } from '../../core/utils'; +import { formatDate, getLocaleDateFormat, isDate } from '../../core/utils'; import { DataType } from '../../data-operations/data-util'; /** @hidden */ @@ -264,19 +263,6 @@ export abstract class DateTimeUtil { return DateTimeUtil.getMask(parts); } - /** Tries to format a date using Angular's DatePipe. Fallbacks to `Intl` if no locale settings have been loaded. */ - public static formatDate(value: number | Date, format: string, locale: string, timezone?: string): string { - let formattedDate: string; - try { - formattedDate = formatDate(value, format, locale, timezone); - } catch { - DateTimeUtil.logMissingLocaleSettings(locale); - const formatter = new Intl.DateTimeFormat(locale); - formattedDate = formatter.format(value); - } - - return formattedDate; - } /** * Returns the date format based on a provided locale. diff --git a/projects/igniteui-angular/src/lib/date-range-picker/date-range-picker-inputs.common.ts b/projects/igniteui-angular/src/lib/date-range-picker/date-range-picker-inputs.common.ts index 6fb9732e4ce..970b95cec64 100644 --- a/projects/igniteui-angular/src/lib/date-range-picker/date-range-picker-inputs.common.ts +++ b/projects/igniteui-angular/src/lib/date-range-picker/date-range-picker-inputs.common.ts @@ -5,7 +5,7 @@ import { IgxInputGroupComponent } from '../input-group/input-group.component'; import { IgxInputGroupBase } from '../input-group/input-group.common'; import { DateTimeUtil } from '../date-common/util/date-time.util'; import { IgxDateTimeEditorDirective } from '../directives/date-time-editor/public_api'; -import { isDate } from '../core/utils'; +import { formatDate, isDate } from '../core/utils'; import { IgxIconComponent } from '../icon/icon.component'; import { IgxSuffixDirective } from '../directives/suffix/suffix.directive'; import { IgxButtonDirective } from '../directives/button/button.directive'; @@ -44,8 +44,8 @@ export class DateRangePickerFormatPipe implements PipeTransform { if (!isDate(end)) { end = DateTimeUtil.parseIsoDate(end); } - const startDate = appliedFormat ? DateTimeUtil.formatDate(start, appliedFormat, locale || 'en') : start?.toLocaleDateString(); - const endDate = appliedFormat ? DateTimeUtil.formatDate(end, appliedFormat, locale || 'en') : end?.toLocaleDateString(); + const startDate = appliedFormat ? formatDate(start, appliedFormat, locale || 'en') : start?.toLocaleDateString(); + const endDate = appliedFormat ? formatDate(end, appliedFormat, locale || 'en') : end?.toLocaleDateString(); let formatted; if (start) { formatted = `${startDate} - `; diff --git a/projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts b/projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts index 7254b3296da..e990cad8e24 100644 --- a/projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts @@ -9,7 +9,7 @@ import { } from '@angular/forms'; import { IgxMaskDirective } from '../mask/mask.directive'; import { MaskParsingService } from '../mask/mask-parsing.service'; -import { isDate, PlatformUtil } from '../../core/utils'; +import { formatDate, isDate, PlatformUtil } from '../../core/utils'; import { IgxDateTimeEditorEventArgs, DatePartInfo, DatePart } from './date-time-editor.common'; import { noop } from 'rxjs'; import { DatePartDeltas } from './date-time-editor.common'; @@ -549,7 +549,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh } const format = this.displayFormat || this.inputFormat; if (format) { - this.inputValue = DateTimeUtil.formatDate(this.dateValue, format.replace('tt', 'aa'), this.locale); + this.inputValue = formatDate(this.dateValue, format.replace('tt', 'aa'), this.locale); } else { this.inputValue = this.dateValue.toLocaleString(); } From ea41d72d4e86851383b8c37a0df50b20c8fa97ca Mon Sep 17 00:00:00 2001 From: MKirova Date: Wed, 24 Sep 2025 14:33:56 +0300 Subject: [PATCH 3/8] chore(*): Use default locale from core when resolving default input format. --- .../src/lib/date-common/util/date-time.util.ts | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts index 71de5871c35..572ff26dbfa 100644 --- a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts +++ b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts @@ -2,6 +2,7 @@ import { DatePart, DatePartInfo } from '../../directives/date-time-editor/date-t import { ValidationErrors } from '@angular/forms'; import { formatDate, getLocaleDateFormat, isDate } from '../../core/utils'; import { DataType } from '../../data-operations/data-util'; +import { getDateFormatter } from 'igniteui-i18n-core'; /** @hidden */ const enum FormatDesc { @@ -249,18 +250,12 @@ export abstract class DateTimeUtil { /** Builds a date-time editor's default input format based on provided locale settings and data type. */ public static getDefaultInputFormat(locale: string, dataType: DataType = DataType.Date): string { locale = locale || DateTimeUtil.DEFAULT_LOCALE; - if (!Intl || !Intl.DateTimeFormat || !Intl.DateTimeFormat.prototype.formatToParts) { - // TODO: fallback with Intl.format for IE? - return DateTimeUtil.DEFAULT_INPUT_FORMAT; - } - const parts = DateTimeUtil.getDefaultLocaleMask(locale, dataType); - parts.forEach(p => { - if (p.type !== DatePart.Year && p.type !== DateTimeUtil.SEPARATOR && p.type !== DatePart.AmPm) { - p.formatType = FormatDesc.TwoDigits; - } - }); - return DateTimeUtil.getMask(parts); + if (dataType === DataType.Date) { + return getDateFormatter().getLocaleDateTimeFormat(locale, true); + } else if(dataType === DataType.DateTime) { + return getDateFormatter().getLocaleDateTimeFormat(locale, true); + } } From 2961c922bf880918333afdfec863ceec8d9f279f Mon Sep 17 00:00:00 2001 From: MKirova Date: Wed, 24 Sep 2025 14:41:27 +0300 Subject: [PATCH 4/8] chore(*): Pass specific input options to intl formatter in core. --- .../src/lib/date-common/util/date-time.util.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts index 572ff26dbfa..eab5b0131e8 100644 --- a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts +++ b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts @@ -544,10 +544,8 @@ export abstract class DateTimeUtil { options[p] = FormatDesc.TwoDigits; } }); - const formatter = new Intl.DateTimeFormat(locale, options); - const dateStruct = DateTimeUtil.getDateStructFromParts(formatter.formatToParts(new Date()), formatter); - DateTimeUtil.fillDatePartsPositions(dateStruct); - return DateTimeUtil.getMask(dateStruct); + + return getDateFormatter().getLocaleDateTimeFormat(locale, true, options); } private static addCurrentPart(currentPart: DatePartInfo, dateTimeParts: DatePartInfo[]): void { From f3fb8ec49149430f3088212f00d3e1bb4f5d28e9 Mon Sep 17 00:00:00 2001 From: MKirova Date: Wed, 24 Sep 2025 14:44:02 +0300 Subject: [PATCH 5/8] chore(*): Remove unused functions in util. --- .../lib/date-common/util/date-time.util.ts | 162 ------------------ 1 file changed, 162 deletions(-) diff --git a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts index eab5b0131e8..85cca56668c 100644 --- a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts +++ b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts @@ -563,70 +563,6 @@ export abstract class DateTimeUtil { return result; } - private static getMask(dateStruct: any[]): string { - const mask = []; - for (const part of dateStruct) { - if (part.formatType === FormatDesc.Numeric) { - switch (part.type) { - case DateParts.Day: - mask.push('d'); - break; - case DateParts.Month: - mask.push('M'); - break; - case DateParts.Year: - mask.push('yyyy'); - break; - case DateParts.Hour: - mask.push(part.hour12 ? 'h' : 'H'); - break; - case DateParts.Minute: - mask.push('m'); - break; - case DateParts.Second: - mask.push('s'); - break; - } - } else if (part.formatType === FormatDesc.TwoDigits) { - switch (part.type) { - case DateParts.Day: - mask.push('dd'); - break; - case DateParts.Month: - mask.push('MM'); - break; - case DateParts.Year: - mask.push('yy'); - break; - case DateParts.Hour: - mask.push(part.hour12 ? 'hh' : 'HH'); - break; - case DateParts.Minute: - mask.push('mm'); - break; - case DateParts.Second: - mask.push('ss'); - break; - } - } - - if (part.type === DateParts.AmPm) { - mask.push('tt'); - } - - if (part.type === DateTimeUtil.SEPARATOR) { - mask.push(part.value); - } - } - - return mask.join(''); - } - - private static logMissingLocaleSettings(locale: string): void { - console.warn(`Missing locale data for the locale ${locale}. Please refer to https://angular.io/guide/i18n#i18n-pipes`); - console.warn('Using default browser locale settings.'); - } - private static prependValue(value: number, partLength: number, prependChar: string): string { return (prependChar + value.toString()).slice(-partLength); } @@ -716,102 +652,4 @@ export abstract class DateTimeUtil { return { }; } } - - private static getDefaultLocaleMask(locale: string, dataType: DataType = DataType.Date) { - const options = DateTimeUtil.getFormatOptions(dataType); - const formatter = new Intl.DateTimeFormat(locale, options); - const formatToParts = formatter.formatToParts(new Date()); - const dateStruct = DateTimeUtil.getDateStructFromParts(formatToParts, formatter); - DateTimeUtil.fillDatePartsPositions(dateStruct); - return dateStruct; - } - - private static getDateStructFromParts(parts: Intl.DateTimeFormatPart[], formatter: Intl.DateTimeFormat): any[] { - const dateStruct = []; - for (const part of parts) { - if (part.type === DateTimeUtil.SEPARATOR) { - dateStruct.push({ - type: DateTimeUtil.SEPARATOR, - value: part.value - }); - } else { - dateStruct.push({ - type: part.type - }); - } - } - const formatterOptions = formatter.resolvedOptions(); - for (const part of dateStruct) { - switch (part.type) { - case DateParts.Day: { - part.formatType = formatterOptions.day; - break; - } - case DateParts.Month: { - part.formatType = formatterOptions.month; - break; - } - case DateParts.Year: { - part.formatType = formatterOptions.year; - break; - } - case DateParts.Hour: { - part.formatType = formatterOptions.hour; - if (formatterOptions.hour12) { - part.hour12 = true; - } - break; - } - case DateParts.Minute: { - part.formatType = formatterOptions.minute; - break; - } - case DateParts.Second: { - part.formatType = formatterOptions.second; - break; - } - case DateParts.AmPm: { - part.formatType = formatterOptions.dayPeriod; - break; - } - } - } - return dateStruct; - } - - private static fillDatePartsPositions(dateArray: any[]): void { - let currentPos = 0; - - for (const part of dateArray) { - // Day|Month|Hour|Minute|Second|AmPm part positions - if (part.type === DateParts.Day || part.type === DateParts.Month || - part.type === DateParts.Hour || part.type === DateParts.Minute || part.type === DateParts.Second || - part.type === DateParts.AmPm - ) { - // Offset 2 positions for number - part.position = [currentPos, currentPos + 2]; - currentPos += 2; - } else if (part.type === DateParts.Year) { - // Year part positions - switch (part.formatType) { - case FormatDesc.Numeric: { - // Offset 4 positions for full year - part.position = [currentPos, currentPos + 4]; - currentPos += 4; - break; - } - case FormatDesc.TwoDigits: { - // Offset 2 positions for short year - part.position = [currentPos, currentPos + 2]; - currentPos += 2; - break; - } - } - } else if (part.type === DateTimeUtil.SEPARATOR) { - // Separator positions - part.position = [currentPos, currentPos + 1]; - currentPos++; - } - } - } } From 8a5c1f6815ad5c4277758ba5b96ca6b43bd7599a Mon Sep 17 00:00:00 2001 From: MKirova Date: Wed, 24 Sep 2025 17:49:51 +0300 Subject: [PATCH 6/8] chore(*): Pass format options based on dataType. --- .../src/lib/date-common/util/date-time.util.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts index 85cca56668c..2ac1745b1d8 100644 --- a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts +++ b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts @@ -250,12 +250,7 @@ export abstract class DateTimeUtil { /** Builds a date-time editor's default input format based on provided locale settings and data type. */ public static getDefaultInputFormat(locale: string, dataType: DataType = DataType.Date): string { locale = locale || DateTimeUtil.DEFAULT_LOCALE; - - if (dataType === DataType.Date) { - return getDateFormatter().getLocaleDateTimeFormat(locale, true); - } else if(dataType === DataType.DateTime) { - return getDateFormatter().getLocaleDateTimeFormat(locale, true); - } + return getDateFormatter().getLocaleDateTimeFormat(locale, true, DateTimeUtil.getFormatOptions(dataType)); } From bb218ffb9df5183f5e9eee3db22669344ab1c599 Mon Sep 17 00:00:00 2001 From: MKirova Date: Thu, 25 Sep 2025 15:45:52 +0300 Subject: [PATCH 7/8] chore(*): Update formats in tests to match Intl. --- .../src/lib/date-common/util/date-time.util.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.spec.ts b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.spec.ts index 4777e412448..65033acd12f 100644 --- a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.spec.ts +++ b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.spec.ts @@ -239,7 +239,7 @@ describe(`DateTimeUtil Unit tests`, () => { it('should properly build input formats based on locale for dateTime data type ', () => { let result = DateTimeUtil.getDefaultInputFormat('en-US', DataType.DateTime); - expect(result.normalize('NFKC')).toEqual('MM/dd/yyyy, hh:mm:ss tt'); + expect(result.normalize('NFKC')).toEqual('MM/dd/yyyy, hh:mm:ss a'); result = DateTimeUtil.getDefaultInputFormat('bg-BG', DataType.DateTime); expect(result.normalize('NFKC')).toEqual('dd.MM.yyyy г., HH:mm:ss'); @@ -250,7 +250,7 @@ describe(`DateTimeUtil Unit tests`, () => { it('should properly build input formats based on locale for time data type ', () => { let result = DateTimeUtil.getDefaultInputFormat('en-US', DataType.Time); - expect(result.normalize('NFKC')).toEqual('hh:mm tt'); + expect(result.normalize('NFKC')).toEqual('hh:mm a'); result = DateTimeUtil.getDefaultInputFormat('bg-BG', DataType.Time); expect(result.normalize('NFKC')).toEqual('HH:mm'); From da834943c69d880965c38eda626abe3daa280360 Mon Sep 17 00:00:00 2001 From: skrustev Date: Thu, 6 Nov 2025 13:47:16 +0200 Subject: [PATCH 8/8] refactor(localization): Update Intl use to latest changes from localization. --- .../date-common/util/date-time.util.spec.ts | 41 ++++++++++--------- .../lib/date-common/util/date-time.util.ts | 20 +++------ .../date-range-picker-inputs.common.ts | 11 +++-- .../date-range-picker.component.ts | 2 +- .../date-time-editor.directive.ts | 12 +++--- 5 files changed, 43 insertions(+), 43 deletions(-) diff --git a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.spec.ts b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.spec.ts index 65033acd12f..86af2d68b98 100644 --- a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.spec.ts +++ b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.spec.ts @@ -3,6 +3,7 @@ import { DatePart, DatePartInfo } from '../../directives/date-time-editor/date-t import { DataType } from '../../data-operations/data-util'; import { registerLocaleData } from '@angular/common'; import localeBg from "@angular/common/locales/bg"; +import { BaseFormatter } from '../../core/i18n/formatters/formatter-base'; const reduceToDictionary = (parts: DatePartInfo[]) => parts.reduce((obj, x) => { obj[x.type] = x; @@ -658,6 +659,7 @@ describe(`DateTimeUtil Unit tests`, () => { it('should correctly identify formats that would resolve to only numeric parts (and period) for the date/time parts', () => { // test with locale covering non-ASCII characters as well const locale = 'bg'; + const angularFormatter = new BaseFormatter; const numericFormats = ['y', 'yy', 'yyy', 'yyyy', 'M', 'MM', 'd', 'dd', 'h', 'hh', 'H', 'HH', 'm', 'mm', 's', 'ss', 'S', 'SS', 'SSS', @@ -666,47 +668,48 @@ describe(`DateTimeUtil Unit tests`, () => { 'dd/MM/yyyy test hh:mm' ]; numericFormats.forEach(format => { - expect(DateTimeUtil.isFormatNumeric(locale, format)).withContext(`Format: ${format}`).toBeTrue(); + expect(DateTimeUtil.isFormatNumeric(locale, format, angularFormatter)).withContext(`Format: ${format}`).toBeTrue(); }); const nonNumericFormats = ['MMM', 'MMMM', 'MMMMM', 'medium', 'long', 'full', 'mediumDate', 'longDate', 'fullDate', 'longTime', 'fullTime', 'dd-MMM-yyyy', 'E', 'EE']; nonNumericFormats.forEach(format => { - expect(DateTimeUtil.isFormatNumeric(locale, format)).withContext(`Format: ${format}`).toBeFalse(); + expect(DateTimeUtil.isFormatNumeric(locale, format, angularFormatter)).withContext(`Format: ${format}`).toBeFalse(); }); }); it('getNumericInputFormat should return formats with date parts that the date-time editors can handle', () => { let locale = 'en-US'; + const angularFormatter = new BaseFormatter; // returns the equivalent of the predefined numeric formats as date parts // should be transformed as inputFormats for editing (numeric year, 2-digit parts for the rest) - expect(DateTimeUtil.getNumericInputFormat(locale, 'short')).toBe('MM/dd/yyyy, hh:mm tt'); - expect(DateTimeUtil.getNumericInputFormat(locale, 'shortDate')).toBe('MM/dd/yyyy'); - expect(DateTimeUtil.getNumericInputFormat(locale, 'shortTime').normalize('NFKD')).toBe('hh:mm tt'); - expect(DateTimeUtil.getNumericInputFormat(locale, 'mediumTime').normalize('NFKD')).toBe('hh:mm:ss tt'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'short', angularFormatter)).toBe('MM/dd/yyyy, hh:mm tt'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'shortDate', angularFormatter)).toBe('MM/dd/yyyy'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'shortTime', angularFormatter).normalize('NFKD')).toBe('hh:mm tt'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'mediumTime', angularFormatter).normalize('NFKD')).toBe('hh:mm:ss tt'); // handle the predefined formats for different locales locale = 'bg-BG'; - expect(DateTimeUtil.getNumericInputFormat(locale, 'short').normalize('NFKD')).toBe('dd.MM.yyyy г., HH:mm'); - expect(DateTimeUtil.getNumericInputFormat(locale, 'shortDate').normalize('NFKD')).toBe('dd.MM.yyyy г.'); - expect(DateTimeUtil.getNumericInputFormat(locale, 'shortTime').normalize('NFKD')).toBe('HH:mm'); - expect(DateTimeUtil.getNumericInputFormat(locale, 'mediumTime').normalize('NFKD')).toBe('HH:mm:ss'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'short', angularFormatter).normalize('NFKD')).toBe('dd.MM.yyyy г., HH:mm'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'shortDate', angularFormatter).normalize('NFKD')).toBe('dd.MM.yyyy г.'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'shortTime', angularFormatter).normalize('NFKD')).toBe('HH:mm'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'mediumTime', angularFormatter).normalize('NFKD')).toBe('HH:mm:ss'); locale = 'ja-JP'; - expect(DateTimeUtil.getNumericInputFormat(locale, 'short')).toBe('yyyy/MM/dd HH:mm'); - expect(DateTimeUtil.getNumericInputFormat(locale, 'shortDate')).toBe('yyyy/MM/dd'); - expect(DateTimeUtil.getNumericInputFormat(locale, 'shortTime').normalize('NFKD')).toBe('HH:mm'); - expect(DateTimeUtil.getNumericInputFormat(locale, 'mediumTime').normalize('NFKD')).toBe('HH:mm:ss'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'short', angularFormatter)).toBe('yyyy/MM/dd HH:mm'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'shortDate', angularFormatter)).toBe('yyyy/MM/dd'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'shortTime', angularFormatter).normalize('NFKD')).toBe('HH:mm'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'mediumTime', angularFormatter).normalize('NFKD')).toBe('HH:mm:ss'); // returns the same format if it is custom and numeric - expect(DateTimeUtil.getNumericInputFormat(locale, 'dd-MM-yyyy')).toBe('dd-MM-yyyy'); - expect(DateTimeUtil.getNumericInputFormat(locale, 'dd/M/yyyy hh:mm:ss:SS aa')).toBe('dd/M/yyyy hh:mm:ss:SS aa'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'dd-MM-yyyy', angularFormatter)).toBe('dd-MM-yyyy'); + expect(DateTimeUtil.getNumericInputFormat(locale, 'dd/M/yyyy hh:mm:ss:SS aa', angularFormatter)).toBe('dd/M/yyyy hh:mm:ss:SS aa'); // returns empty string if predefined and not among the numeric ones - expect(DateTimeUtil.getNumericInputFormat(locale, 'medium')).toBe(''); - expect(DateTimeUtil.getNumericInputFormat(locale, 'mediumDate')).toBe(''); - expect(DateTimeUtil.getNumericInputFormat(locale, 'longTime')).toBe(''); + expect(DateTimeUtil.getNumericInputFormat(locale, 'medium', angularFormatter)).toBe(''); + expect(DateTimeUtil.getNumericInputFormat(locale, 'mediumDate', angularFormatter)).toBe(''); + expect(DateTimeUtil.getNumericInputFormat(locale, 'longTime', angularFormatter)).toBe(''); }); }); diff --git a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts index 2ac1745b1d8..d07200b8793 100644 --- a/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts +++ b/projects/igniteui-angular/src/lib/date-common/util/date-time.util.ts @@ -1,8 +1,9 @@ import { DatePart, DatePartInfo } from '../../directives/date-time-editor/date-time-editor.common'; import { ValidationErrors } from '@angular/forms'; -import { formatDate, getLocaleDateFormat, isDate } from '../../core/utils'; +import { isDate } from '../../core/utils'; import { DataType } from '../../data-operations/data-util'; import { getDateFormatter } from 'igniteui-i18n-core'; +import { BaseFormatter } from '../../core/i18n/formatters/formatter-base'; /** @hidden */ const enum FormatDesc { @@ -253,15 +254,6 @@ export abstract class DateTimeUtil { return getDateFormatter().getLocaleDateTimeFormat(locale, true, DateTimeUtil.getFormatOptions(dataType)); } - - /** - * Returns the date format based on a provided locale. - * Supports Angular's DatePipe format options such as `shortDate`, `longDate`. - */ - public static getLocaleDateFormat(locale: string, displayFormat?: string): string { - return getLocaleDateFormat(locale, displayFormat); - } - /** Determines if a given character is `d/M/y` or `h/m/s`. */ public static isDateOrTimeChar(char: string): boolean { return DATE_CHARS.indexOf(char) !== -1 || TIME_CHARS.indexOf(char) !== -1; @@ -490,7 +482,7 @@ export abstract class DateTimeUtil { return false; } - public static isFormatNumeric(locale: string, inputFormat: string): boolean { + public static isFormatNumeric(locale: string, inputFormat: string, formatter: BaseFormatter): boolean { const dateParts = DateTimeUtil.parseDateTimeFormat(inputFormat); if (predefinedNonNumericFormats.has(inputFormat) || dateParts.every(p => p.type === DatePart.Literal)) { return false; @@ -499,7 +491,7 @@ export abstract class DateTimeUtil { if (dateParts[i].type === DatePart.AmPm || dateParts[i].type === DatePart.Literal) { continue; } - const transformedValue = formatDate(new Date(), dateParts[i].format, locale); + const transformedValue = formatter.formatDate(new Date(), dateParts[i].format, locale); // check if the transformed date/time part contains any kind of letter from any language if (/\p{L}+/gu.test(transformedValue)) { return false; @@ -515,7 +507,7 @@ export abstract class DateTimeUtil { * for the corresponding numeric date parts * - otherwise, return an empty string */ - public static getNumericInputFormat(locale: string, format: string): string { + public static getNumericInputFormat(locale: string, format: string, formatter: BaseFormatter): string { let resultFormat = ''; if (!format) { return resultFormat; @@ -523,7 +515,7 @@ export abstract class DateTimeUtil { if (predefinedNumericFormats.has(format)) { resultFormat = DateTimeUtil.getLocaleInputFormatFromParts(locale, predefinedNumericFormats.get(format)); - } else if (DateTimeUtil.isFormatNumeric(locale, format)) { + } else if (DateTimeUtil.isFormatNumeric(locale, format, formatter)) { resultFormat = format; } return resultFormat; diff --git a/projects/igniteui-angular/src/lib/date-range-picker/date-range-picker-inputs.common.ts b/projects/igniteui-angular/src/lib/date-range-picker/date-range-picker-inputs.common.ts index 970b95cec64..bc89fbefdde 100644 --- a/projects/igniteui-angular/src/lib/date-range-picker/date-range-picker-inputs.common.ts +++ b/projects/igniteui-angular/src/lib/date-range-picker/date-range-picker-inputs.common.ts @@ -1,16 +1,17 @@ -import { Component, ContentChild, Pipe, PipeTransform, Directive } from '@angular/core'; +import { Component, ContentChild, Pipe, PipeTransform, Directive, Inject, inject } from '@angular/core'; import { NgControl } from '@angular/forms'; import { IgxInputDirective, IgxInputState } from '../input-group/public_api'; import { IgxInputGroupComponent } from '../input-group/input-group.component'; import { IgxInputGroupBase } from '../input-group/input-group.common'; import { DateTimeUtil } from '../date-common/util/date-time.util'; import { IgxDateTimeEditorDirective } from '../directives/date-time-editor/public_api'; -import { formatDate, isDate } from '../core/utils'; +import { isDate } from '../core/utils'; import { IgxIconComponent } from '../icon/icon.component'; import { IgxSuffixDirective } from '../directives/suffix/suffix.directive'; import { IgxButtonDirective } from '../directives/button/button.directive'; import { IgxPrefixDirective } from '../directives/prefix/prefix.directive'; import { NgTemplateOutlet } from '@angular/common'; +import { BaseFormatter, I18N_FORMATTER } from '../core/i18n/formatters/formatter-base'; /** Represents a range between two dates. */ export interface DateRange { @@ -29,6 +30,8 @@ export interface CustomDateRange { standalone: true }) export class DateRangePickerFormatPipe implements PipeTransform { + private i18nFormatter = inject(I18N_FORMATTER); + public transform(values: DateRange, appliedFormat?: string, locale?: string, formatter?: (_: DateRange) => string): string { if (!values || !values.start && !values.end) { @@ -44,8 +47,8 @@ export class DateRangePickerFormatPipe implements PipeTransform { if (!isDate(end)) { end = DateTimeUtil.parseIsoDate(end); } - const startDate = appliedFormat ? formatDate(start, appliedFormat, locale || 'en') : start?.toLocaleDateString(); - const endDate = appliedFormat ? formatDate(end, appliedFormat, locale || 'en') : end?.toLocaleDateString(); + const startDate = appliedFormat ? this.i18nFormatter.formatDate(start, appliedFormat, locale || 'en') : start?.toLocaleDateString(); + const endDate = appliedFormat ? this.i18nFormatter.formatDate(end, appliedFormat, locale || 'en') : end?.toLocaleDateString(); let formatted; if (start) { formatted = `${startDate} - `; diff --git a/projects/igniteui-angular/src/lib/date-range-picker/date-range-picker.component.ts b/projects/igniteui-angular/src/lib/date-range-picker/date-range-picker.component.ts index 5027775638d..0ca10b12cf4 100644 --- a/projects/igniteui-angular/src/lib/date-range-picker/date-range-picker.component.ts +++ b/projects/igniteui-angular/src/lib/date-range-picker/date-range-picker.component.ts @@ -436,7 +436,7 @@ export class IgxDateRangePickerComponent extends PickerBaseDirective /** @hidden @internal */ public get appliedFormat(): string { - return DateTimeUtil.getLocaleDateFormat(this.locale, this.displayFormat) + return this.i18nFormatter.getLocaleDateFormat(this.locale, this.displayFormat) || DateTimeUtil.DEFAULT_INPUT_FORMAT; } diff --git a/projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts b/projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts index e990cad8e24..5c0df14f1b7 100644 --- a/projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts @@ -9,11 +9,12 @@ import { } from '@angular/forms'; import { IgxMaskDirective } from '../mask/mask.directive'; import { MaskParsingService } from '../mask/mask-parsing.service'; -import { formatDate, isDate, PlatformUtil } from '../../core/utils'; +import { isDate, PlatformUtil } from '../../core/utils'; import { IgxDateTimeEditorEventArgs, DatePartInfo, DatePart } from './date-time-editor.common'; import { noop } from 'rxjs'; import { DatePartDeltas } from './date-time-editor.common'; import { DateTimeUtil } from '../../date-common/util/date-time.util'; +import { BaseFormatter, I18N_FORMATTER } from '../../core/i18n/formatters/formatter-base'; /** * Date Time Editor provides a functionality to input, edit and format date and time. @@ -139,7 +140,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh } public get displayFormat(): string { - return this._displayFormat || this._inputFormat || DateTimeUtil.getLocaleDateFormat(this.locale, 'short'); + return this._displayFormat || this._inputFormat || this._i18nFormatter.getLocaleDateFormat(this.locale, 'short'); } /** @@ -303,7 +304,8 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh maskParser: MaskParsingService, platform: PlatformUtil, @Inject(DOCUMENT) private _document: any, - @Inject(LOCALE_ID) private _locale: any) { + @Inject(LOCALE_ID) private _locale: any, + @Inject(I18N_FORMATTER) private _i18nFormatter: BaseFormatter,) { super(elementRef, maskParser, renderer, platform); this.document = this._document as Document; this.locale = this.locale || this._locale; @@ -526,7 +528,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh protected override setPlaceholder(_value: string): void { } private updateDefaultFormat(): void { - this._defaultInputFormat = DateTimeUtil.getNumericInputFormat(this.locale, this._displayFormat) + this._defaultInputFormat = DateTimeUtil.getNumericInputFormat(this.locale, this._displayFormat, this._i18nFormatter) || DateTimeUtil.getDefaultInputFormat(this.locale, this.defaultFormatType); this.setMask(this.inputFormat); } @@ -549,7 +551,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh } const format = this.displayFormat || this.inputFormat; if (format) { - this.inputValue = formatDate(this.dateValue, format.replace('tt', 'aa'), this.locale); + this.inputValue = this._i18nFormatter.formatDate(this.dateValue, format.replace('tt', 'aa'), this.locale); } else { this.inputValue = this.dateValue.toLocaleString(); }