Skip to content

Commit

Permalink
BREAKING: Refactor and add more time utils (#9)
Browse files Browse the repository at this point in the history
This PR refactors the time utils and adds an `inMilliseconds` function. `Week` and `Year` are added to to the time constants, and the constants are moved to a new `enum`, `Duration`. `inMilliseconds` returns the specified number of units of time, in milliseconds.

Co-authored-by: Maarten Zuidhoorn <[email protected]>
  • Loading branch information
rekmarks and Mrtenz authored May 16, 2022
1 parent a915c8f commit 9e631c1
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 19 deletions.
52 changes: 49 additions & 3 deletions src/time.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,56 @@
import { timeSince } from '.';
import { Duration, inMilliseconds, timeSince } from '.';

describe('time utilities', () => {
describe('Duration', () => {
it('has the correct values', () => {
expect(Duration.Millisecond).toBe(1);
expect(Duration.Second).toBe(Duration.Millisecond * 1000);
expect(Duration.Minute).toBe(Duration.Second * 60);
expect(Duration.Hour).toBe(Duration.Minute * 60);
expect(Duration.Day).toBe(Duration.Hour * 24);
expect(Duration.Week).toBe(Duration.Day * 7);
expect(Duration.Year).toBe(Duration.Day * 365);
});
});

describe('inMilliseconds', () => {
it('throws if the number is negative or a float', () => {
expect(() => inMilliseconds(1.1, Duration.Second)).toThrow(
'"count" must be a non-negative integer. Received: "1.1".',
);

expect(() => inMilliseconds(-1, Duration.Second)).toThrow(
'"count" must be a non-negative integer. Received: "-1".',
);
});

it('counts durations correctly', () => {
// A count that won't overflow for any Duration value.
const getRandomCount = () => Math.floor(Math.random() * 1000);

Object.values(Duration).forEach((duration) => {
const count = getRandomCount();
expect(inMilliseconds(count, duration as Duration)).toBe(
count * (duration as Duration),
);
});
});
});

describe('timeSince', () => {
it('throws if the number is negative or a float', () => {
expect(() => timeSince(1.1)).toThrow(
'"timestamp" must be a non-negative integer. Received: "1.1".',
);

expect(() => timeSince(-1)).toThrow(
'"timestamp" must be a non-negative integer. Received: "-1".',
);
});

it('computes the elapsed time', () => {
const currentTime = 10;
jest.spyOn(Date, 'now').mockImplementation(() => currentTime);
// Set the "current time" to "10".
jest.spyOn(Date, 'now').mockImplementation(() => 10);

[
[10, 0],
Expand Down
71 changes: 55 additions & 16 deletions src/time.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,65 @@
/**
* A millisecond.
* Common duration constants, in milliseconds.
*/
export const MILLISECOND = 1;
export enum Duration {
/**
* A millisecond.
*/
Millisecond = 1,

/**
* A second, in milliseconds.
*/
export const SECOND = 1000; // MILLISECOND * 1000
/**
* A second, in milliseconds.
*/
Second = 1000, // Millisecond * 1000

/**
* A minute, in milliseconds.
*/
export const MINUTE = 60_000; // SECOND * 60
/**
* A minute, in milliseconds.
*/
Minute = 60_000, // Second * 60

/**
* An hour, in milliseconds.
*/
export const HOUR = 3_600_000; // MINUTE * 60
/**
* An hour, in milliseconds.
*/
Hour = 3_600_000, // Minute * 60

/**
* A day, in milliseconds.
*/
Day = 86_400_000, // Hour * 24

/**
* A week, in milliseconds.
*/
Week = 604_800_000, // Day * 7

/**
* A year, in milliseconds.
*/
Year = 31_536_000_000, // Day * 365
}

const isNonNegativeInteger = (number: number) =>
Number.isInteger(number) && number >= 0;

const assertIsNonNegativeInteger = (number: number, name: string) => {
if (!isNonNegativeInteger(number)) {
throw new Error(
`"${name}" must be a non-negative integer. Received: "${number}".`,
);
}
};

/**
* A day, in milliseconds.
* Calculates the millisecond value of the specified number of units of time.
*
* @param count - The number of units of time.
* @param duration - The unit of time to count.
* @returns The count multiplied by the specified duration.
*/
export const DAY = 86_400_000; // HOUR * 24
export function inMilliseconds(count: number, duration: Duration): number {
assertIsNonNegativeInteger(count, 'count');
return count * duration;
}

/**
* Gets the milliseconds since a particular Unix epoch timestamp.
Expand All @@ -30,5 +68,6 @@ export const DAY = 86_400_000; // HOUR * 24
* @returns The number of milliseconds elapsed since the specified timestamp.
*/
export function timeSince(timestamp: number): number {
assertIsNonNegativeInteger(timestamp, 'timestamp');
return Date.now() - timestamp;
}

0 comments on commit 9e631c1

Please sign in to comment.