import * as i2 from 'rxjs';
import { Subject } from 'rxjs';
import * as i0 from '@angular/core';
import { InjectionToken, Optional, Inject, Pipe, LOCALE_ID, Injectable, NgModule } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { TranslationResolver, FD_LANGUAGE } from '@fundamental-ngx/i18n';
import { INVALID_DATE_ERROR, range, LETTERS_UNICODE_RANGE } from '@fundamental-ngx/cdk/utils';
import * as i1 from '@angular/cdk/platform';
import { PlatformModule } from '@angular/cdk/platform';

/**
 * Datetime Adapter is an abstract class that must be implemented by each adapter.
 * It's used to encapsulate a date/time manipulations as result
 * others places that uses it remain date type agnostic.
 *
 */
class DatetimeAdapter {
    constructor() {
        /** @hidden */
        this._localeChanges = new Subject();
        this.localeChanges = this._localeChanges.asObservable();
    }
    /**
     * Sets the locale used for all dates.
     * @param locale The new locale.
     */
    setLocale(locale) {
        this.locale = locale;
        this._localeChanges.next();
    }
    /**
     * Set hours, minutes and seconds at once.
     * @param date The date to set time to.
     * @param hours
     * @param minutes
     * @param seconds
     * @returns The new date instance.
     */
    setTime(date, hours, minutes, seconds) {
        date = this.setHours(date, hours);
        date = this.setMinutes(date, minutes);
        date = this.setSeconds(date, seconds);
        return date;
    }
    /**
     * Get Amount of weeks in given month/year
     * @param year The year of the date
     * @param month The month of the date
     * @param firstDayOfWeek The first day of week. 1 - Sunday, 2 - Monday...
     * @returns Number of weeks in the given month
     */
    getAmountOfWeeks(year, month, firstDayOfWeek) {
        const firstOfMonth = new Date(year, month - 1, 1);
        const lastOfMonth = new Date(year, month, 0);
        const dayOffset = (firstOfMonth.getDay() - firstDayOfWeek + 8) % 7;
        const used = dayOffset + lastOfMonth.getDate();
        return Math.ceil(used / 7);
    }
    /**
     * Compares two dates.
     * @param first The first date to compare.
     * @param second The second date to compare.
     * @returns 0 if the dates are equal, a number less than 0 if the first date is earlier,
     *     a number greater than 0 if the first date is later.
     */
    compareDate(first, second) {
        return (this.getYear(first) - this.getYear(second) ||
            this.getMonth(first) - this.getMonth(second) ||
            this.getDate(first) - this.getDate(second) ||
            this.getHours(first) - this.getHours(second) ||
            this.getMinutes(first) - this.getMinutes(second) ||
            this.getSeconds(first) - this.getSeconds(second));
    }
}

/**
 * DateTimeFormats injection token
 */
const DATE_TIME_FORMATS = new InjectionToken('date-formats');

class DateFormatPipe {
    /** @hidden */
    constructor(_dateTimeAdapter, _dateTimeFormats) {
        this._dateTimeAdapter = _dateTimeAdapter;
        this._dateTimeFormats = _dateTimeFormats;
    }
    /** Format date object */
    transform(date, noDateMessage = '') {
        if (date) {
            return this._dateTimeAdapter.format(date, this._dateTimeFormats.display.dateInput);
        }
        else {
            return noDateMessage;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateFormatPipe, deps: [{ token: DatetimeAdapter }, { token: DATE_TIME_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: DateFormatPipe, isStandalone: true, name: "dateFormat" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateFormatPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'dateFormat',
                    standalone: true
                }]
        }], ctorParameters: () => [{ type: DatetimeAdapter }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [DATE_TIME_FORMATS]
                }] }] });
class DateTimeFormatPipe {
    /** @hidden */
    constructor(_dateTimeAdapter, _dateTimeFormats) {
        this._dateTimeAdapter = _dateTimeAdapter;
        this._dateTimeFormats = _dateTimeFormats;
    }
    /** Format date object */
    transform(date, noDateMessage = '') {
        if (date) {
            return this._dateTimeAdapter.format(date, this._dateTimeFormats.display.dateTimeInput);
        }
        else {
            return noDateMessage;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateTimeFormatPipe, deps: [{ token: DatetimeAdapter }, { token: DATE_TIME_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: DateTimeFormatPipe, isStandalone: true, name: "dateTimeFormat" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateTimeFormatPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'dateTimeFormat',
                    standalone: true
                }]
        }], ctorParameters: () => [{ type: DatetimeAdapter }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [DATE_TIME_FORMATS]
                }] }] });
