Skip to content

Commit ea71d16

Browse files
committed
fix: fix handling of milliseconds
in parsing and in formatting iso duration in parsing of timestamp
1 parent 13e929e commit ea71d16

File tree

2 files changed

+69
-30
lines changed

2 files changed

+69
-30
lines changed

src/tools/duration-calculator/duration-calculator.service.test.ts

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ describe('duration-calculator', () => {
2424
describe('computeDuration', () => {
2525
it('should compute correct sum/values', () => {
2626
expect(computeDuration('')).to.deep.eq(zeroResult);
27+
expect(computeDuration('00:00:00')).to.deep.eq(zeroResult);
28+
expect(computeDuration('0h')).to.deep.eq(zeroResult);
2729
expect(computeDuration('0s')).to.deep.eq(zeroResult);
2830
expect(computeDuration('3600s')).to.deep.eq({
2931
errors: [],
@@ -120,7 +122,7 @@ describe('duration-calculator', () => {
120122
total: {
121123
days: 0.11128616898148148,
122124
hours: 2.6708680555555557,
123-
iso8601Duration: 'P0Y0M0DT2H40M15S',
125+
iso8601Duration: 'P0Y0M0DT2H40M15.125S',
124126
milliseconds: 9615125,
125127
minutes: 160.25208333333333,
126128
prettified: '2h 40m 15s 125ms',
@@ -173,19 +175,19 @@ describe('duration-calculator', () => {
173175
expect(computeDuration('P4DT12H20M20.3S')).to.deep.eq({
174176
errors: [],
175177
total: {
176-
days: 0.5141238425925926,
177-
hours: 12.338972222222223,
178-
iso8601Duration: 'P0Y0M0DT12H20M20S',
179-
milliseconds: 44420300,
180-
minutes: 740.3383333333334,
181-
prettified: '12h 20m 20s 300ms',
182-
prettifiedColonNotation: '12:20:20.3',
183-
prettifiedDaysColon: '12:20:20.300',
184-
prettifiedHoursColon: '12:20:20.300',
185-
prettifiedVerbose: '12 hours 20 minutes 20 seconds 300 milliseconds',
186-
seconds: 44420.3,
187-
weeks: 0.07344626322751323,
188-
years: 0.0014085584728564182,
178+
days: 4.514123842592593,
179+
hours: 108.33897222222222,
180+
iso8601Duration: 'P0Y0M4DT12H20M20.3S',
181+
milliseconds: 390020300,
182+
minutes: 6500.338333333333,
183+
prettified: '4d 12h 20m 20s 300ms',
184+
prettifiedColonNotation: '4:12:20:20.3',
185+
prettifiedDaysColon: '4d 12:20:20.300',
186+
prettifiedHoursColon: '108:20:20.300',
187+
prettifiedVerbose: '4 days 12 hours 20 minutes 20 seconds 300 milliseconds',
188+
seconds: 390020.3,
189+
weeks: 0.6448748346560846,
190+
years: 0.012367462582445459,
189191
},
190192
});
191193
expect(computeDuration('25s\n+PT20H\n-10s')).to.deep.eq({
@@ -315,7 +317,7 @@ describe('duration-calculator', () => {
315317
total: {
316318
days: 2.000001446759259,
317319
hours: 48.000034722222225,
318-
iso8601Duration: 'P0Y0M2DT0H0M0S',
320+
iso8601Duration: 'P0Y0M2DT0H0M0.125S',
319321
milliseconds: 172800125,
320322
minutes: 2880.0020833333333,
321323
prettified: '2d 125ms',
@@ -328,6 +330,42 @@ describe('duration-calculator', () => {
328330
years: 0.005479456018518519,
329331
},
330332
});
333+
expect(computeDuration('12:12:12.1')).to.deep.eq({
334+
errors: [],
335+
total: {
336+
days: 0.5084733796296297,
337+
hours: 12.20336111111111,
338+
iso8601Duration: 'P0Y0M0DT12H12M12.1S',
339+
milliseconds: 43932100,
340+
minutes: 732.2016666666667,
341+
prettified: '12h 12m 12s 100ms',
342+
prettifiedColonNotation: '12:12:12.1',
343+
prettifiedDaysColon: '12:12:12.100',
344+
prettifiedHoursColon: '12:12:12.100',
345+
prettifiedVerbose: '12 hours 12 minutes 12 seconds 100 milliseconds',
346+
seconds: 43932.1,
347+
weeks: 0.07263905423280423,
348+
years: 0.0013930777524099442,
349+
},
350+
});
351+
expect(computeDuration('12:12:12.12')).to.deep.eq({
352+
errors: [],
353+
total: {
354+
days: 0.5084736111111111,
355+
hours: 12.203366666666666,
356+
iso8601Duration: 'P0Y0M0DT12H12M12.12S',
357+
milliseconds: 43932120,
358+
minutes: 732.202,
359+
prettified: '12h 12m 12s 120ms',
360+
prettifiedColonNotation: '12:12:12.1',
361+
prettifiedDaysColon: '12:12:12.120',
362+
prettifiedHoursColon: '12:12:12.120',
363+
prettifiedVerbose: '12 hours 12 minutes 12 seconds 120 milliseconds',
364+
seconds: 43932.12,
365+
weeks: 0.0726390873015873,
366+
years: 0.001393078386605784,
367+
},
368+
});
331369
});
332370
});
333371
});

src/tools/duration-calculator/duration-calculator.service.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ interface DurationLine {
2323
rawLine: string
2424
cleanedDuration: string
2525
sign: number
26-
durationMS: number | undefined
26+
durationMS: number | null
2727
isValid: boolean
2828
}
2929

@@ -33,14 +33,14 @@ export function computeDuration(s: string): {
3333
} {
3434
const lines: DurationLine[] = s.split('\n').filter(l => l && !/^\s*#/.test(l)).map((l) => {
3535
const isNeg = /^\s*-/.test(l);
36-
const cleanedDuration = l.replace(/^\s*[+-]\s*/, '');
36+
const cleanedDuration = l.replace(/^\s*[+-]\s*/, '').replace(/\s*#.*$/, ''); // NOSONAR
3737
const durationMS = convertDurationMS(cleanedDuration);
3838
return {
3939
rawLine: l,
4040
cleanedDuration,
4141
sign: isNeg ? -1 : 1,
4242
durationMS,
43-
isValid: typeof durationMS !== 'undefined',
43+
isValid: durationMS !== null,
4444
};
4545
});
4646

@@ -60,8 +60,8 @@ export function computeDuration(s: string): {
6060
};
6161
}
6262

63-
function convertDurationMS(s: string): number | undefined {
64-
const hoursHandled = s.replace(/\b(?:(\d+)\.)?(\d+):(\d+)(?::(\d+)(?:\.(\d+))?)?\b/g,
63+
function convertDurationMS(s: string): number | null {
64+
const hoursHandled = s.trim().replace(/^(?:(\d+)\.)?(\d+):(\d+)(?::(\d+)(?:\.(\d+))?)?$/g,
6565
(_, d, h, m, s, ms) => {
6666
const timeArr: string[] = [];
6767
const addPart = (part: string, unit: string) => {
@@ -76,26 +76,27 @@ function convertDurationMS(s: string): number | undefined {
7676
addPart(h, 'h');
7777
addPart(m, 'm');
7878
addPart(s, 's');
79-
addPart(ms, 'ms');
79+
addPart(ms?.padEnd(3, '0'), 'ms');
8080
return timeArr.join(' ');
8181
});
8282
if (!hoursHandled) {
8383
return 0;
8484
}
8585

86-
let parsedDuration = parse(hoursHandled);
87-
if (parsedDuration !== 0 && !parsedDuration) {
88-
try {
89-
parsedDuration = iso8601Duration.toMilliseconds(iso8601Duration.parse(hoursHandled));
90-
}
91-
catch (_) {
92-
return undefined;
86+
try {
87+
return iso8601Duration.toMilliseconds(iso8601Duration.parse(hoursHandled));
88+
}
89+
catch (_) {
90+
const result = parse(hoursHandled);
91+
if (typeof result === 'undefined') {
92+
return null;
9393
}
94+
return result;
9495
}
95-
return parsedDuration;
9696
}
97-
function prepareDurationResult(durationMS: any): ConvertedDuration {
97+
function prepareDurationResult(durationMS: number): ConvertedDuration {
9898
const dateFnsDuration = intervalToDuration({ start: 0, end: durationMS });
99+
dateFnsDuration.seconds = (dateFnsDuration.seconds || 0) + (durationMS % 1000) / 1000;
99100
return {
100101
prettified: prettyMilliseconds(durationMS, { formatSubMilliseconds: true }),
101102
prettifiedVerbose: prettyMilliseconds(durationMS, { verbose: true, formatSubMilliseconds: true }),

0 commit comments

Comments
 (0)