From 3fb21de8fdebcabe7f0871266194dc53cfef4986 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Stephan=20M=C3=BCller?= Date: Wed, 27 Mar 2019 13:27:51 +0100 Subject: [PATCH] mgr/dashboard: Time diff service MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The time diff service can easily calculate the difference between two dates and print it out in a human readable duration format. It also can calculate a end or start date based on a date and a duration string. Fixes: https://tracker.ceph.com/issues/36722 Signed-off-by: Stephan Müller --- .../shared/services/time-diff.service.spec.ts | 66 +++++++++++++++++++ .../app/shared/services/time-diff.service.ts | 51 ++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/services/time-diff.service.spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/services/time-diff.service.ts diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/time-diff.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/time-diff.service.spec.ts new file mode 100644 index 0000000000000..59b52ae603993 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/time-diff.service.spec.ts @@ -0,0 +1,66 @@ +import { TestBed } from '@angular/core/testing'; + +import { configureTestBed } from '../../../testing/unit-test-helper'; +import { TimeDiffService } from './time-diff.service'; + +describe('TimeDiffService', () => { + let service: TimeDiffService; + const baseTime = new Date('2022-02-22T00:00:00'); + + configureTestBed({ + providers: [TimeDiffService] + }); + + beforeEach(() => { + service = TestBed.get(TimeDiffService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it('calculates a new date that happens after the given date', () => { + expect(service.calculateDate(new Date('2022-02-28T04:05:00'), '2h')).toEqual( + new Date('2022-02-28T06:05:00') + ); + expect(service.calculateDate(baseTime, '15m')).toEqual(new Date('2022-02-22T00:15')); + expect(service.calculateDate(baseTime, '5d 23h')).toEqual(new Date('2022-02-27T23:00')); + }); + + it('calculates a new date that happens before the given date', () => { + expect(service.calculateDate(new Date('2022-02-22T02:00:00'), '2h', true)).toEqual(baseTime); + }); + + it('calculates the difference of two dates', () => { + expect( + service.calculateDuration(new Date('2022-02-22T00:45:00'), new Date('2022-02-22T02:00:00')) + ).toBe('1h 15m'); + expect(service.calculateDuration(baseTime, new Date('2022-02-28T04:05:00'))).toBe('6d 4h 5m'); + }); + + describe('testing duration calculation in detail', () => { + const minutes = 60 * 1000; + const hours = 60 * minutes; + const days = 24 * hours; + + it('should allow different writings', () => { + const expectDurationToBeMs = (duration, ms) => + expect(service['getDurationMs'](duration)).toBe(ms); + expectDurationToBeMs('2h', 2 * hours); + expectDurationToBeMs('4 Days', 4 * days); + expectDurationToBeMs('3 minutes', 3 * minutes); + expectDurationToBeMs('4 Days 2h 3 minutes', 4 * days + 2 * hours + 3 * minutes); + expectDurationToBeMs('5d3h120m', 5 * days + 5 * hours); + }); + + it('should create duration string from ms', () => { + const expectMsToBeDuration = (ms, duration) => + expect(service['getDuration'](ms)).toBe(duration); + expectMsToBeDuration(2 * hours, '2h'); + expectMsToBeDuration(4 * days, '4d'); + expectMsToBeDuration(3 * minutes, '3m'); + expectMsToBeDuration(4 * days + 2 * hours + 3 * minutes, '4d 2h 3m'); + expectMsToBeDuration(service['getDurationMs']('5d3h120m'), '5d 5h'); + }); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/time-diff.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/time-diff.service.ts new file mode 100644 index 0000000000000..051d104906e75 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/time-diff.service.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; + +import * as _ from 'lodash'; + +@Injectable({ + providedIn: 'root' +}) +export class TimeDiffService { + constructor() {} + + calculateDuration(startDate: Date, endDate: Date): string { + const startTime = +startDate; + const endTime = +endDate; + const duration = this.getDuration(Math.abs(startTime - endTime)); + if (startTime > endTime) { + return '-' + duration; + } + return duration; + } + + private getDuration(ms: number): string { + const date = new Date(ms); + const h = date.getUTCHours(); + const m = date.getUTCMinutes(); + const d = Math.floor(ms / (24 * 3600 * 1000)); + + const format = (n, s) => (n ? n + s : n); + return [format(d, 'd'), format(h, 'h'), format(m, 'm')].filter((x) => x).join(' '); + } + + calculateDate(date: Date, duration: string, reverse?: boolean): Date { + const time = +date; + if (_.isNaN(time)) { + return; + } + const diff = this.getDurationMs(duration) * (reverse ? -1 : 1); + return new Date(time + diff); + } + + private getDurationMs(duration: string): number { + const d = this.getNumbersFromString(duration, 'd'); + const h = this.getNumbersFromString(duration, 'h'); + const m = this.getNumbersFromString(duration, 'm'); + return ((d * 24 + h) * 60 + m) * 60000; + } + + private getNumbersFromString(duration, prefix): number { + const match = duration.match(new RegExp(`[0-9 ]+${prefix}`, 'i')); + return match ? parseInt(match, 10) : 0; + } +} -- 2.39.5