class DateFromNowPipe {
    /** @hidden */
    constructor(_dateTimeAdapter) {
        this._dateTimeAdapter = _dateTimeAdapter;
    }
    /** Format date object */
    transform(date, noDateMessage = '') {
        if (this._dateTimeAdapter.fromNow && typeof this._dateTimeAdapter.fromNow === 'function') {
            if (date) {
                return this._dateTimeAdapter.fromNow(date);
            }
            else {
                return noDateMessage;
            }
        }
        else {
            console.warn('No fromNow function provided to the DatetimeAdapter');
            return '';
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateFromNowPipe, deps: [{ token: DatetimeAdapter }], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: DateFromNowPipe, isStandalone: true, name: "dateFromNow" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateFromNowPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'dateFromNow',
                    standalone: true
                }]
        }], ctorParameters: () => [{ type: DatetimeAdapter }] });
class DayPeriodFormatPipe {
    /** @hidden */
    constructor(_dateTimeAdapter, _dateTimeFormats) {
        this._dateTimeAdapter = _dateTimeAdapter;
        this._dateTimeFormats = _dateTimeFormats;
    }
    /** Format date object for day period */
    transform(date, customFormat = {}, noDateMessage = '') {
        if (!date) {
            return noDateMessage;
        }
        return this._dateTimeAdapter.format(date, customFormat);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DayPeriodFormatPipe, deps: [{ token: DatetimeAdapter }, { token: DATE_TIME_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: DayPeriodFormatPipe, isStandalone: true, name: "dayPeriodFormat" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DayPeriodFormatPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'dayPeriodFormat',
                    standalone: true
                }]
        }], ctorParameters: () => [{ type: DatetimeAdapter }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [DATE_TIME_FORMATS]
                }] }] });
class TranslateDayPeriodPipe {
    /** @hidden */
    constructor(_language$) {
        this._language$ = _language$;
        /** @hidden */
        this._translationResolver = new TranslationResolver();
        this._currentLanguageSignal = toSignal(this._language$, { initialValue: {} });
    }
    /** Format date object for day period */
    transform(value) {
        if (!value) {
            return value;
        }
        const dayPeriodPattern = /(coreTime\.\w+Label)/;
        const match = value.match(dayPeriodPattern);
        if (match?.[0]) {
            const currentLanguage = this._currentLanguageSignal();
            const translatedValue = this._translationResolver.resolve(currentLanguage, match[0]);
            return translatedValue ? value.replace(dayPeriodPattern, translatedValue) : value;
        }
        // If no day period pattern is found, return the original value
        return value;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TranslateDayPeriodPipe, deps: [{ token: FD_LANGUAGE }], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: TranslateDayPeriodPipe, isStandalone: true, name: "translateDayPeriod", pure: false }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TranslateDayPeriodPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'translateDayPeriod',
                    standalone: true,
                    pure: false // required to update the value when the observable is resolved
                }]
        }], ctorParameters: () => [{ type: i2.Observable, decorators: [{
                    type: Inject,
                    args: [FD_LANGUAGE]
                }] }] });

/**
 * Converts a given time string to a desired format.
 *
 * @param {string} inputStr - The input time string to be converted.
 * @returns {string} - The converted time string in the desired format.
 */
function convertToDesiredFormat(inputStr) {
    const dayPeriodMapping = {
        morning: 0,
        afternoon: 12,
        evening: 12,
        night: 0
    };
    const dayPeriodPattern = /\b(morning|afternoon|evening|night)\b/;
    const amPmPattern = /\b(AM|PM)\b/i;
    const convertDayPeriod = (input) => {
        const match = input.match(dayPeriodPattern);
        if (match) {
            const period = match[0].toLowerCase();
            const timeShift = dayPeriodMapping[period];
            input = input.replace(dayPeriodPattern, '').trim();
            const timeMatch = input.match(/\d{1,2}:\d{2}/);
            if (timeMatch) {
                const [hoursStr, minutesStr] = timeMatch[0].split(':');
                let hours = Number(hoursStr);
                const minutes = Number(minutesStr);
                hours = (hours % 12) + timeShift;
                input = input.replace(timeMatch[0], `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`);
            }
        }
        return input;
    };
    const convertAmPm = (input) => {
        const match = input.match(amPmPattern);
        if (match) {
            const period = match[0].toUpperCase();
            input = input.replace(amPmPattern, '').trim();
            const timeMatch = input.match(/\d{1,2}:\d{2}/);
            if (timeMatch) {
                const [hoursStr, minutesStr] = timeMatch[0].split(':');
                let hours = Number(hoursStr);
                const minutes = Number(minutesStr);
                if (period === 'PM' && hours < 12) {
                    hours += 12;
                }
                if (period === 'AM' && hours === 12) {
                    hours = 0;
                }
                input = input.replace(timeMatch[0], `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`);
            }
        }
        return input;
    };
    inputStr = convertDayPeriod(inputStr);
    inputStr = convertAmPm(inputStr);
    return inputStr.replace(/\bat\b/i, '').trim();
}

