From 06a0577787437ef8dee595a4aef1d9139385597d Mon Sep 17 00:00:00 2001 From: reverie3 <37984867+reverie3@users.noreply.github.com> Date: Thu, 26 Dec 2024 14:02:33 +0300 Subject: [PATCH] fix(cdk): `TuiTime.shift` doesn't shift higher order units --- projects/cdk/date-time/test/time.spec.ts | 23 ++++++++++++- projects/cdk/date-time/time.ts | 42 ++++++++++++------------ 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/projects/cdk/date-time/test/time.spec.ts b/projects/cdk/date-time/test/time.spec.ts index 007742a7da1e..54f40e8f3039 100644 --- a/projects/cdk/date-time/test/time.spec.ts +++ b/projects/cdk/date-time/test/time.spec.ts @@ -330,7 +330,28 @@ describe('TuiTime', () => { ms: -1000 * 60 * 60 - 1000 * 60 - 1000 - 10, }); - expect(increasedTime.toString()).toBe('03:23:55.990'); + expect(increasedTime.toString()).toBe('03:22:54.990'); + }); + + it('seconds are increased if milliseconds reach 1000', () => { + const time = new TuiTime(15, 0, 0, 999); + const increasedTime = time.shift({ms: 1}); + + expect(increasedTime.toString()).toBe('15:00:01'); + }); + + it('minutes are increased if seconds reach 60', () => { + const time = new TuiTime(15, 0, 59); + const increasedTime = time.shift({seconds: 1}); + + expect(increasedTime.toString()).toBe('15:01'); + }); + + it('hours are increased if minutes reach 60', () => { + const time = new TuiTime(15, 59); + const increasedTime = time.shift({minutes: 1}); + + expect(increasedTime.toString()).toBe('16:00'); }); }); diff --git a/projects/cdk/date-time/time.ts b/projects/cdk/date-time/time.ts index 5d7958412f5d..48218c38ab00 100644 --- a/projects/cdk/date-time/time.ts +++ b/projects/cdk/date-time/time.ts @@ -8,6 +8,7 @@ import { MILLISECONDS_IN_DAY, MILLISECONDS_IN_HOUR, MILLISECONDS_IN_MINUTE, + MILLISECONDS_IN_SECOND, MINUTES_IN_HOUR, SECONDS_IN_MINUTE, } from './date-time'; @@ -138,27 +139,22 @@ export class TuiTime implements TuiTimeLike { * Shifts time by hours and minutes */ shift({hours = 0, minutes = 0, seconds = 0, ms = 0}: TuiTimeLike): TuiTime { - const newMs = (1000 + this.ms + (ms % 1000)) % 1000; - - const secondsInMs = ms < 0 ? Math.ceil(ms / 1000) : Math.floor(ms / 1000); - const secondsToAdd = secondsInMs + seconds; - const newSeconds = (60 + this.seconds + (secondsToAdd % 60)) % 60; - - const minutesInSeconds = - secondsToAdd < 0 - ? Math.ceil(secondsToAdd / 60) - : Math.floor(secondsToAdd / 60); - const minutesToAdd = minutesInSeconds + minutes; - const newMinutes = (60 + this.minutes + (minutesToAdd % 60)) % 60; - - const hoursInMinutes = - minutesToAdd < 0 - ? Math.ceil(minutesToAdd / 60) - : Math.floor(minutesToAdd / 60); - const hoursToAdd = hoursInMinutes + hours; - const newHours = (24 + this.hours + (hoursToAdd % 24)) % 24; - - return new TuiTime(newHours, newMinutes, newSeconds, newMs); + const totalMs = + this.toAbsoluteMilliseconds() + + hours * MILLISECONDS_IN_HOUR + + minutes * MILLISECONDS_IN_MINUTE + + seconds * MILLISECONDS_IN_SECOND + + ms; + const totalSeconds = Math.floor(totalMs / MILLISECONDS_IN_SECOND); + const totalMinutes = Math.floor(totalSeconds / SECONDS_IN_MINUTE); + const totalHours = Math.floor(totalMinutes / MINUTES_IN_HOUR); + + return new TuiTime( + this.normalizeToRange(totalHours, HOURS_IN_DAY), + this.normalizeToRange(totalMinutes, MINUTES_IN_HOUR), + this.normalizeToRange(totalSeconds, SECONDS_IN_MINUTE), + this.normalizeToRange(totalMs, MILLISECONDS_IN_SECOND), + ); } /** @@ -204,4 +200,8 @@ export class TuiTime implements TuiTimeLike { private formatTime(time: number, digits: number = 2): string { return String(time).padStart(digits, '0'); } + + private normalizeToRange(value: number, modulus: number): number { + return ((value % modulus) + modulus) % modulus; + } }