diffBy
Returns the difference between two dates by a specified unit.
1/**
2 * Returns the difference between two dates by a specified unit.
3 *
4 * @param date1 - The first date.
5 * @param date2 - The second date.
6 * @param unit - The unit to compare by ('year', 'month', 'week', etc).
7 * @returns The signed difference in the specified unit.
8 */
9export function diffBy(
10 date1: Date,
11 date2: Date,
12 unit: 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond'
13): number {
14 const ms1 = date1.getTime();
15 const ms2 = date2.getTime();
16 const diffMs = ms2 - ms1;
17
18 switch (unit) {
19 case 'millisecond':
20 return diffMs;
21 case 'second':
22 return diffMs / 1000;
23 case 'minute':
24 return diffMs / (1000 * 60);
25 case 'hour':
26 return diffMs / (1000 * 60 * 60);
27 case 'day':
28 return diffMs / (1000 * 60 * 60 * 24);
29 case 'week':
30 return diffMs / (1000 * 60 * 60 * 24 * 7);
31 case 'month':
32 return (
33 (date2.getFullYear() - date1.getFullYear()) * 12 +
34 (date2.getMonth() - date1.getMonth())
35 );
36 case 'year':
37 return date2.getFullYear() - date1.getFullYear();
38 default:
39 throw new Error(`Unsupported unit: ${unit}`);
40 }
41}
Multi-Unit Flexibility
Supports a wide range of time units (from milliseconds to years), allowing for versatile date comparisons in various contexts.
Signed Result
Returns a signed difference, making it easy to determine directionality (past vs. future).
Efficient and Direct
Uses minimal computation for high performance, especially with simple arithmetic on timestamps.
Readable and Maintainable
The clear switch-case structure makes the code easy to read and extend if new units are added.
Granular Control
Offers developers precise control over the level of time comparison they need without additional logic.
Tests | Examples
1test('diffBy - year difference', () => {
2 expect(diffBy(new Date('2020-01-01'), new Date('2023-01-01'), 'year')).toBe(3);
3 expect(diffBy(new Date('2023-01-01'), new Date('2020-01-01'), 'year')).toBe(-3);
4});
5
6test('diffBy - month difference', () => {
7 expect(diffBy(new Date('2022-01-01'), new Date('2022-04-01'), 'month')).toBe(3);
8 expect(diffBy(new Date('2022-04-01'), new Date('2022-01-01'), 'month')).toBe(-3);
9});
10
11test('diffBy - week difference', () => {
12 expect(diffBy(new Date('2023-06-01'), new Date('2023-06-15'), 'week'))
13 .toBeCloseTo(2);
14 expect(diffBy(new Date('2023-06-01'), new Date('2023-06-18'), 'week'))
15 .toBeCloseTo(2.4285, 4);
16 expect(diffBy(new Date('2023-06-18'), new Date('2023-06-01'), 'week'))
17 .toBeCloseTo(-2.4285, 4);
18});
19
20test('diffBy - day difference', () => {
21 expect(diffBy(new Date('2023-06-01'), new Date('2023-06-05'), 'day')).toBe(4);
22});
23
24test('diffBy - hour difference', () => {
25 expect(diffBy(
26 new Date('2023-06-01T00:00:00'),
27 new Date('2023-06-01T03:00:00'),
28 'hour'
29 )).toBe(3);
30});
31
32test('diffBy - minute difference', () => {
33 expect(diffBy(
34 new Date('2023-06-01T00:00:00'),
35 new Date('2023-06-01T00:45:00'),
36 'minute'
37 )).toBe(45);
38});
39
40test('diffBy - second difference', () => {
41 expect(diffBy(
42 new Date('2023-06-01T00:00:00'),
43 new Date('2023-06-01T00:00:05'),
44 'second'
45 )).toBe(5);
46});
47
48test('diffBy - millisecond difference', () => {
49 expect(diffBy(
50 new Date('2023-06-01T00:00:00.000'),
51 new Date('2023-06-01T00:00:00.250'),
52 'millisecond'
53 )).toBe(250);
54});
Common Use Cases
Countdowns and Timers
Calculate time remaining or elapsed in seconds, minutes, or hours.
Activity or Session Tracking
Determine time differences for user sessions, idle time, or last login durations.
Analytics and Reporting
Compute date differences for aggregating data by week, month, or year.
UI Display Logic
Show "x days ago" or "3 months remaining" labels in user interfaces.
Validation and Business Rules
Enforce policies like “must be 18 years old” or “within 30 days of purchase.”