Skip to content

Commit

Permalink
feat(datetime): support for seconds & milliseconds (#1016)
Browse files Browse the repository at this point in the history
* feat: support for seconds & milliseconds
  • Loading branch information
surya-pabbineedi authored Nov 2, 2023
1 parent c6f258f commit a8ecf79
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 56 deletions.
2 changes: 2 additions & 0 deletions projects/swimlane/ngx-ui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## HEAD (unreleased)

- Enhancement (`ngx-datetime`): Supports seconds and milliseconds in the time picker.

## 45.0.4 (2023-8-9)

- Enhancement (`fonts`): New set of fonts added.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
'icon-clock': inputType === 'time'
}"
class="calendar-dialog-btn"
></button>
></button>
</div>

<ng-template #dialogTpl>
Expand Down Expand Up @@ -98,6 +98,33 @@ <h1>
>
</ngx-input>
</div>
<div>
<ngx-input
type="number"
hint="Second"
[id]="id + '-second'"
[ngModel]="second"
min="0"
max="59"
(change)="secondChanged($event)"
[disabled]="isTimeDisabled('second')"
>
</ngx-input>
</div>
<div>
<ngx-input
type="number"
hint="Millisecond"
[id]="id + '-millisecond'"
[ngModel]="millisecond"
min="0"
max="999"
(change)="millisecondChanged($event)"
[disabled]="isTimeDisabled('millisecond')"
class="milliseconds"
>
</ngx-input>
</div>
<div>
<button
class="ampm"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,17 @@ $input-invalid-color: $color-red;
justify-content: space-between;

> * {
flex: 0 0 calc(33% - 6px);
flex: 0 0 calc(15% - 6px);
}

