Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add humanTimeDiff to @wordpress/date #41598

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/date/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

### New Feature
- Add `humanTimeDiff` function to get the difference between two timestamps in a human-readable format.

## 4.10.0 (2022-06-01)

## 4.9.0 (2022-05-18)
Expand Down
14 changes: 14 additions & 0 deletions packages/date/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,20 @@ _Returns_

- `string`: Formatted date.

### humanTimeDiff

Returns the difference between two timestamps in a human-readable format.

_Parameters_

- _from_ `Moment | Date | string | undefined`: The timestamp to measure from. Defaults to the current time if undefined or invalid.
- _to_ `Moment | Date | string | undefined`: The timestamp to measure to. Defaults to the current time if undefined or invalid.
- _includeAffix_ `boolean`: Whether to include the "ago" or "to" affix in the comparison.

_Returns_

- `string`: The difference between the timestamps.

### isInTheFuture

Check whether a date is considered in the future according to the WordPress settings.
Expand Down
15 changes: 15 additions & 0 deletions packages/date/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,21 @@ export function getDate( dateString ) {
return momentLib.tz( dateString, WP_ZONE ).toDate();
}

/**
* Returns the difference between two timestamps in a human-readable format.
*
* @param {Moment | Date | string | undefined} from The timestamp to measure from. Defaults to the current time if undefined or invalid.
* @param {Moment | Date | string | undefined} to The timestamp to measure to. Defaults to the current time if undefined or invalid.
* @param {boolean} includeAffix Whether to include the "ago" or "to" affix in the comparison.
* @return {string} The difference between the timestamps.
*/
export function humanTimeDiff( from, to, includeAffix ) {
// Normalize inputs to a moment object, defaults to current time.
from = momentLib( from );
to = momentLib( to );
return from.from( to, ! includeAffix );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth it, in order to avoid mutations and help readability, to define to and from as new constants with a distinct name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review. I agree!

I chose momentTo and momentFrom, do you have any better suggestions?

}

/**
* Creates a moment instance using the given timezone or, if none is provided, using global settings.
*
Expand Down
228 changes: 228 additions & 0 deletions packages/date/src/test/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* External dependencies
*/
import momentLib from 'moment';

/**
* Internal dependencies
*/
Expand All @@ -8,6 +13,7 @@ import {
getDate,
gmdate,
gmdateI18n,
humanTimeDiff,
isInTheFuture,
setSettings,
} from '../';
Expand Down Expand Up @@ -590,6 +596,228 @@ describe( 'Function gmdateI18n', () => {
} );
} );

describe( 'Function humanTimeDiff', () => {
it( 'should show a human readable string showing the difference between two timestamps', () => {
// Set a date one second in the past and check it works between then and now.
expect(
humanTimeDiff( new Date( Number( getDate() ) - 1000 ) )
).toEqual( 'a few seconds' );

// Set a date two seconds in the past and check it works between then and now.
expect(
humanTimeDiff( new Date( Number( getDate() ) - 1000 * 2 ) )
).toEqual( 'a few seconds' );

// Check it works when two timestamps are supplied.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 2 ),
new Date( Number( getDate() ) - 1000 * 3 )
)
).toEqual( 'a few seconds' );
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 2 ),
new Date( Number( getDate() ) - 1000 * 61 )
)
).toEqual( 'a minute' );

// Set a date one minute in the past and check it works between then and now.
expect(
humanTimeDiff( new Date( Number( getDate() ) - 1000 * 60 ) )
).toEqual( 'a minute' );

// Set a date two minutes in the past and check it works between then and now.
expect(
humanTimeDiff( new Date( Number( getDate() ) - 1000 * 120 ) )
).toEqual( '2 minutes' );

// Check it works when two timestamps are supplied.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 ),
new Date( Number( getDate() ) - 1000 * 120 )
)
).toEqual( 'a minute' );
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 2 ),
new Date( Number( getDate() ) - 1000 * 60 * 44 )
)
).toEqual( '42 minutes' );

// Set a date one hour in the past and check it works between then and now.
expect(
humanTimeDiff( new Date( Number( getDate() ) - 1000 * 60 * 60 ) )
).toEqual( 'an hour' );

// Set a date two hours in the past and check it works between then and now.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 2 )
)
).toEqual( '2 hours' );

// Check it works when two timestamps are supplied.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 ),
new Date( Number( getDate() ) - 1000 * 60 * 60 * 2 )
)
).toEqual( 'an hour' );
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 2 ),
new Date( Number( getDate() ) - 1000 * 60 * 60 * 7 )
)
).toEqual( '5 hours' );

// Set a date one day in the past and check it works between then and now.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 )
)
).toEqual( 'a day' );

// Set a date two hours in the past and check it works between then and now.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 2 )
)
).toEqual( '2 days' );

// Check it works when two timestamps are supplied.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 2 ),
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 3 )
)
).toEqual( 'a day' );
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 2 ),
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 8 )
)
).toEqual( '6 days' );

// Set a date one month in the past and check it works between then and now.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 30 )
)
).toEqual( 'a month' );

// Set a date two months in the past and check it works between then and now.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 60 )
)
).toEqual( '2 months' );

// Check it works when two timestamps are supplied.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 60 ),
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 90 )
)
).toEqual( 'a month' );
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 30 * 2 ),
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 30 * 9 )
)
).toEqual( '7 months' );

// Set a date one year in the past and check it works between then and now.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 365 )
)
).toEqual( 'a year' );

// Set a date one year in the future and check it works between then and now.
expect(
humanTimeDiff(
new Date( Number( getDate() ) + 1000 * 60 * 60 * 24 * 365 )
)
).toEqual( 'a year' );

// Set a date two months in the past and check it works between then and now.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 365 * 2 )
)
).toEqual( '2 years' );

// Check it works when two timestamps are supplied.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 365 ),
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 365 * 2 )
)
).toEqual( 'a year' );
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 365 ),
new Date( Number( getDate() ) - 1000 * 60 * 60 * 24 * 365 * 12 )
)
).toEqual( '11 years' );
} );

it( 'should include the suffix if includeAffix is true', () => {
// Set a date one second in the past and check it works between then and now.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 ),
new Date( Number( getDate() ) - 1000 ),
true
)
).toEqual( 'a few seconds ago' );

expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 44 ),
new Date( Number( getDate() ) - 1000 * 60 * 2 ),
true
)
).toEqual( '42 minutes ago' );

expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 * 60 * 2 ),
new Date( Number( getDate() ) - 1000 * 60 * 44 ),
true
)
).toEqual( 'in 42 minutes' );
} );
it( 'should ignore the timezone if both dates are in the same timezone', () => {
const settings = __experimentalGetSettings();

// Set a timezone in the past.
setSettings( {
...settings,
timezone: { offset: '-4', string: 'America/New_York' },
} );
// Set a date one second in the past and check it works between then and now.
expect(
humanTimeDiff(
new Date( Number( getDate() ) - 1000 ),
new Date( Number( getDate() ) - 2000 )
)
).toEqual( 'a few seconds' );
} );

it( 'should compare across two different timezones', () => {
// Set a date in UTC and another in America/New_York (4 hours in the past) and check it works between the different timestamps.
expect(
humanTimeDiff(
momentLib.tz( '2022-06-07T22:31:18', 'America/New_York' ),
momentLib.tz( '2022-06-07T22:31:18', 'Etc/UTC' )
)
).toEqual( '4 hours' );
} );
} );

describe( 'Moment.js Localization', () => {
it( 'should change the relative time strings', () => {
const settings = __experimentalGetSettings();
Expand Down