/** Adds 0 if number is less then 10 */
function _leftPad(n) {
    return n === n % 10 ? `0${n}` : `${n}`;
}
/** Converts date to ISO8601 */
function toIso8601(fdDate) {
    return [
        [fdDate.year, _leftPad(fdDate.month), _leftPad(fdDate.day)].join('-'),
        'T',
        [_leftPad(fdDate.hour), _leftPad(fdDate.minute), _leftPad(fdDate.second)].join(':')
    ].join('');
}
/**
 * @param params e.g. { year: 2020, month: 1, day: 1, hour: 0, minute: 0, second: 0 }
 */
function isValidByParams(params) {
    const { year, month, day, hour, minute, second } = params;
    if (!undefinedOrInRange(month, 1, 12) ||
        !undefinedOrInRange(day, 1, 31) ||
        !undefinedOrInRange(hour, 0, 23) ||
        !undefinedOrInRange(minute, 0, 59) ||
        !undefinedOrInRange(second, 0, 59)) {
        return false;
    }
    if (!isNaN(year) && !isNaN(month) && day != null && !isNaN(day)) {
        const tempDate = new Date(year, month - 1, day);
        if (tempDate.getMonth() + 1 !== month) {
            return false;
        }
    }
    const date = new Date(year, month - 1, day, hour, minute, second);
    return !Number.isNaN(date.getTime());
}
function undefinedOrInRange(value, from, to) {
    return value == null || (value >= from && value <= to);
}

/**
 * FdDate class is used to represent date and time.
 *
 * It's a simplified analog of native Date instance.
 * It gives some convenience methods to work with date or time data.
 *
 */