.ngx-input {
margin-top: 0;
padding-top: 0;
width: 35px;

&.milliseconds {
width: 55px;
}

.ngx-input-underline {
background-color: $color-input-text;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const LOCAL_YEAR = '' + MOON_LANDING_DATE.toLocaleDateString('en-US', { year: 'n

const LOCAL_HOUR = LOCAL_TIME.split(':')[0];
const LOCAL_MIN = MOON_LANDING_DATE.toLocaleTimeString('en-US', { minute: 'numeric' });
const LOCAL_SEC = MOON_LANDING_DATE.toLocaleTimeString('en-US', { second: 'numeric' });
const LOCAL_AM_PM = LOCAL_TIME.slice(-2);

describe('DateTimeComponent', () => {
Expand Down Expand Up @@ -337,6 +338,20 @@ describe('DateTimeComponent', () => {
expect(typeof component.displayValue === 'string').toBeTruthy();
expect(component.displayValue).toEqual('Jul 21, 1969 05:17:43 +09:00 (JST)');
});

it('should support seconds & milliseconds', () => {
component.format = 'MMM DD, YYYY HH:mm:ss:SSS';
component.timezone = 'Asia/Tokyo';

const isoDateString = '2023-10-27T05:57:12.890Z';
component.writeValue(new Date(isoDateString));
fixture.detectChanges();

expect(component.value).toBeTruthy();
expect(component.value instanceof Date).toBeTruthy();
expect(typeof component.displayValue === 'string').toBeTruthy();
expect(component.displayValue).toEqual('Oct 27, 2023 14:57:12:890');
});
});
});

Expand Down Expand Up @@ -415,6 +430,7 @@ describe('DateTimeComponent', () => {
expect(component.dialogModel.isSame(MOON_LANDING_DATE)).toBeTruthy();
expect(component.hour).toBe(+LOCAL_HOUR);
expect(component.minute).toBe(LOCAL_MIN);
expect(component.second).toBe(LOCAL_SEC);
expect(component.amPmVal).toBe(LOCAL_AM_PM);
expect(component.isCurrent()).toBe(false);

Expand Down Expand Up @@ -458,6 +474,59 @@ describe('DateTimeComponent', () => {
expect(component.displayValue).toEqual(`${LOCAL_DATE} 11:${LOCAL_MIN} ${LOCAL_AM_PM}`);
});

it('should update seconds', () => {
component.format = 'MM/DD/YYYY hh:mm:ss:SSS';
expect(component.dialogModel).toBeTruthy();
expect(moment.isMoment(component.dialogModel)).toBeTruthy();

expect(component.hour).toBe(+LOCAL_HOUR);
expect(component.minute).toBe(LOCAL_MIN);
expect(component.amPmVal).toBe(LOCAL_AM_PM);
expect(component.isCurrent()).toBe(false);
component.apply();

expect(component.displayValue).toEqual(`${LOCAL_DATE} 0${LOCAL_HOUR}:${LOCAL_MIN}:${LOCAL_SEC}:000`);

const SECONDS_VALUE = 55;
component.secondChanged(SECONDS_VALUE);

expect(component.isCurrent()).toBe(false);
expect(component.second).toBe(SECONDS_VALUE + '');

component.apply();
expect(component.displayValue).toEqual(`${LOCAL_DATE} 0${LOCAL_HOUR}:${LOCAL_MIN}:${SECONDS_VALUE}:000`);
});

it('should update milliseconds', () => {
component.format = 'MM/DD/YYYY hh:mm:ss:SSS';
expect(component.dialogModel).toBeTruthy();
expect(moment.isMoment(component.dialogModel)).toBeTruthy();

expect(component.hour).toBe(+LOCAL_HOUR);
expect(component.minute).toBe(LOCAL_MIN);
expect(component.second).toBe(LOCAL_SEC);
expect(component.amPmVal).toBe(LOCAL_AM_PM);
expect(component.isCurrent()).toBe(false);
component.apply();

expect(component.displayValue).toEqual(`${LOCAL_DATE} 0${LOCAL_HOUR}:${LOCAL_MIN}:${LOCAL_SEC}:000`);

const MILLISECONDS_VALUE = 786;
component.millisecondChanged(MILLISECONDS_VALUE);

expect(component.hour).toBe(+LOCAL_HOUR);
expect(component.minute).toBe(LOCAL_MIN);
expect(component.second).toBe(LOCAL_SEC);
expect(component.millisecond).toBe(MILLISECONDS_VALUE + '');
expect(component.amPmVal).toBe(LOCAL_AM_PM);
expect(component.isCurrent()).toBe(false);

component.apply();
expect(component.displayValue).toEqual(
`${LOCAL_DATE} 0${LOCAL_HOUR}:${LOCAL_MIN}:${LOCAL_SEC}:${MILLISECONDS_VALUE}`
);
});

it('should update am/pm', () => {
expect(component.dialogModel).toBeTruthy();
expect(moment.isMoment(component.dialogModel)).toBeTruthy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,8 @@ export class DateTimeComponent implements OnDestroy, OnChanges, ControlValueAcce
dialogModel: moment.Moment;
hour: number;
minute: string;
second: string;
millisecond: string;
amPmVal: string;
modes = ['millisecond', 'second', 'minute', 'hour', 'date', 'month', 'year'];
timeValues = {};
Expand Down Expand Up @@ -395,6 +397,8 @@ export class DateTimeComponent implements OnDestroy, OnChanges, ControlValueAcce
this.dialogModel = this.createMoment(date);
this.hour = +this.dialogModel.format('hh');
this.minute = this.dialogModel.format('mm');
this.second = this.dialogModel.format('ss');
this.millisecond = this.dialogModel.format('SSS');
this.amPmVal = this.dialogModel.format('A');
}

Expand All @@ -403,6 +407,16 @@ export class DateTimeComponent implements OnDestroy, OnChanges, ControlValueAcce
this.minute = this.dialogModel.format('mm');
}

secondChanged(newVal: number): void {
this.dialogModel = this.dialogModel.clone().second(newVal);
this.second = this.dialogModel.format('ss');
}

millisecondChanged(newVal: number): void {
this.dialogModel = this.dialogModel.clone().millisecond(newVal);
this.millisecond = this.dialogModel.format('SSS');
}

hourChanged(newVal: number): void {
newVal = +newVal % 12;
if (this.amPmVal === 'PM') {
Expand All @@ -419,9 +433,14 @@ export class DateTimeComponent implements OnDestroy, OnChanges, ControlValueAcce
isCurrent() {
const now = this.createMoment(new Date());
if (this.inputType === 'time') {
return now.hour() === this.dialogModel.hour() && now.minute() === this.dialogModel.minute();
return (
now.hour() === this.dialogModel.hour() &&
now.minute() === this.dialogModel.minute() &&
now.second() === this.dialogModel.second() &&
now.millisecond() === this.dialogModel.millisecond()
);
}
return now.isSame(this.dialogModel, 'minute');
return now.isSame(this.dialogModel, this.inputType === 'datetime' ? 'millisecond' : 'minute');
}

clear(): void {
Expand Down
Loading

0 comments on commit a8ecf79

Please sign in to comment.