selectDate(date, params = {}) {
        let {currentView, parsedViewDate, selectedDates} = this;
        let {updateTime, silent} = params;
        let {
            moveToOtherMonthsOnSelect,
            moveToOtherYearsOnSelect,
            multipleDates,
            range,
            autoClose,
            onBeforeSelect,
        } = this.opts;
        let selectedDaysLen = selectedDates.length;
        let newViewDate;

        if (Array.isArray(date)) {
            date.forEach((d) => {
                this.selectDate(d, params);
            });

            return new Promise((resolve) => {
                setTimeout(resolve);
            });
        }

        date = createDate(date);

        if (!(date instanceof Date)) return;

        if (onBeforeSelect && !silent && !onBeforeSelect({date, datepicker: this})) {
            return Promise.resolve();
        }

        // Checks if selected date is out of current month or decade
        // If so, change `viewDate`
        if (currentView === consts.days) {
            if (date.getMonth() !== parsedViewDate.month && moveToOtherMonthsOnSelect) {
                newViewDate = new Date(date.getFullYear(), date.getMonth(), 1);
            }
        }

        if (currentView === consts.years) {
            if (date.getFullYear() !== parsedViewDate.year && moveToOtherYearsOnSelect) {
                newViewDate = new Date(date.getFullYear(), 0, 1);
            }
        }

        if (newViewDate) {
            this.setViewDate(newViewDate);
        }

        if (multipleDates && !range) {
            if (selectedDaysLen === multipleDates) return;
            if (!this._checkIfDateIsSelected(date)) {
                selectedDates.push(date);
            }
        } else if (range) {
            switch (selectedDaysLen) {
                case 1:
                    selectedDates.push(date);
                    // Need to define this manually if call selectDate programmatically
                    if (!this.rangeDateTo) {
                        this.rangeDateTo = date;
                    }
                    // Swap dates if they were selected via dp.selectDate() and second date was smaller then first
                    if (isDateBigger(this.rangeDateFrom, this.rangeDateTo)) {
                        this.rangeDateTo = this.rangeDateFrom;
                        this.rangeDateFrom = date;
                    }
                    this.selectedDates = [this.rangeDateFrom, this.rangeDateTo];
                    break;
                case 2:
                    this.selectedDates = [date];
                    this.rangeDateFrom = date;
                    this.rangeDateTo = '';
                    break;
                default:
                    this.selectedDates = [date];
                    this.rangeDateFrom = date;
            }
        } else {
            this.selectedDates = [date];
        }

        this.trigger(consts.eventChangeSelectedDate, {
            action: consts.actionSelectDate,
            silent: params?.silent,
            date,
            updateTime
        });
        this._updateLastSelectedDate(date);

        if (autoClose && !this.timepickerIsActive && this.visible) {
            if (!multipleDates && !range) {
                this.hide();
            } else if (range && selectedDaysLen === 1) {
                this.hide();
            }
        }

        return new Promise((resolve) => {
            setTimeout(resolve);
        });
    }
Selects date, if array is passed then selects dates one by one
@param {DateLike|Array<DateLike>} date
@param {object} [params] - extra parameters
@param {boolean} [params.updateTime] - should update timepicker's time from passed date
@param {boolean} [params.silent] - if true, then onChange and onBeforeSelect events won't be triggered
@return {Promise<void>} - returns promise, since input value updates asynchronously, after promise resolves, we need a promise to be able to get current input value
@example selectDate(new Date()).then(() => {console.log(dp.$el.value)})