class FdDate {
    /**
     * Create FdDate
     * @param year e.g. 2020
     * @param month 1 = January, 12 = December
     * @param day 1 - 31
     * @param hour 0 - 23
     * @param minute 0 - 59
     * @param second 0 - 59
     */
    constructor(year, month = 1, day = 1, hour = 0, minute = 0, second = 0) {
        if (year === undefined) {
            return FdDate.getNow();
        }
        year = Number.parseInt(year + '', 10);
        month = Number.parseInt(month + '', 10);
        day = Number.parseInt(day + '', 10);
        hour = Number.parseInt(hour + '', 10);
        minute = Number.parseInt(minute + '', 10);
        second = Number.parseInt(second + '', 10);
        this._isValid = isValidByParams({
            year,
            month,
            day,
            hour,
            minute,
            second
        });
        this.year = this._isValid ? year : NaN;
        this.month = this._isValid ? month : NaN;
        this.day = this._isValid ? day : NaN;
        this.hour = this._isValid ? hour : NaN;
        this.minute = this._isValid ? minute : NaN;
        this.second = this._isValid ? second : NaN;
        return this;
    }
    /**
     * Create FdDate instance of the current moment
     */
    static getNow() {
        return FdDate.getFdDateByDate(new Date());
    }
    /**
     * Gets today's FdDate where hour, minute and second is set to 0
     */
    static getToday() {
        return FdDate.getNow().setTime(0, 0, 0);
    }
    /**
     *  Convert js date object to FdDate model
     */
    static getFdDateByDate(date) {
        return new FdDate(date.getFullYear(), date.getMonth() + 1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());
    }
    /**
     * Set hour, minute and second data
     * @param hour
     * @param minute
     * @param second
     */
    setTime(hour, minute, second) {
        this._isValid = isValidByParams({
            year: this.year,
            month: this.month,
            day: this.day,
            hour,
            minute,
            second
        });
        if (!this._isValid) {
            this.hour = NaN;
            this.minute = NaN;
            this.second = NaN;
        }
        else {
            this.hour = hour || hour === 0 ? hour : this.hour;
            this.minute = minute || minute === 0 ? minute : this.minute;
            this.second = second || second === 0 ? second : this.second;
        }
        return this;
    }
    /**
     * Get amount of milliseconds from 01.01.1970
     */
    getTimeStamp() {
        return this.toDate().getTime();
    }
    /**
     * Get number of weekday ex. Sunday = 1, Monday = 2, Tuesday = 3 etc.
     */
    getDayOfWeek() {
        return this.toDate().getDay() + 1;
    }
    /**
     * Get native date object from FdDate.
     */
    toDate() {
        // We have stricter validation rules than Date object.
        // For example, Date allows values for month=100 or for day=100.
        // Therefore, we need to do this trick for the consistency of the validation status
        if (!this.isDateValid()) {
            return new Date(NaN);
        }
        return new Date(this.year, this.month - 1, this.day, this.hour, this.minute, this.second);
    }
    /**
     * Method that checks validity of current FdDate instance.
     */
    isDateValid() {
        return this instanceof FdDate && this._isValid;
    }
    /**
     * Get string representation in yyyy-mm-ddThh:mm:ss format
     */
    toString() {
        if (!this.isDateValid()) {
            return INVALID_DATE_ERROR;
        }
        if (!this.year || !this.month || !this.day) {
            return '';
        }
        return toIso8601(this);
    }
    /**
     * The valueOf() method returns the primitive value of a FdDate.
     * Returns: The number of milliseconds between 1 January 1970 00:00:00 UTC and the given date.
     */
    valueOf() {
        return this.getTimeStamp();
    }
    /**
     * Get date string in yyyy-mm-dd format
     */
    toDateString() {
        if (!this.isDateValid()) {
            return INVALID_DATE_ERROR;
        }
        if (!this.year || !this.month || !this.day) {
            return '';
        }
        return toIso8601(this).split('T')[0];
    }
    /**
     * Get time string in hh:mm:ss format
     */
    toTimeString() {
        if (!this.isDateValid()) {
            return INVALID_DATE_ERROR;
        }
        if (!this.year || !this.month || !this.day) {
            return '';
        }
        return toIso8601(this).split('T')[1];
    }
}

const dateInput = { year: 'numeric', month: 'numeric', day: 'numeric' };
const timeInput = { hour: 'numeric', minute: '2-digit' };
const dateTimeInput = {
    year: 'numeric',
    month: 'numeric',
    day: 'numeric',
    hour: 'numeric',
    minute: '2-digit'
};
const FD_DATETIME_FORMATS = {
    parse: {
        dateInput,
        timeInput,
        dateTimeInput
    },
    display: {
        dateInput,
        timeInput,
        dateTimeInput,
        dateA11yLabel: { year: 'numeric', month: 'long', day: 'numeric' },
        monthA11yLabel: { month: 'long', year: 'numeric' },
        yearA11yLabel: { year: 'numeric' }
    },
    rangeDelimiter: ' - '
};

const AM_DAY_PERIOD_DEFAULT = 'AM';
const PM_DAY_PERIOD_DEFAULT = 'PM';
/**
 * DatetimeAdapter implementation based on FdDate.
 *
 * This uses FdDate as a date model and relies on Intl.DateTimeFormat
 * for formatting and translation purposes.
 *
 */
