Skip to content

Commit 615cf86

Browse files
committed
Refactor time functions
Rename, add comments, and extract some local variables.
1 parent d63a209 commit 615cf86

File tree

5 files changed

+84
-68
lines changed

5 files changed

+84
-68
lines changed

extensions/ql-vscode/src/pure/time.ts

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,63 +7,77 @@ const durationFormatter = new Intl.RelativeTimeFormat('en', {
77
numeric: 'auto',
88
});
99

10-
// All these are approximate, specifically months and years
10+
// Months and years are approximate
1111
const MINUTE_IN_MILLIS = 1000 * 60;
1212
const HOUR_IN_MILLIS = 60 * MINUTE_IN_MILLIS;
1313
const DAY_IN_MILLIS = 24 * HOUR_IN_MILLIS;
1414
const MONTH_IN_MILLIS = 30 * DAY_IN_MILLIS;
1515
const YEAR_IN_MILLIS = 365 * DAY_IN_MILLIS;
1616

17-
export function humanizeDuration(diffInMs?: number) {
18-
if (diffInMs === undefined) {
17+
/**
18+
* Converts a number of milliseconds into a human-readable string with units, indicating a relative time in the past or future.
19+
*
20+
* @param relativeTimeMillis The duration in milliseconds. A negative number indicates a duration in the past. And a positive number is
21+
* the future.
22+
* @returns A humanized duration. For example, "in 2 minutes", "2 minutes ago", "yesterday", or "tomorrow".
23+
*/
24+
export function humanizeRelativeTime(relativeTimeMillis?: number) {
25+
if (relativeTimeMillis === undefined) {
1926
return '';
2027
}
2128

22-
if (Math.abs(diffInMs) < HOUR_IN_MILLIS) {
23-
return durationFormatter.format(Math.floor(diffInMs / MINUTE_IN_MILLIS), 'minute');
24-
} else if (Math.abs(diffInMs) < DAY_IN_MILLIS) {
25-
return durationFormatter.format(Math.floor(diffInMs / HOUR_IN_MILLIS), 'hour');
26-
} else if (Math.abs(diffInMs) < MONTH_IN_MILLIS) {
27-
return durationFormatter.format(Math.floor(diffInMs / DAY_IN_MILLIS), 'day');
28-
} else if (Math.abs(diffInMs) < YEAR_IN_MILLIS) {
29-
return durationFormatter.format(Math.floor(diffInMs / MONTH_IN_MILLIS), 'month');
29+
if (Math.abs(relativeTimeMillis) < HOUR_IN_MILLIS) {
30+
return durationFormatter.format(Math.floor(relativeTimeMillis / MINUTE_IN_MILLIS), 'minute');
31+
} else if (Math.abs(relativeTimeMillis) < DAY_IN_MILLIS) {
32+
return durationFormatter.format(Math.floor(relativeTimeMillis / HOUR_IN_MILLIS), 'hour');
33+
} else if (Math.abs(relativeTimeMillis) < MONTH_IN_MILLIS) {
34+
return durationFormatter.format(Math.floor(relativeTimeMillis / DAY_IN_MILLIS), 'day');
35+
} else if (Math.abs(relativeTimeMillis) < YEAR_IN_MILLIS) {
36+
return durationFormatter.format(Math.floor(relativeTimeMillis / MONTH_IN_MILLIS), 'month');
3037
} else {
31-
return durationFormatter.format(Math.floor(diffInMs / YEAR_IN_MILLIS), 'year');
38+
return durationFormatter.format(Math.floor(relativeTimeMillis / YEAR_IN_MILLIS), 'year');
3239
}
3340
}
3441

35-
function createFormatter(unit: string) {
36-
return Intl.NumberFormat('en-US', {
37-
style: 'unit',
38-
unit,
39-
unitDisplay: 'long'
40-
});
41-
}
42-
43-
export function humanizeUnit(diffInMs?: number): string {
42+
/**
43+
* Converts a number of milliseconds into a human-readable string with units, indicating an amount of time.
44+
* Negative numbers have no meaning and are considered to be "Less than a minute".
45+
*
46+
* @param millis The number of milliseconds to convert.
47+
* @returns A humanized duration. For example, "2 minutes", "2 hours", "2 days", or "2 months".
48+
*/
49+
export function humanizeUnit(millis?: number): string {
4450
// assume a blank or empty string is a zero
4551
// assume anything less than 0 is a zero
46-
if (!diffInMs || diffInMs < MINUTE_IN_MILLIS) {
52+
if (!millis || millis < MINUTE_IN_MILLIS) {
4753
return 'Less than a minute';
4854
}
4955
let unit: string;
5056
let unitDiff: number;
51-
if (diffInMs < HOUR_IN_MILLIS) {
57+
if (millis < HOUR_IN_MILLIS) {
5258
unit = 'minute';
53-
unitDiff = Math.floor(diffInMs / MINUTE_IN_MILLIS);
54-
} else if (diffInMs < DAY_IN_MILLIS) {
59+
unitDiff = Math.floor(millis / MINUTE_IN_MILLIS);
60+
} else if (millis < DAY_IN_MILLIS) {
5561
unit = 'hour';
56-
unitDiff = Math.floor(diffInMs / HOUR_IN_MILLIS);
57-
} else if (diffInMs < MONTH_IN_MILLIS) {
62+
unitDiff = Math.floor(millis / HOUR_IN_MILLIS);
63+
} else if (millis < MONTH_IN_MILLIS) {
5864
unit = 'day';
59-
unitDiff = Math.floor(diffInMs / DAY_IN_MILLIS);
60-
} else if (diffInMs < YEAR_IN_MILLIS) {
65+
unitDiff = Math.floor(millis / DAY_IN_MILLIS);
66+
} else if (millis < YEAR_IN_MILLIS) {
6167
unit = 'month';
62-
unitDiff = Math.floor(diffInMs / MONTH_IN_MILLIS);
68+
unitDiff = Math.floor(millis / MONTH_IN_MILLIS);
6369
} else {
6470
unit = 'year';
65-
unitDiff = Math.floor(diffInMs / YEAR_IN_MILLIS);
71+
unitDiff = Math.floor(millis / YEAR_IN_MILLIS);
6672
}
6773

6874
return createFormatter(unit).format(unitDiff);
6975
}
76+
77+
function createFormatter(unit: string) {
78+
return Intl.NumberFormat('en-US', {
79+
style: 'unit',
80+
unit,
81+
unitDisplay: 'long'
82+
});
83+
}

extensions/ql-vscode/src/remote-queries/gh-actions-api-client.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,8 @@ export async function getRepositoriesMetadata(credentials: Credentials, nwos: st
395395
const owner = node.owner.login;
396396
const name = node.name;
397397
const starCount = node.stargazerCount;
398-
const lastUpdated = Date.now() - new Date(node.updatedAt).getTime();
398+
// lastUpdated is always negative since it happened in the past.
399+
const lastUpdated = new Date(node.updatedAt).getTime() - Date.now();
399400
metadata[`${owner}/${name}`] = {
400401
starCount, lastUpdated
401402
};

extensions/ql-vscode/src/remote-queries/view/LastUpdated.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as React from 'react';
22
import { RepoPushIcon } from '@primer/octicons-react';
33
import styled from 'styled-components';
44

5-
import { humanizeDuration } from '../../pure/time';
5+
import { humanizeRelativeTime } from '../../pure/time';
66

77
const IconContainer = styled.span`
88
flex-grow: 0;
@@ -19,13 +19,15 @@ const Duration = styled.span`
1919
type Props = { lastUpdated?: number };
2020

2121
const LastUpdated = ({ lastUpdated }: Props) => (
22+
// lastUpdated will be undefined for older results that were
23+
// created before the lastUpdated field was added.
2224
Number.isFinite(lastUpdated) ? (
2325
<>
2426
<IconContainer>
2527
<RepoPushIcon size={16} />
2628
</IconContainer>
2729
<Duration>
28-
{humanizeDuration(lastUpdated === undefined ? undefined : -lastUpdated)}
30+
{humanizeRelativeTime(lastUpdated)}
2931
</Duration>
3032
</>
3133
) : (

extensions/ql-vscode/src/remote-queries/view/RemoteQueries.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,8 @@ const openQueryTextVirtualFile = (queryResult: RemoteQueryResult) => {
7272
};
7373

7474
function createResultsDescription(queryResult: RemoteQueryResult) {
75-
return `${queryResult.totalResultCount} results from running against ${queryResult.totalRepositoryCount
76-
} ${queryResult.totalRepositoryCount === 1 ? 'repository' : 'repositories'
77-
} (${queryResult.executionDuration}), ${queryResult.executionTimestamp}`;
75+
const reposCount = `${queryResult.totalRepositoryCount} ${queryResult.totalRepositoryCount === 1 ? 'repository' : 'repositories'}`;
76+
return `${queryResult.totalResultCount} results from running against ${reposCount} (${queryResult.executionDuration}), ${queryResult.executionTimestamp}`;
7877
}
7978

8079
const sumAnalysesResults = (analysesResults: AnalysisResults[]) =>
Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { expect } from 'chai';
22
import 'mocha';
33

4-
import { humanizeDuration, humanizeUnit } from '../../src/pure/time';
4+
import { humanizeRelativeTime, humanizeUnit } from '../../src/pure/time';
55

66
describe('Time', () => {
77
it('should return a humanized unit', () => {
@@ -28,46 +28,46 @@ describe('Time', () => {
2828
});
2929

3030
it('should return a humanized duration positive', () => {
31-
expect(humanizeDuration(undefined)).to.eq('');
32-
expect(humanizeDuration(0)).to.eq('this minute');
33-
expect(humanizeDuration(1)).to.eq('this minute');
34-
expect(humanizeDuration(1000 * 60 - 1)).to.eq('this minute');
35-
expect(humanizeDuration(1000 * 60)).to.eq('in 1 minute');
36-
expect(humanizeDuration(1000 * 60 * 2 - 1)).to.eq('in 1 minute');
37-
expect(humanizeDuration(1000 * 60 * 2)).to.eq('in 2 minutes');
38-
expect(humanizeDuration(1000 * 60 * 60)).to.eq('in 1 hour');
39-
expect(humanizeDuration(1000 * 60 * 60 * 2)).to.eq('in 2 hours');
40-
expect(humanizeDuration(1000 * 60 * 60 * 24)).to.eq('tomorrow');
41-
expect(humanizeDuration(1000 * 60 * 60 * 24 * 2)).to.eq('in 2 days');
31+
expect(humanizeRelativeTime(undefined)).to.eq('');
32+
expect(humanizeRelativeTime(0)).to.eq('this minute');
33+
expect(humanizeRelativeTime(1)).to.eq('this minute');
34+
expect(humanizeRelativeTime(1000 * 60 - 1)).to.eq('this minute');
35+
expect(humanizeRelativeTime(1000 * 60)).to.eq('in 1 minute');
36+
expect(humanizeRelativeTime(1000 * 60 * 2 - 1)).to.eq('in 1 minute');
37+
expect(humanizeRelativeTime(1000 * 60 * 2)).to.eq('in 2 minutes');
38+
expect(humanizeRelativeTime(1000 * 60 * 60)).to.eq('in 1 hour');
39+
expect(humanizeRelativeTime(1000 * 60 * 60 * 2)).to.eq('in 2 hours');
40+
expect(humanizeRelativeTime(1000 * 60 * 60 * 24)).to.eq('tomorrow');
41+
expect(humanizeRelativeTime(1000 * 60 * 60 * 24 * 2)).to.eq('in 2 days');
4242

4343
// assume every month has 30 days
44-
expect(humanizeDuration(1000 * 60 * 60 * 24 * 30)).to.eq('next month');
45-
expect(humanizeDuration(1000 * 60 * 60 * 24 * 30 * 2)).to.eq('in 2 months');
46-
expect(humanizeDuration(1000 * 60 * 60 * 24 * 30 * 12)).to.eq('in 12 months');
44+
expect(humanizeRelativeTime(1000 * 60 * 60 * 24 * 30)).to.eq('next month');
45+
expect(humanizeRelativeTime(1000 * 60 * 60 * 24 * 30 * 2)).to.eq('in 2 months');
46+
expect(humanizeRelativeTime(1000 * 60 * 60 * 24 * 30 * 12)).to.eq('in 12 months');
4747

4848
// assume every year has 365 days
49-
expect(humanizeDuration(1000 * 60 * 60 * 24 * 365)).to.eq('next year');
50-
expect(humanizeDuration(1000 * 60 * 60 * 24 * 365 * 2)).to.eq('in 2 years');
49+
expect(humanizeRelativeTime(1000 * 60 * 60 * 24 * 365)).to.eq('next year');
50+
expect(humanizeRelativeTime(1000 * 60 * 60 * 24 * 365 * 2)).to.eq('in 2 years');
5151
});
5252

5353
it('should return a humanized duration negative', () => {
54-
expect(humanizeDuration(-1)).to.eq('1 minute ago');
55-
expect(humanizeDuration(-1000 * 60)).to.eq('1 minute ago');
56-
expect(humanizeDuration(-1000 * 60 - 1)).to.eq('2 minutes ago');
57-
expect(humanizeDuration(-1000 * 60 * 2)).to.eq('2 minutes ago');
58-
expect(humanizeDuration(-1000 * 60 * 2 - 1)).to.eq('3 minutes ago');
59-
expect(humanizeDuration(-1000 * 60 * 60)).to.eq('1 hour ago');
60-
expect(humanizeDuration(-1000 * 60 * 60 * 2)).to.eq('2 hours ago');
61-
expect(humanizeDuration(-1000 * 60 * 60 * 24)).to.eq('yesterday');
62-
expect(humanizeDuration(-1000 * 60 * 60 * 24 * 2)).to.eq('2 days ago');
54+
expect(humanizeRelativeTime(-1)).to.eq('1 minute ago');
55+
expect(humanizeRelativeTime(-1000 * 60)).to.eq('1 minute ago');
56+
expect(humanizeRelativeTime(-1000 * 60 - 1)).to.eq('2 minutes ago');
57+
expect(humanizeRelativeTime(-1000 * 60 * 2)).to.eq('2 minutes ago');
58+
expect(humanizeRelativeTime(-1000 * 60 * 2 - 1)).to.eq('3 minutes ago');
59+
expect(humanizeRelativeTime(-1000 * 60 * 60)).to.eq('1 hour ago');
60+
expect(humanizeRelativeTime(-1000 * 60 * 60 * 2)).to.eq('2 hours ago');
61+
expect(humanizeRelativeTime(-1000 * 60 * 60 * 24)).to.eq('yesterday');
62+
expect(humanizeRelativeTime(-1000 * 60 * 60 * 24 * 2)).to.eq('2 days ago');
6363

6464
// assume every month has 30 days
65-
expect(humanizeDuration(-1000 * 60 * 60 * 24 * 30)).to.eq('last month');
66-
expect(humanizeDuration(-1000 * 60 * 60 * 24 * 30 * 2)).to.eq('2 months ago');
67-
expect(humanizeDuration(-1000 * 60 * 60 * 24 * 30 * 12)).to.eq('12 months ago');
65+
expect(humanizeRelativeTime(-1000 * 60 * 60 * 24 * 30)).to.eq('last month');
66+
expect(humanizeRelativeTime(-1000 * 60 * 60 * 24 * 30 * 2)).to.eq('2 months ago');
67+
expect(humanizeRelativeTime(-1000 * 60 * 60 * 24 * 30 * 12)).to.eq('12 months ago');
6868

6969
// assume every year has 365 days
70-
expect(humanizeDuration(-1000 * 60 * 60 * 24 * 365)).to.eq('last year');
71-
expect(humanizeDuration(-1000 * 60 * 60 * 24 * 365 * 2)).to.eq('2 years ago');
70+
expect(humanizeRelativeTime(-1000 * 60 * 60 * 24 * 365)).to.eq('last year');
71+
expect(humanizeRelativeTime(-1000 * 60 * 60 * 24 * 365 * 2)).to.eq('2 years ago');
7272
});
7373
});

0 commit comments

Comments
 (0)