diff --git a/src/app/components/calendar/calendar.spec.ts b/src/app/components/calendar/calendar.spec.ts index 3863afaf955..c8d8d8e8a16 100755 --- a/src/app/components/calendar/calendar.spec.ts +++ b/src/app/components/calendar/calendar.spec.ts @@ -1941,4 +1941,31 @@ describe('Calendar', () => { calendar.updateTime(); expect((calendar.value as Date).toISOString()).toBe(maxDateISO); }); + + it('should set input element date to minDate including the set time', () => { + const minDate = new Date(2022, 0, 1, 20, 30, 0); + const date = new Date(2022, 0, 2); + calendar.minDate = minDate; + calendar.defaultDate = date; + calendar.hourFormat = '12'; + jasmine.clock().mockDate(date); + fixture.detectChanges(); + + const inputEl = fixture.debugElement.query(By.css('input')).nativeElement; + const focusEvent = new Event('focus'); + inputEl.click(); + calendar.currentHour = 11; + calendar.currentMinute = 30; + inputEl.dispatchEvent(focusEvent); + fixture.detectChanges(); + + const selectdateSpy = spyOn(calendar, 'selectDate').and.callThrough(); + const calendarContainer = fixture.debugElement.query(By.css('.p-datepicker-calendar-container')); + const dates = calendarContainer.query(By.css('tbody')).queryAll(By.css('span:not(.p-datepicker-weeknumber):not(.p-disabled)')); + dates[0].nativeElement.click(); + fixture.detectChanges(); + + expect(selectdateSpy).toHaveBeenCalled(); + expect(calendar.value).toEqual(minDate); + }); }); diff --git a/src/app/components/calendar/calendar.ts b/src/app/components/calendar/calendar.ts index a29a274a161..2c185a590b7 100644 --- a/src/app/components/calendar/calendar.ts +++ b/src/app/components/calendar/calendar.ts @@ -1604,6 +1604,7 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor { formatDateTime(date: any) { let formattedValue = this.keepInvalid ? date : null; + const isDateValid = this.isValidDateForTimeConstraints(date); if (this.isValidDate(date)) { if (this.timeOnly) { @@ -1617,7 +1618,7 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor { } else if (this.dataType === 'string') { formattedValue = date; } - + formattedValue = isDateValid ? formattedValue : ''; return formattedValue; } @@ -2510,7 +2511,7 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor { this.createMonths(this.currentMonth, this.currentYear); } - convertTo24Hour = function (hours: number, pm: boolean) { + convertTo24Hour(hours: number, pm: boolean) { //@ts-ignore if (this.hourFormat == '12') { if (hours === 12) { @@ -2520,10 +2521,11 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor { } } return hours; - }; + } constrainTime(hour: number, minute: number, second: number, pm: boolean) { let returnTimeTriple: number[] = [hour, minute, second]; + let minHoursExceeds12: boolean; let value = this.value; const convertedHour = this.convertTo24Hour(hour, pm); const isRange = this.isRangeSelection(), @@ -2544,9 +2546,38 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor { const valueDateString = value ? value.toDateString() : null; let isMinDate = this.minDate && valueDateString && this.minDate.toDateString() === valueDateString; let isMaxDate = this.maxDate && valueDateString && this.maxDate.toDateString() === valueDateString; + + if (isMinDate) { + minHoursExceeds12 = this.minDate.getHours() >= 12; + } + switch ( true // intentional fall through ) { + case isMinDate && minHoursExceeds12 && this.minDate.getHours() === 12 && this.minDate.getHours() > convertedHour: + returnTimeTriple[0] = 11; + case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() > minute: + returnTimeTriple[1] = this.minDate.getMinutes(); + case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() === minute && this.minDate.getSeconds() > second: + returnTimeTriple[2] = this.minDate.getSeconds(); + break; + case isMinDate && !minHoursExceeds12 && this.minDate.getHours() - 1 === convertedHour && this.minDate.getHours() > convertedHour: + returnTimeTriple[0] = 11; + this.pm = true; + case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() > minute: + returnTimeTriple[1] = this.minDate.getMinutes(); + case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() === minute && this.minDate.getSeconds() > second: + returnTimeTriple[2] = this.minDate.getSeconds(); + break; + + case isMinDate && minHoursExceeds12 && this.minDate.getHours() > convertedHour && convertedHour !== 12: + this.setCurrentHourPM(this.minDate.getHours()); + returnTimeTriple[0] = this.currentHour; + case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() > minute: + returnTimeTriple[1] = this.minDate.getMinutes(); + case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() === minute && this.minDate.getSeconds() > second: + returnTimeTriple[2] = this.minDate.getSeconds(); + break; case isMinDate && this.minDate.getHours() > convertedHour: returnTimeTriple[0] = this.minDate.getHours(); case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() > minute: @@ -2562,6 +2593,7 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor { returnTimeTriple[2] = this.maxDate.getSeconds(); break; } + return returnTimeTriple; } @@ -2577,11 +2609,22 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor { } newHour = newHour >= 13 ? newHour - 12 : newHour; } + this.toggleAMPMIfNotMinDate(newPM); [this.currentHour, this.currentMinute, this.currentSecond] = this.constrainTime(newHour, this.currentMinute!, this.currentSecond!, newPM!); - this.pm = newPM; event.preventDefault(); } + toggleAMPMIfNotMinDate(newPM: boolean) { + let value = this.value; + const valueDateString = value ? value.toDateString() : null; + let isMinDate = this.minDate && valueDateString && this.minDate.toDateString() === valueDateString; + if (isMinDate && this.minDate.getHours() >= 12) { + this.pm = true; + } else { + this.pm = newPM; + } + } + onTimePickerElementMouseDown(event: Event, type: number, direction: number) { if (!this.disabled) { this.repeat(event, null, type, direction); @@ -2650,8 +2693,8 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor { } newHour = newHour <= 0 ? 12 + newHour : newHour; } + this.toggleAMPMIfNotMinDate(newPM); [this.currentHour, this.currentMinute, this.currentSecond] = this.constrainTime(newHour, this.currentMinute!, this.currentSecond!, newPM!); - this.pm = newPM; event.preventDefault(); } @@ -2718,8 +2761,8 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor { toggleAMPM(event: any) { const newPM = !this.pm; - [this.currentHour, this.currentMinute, this.currentSecond] = this.constrainTime(this.currentHour, this.currentMinute, this.currentSecond, newPM); this.pm = newPM; + [this.currentHour, this.currentMinute, this.currentSecond] = this.constrainTime(this.currentHour, this.currentMinute, this.currentSecond, newPM); this.updateTime(); event.preventDefault(); } @@ -3383,6 +3426,10 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor { this.filled = (this.inputFieldValue && this.inputFieldValue != '') as boolean; } + isValidDateForTimeConstraints(selectedDate: Date) { + return (!this.minDate || selectedDate >= this.minDate) && (!this.maxDate || selectedDate <= this.maxDate); + } + onTodayButtonClick(event: any) { const date: Date = new Date(); const dateMeta = { day: date.getDate(), month: date.getMonth(), year: date.getFullYear(), otherMonth: date.getMonth() !== this.currentMonth || date.getFullYear() !== this.currentYear, today: true, selectable: true };