class FdDatetimeAdapter extends DatetimeAdapter {
    /** @hidden */
    constructor(localeId, platform) {
        super();
        super.setLocale(localeId);
        this._fixYearsRangeIssue = platform.TRIDENT || platform.EDGE;
    }
    /** Get year */
    getYear(date) {
        return date.year;
    }
    /** Get month */
    getMonth(date) {
        return date.month;
    }
    /** Get date */
    getDate(date) {
        return date.day;
    }
    /** Get day of week */
    getDayOfWeek(date) {
        return this._createDateInstanceByFdDate(date).getDay() + 1;
    }
    /** Get hours */
    getHours(date) {
        return date.hour;
    }
    /** Get minutes */
    getMinutes(date) {
        return date.minute;
    }
    /** Get seconds */
    getSeconds(date) {
        return date.second;
    }
    /** Get week number */
    getWeekNumber(fdDate) {
        const date = this._createDateInstanceByFdDate(fdDate);
        date.setDate(date.getDate() + 3 - ((date.getDay() + 6) % 7));
        // January 4 is always in week 1.
        const firstWeek = new Date(date.getFullYear(), 0, 4);
        // Adjust to Thursday in week 1 and count number of weeks from date to week1.
        return (1 + Math.round(((date.getTime() - firstWeek.getTime()) / 86400000 - 3 + ((firstWeek.getDay() + 6) % 7)) / 7));
    }
    /** Get month names */
    getMonthNames(style) {
        const dateTimeFormat = new Intl.DateTimeFormat(this.locale, { month: style, timeZone: 'utc' });
        return range(12, (i) => this._stripDirectionalityCharacters(this._format(dateTimeFormat, new Date(2017, i, 1))));
    }
    /** Get date names */
    getDateNames() {
        const dateTimeFormat = new Intl.DateTimeFormat(this.locale, { day: 'numeric', timeZone: 'utc' });
        return range(31, (i) => this._stripDirectionalityCharacters(this._format(dateTimeFormat, new Date(2017, 0, i + 1))));
    }
    /** Get day of week names */
    getDayOfWeekNames(style) {
        const dateTimeFormat = new Intl.DateTimeFormat(this.locale, { weekday: style, timeZone: 'utc' });
        return range(7, (i) => this._stripDirectionalityCharacters(this._format(dateTimeFormat, new Date(2017, 0, i + 1))));
    }
    /** Get year name */
    getYearName(date) {
        const dateTimeFormat = new Intl.DateTimeFormat(this.locale, { year: 'numeric', timeZone: 'utc' });
        const dateInstance = this._createDateInstanceByFdDate(date);
        return this._stripDirectionalityCharacters(this._format(dateTimeFormat, dateInstance));
    }
    /** Get week name */
    getWeekName(date) {
        const weekNumber = this.getWeekNumber(date);
        return weekNumber.toLocaleString(this.locale);
    }
    /** Get hour names */
    getHourNames({ meridian, twoDigit }) {
        return range(24, (hour) => {
            if (meridian) {
                hour = hour === 0 || hour === 12 ? 12 : hour % 12;
            }
            return hour.toLocaleString(this.locale, { minimumIntegerDigits: twoDigit ? 2 : 1 });
        });
    }
    /** Get minute names */
    getMinuteNames({ twoDigit, minuteStep = 1 }) {
        const length = Math.ceil(60 / minuteStep);
        return range(length, (index) => {
            const minute = index * minuteStep;
            return minute.toLocaleString(this.locale, { minimumIntegerDigits: twoDigit ? 2 : 1 });
        });
    }
    /** Get second names */
    getSecondNames({ twoDigit }) {
        return range(60, (second) => second.toLocaleString(this.locale, { minimumIntegerDigits: twoDigit ? 2 : 1 }));
    }
    /** Get day period names */
    getDayPeriodNames() {
        const DEFAULT_PERIODS = [AM_DAY_PERIOD_DEFAULT, PM_DAY_PERIOD_DEFAULT];
        const formatter = new Intl.DateTimeFormat(this.locale, {
            hour: 'numeric',
            minute: 'numeric',
            hour12: true
        });
        try {
            const am = formatter.formatToParts(new Date(2020, 0, 1, 6)).find(({ type }) => type === 'dayPeriod')?.value;
            const pm = formatter
                .formatToParts(new Date(2020, 0, 1, 16))
                .find(({ type }) => type === 'dayPeriod')?.value;
            return am && pm ? [am, pm] : DEFAULT_PERIODS;
        }
        catch {
            const dayPeriodRegexp = new RegExp(`(${LETTERS_UNICODE_RANGE}+\\.*)+`, 'g');
            const amRegExpMatch = formatter.format(new Date(2020, 0, 1, 6)).match(dayPeriodRegexp);
            const pmRegExpMatch = formatter.format(new Date(2020, 0, 1, 16)).match(dayPeriodRegexp);
            return amRegExpMatch && pmRegExpMatch
                ? [amRegExpMatch[0], pmRegExpMatch[0]]
                : [AM_DAY_PERIOD_DEFAULT, PM_DAY_PERIOD_DEFAULT];
        }
    }
    /** Set hours */
    setHours(date, hours) {
        const dateInstance = this._createDateInstanceByFdDate(date);
        dateInstance.setHours(hours);
        return this._createFdDateFromDateInstance(dateInstance);
    }
    /** Set minutes */
    setMinutes(date, hours) {
        const dateInstance = this._createDateInstanceByFdDate(date);
        dateInstance.setMinutes(hours);
        return this._createFdDateFromDateInstance(dateInstance);
    }
    /** Set seconds */
    setSeconds(date, hours) {
        const dateInstance = this._createDateInstanceByFdDate(date);
        dateInstance.setSeconds(hours);
        return this._createFdDateFromDateInstance(dateInstance);
    }
    /** Get first day of week */
    getFirstDayOfWeek() {
        // can't retrieve this info from Intl object or Date object, default to Sunday.
        return 0;
    }
    /** Get number of days in a month */
    getNumDaysInMonth(fdDate) {
        const date = this._createDateInstanceByFdDate(fdDate);
        date.setMonth(date.getMonth() + 1);
        date.setDate(0);
        return date.getDate();
    }
    /** Create a date object */
    createDate(year, month = 1, date = 1) {
        return new FdDate(year, month, date);
    }
    /** Get a today date object */
    today() {
        return FdDate.getToday();
    }
    /** Get a now date object */
    now() {
        return FdDate.getNow();
    }
    /** Parse any value to date object */
    parse(value, parseFormat = {}) {
        if (!value && value !== 0) {
            return null;
        }
        if (value instanceof FdDate) {
            return this.clone(value);
        }
        /**
         * We have no way using the native JS Date to set the parse format or locale,
         * so we ignore these parameters.
         */
        let date = new Date(Date.parse(value));
        if (typeof value === 'number') {
            date = new Date(value);
        }
        // Check if we are dealing with a time string
        if (Number.isNaN(date.valueOf()) &&
            typeof value === 'string' &&
            !parseFormat.year &&
            !parseFormat.day &&
            !parseFormat.month &&
            parseFormat.hour) {
            date = this._parseTimeString(value);
        }
        return this._createFdDateFromDateInstance(date);
    }
    /** Format date object to string */
    format(date, displayFormat) {
        if (!this.isValid(date)) {
            return INVALID_DATE_ERROR;
        }
        // On IE and Edge the i18n API will throw a hard error that can crash the entire app
        // if we attempt to format a date whose year is less than 1 or greater than 9999.
        if (this._fixYearsRangeIssue && (date.year < 1 || date.year > 9999)) {
            date = this.clone(date);
            date.year = Math.max(1, Math.min(9999, date.year));
        }
        displayFormat = { ...displayFormat, timeZone: 'utc' };
        return displayFormat.dayPeriod
            ? this._formatWithDayPeriod(date, displayFormat)
            : this._formatWithIntl(date, displayFormat);
    }
    /** Add years to a date */
    addCalendarYears(date, years) {
        return this.addCalendarMonths(date, years * 12);
    }
    /** Add months to a date */
    addCalendarMonths(fdDate, months) {
        const date = this._createDateInstanceByFdDate(fdDate);
        date.setMonth(date.getMonth() + months);
        // It's possible to wind up in the wrong month if the original month has more days than the new
        // month. In this case we want to go to the last day of the desired month.
        if (date.getDate() !== fdDate.day) {
            date.setDate(0);
        }
        return this._createFdDateFromDateInstance(date);
    }
    /** Add days to a date */
    addCalendarDays(fdDate, days) {
        const date = this._createDateInstanceByFdDate(fdDate);
        date.setDate(date.getDate() + days);
        return this._createFdDateFromDateInstance(date);
    }
    /** Clone a date object */
    clone(date) {
        return new FdDate(date.year, date.month, date.day, date.hour, date.minute, date.second);
    }
    /** Check if date object is valid */
    isValid(date) {
        if (!(date instanceof FdDate)) {
            return false;
        }
        return date.isDateValid();
    }
    /** Check if date between given dates */
    isBetween(dateToCheck, startDate, endDate) {
        const date = this._createDateInstanceByFdDate(dateToCheck);
        const start = this._createDateInstanceByFdDate(startDate);
        const end = this._createDateInstanceByFdDate(endDate);
        return date.getTime() > start.getTime() && date.getTime() < end.getTime();
    }
    /** Check if dates are equal */
    datesEqual(date1, date2) {
        if (!date1 || !date2) {
            return false;
        }
        // skip time value
        const date1Str = this.toIso8601(date1).split('T')[0];
        const date2Str = this.toIso8601(date2).split('T')[0];
        return date1Str === date2Str;
    }
    /** Check if dates and time are equal */
    dateTimesEqual(date1, date2) {
        if (!date1 || !date2) {
            return false;
        }
        return this.toIso8601(date1) === this.toIso8601(date2);
    }
    /** Format date object to ISO8601 string */
    toIso8601(fdDate) {
        return toIso8601(fdDate);
    }
    /** Check if a time format includes a day period */
    isTimeFormatIncludesDayPeriod(displayFormat) {
        if (typeof displayFormat?.hour12 === 'boolean') {
            return displayFormat.hour12;
        }
        const formattedDateNoPeriodOption = this.format(this.createDate(2020), displayFormat);
        const formattedDateWithPeriodOption = this.format(this.createDate(2020), { ...displayFormat, hour12: true });
        return formattedDateWithPeriodOption === formattedDateNoPeriodOption;
    }
    /** Check if a time format includes hours */
    isTimeFormatIncludesHours(displayFormat) {
        return typeof displayFormat?.hour === 'string';
    }
    /** Check if a time format includes minutes */
    isTimeFormatIncludesMinutes(displayFormat) {
        return typeof displayFormat?.minute === 'string';
    }
    /** Check if a time format includes seconds */
    isTimeFormatIncludesSeconds(displayFormat) {
        return typeof displayFormat?.second === 'string';
    }
    /** Format with custom pattern including day period names */
    _formatWithDayPeriod(date, displayFormat) {
        const formattedTime = this._formatWithIntl(date, { ...displayFormat, dayPeriod: undefined });
        const dayPeriodName = this._getDayPeriodName(date);
        return this._insertDayPeriod(formattedTime, dayPeriodName, displayFormat);
    }
    /** Insert day period into the formatted string */
    _insertDayPeriod(formattedTime, dayPeriodName, displayFormat) {
        if (displayFormat.year || displayFormat.month || displayFormat.day) {
            return formattedTime
                .replace(/(\d{1,2}:\d{2})( [AP]M)?/, `$1 ${dayPeriodName}`)
                .replace(/,\s*(\d{1,2}:\d{2})/, `, at $1 ${dayPeriodName}`);
        }
        else {
            return formattedTime.replace(/(\d{1,2}:\d{2}(:\d{2})?)/, `$1 ${dayPeriodName}`);
        }
    }
    /** Get day period name based on the hour */
    _getDayPeriodName(date) {
        const hour = date.hour;
        if (hour < 6) {
            return 'coreTime.nightLabel';
        }
        else if (hour < 12) {
            return 'coreTime.morningLabel';
        }
        else if (hour < 18) {
            return 'coreTime.afternoonLabel';
        }
        else {
            return 'coreTime.eveningLabel';
        }
    }
    /** Format date using Intl.DateTimeFormat */
    _formatWithIntl(date, displayFormat) {
        const formatter = new Intl.DateTimeFormat(this.locale, displayFormat);
        const dateInstance = this._createDateInstanceByFdDate(date);
        return this._stripDirectionalityCharacters(this._format(formatter, dateInstance));
    }
    /**
     * @hidden
     * Strip out unicode LTR and RTL characters. Edge and IE insert these into formatted dates while
     * other browsers do not. We remove them to make output consistent and because they interfere with
     * date parsing.
     * @param str The string to strip direction characters from.
     * @returns The stripped string.
     */
    _stripDirectionalityCharacters(str) {
        return str.replace(/[\u200e\u200f]/g, '').replace(/\u202f/g, ' ');
    }
    /** @hidden */
    _format(formatter, date) {
        if (Number.isNaN(date.valueOf())) {
            return INVALID_DATE_ERROR;
        }
        date = this._createUTCDateInstance(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
        return formatter.format(date);
    }
    /**
     * @hidden
     * Create native Date instance from FdDate
     * @param date FdDate instance
     * @returns date Native date instance
     */
    _createDateInstanceByFdDate(fdDate) {
        const { year, month, day, hour, minute, second } = fdDate;
        // We have stricter validation rules than Date object.
        // For example, Date allows values for month=100 or for day=100.
        // Therefore, we need to do this trick for the consistency of the validation status
        if (!this.isValid(fdDate)) {
            return new Date(NaN);
        }
        const date = new Date();
        date.setFullYear(year, month - 1, day);
        date.setHours(hour, minute, second, 0);
        return date;
    }
    /**
     * @hidden
     * Create native Date instance in UTC
     * @param year The year
     * @param month The month as a number between 0 and 11
     * @param day The date as a number between 1 and 31.
     * @param hours The hours as a number between 0 - 24
     * @param minutes The minutes as a number between 0 - 59
     * @param seconds The seconds as a number between 0 - 59
     * @param milliseconds The milliseconds as a number between 0 - 59
     */
    _createUTCDateInstance(year, month, day, hours = 0, minutes = 0, seconds = 0, milliseconds = 0) {
        const utcDate = new Date();
        utcDate.setUTCFullYear(year, month, day);
        utcDate.setUTCHours(hours, minutes, seconds, milliseconds);
        return utcDate;
    }
    /** @hidden */
    _createFdDateFromDateInstance(date) {
        return new FdDate(date.getFullYear(), date.getMonth() + 1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());
    }
    /**
     * @hidden
     *
     * Since FdDatetimeAdapter can parse only "en-US" locale
     * there is no reason to create comprehensive time parse
     * that can understand plenty of locales.
     *
     * @param timeStr Time string to parse (E.g. '10:30 PM')
     * @returns date Native date instance
     *
     */
    _parseTimeString(timeStr) {
        /**
         * Date.parse('10:30 AM') doesn't work so we need do a trick
         * and prepend it by a date string.
         */
        const dateStr = new Intl.DateTimeFormat('en-US').format(new Date());
        const dateTimeString = `${dateStr} ${timeStr}`;
        return new Date(Date.parse(dateTimeString));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeAdapter, deps: [{ token: LOCALE_ID, optional: true }, { token: i1.Platform }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeAdapter }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeAdapter, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [LOCALE_ID]
                }] }, { type: i1.Platform }] });

