From 9c47a55ebd0d42005cbea26c6a786b1fdfa52b0e Mon Sep 17 00:00:00 2001 From: Jason McCollum <83362099+jasonmccollumwoolpert@users.noreply.github.com> Date: Fri, 12 May 2023 05:57:49 -0700 Subject: [PATCH] Fix time to next stop calculation Co-authored-by: Chris Morabito --- .../src/app/core/effects/download.effects.ts | 8 +++--- .../frontend/src/app/core/models/csv.ts | 2 +- .../frontend/src/app/util/duration.spec.ts | 19 +++++++++++++ application/frontend/src/app/util/duration.ts | 27 +++++++++++++++++++ 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/application/frontend/src/app/core/effects/download.effects.ts b/application/frontend/src/app/core/effects/download.effects.ts index e884cee4..6ae3556e 100644 --- a/application/frontend/src/app/core/effects/download.effects.ts +++ b/application/frontend/src/app/core/effects/download.effects.ts @@ -49,7 +49,7 @@ import { import * as fromRoot from 'src/app/reducers'; import * as fromDownload from '../selectors/download.selectors'; import { unparse } from 'papaparse'; -import { durationSeconds, secondsToFormattedTime } from 'src/app/util'; +import { durationSeconds, formattedDurationSeconds } from 'src/app/util'; import { Modal } from '../models'; import * as fromUI from '../selectors/ui.selectors'; import { MatDialog } from '@angular/material/dialog'; @@ -212,7 +212,7 @@ export class DownloadEffects { visitEnd: new Date( durationSeconds(route.vehicleStartTime).toNumber() * 1000 ).toUTCString(), - timeToNextStop: secondsToFormattedTime( + timeToNextStop: formattedDurationSeconds( durationSeconds(route.visits[0]?.startTime || route.vehicleEndTime) .subtract(durationSeconds(route.vehicleStartTime)) .toNumber() @@ -306,13 +306,13 @@ export class DownloadEffects { const endSeconds = durationSeconds(visitRequest.duration).add(startSeconds); let timeToNextStop = null; if (visitIndex < route.visits.length - 1) { - timeToNextStop = secondsToFormattedTime( + timeToNextStop = formattedDurationSeconds( durationSeconds(route.visits[visitIndex + 1].startTime) .subtract(endSeconds) .toNumber() ); } else if (vehicle.endWaypoint) { - timeToNextStop = secondsToFormattedTime( + timeToNextStop = formattedDurationSeconds( durationSeconds(route.vehicleEndTime).subtract(endSeconds).toNumber() ); } diff --git a/application/frontend/src/app/core/models/csv.ts b/application/frontend/src/app/core/models/csv.ts index a4beeca5..2fc8f1c6 100644 --- a/application/frontend/src/app/core/models/csv.ts +++ b/application/frontend/src/app/core/models/csv.ts @@ -125,7 +125,7 @@ export const CSV_DATA_LABELS = { visitEnd: 'Visit end', shipmentIndex: 'Shipment index', shipmentLabel: 'Shipment label', - timeToNextStop: 'Time to next stop (HH:MM:SS)', + timeToNextStop: 'Time to next stop', location: 'Visit location (lat, lng)', }; diff --git a/application/frontend/src/app/util/duration.spec.ts b/application/frontend/src/app/util/duration.spec.ts index 1f51be67..c502fd5d 100644 --- a/application/frontend/src/app/util/duration.spec.ts +++ b/application/frontend/src/app/util/duration.spec.ts @@ -13,6 +13,7 @@ import { durationSeconds, durationToMinutes, durationToRequestString, + formattedDurationSeconds, minutesToDuration, pad, secondsToDuration, @@ -140,4 +141,22 @@ describe('duration util', () => { ).toEqual([Long.fromValue(1), Long.fromValue(2)]); }); }); + + describe('formattedDurationSeconds', () => { + it('should return a defaul timestamp', () => { + expect(formattedDurationSeconds(null)).toBe('0s'); + }); + it('should return a formatted duration', () => { + expect(formattedDurationSeconds(0)).toBe('0s'); + expect(formattedDurationSeconds(30)).toBe('30s'); + expect(formattedDurationSeconds(60)).toBe('1m 0s'); + expect(formattedDurationSeconds(95)).toBe('1m 35s'); + expect(formattedDurationSeconds(601)).toBe('10m 1s'); + expect(formattedDurationSeconds(3600)).toBe('1h 0m 0s'); + expect(formattedDurationSeconds(4201)).toBe('1h 10m 1s'); + expect(formattedDurationSeconds(46800)).toBe('13h 0m 0s'); + expect(formattedDurationSeconds(172800)).toBe('2d 0h 0m 0s'); + expect(formattedDurationSeconds(173409)).toBe('2d 0h 10m 9s'); + }); + }); }); diff --git a/application/frontend/src/app/util/duration.ts b/application/frontend/src/app/util/duration.ts index cc104862..44c314ed 100644 --- a/application/frontend/src/app/util/duration.ts +++ b/application/frontend/src/app/util/duration.ts @@ -38,6 +38,33 @@ export function secondsToFormattedTime(seconds: Long | number): string { return new Date(1000 * seconds).toISOString().substring(11, 19); } +export function formattedDurationSeconds(seconds: Long | number): string { + if (!seconds) { + return '0s'; + } + + seconds = Long.fromValue(seconds).toNumber(); + + const days = Math.floor(seconds / 86400); + seconds -= days * 86400; + const hours = Math.floor(seconds / 3600); + seconds -= hours * 3600; + const minutes = Math.floor(seconds / 60); + seconds -= minutes * 60; + + // Format string based on the highest unit of time in the duration + if (days) { + return `${days}d ${hours}h ${minutes}m ${seconds}s`; + } + if (hours) { + return `${hours}h ${minutes}m ${seconds}s`; + } + if (minutes) { + return `${minutes}m ${seconds}s`; + } + return `${seconds}s`; +} + export function durationSeconds(duration: IDuration | ITimestamp, defaultValue = Long.ZERO): Long { let seconds: Long; if (duration) {