` | - |
diff --git a/components/time-picker/nz-time-picker-panel.component.html b/components/time-picker/nz-time-picker-panel.component.html
index 88db37beb74..aa36a6eaf19 100644
--- a/components/time-picker/nz-time-picker-panel.component.html
+++ b/components/time-picker/nz-time-picker-panel.component.html
@@ -69,6 +69,24 @@
+
+
+
+ -
+ {{ range.value }}
+
+
+
+
diff --git a/components/time-picker/nz-time-picker-panel.component.spec.ts b/components/time-picker/nz-time-picker-panel.component.spec.ts
index 5e03ac97cbe..cb365e91876 100644
--- a/components/time-picker/nz-time-picker-panel.component.spec.ts
+++ b/components/time-picker/nz-time-picker-panel.component.spec.ts
@@ -4,13 +4,18 @@ import { FormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { NzI18nModule } from '../i18n/nz-i18n.module';
import { NzTimePickerPanelComponent } from './nz-time-picker-panel.component';
-
describe('time-picker-panel', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [FormsModule, NzI18nModule],
schemas: [NO_ERRORS_SCHEMA],
- declarations: [NzTimePickerPanelComponent, NzTestTimePanelComponent, NzTestTimePanelDisabledComponent]
+ declarations: [
+ NzTimePickerPanelComponent,
+ NzTestTimePanelComponent,
+ NzTestTimePanelDisabledComponent,
+ NzTest12HourTimePanelComponent,
+ NzTest12HourTimePanelDisabeledComponent
+ ]
});
TestBed.compileComponents();
}));
@@ -149,6 +154,134 @@ describe('time-picker-panel', () => {
expect(listOfSelectContainer[2].firstElementChild.children.length).toBe(54);
}));
});
+ describe('12-hour time-picker-panel', () => {
+ let panelElement: DebugElement;
+ let fixture12Hour: ComponentFixture;
+ let testComponent: NzTest12HourTimePanelComponent;
+ beforeEach(() => {
+ fixture12Hour = TestBed.createComponent(NzTest12HourTimePanelComponent);
+ testComponent = fixture12Hour.debugElement.componentInstance;
+ fixture12Hour.detectChanges();
+ panelElement = fixture12Hour.debugElement.query(By.directive(NzTimePickerPanelComponent));
+ });
+ it('basic 12-hour time-picker-panel', fakeAsync(() => {
+ fixture12Hour.detectChanges();
+ expect(testComponent.nzTimePickerPanelComponent.enabledColumns).toBe(4);
+ const listColumns: HTMLElement[] = panelElement.nativeElement.querySelectorAll('.ant-time-picker-panel-select');
+ expect(listColumns[0].querySelectorAll('li')[0].innerText).toBe('12');
+ const hour12labels = listColumns[3].querySelectorAll('li');
+ expect(hour12labels[0].innerText).toBe('am');
+ expect(hour12labels[1].innerText).toBe('pm');
+ }));
+ it('default value 12-hour time-picker-panel', fakeAsync(() => {
+ testComponent.nzTimePickerPanelComponent.opened = true;
+ fixture12Hour.detectChanges();
+ tick(1000);
+ fixture12Hour.detectChanges();
+ const listOfSelectedLi = panelElement.nativeElement.querySelectorAll(
+ '.ant-time-picker-panel-select-option-selected'
+ );
+ expect(listOfSelectedLi[0].innerText).toBe('12');
+ expect(listOfSelectedLi[1].innerText).toBe('00');
+ expect(listOfSelectedLi[2].innerText).toBe('00');
+ expect(listOfSelectedLi[3].innerText).toBe('am');
+ }));
+ it('should scroll work in 12-hour', fakeAsync(() => {
+ fixture12Hour.componentInstance.openValue = new Date(0, 0, 0, 5, 6, 7);
+ fixture12Hour.componentInstance.nzTimePickerPanelComponent.select12Hours({ index: 1, value: 'pm' });
+ fixture12Hour.componentInstance.nzTimePickerPanelComponent.opened = true;
+ fixture12Hour.detectChanges();
+ tick(1000);
+ fixture12Hour.detectChanges();
+ let listOfSelectedLi = panelElement.nativeElement.querySelectorAll(
+ '.ant-time-picker-panel-select-option-selected'
+ );
+ expect(listOfSelectedLi[0].innerText).toBe('05');
+ expect(listOfSelectedLi[1].innerText).toBe('06');
+ expect(listOfSelectedLi[2].innerText).toBe('07');
+ expect(listOfSelectedLi[3].innerText).toBe('pm');
+ fixture12Hour.componentInstance.nzTimePickerPanelComponent.opened = false;
+ fixture12Hour.detectChanges();
+ tick(1000);
+ fixture12Hour.detectChanges();
+ fixture12Hour.componentInstance.value = new Date(0, 0, 0, 6, 7, 8);
+ fixture12Hour.detectChanges();
+ fixture12Hour.componentInstance.nzTimePickerPanelComponent.opened = true;
+ fixture12Hour.detectChanges();
+ tick(1000);
+ fixture12Hour.detectChanges();
+ listOfSelectedLi = panelElement.nativeElement.querySelectorAll('.ant-time-picker-panel-select-option-selected');
+ expect(listOfSelectedLi[0].innerText).toBe('06');
+ expect(listOfSelectedLi[1].innerText).toBe('07');
+ expect(listOfSelectedLi[2].innerText).toBe('08');
+ }));
+ it('select hour and 12-hour in 12-hour-time-picker-panel', fakeAsync(() => {
+ fixture12Hour.detectChanges();
+ testComponent.nzTimePickerPanelComponent.selectHour({ index: 3, disabled: false });
+ testComponent.nzTimePickerPanelComponent.select12Hours({ index: 1, value: 'pm' });
+ fixture12Hour.detectChanges();
+ flush();
+ fixture12Hour.detectChanges();
+ expect(testComponent.value.getHours()).toBe(15);
+ testComponent.nzTimePickerPanelComponent.select12Hours({ index: 0, value: 'am' });
+ fixture12Hour.detectChanges();
+ flush();
+ fixture12Hour.detectChanges();
+ expect(testComponent.value.getHours()).toBe(3);
+ }));
+ it('hour step in 12-hour-time-picker-panel', fakeAsync(() => {
+ testComponent.hourStep = 2;
+ fixture12Hour.detectChanges();
+ const listOfHourContainer = panelElement.nativeElement.querySelectorAll('.ant-time-picker-panel-select');
+ expect(listOfHourContainer[0].firstElementChild.children.length).toEqual(6);
+ }));
+ });
+
+ describe('disabled and format 12-hour time-picker-panel', () => {
+ let panelElement: DebugElement;
+ let fixture12Hour: ComponentFixture;
+ let testComponent: NzTest12HourTimePanelDisabeledComponent;
+
+ beforeEach(() => {
+ fixture12Hour = TestBed.createComponent(NzTest12HourTimePanelDisabeledComponent);
+ testComponent = fixture12Hour.debugElement.componentInstance;
+ fixture12Hour.detectChanges();
+ panelElement = fixture12Hour.debugElement.query(By.directive(NzTimePickerPanelComponent));
+ });
+
+ it('format in 12-hour-time-pick-panel', fakeAsync(() => {
+ testComponent.format = 'hh:mm:ss A';
+ fixture12Hour.detectChanges();
+ const list12HourLi = panelElement.nativeElement
+ .querySelectorAll('.ant-time-picker-panel-select')[3]
+ .querySelectorAll('li');
+ expect(list12HourLi[0].innerText).toBe('AM');
+ expect(list12HourLi[1].innerText).toBe('PM');
+ }));
+
+ it('disabled hour in 12-hour-time-picker-panel', fakeAsync(() => {
+ fixture12Hour.detectChanges();
+ flush();
+ testComponent.disabledHours = (): number[] => [0, 3, 4, 5, 12, 18, 19, 20, 24];
+ fixture12Hour.detectChanges();
+ let listHourLi = panelElement.nativeElement
+ .querySelectorAll('.ant-time-picker-panel-select')[0]
+ .querySelectorAll('li');
+ expect(listHourLi[0].classList).toContain('ant-time-picker-panel-select-option-disabled');
+ expect(listHourLi[3].classList).toContain('ant-time-picker-panel-select-option-disabled');
+ expect(listHourLi[4].classList).toContain('ant-time-picker-panel-select-option-disabled');
+ expect(listHourLi[5].classList).toContain('ant-time-picker-panel-select-option-disabled');
+ testComponent.nzTimePickerPanelComponent.select12Hours({ index: 1, value: 'pm' });
+ fixture12Hour.detectChanges();
+ listHourLi = panelElement.nativeElement
+ .querySelectorAll('.ant-time-picker-panel-select')[0]
+ .querySelectorAll('li');
+ expect(listHourLi[0].classList).toContain('ant-time-picker-panel-select-option-disabled');
+ expect(listHourLi[6].classList).toContain('ant-time-picker-panel-select-option-disabled');
+ expect(listHourLi[7].classList).toContain('ant-time-picker-panel-select-option-disabled');
+ expect(listHourLi[8].classList).toContain('ant-time-picker-panel-select-option-disabled');
+ }));
+ });
});
@Component({
@@ -229,3 +362,61 @@ export class NzTestTimePanelDisabledComponent {
}
}
}
+@Component({
+ selector: 'nz-test-12-hour-time-panel',
+ encapsulation: ViewEncapsulation.None,
+ template: `
+
+
+ `,
+ styleUrls: ['../style/index.less', './style/index.less']
+})
+export class NzTest12HourTimePanelComponent {
+ @ViewChild(NzTimePickerPanelComponent) nzTimePickerPanelComponent: NzTimePickerPanelComponent;
+ format = 'hh:mm:ss a';
+ hourStep = 1;
+ value: Date;
+ openValue = new Date(0, 0, 0, 0, 0, 0);
+}
+@Component({
+ selector: 'nz-test-12-hour-time-panel',
+ encapsulation: ViewEncapsulation.None,
+ template: `
+
+
+ `,
+ styleUrls: ['../style/index.less', './style/index.less']
+})
+export class NzTest12HourTimePanelDisabeledComponent {
+ @ViewChild(NzTimePickerPanelComponent) nzTimePickerPanelComponent: NzTimePickerPanelComponent;
+ format = 'hh:mm:ss a';
+ value = new Date(0, 0, 0, 1, 1, 1);
+ disabledHours = (): number[] => [];
+ disabledMinutes(hour: number): number[] {
+ if (hour === 4) {
+ return [20, 21, 22, 23, 24, 25];
+ } else {
+ return [];
+ }
+ }
+ disabledSeconds(hour: number, minute: number): number[] {
+ if (hour === 5 && minute === 1) {
+ return [20, 21, 22, 23, 24, 25];
+ } else {
+ return [];
+ }
+ }
+}
diff --git a/components/time-picker/nz-time-picker-panel.component.ts b/components/time-picker/nz-time-picker-panel.component.ts
index 6e3c38040b8..9c364db378f 100644
--- a/components/time-picker/nz-time-picker-panel.component.ts
+++ b/components/time-picker/nz-time-picker-panel.component.ts
@@ -5,8 +5,10 @@ import {
DebugElement,
ElementRef,
Input,
+ OnChanges,
OnDestroy,
OnInit,
+ SimpleChanges,
TemplateRef,
ViewChild,
ViewEncapsulation
@@ -18,15 +20,16 @@ import { takeUntil } from 'rxjs/operators';
import { reqAnimFrame } from '../core/polyfill/request-animation';
import { NzUpdateHostClassService as UpdateCls } from '../core/services/update-host-class.service';
+import { InputBoolean } from '../core/util';
import { isNotNil } from '../core/util/check';
import { NzTimeValueAccessorDirective } from './nz-time-value-accessor.directive';
import { TimeHolder } from './time-holder';
-function makeRange(length: number, step: number = 1): number[] {
- return new Array(Math.ceil(length / step)).fill(0).map((_, i) => i * step);
+function makeRange(length: number, step: number = 1, start: number = 0): number[] {
+ return new Array(Math.ceil(length / step)).fill(0).map((_, i) => (i + start) * step);
}
-export type NzTimePickerUnit = 'hour' | 'minute' | 'second';
+export type NzTimePickerUnit = 'hour' | 'minute' | 'second' | '12-hour';
@Component({
encapsulation: ViewEncapsulation.None,
@@ -35,7 +38,7 @@ export type NzTimePickerUnit = 'hour' | 'minute' | 'second';
templateUrl: './nz-time-picker-panel.component.html',
providers: [UpdateCls, { provide: NG_VALUE_ACCESSOR, useExisting: NzTimePickerPanelComponent, multi: true }]
})
-export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit, OnDestroy {
+export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit, OnDestroy, OnChanges {
private _nzHourStep = 1;
private _nzMinuteStep = 1;
private _nzSecondStep = 1;
@@ -58,15 +61,20 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
hourRange: ReadonlyArray<{ index: number; disabled: boolean }>;
minuteRange: ReadonlyArray<{ index: number; disabled: boolean }>;
secondRange: ReadonlyArray<{ index: number; disabled: boolean }>;
+ use12HoursRange: ReadonlyArray<{ index: number; value: string }>;
@ViewChild(NzTimeValueAccessorDirective) nzTimeValueAccessorDirective: NzTimeValueAccessorDirective;
+
@ViewChild('hourListElement') hourListElement: DebugElement;
@ViewChild('minuteListElement') minuteListElement: DebugElement;
@ViewChild('secondListElement') secondListElement: DebugElement;
+ @ViewChild('use12HoursListElement') use12HoursListElement: DebugElement;
+
@Input() nzInDatePicker: boolean = false; // If inside a date-picker, more diff works need to be done
@Input() nzAddOn: TemplateRef;
@Input() nzHideDisabledOptions = false;
@Input() nzClearText: string;
@Input() nzPlaceHolder: string;
+ @Input() @InputBoolean() nzUse12Hours = false;
@Input()
set nzAllowEmpty(value: boolean) {
@@ -158,6 +166,9 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
if (this.secondEnabled) {
this.enabledColumns++;
}
+ if (this.nzUse12Hours) {
+ this.build12Hours();
+ }
}
}
@@ -210,12 +221,40 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
}
buildHours(): void {
- this.hourRange = makeRange(24, this.nzHourStep).map(r => {
+ let hourRanges = 24;
+ let disabledHours = this.nzDisabledHours && this.nzDisabledHours();
+ let startIndex = 0;
+ if (this.nzUse12Hours) {
+ hourRanges = 12;
+ if (disabledHours) {
+ if (this.time.selected12Hours === 'PM') {
+ /**
+ * Filter and transform hours which greater or equal to 12
+ * [0, 1, 2, ..., 12, 13, 14, 15, ..., 23] => [12, 1, 2, 3, ..., 11]
+ */
+ disabledHours = disabledHours.filter(i => i >= 12).map(i => (i > 12 ? i - 12 : i));
+ } else {
+ /**
+ * Filter and transform hours which less than 12
+ * [0, 1, 2,..., 12, 13, 14, 15, ...23] => [12, 1, 2, 3, ..., 11]
+ */
+ disabledHours = disabledHours.filter(i => i < 12 || i === 24).map(i => (i === 24 || i === 0 ? 12 : i));
+ }
+ }
+ startIndex = 1;
+ }
+ this.hourRange = makeRange(hourRanges, this.nzHourStep, startIndex).map(r => {
return {
index: r,
- disabled: this.nzDisabledHours && this.nzDisabledHours().indexOf(r) !== -1
+ disabled: this.nzDisabledHours && disabledHours.indexOf(r) !== -1
};
});
+ if (this.nzUse12Hours && this.hourRange[this.hourRange.length - 1].index === 12) {
+ const temp = [...this.hourRange];
+ temp.unshift(temp[temp.length - 1]);
+ temp.splice(temp.length - 1, 1);
+ this.hourRange = temp;
+ }
}
buildMinutes(): void {
@@ -237,10 +276,25 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
});
}
+ build12Hours(): void {
+ const isUpperForamt = this._format.includes('A');
+ this.use12HoursRange = [
+ {
+ index: 0,
+ value: isUpperForamt ? 'AM' : 'am'
+ },
+ {
+ index: 1,
+ value: isUpperForamt ? 'PM' : 'pm'
+ }
+ ];
+ }
+
buildTimes(): void {
this.buildHours();
this.buildMinutes();
this.buildSeconds();
+ this.build12Hours();
}
selectHour(hour: { index: number; disabled: boolean }): void {
@@ -268,6 +322,20 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
this.scrollToSelected(this.secondListElement.nativeElement, second.index, 120, 'second');
}
+ select12Hours(value: { index: number; value: string }): void {
+ this.time.selected12Hours = value.value;
+ if (this._disabledHours) {
+ this.buildHours();
+ }
+ if (this._disabledMinutes) {
+ this.buildMinutes();
+ }
+ if (this._disabledSeconds) {
+ this.buildSeconds();
+ }
+ this.scrollToSelected(this.use12HoursListElement.nativeElement, value.index, 120, '12-hour');
+ }
+
scrollToSelected(instance: HTMLElement, index: number, duration: number = 0, unit: NzTimePickerUnit): void {
const transIndex = this.translateIndex(index, unit);
const currentOption = (instance.children[0].children[transIndex] ||
@@ -282,10 +350,13 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
} else if (unit === 'minute') {
const disabledMinutes = this.nzDisabledMinutes && this.nzDisabledMinutes(this.time.hours!);
return this.calcIndex(disabledMinutes, this.minuteRange.map(item => item.index).indexOf(index));
- } else {
+ } else if (unit === 'second') {
// second
const disabledSeconds = this.nzDisabledSeconds && this.nzDisabledSeconds(this.time.hours!, this.time.minutes!);
return this.calcIndex(disabledSeconds, this.secondRange.map(item => item.index).indexOf(index));
+ } else {
+ // 12-hour
+ return this.calcIndex([], this.use12HoursRange.map(item => item.index).indexOf(index));
}
}
@@ -341,7 +412,10 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
}
isSelectedHour(hour: { index: number; disabled: boolean }): boolean {
- return hour.index === this.time.hours || (!isNotNil(this.time.hours) && hour.index === this.time.defaultHours);
+ return (
+ hour.index === this.time.viewHours ||
+ (!isNotNil(this.time.viewHours) && hour.index === this.time.defaultViewHours)
+ );
}
isSelectedMinute(minute: { index: number; disabled: boolean }): boolean {
@@ -356,13 +430,20 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
);
}
+ isSelected12Hours(value: { index: number; value: string }): boolean {
+ return (
+ value.value.toUpperCase() === this.time.selected12Hours ||
+ (!isNotNil(this.time.selected12Hours) && value.value.toUpperCase() === this.time.default12Hours)
+ );
+ }
+
initPosition(): void {
setTimeout(() => {
if (this.hourEnabled && this.hourListElement) {
- if (isNotNil(this.time.hours)) {
- this.scrollToSelected(this.hourListElement.nativeElement, this.time.hours!, 0, 'hour');
+ if (isNotNil(this.time.viewHours)) {
+ this.scrollToSelected(this.hourListElement.nativeElement, this.time.viewHours!, 0, 'hour');
} else {
- this.scrollToSelected(this.hourListElement.nativeElement, this.time.defaultHours, 0, 'hour');
+ this.scrollToSelected(this.hourListElement.nativeElement, this.time.defaultViewHours, 0, 'hour');
}
}
if (this.minuteEnabled && this.minuteListElement) {
@@ -379,6 +460,13 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
this.scrollToSelected(this.secondListElement.nativeElement, this.time.defaultSeconds, 0, 'second');
}
}
+ if (this.nzUse12Hours && this.use12HoursListElement) {
+ const selectedHours = isNotNil(this.time.selected12Hours)
+ ? this.time.selected12Hours
+ : this.time.default12Hours;
+ const index = selectedHours === 'AM' ? 0 : 1;
+ this.scrollToSelected(this.use12HoursListElement.nativeElement, index, 0, '12-hour');
+ }
});
}
@@ -402,8 +490,16 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
this.unsubscribe$.complete();
}
+ ngOnChanges(changes: SimpleChanges): void {
+ const { nzUse12Hours } = changes;
+ if (nzUse12Hours && !nzUse12Hours.previousValue && nzUse12Hours.currentValue) {
+ this.build12Hours();
+ this.enabledColumns++;
+ }
+ }
+
writeValue(value: Date): void {
- this.time.value = value;
+ this.time.setValue(value, this.nzUse12Hours);
this.buildTimes();
// Mark this component to be checked manually with internal properties changing (see: https://github.com/angular/angular/issues/10816)
diff --git a/components/time-picker/nz-time-picker.component.html b/components/time-picker/nz-time-picker.component.html
index 1d09aad15b5..338fd8585a1 100644
--- a/components/time-picker/nz-time-picker.component.html
+++ b/components/time-picker/nz-time-picker.component.html
@@ -44,6 +44,7 @@
[nzDisabledSeconds]="nzDisabledSeconds"
[nzPlaceHolder]="nzPlaceHolder || ('TimePicker.placeholder' | nzI18n)"
[nzHideDisabledOptions]="nzHideDisabledOptions"
+ [nzUse12Hours]="nzUse12Hours"
[nzDefaultOpenValue]="nzDefaultOpenValue"
[nzAddOn]="nzAddOn"
[opened]="nzOpen"
diff --git a/components/time-picker/nz-time-picker.component.spec.ts b/components/time-picker/nz-time-picker.component.spec.ts
index 8e6652178f4..73d3839b2e3 100644
--- a/components/time-picker/nz-time-picker.component.spec.ts
+++ b/components/time-picker/nz-time-picker.component.spec.ts
@@ -97,6 +97,11 @@ describe('time-picker', () => {
fixture.detectChanges();
expect(testComponent.date).toBeNull();
}));
+ it('should support default nzfomat in 12-hours', () => {
+ testComponent.use12Hours = true;
+ fixture.detectChanges();
+ expect(testComponent.nzTimePickerComponent.nzFormat).toBe('h:mm:ss a');
+ });
});
});
@@ -109,6 +114,7 @@ describe('time-picker', () => {
[(nzOpen)]="open"
(nzOpenChange)="openChange($event)"
[nzDisabled]="disabled"
+ [nzUse12Hours]="use12Hours"
>
`
})
@@ -118,5 +124,6 @@ export class NzTestTimePickerComponent {
autoFocus = false;
date = new Date();
disabled = false;
+ use12Hours = false;
@ViewChild(NzTimePickerComponent) nzTimePickerComponent: NzTimePickerComponent;
}
diff --git a/components/time-picker/nz-time-picker.component.ts b/components/time-picker/nz-time-picker.component.ts
index 1eb785b68ec..52a33b5531e 100644
--- a/components/time-picker/nz-time-picker.component.ts
+++ b/components/time-picker/nz-time-picker.component.ts
@@ -7,9 +7,11 @@ import {
ElementRef,
EventEmitter,
Input,
+ OnChanges,
OnInit,
Output,
Renderer2,
+ SimpleChanges,
TemplateRef,
ViewChild,
ViewEncapsulation
@@ -28,7 +30,7 @@ import { toBoolean } from '../core/util/convert';
animations: [slideMotion],
providers: [UpdateCls, { provide: NG_VALUE_ACCESSOR, useExisting: NzTimePickerComponent, multi: true }]
})
-export class NzTimePickerComponent implements ControlValueAccessor, OnInit, AfterViewInit {
+export class NzTimePickerComponent implements ControlValueAccessor, OnInit, AfterViewInit, OnChanges {
private _disabled = false;
private _value: Date | null = null;
private _allowEmpty = true;
@@ -63,6 +65,7 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
@Input() nzDisabledSeconds: (hour: number, minute: number) => number[];
@Input() nzFormat = 'HH:mm:ss';
@Input() nzOpen = false;
+ @Input() nzUse12Hours = false;
@Output() readonly nzOpenChange = new EventEmitter();
@Input()
@@ -180,6 +183,13 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
this.origin = new CdkOverlayOrigin(this.element);
}
+ ngOnChanges(changes: SimpleChanges): void {
+ const { nzUse12Hours, nzFormat } = changes;
+ if (nzUse12Hours && !nzUse12Hours.previousValue && nzUse12Hours.currentValue && !nzFormat) {
+ this.nzFormat = 'h:mm:ss a';
+ }
+ }
+
ngAfterViewInit(): void {
this.isInit = true;
this.updateAutoFocus();
diff --git a/components/time-picker/time-holder.spec.ts b/components/time-picker/time-holder.spec.ts
index a65566d0e11..ea354425024 100644
--- a/components/time-picker/time-holder.spec.ts
+++ b/components/time-picker/time-holder.spec.ts
@@ -74,4 +74,33 @@ describe('time holder', () => {
holder.setMinutes(23, false);
expect(holder.value).toEqual(new Date(2001, 10, 1, 23, 23, 20));
});
+ it('should 12-hour worked', () => {
+ const holder = new TimeHolder().setValue(new Date(0, 0, 0, 0, 0, 0));
+ holder.setUse12Hours(true);
+ holder.selected12Hours = 'pm';
+ holder.setHours(3, false);
+ expect(holder.viewHours).toBe(3);
+ expect(holder.realHours).toBe(15);
+ const date = new Date(0, 0, 0, 15, 0, 0, 0);
+ expect(mathSecondRound(holder.value!)).toEqual(mathSecondRound(date));
+ });
+ it('should set defaultRealHours and defaultViewHours correctly', () => {
+ const holder = new TimeHolder().setValue(undefined, true).setDefaultOpenValue(new Date(0, 0, 0, 15, 2, 3));
+ expect(holder.defaultRealHours).toBe(15);
+ expect(holder.defaultViewHours).toBe(3);
+ });
+ it('should set default selected 12-hours with value', () => {
+ const holderPM = new TimeHolder().setValue(new Date(0, 0, 0, 15, 2, 3), true);
+ expect(holderPM.selected12Hours).toBe('PM');
+ const holderAM = new TimeHolder().setValue(new Date(0, 0, 0, 0, 2, 3), true);
+ expect(holderAM.selected12Hours).toBe('AM');
+ });
+ it('should transform special value in 12-hour', () => {
+ const holder = new TimeHolder().setValue(new Date(), true);
+ holder.selected12Hours = 'am';
+ holder.setHours(12, false);
+ expect(holder.realHours).toBe(0);
+ holder.selected12Hours = 'pm';
+ expect(holder.realHours).toBe(12);
+ });
});
diff --git a/components/time-picker/time-holder.ts b/components/time-picker/time-holder.ts
index 031ad43a470..e69ec3ecb25 100644
--- a/components/time-picker/time-holder.ts
+++ b/components/time-picker/time-holder.ts
@@ -6,6 +6,8 @@ export class TimeHolder {
private _seconds: number | undefined = undefined;
private _hours: number | undefined = undefined;
private _minutes: number | undefined = undefined;
+ private _selected12Hours: string | undefined = undefined;
+ private _use12Hours: boolean = false;
private _defaultOpenValue: Date = new Date();
private _value: Date | undefined;
private _changes = new Subject();
@@ -43,6 +45,11 @@ export class TimeHolder {
return this;
}
+ setUse12Hours(value: boolean): this {
+ this._use12Hours = value;
+ return this;
+ }
+
get changes(): Observable {
return this._changes.asObservable();
}
@@ -58,13 +65,19 @@ export class TimeHolder {
this._hours = this._value!.getHours();
this._minutes = this._value!.getMinutes();
this._seconds = this._value!.getSeconds();
+ if (this._use12Hours && isNotNil(this._hours)) {
+ this._selected12Hours = this._hours >= 12 ? 'PM' : 'AM';
+ }
} else {
this._clear();
}
}
}
- setValue(value: Date | undefined): this {
+ setValue(value: Date | undefined, use12Hours?: boolean): this {
+ if (isNotNil(use12Hours)) {
+ this._use12Hours = use12Hours as boolean;
+ }
this.value = value;
return this;
}
@@ -82,6 +95,7 @@ export class TimeHolder {
this._hours = undefined;
this._minutes = undefined;
this._seconds = undefined;
+ this._selected12Hours = undefined;
}
private update(): void {
@@ -106,6 +120,20 @@ export class TimeHolder {
this._value!.setSeconds(this.seconds!);
}
+ if (this._use12Hours) {
+ if (!isNotNil(this._selected12Hours)) {
+ this._selected12Hours = this.default12Hours;
+ }
+ if (this.selected12Hours === 'PM' && this._hours! < 12) {
+ this._hours! += 12;
+ this._value!.setHours(this._hours!);
+ }
+ if (this.selected12Hours === 'AM' && this._hours! >= 12) {
+ this._hours! -= 12;
+ this._value!.setHours(this._hours!);
+ }
+ }
+
this._value = new Date(this._value!);
}
this.changed();
@@ -115,13 +143,50 @@ export class TimeHolder {
this._changes.next(this._value);
}
+ /**
+ * @description
+ * UI view hours
+ * Get viewHours which is selected in `time-picker-panel` and its range is [12, 1, 2, ..., 11]
+ */
+ get viewHours(): number | undefined {
+ return this._use12Hours && isNotNil(this._hours) ? this.calculateViewHour(this._hours!) : this._hours;
+ }
+
+ /**
+ * @description
+ * Value hours
+ * Get realHours and its range is [0, 1, 2, ..., 22, 23]
+ */
+ get realHours(): number | undefined {
+ return this._hours;
+ }
+
+ /**
+ * @description
+ * Same as realHours
+ * @see realHours
+ */
get hours(): number | undefined {
return this._hours;
}
+ /**
+ * @description
+ * Set viewHours to realHours
+ */
set hours(value: number | undefined) {
if (value !== this._hours) {
- this._hours = value;
+ if (this._use12Hours) {
+ if (this.selected12Hours === 'PM' && value !== 12) {
+ this._hours! = (value as number) + 12;
+ } else if (this.selected12Hours === 'AM' && value === 12) {
+ this._hours = 0;
+ } else {
+ this._hours = value;
+ }
+ } else {
+ this._hours = value;
+ }
this.update();
}
}
@@ -148,6 +213,17 @@ export class TimeHolder {
}
}
+ get selected12Hours(): string | undefined {
+ return this._selected12Hours;
+ }
+
+ set selected12Hours(value: string | undefined) {
+ if (value!.toUpperCase() !== this._selected12Hours) {
+ this._selected12Hours = value!.toUpperCase();
+ this.update();
+ }
+ }
+
get defaultOpenValue(): Date {
return this._defaultOpenValue;
}
@@ -164,6 +240,29 @@ export class TimeHolder {
return this;
}
+ /**
+ * @description
+ * Get deafultViewHours when defaultOpenValue is setted
+ * @see viewHours
+ */
+ get defaultViewHours(): number {
+ const hours = this._defaultOpenValue.getHours();
+ return this._use12Hours && isNotNil(hours) ? this.calculateViewHour(hours) : hours;
+ }
+
+ /**
+ * @description
+ * Get defaultRealHours when defaultOpenValue is setted
+ * @see realHours
+ */
+ get defaultRealHours(): number {
+ return this._defaultOpenValue.getHours();
+ }
+
+ /**
+ * @description
+ * Same as defaultRealHours
+ */
get defaultHours(): number {
return this._defaultOpenValue.getHours();
}
@@ -176,5 +275,20 @@ export class TimeHolder {
return this._defaultOpenValue.getSeconds();
}
+ get default12Hours(): string {
+ return this._defaultOpenValue.getHours() >= 12 ? 'PM' : 'AM';
+ }
+
constructor() {}
+
+ private calculateViewHour(value: number): number {
+ const selected12Hours = this._selected12Hours || this.default12Hours;
+ if (selected12Hours === 'PM' && value > 12) {
+ return value - 12;
+ }
+ if (selected12Hours === 'AM' && value === 0) {
+ return 12;
+ }
+ return value;
+ }
}