const PIPES = [
    DateFormatPipe,
    DateTimeFormatPipe,
    DateFromNowPipe,
    DayPeriodFormatPipe,
    TranslateDayPeriodPipe
];
/**
 * @deprecated
 * Use imports of `DateFormatPipe`, `DateTimeFormatPipe`, `DateFromNowPipe` instead.
 */
class FdDatetimePipesModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimePipesModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimePipesModule, imports: [DateFormatPipe,
            DateTimeFormatPipe,
            DateFromNowPipe,
            DayPeriodFormatPipe,
            TranslateDayPeriodPipe], exports: [DateFormatPipe,
            DateTimeFormatPipe,
            DateFromNowPipe,
            DayPeriodFormatPipe,
            TranslateDayPeriodPipe] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimePipesModule }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimePipesModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [...PIPES],
                    exports: [...PIPES]
                }]
        }] });

/**
 * @deprecated
 * Use direct imports of components and directives.
 */
class FdDatetimeAdapterModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeAdapterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeAdapterModule, imports: [PlatformModule] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeAdapterModule, providers: [{ provide: DatetimeAdapter, useClass: FdDatetimeAdapter }], imports: [PlatformModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeAdapterModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [PlatformModule],
                    providers: [{ provide: DatetimeAdapter, useClass: FdDatetimeAdapter }]
                }]
        }] });
class FdDatetimeModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeModule, imports: [FdDatetimeAdapterModule, FdDatetimePipesModule], exports: [FdDatetimePipesModule, FdDatetimeAdapterModule] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeModule, providers: [{ provide: DATE_TIME_FORMATS, useValue: FD_DATETIME_FORMATS }], imports: [FdDatetimeAdapterModule, FdDatetimePipesModule, FdDatetimePipesModule, FdDatetimeAdapterModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: FdDatetimeModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [FdDatetimeAdapterModule, FdDatetimePipesModule],
                    exports: [FdDatetimePipesModule, FdDatetimeAdapterModule],
                    providers: [{ provide: DATE_TIME_FORMATS, useValue: FD_DATETIME_FORMATS }]
                }]
        }] });

/**
 * Provides default datetime formats and datetime adapter.
 */
function provideDateTimeFormats() {
    return [
        { provide: DATE_TIME_FORMATS, useValue: FD_DATETIME_FORMATS },
        {
            provide: DatetimeAdapter,
            useClass: FdDatetimeAdapter
        }
    ];
}

/**
 * Generated bundle index. Do not edit.
 */

export { DATE_TIME_FORMATS, DateFormatPipe, DateFromNowPipe, DateTimeFormatPipe, DatetimeAdapter, DayPeriodFormatPipe, FD_DATETIME_FORMATS, FdDate, FdDatetimeAdapter, FdDatetimeAdapterModule, FdDatetimeModule, FdDatetimePipesModule, TranslateDayPeriodPipe, _leftPad, convertToDesiredFormat, isValidByParams, provideDateTimeFormats, toIso8601 };
//# sourceMappingURL=fundamental-ngx-core-datetime.mjs.map
