diff --git a/src/components/generics/Timing.jsx b/src/components/generics/Timing.jsx
new file mode 100644
index 00000000..269d6d0a
--- /dev/null
+++ b/src/components/generics/Timing.jsx
@@ -0,0 +1,80 @@
+import PropTypes from 'prop-types'
+
+import {
+ formatDuration,
+ formatTime,
+ formatDateTime,
+ formatTimeRelative,
+} from 'utils'
+
+export function Duration({ duration }) {
+ const [iso, hhmm, ss] = formatDuration(duration)
+
+ return (
+
+ {hhmm}
+ {ss}
+
+ )
+}
+
+Duration.propTypes = {
+ duration: PropTypes.string.isRequired,
+}
+
+export function Time({ iso }) {
+ const date = formatTime(iso)
+
+ return (
+
+ {date}
+
+ )
+}
+
+Time.propTypes = {
+ iso: PropTypes.string.isRequired,
+}
+
+export function DateTime({ iso, showSeconds = false }) {
+ const [date, ss] = formatDateTime(iso, showSeconds)
+
+ return (
+
+ {date}
+ {showSeconds && {ss} }
+
+ )
+}
+
+DateTime.propTypes = {
+ iso: PropTypes.string.isRequired,
+ showSeconds: PropTypes.bool,
+}
+
+export function TimeRelative({
+ iso,
+ relativeToIso,
+ withoutSuffix = false,
+ withoutTimeTruncate = false,
+}) {
+ const date = formatTimeRelative(
+ iso,
+ relativeToIso,
+ withoutSuffix,
+ withoutTimeTruncate
+ )
+
+ return (
+
+ {date}
+
+ )
+}
+
+TimeRelative.propTypes = {
+ iso: PropTypes.string.isRequired,
+ relativeToIso: PropTypes.string,
+ withoutSuffix: PropTypes.bool,
+ withoutTimeTruncate: PropTypes.bool,
+}
diff --git a/src/components/karaoke/player/Carousel.jsx b/src/components/karaoke/player/Carousel.jsx
index ab45711e..e0f3f4d6 100644
--- a/src/components/karaoke/player/Carousel.jsx
+++ b/src/components/karaoke/player/Carousel.jsx
@@ -1,14 +1,11 @@
import dayjs from 'dayjs'
-import relativeTime from 'dayjs/plugin/relativeTime'
import queryString from 'query-string'
import { useSelector } from 'react-redux'
import { Link } from 'react-router'
import { CarouselEntry } from 'components/generics/Carousel'
+import { Duration, Time, TimeRelative } from 'components/generics/Timing'
import PlaylistEntryWidget from 'components/playlist/widgets/PlaylistEntry'
-import { formatDate, formatDuration } from 'utils'
-
-dayjs.extend(relativeTime)
export function CarouselEntryCurrentSong() {
const { data: playerStatus } = useSelector(
@@ -39,9 +36,13 @@ export function CarouselEntryCurrentSong() {
truncatable
/>
-
-
{formatDuration(timing)}
-
{formatDuration(entry.song.duration)}
+
)
@@ -77,9 +78,11 @@ export function CarouselEntryNextSong() {
}
export function CarouselEntryStats() {
- const { queuingEntries, playedEntries, dateEnd } = useSelector(
- (state) => state.playlist.digest.entries.data
- )
+ const {
+ queuingEntries,
+ playedEntries,
+ dateEnd: playlistDateEnd,
+ } = useSelector((state) => state.playlist.digest.entries.data)
const { data: playerStatus } = useSelector(
(state) => state.playlist.playerStatus
)
@@ -136,57 +139,86 @@ export function CarouselEntryStats() {
* well together. At least, the code is easy to understand.
*/
- const playlistEndDate =
- dateEnd && (countQueuingEntries || playerStatus.playlist_entry)
- ? dayjs(dateEnd)
- : null
- const karaokeEndDate = karaokeDateStop ? dayjs(karaokeDateStop) : null
+ const karaokeHasDateStop = !!karaokeDateStop
+
+ // the playlist has a date end if a date end is calculated and either there
+ // are songs queuing or there is one song playing
+ const playlistHasDateEnd =
+ playlistDateEnd && (countQueuingEntries || playerStatus.playlist_entry)
let end
// only playlist date end
- if (playlistEndDate && !karaokeEndDate) {
+ if (playlistHasDateEnd && !karaokeHasDateStop) {
end = (
- Playlist ends at {formatDate(playlistEndDate)}
+ Playlist ends at{' '}
+
+
+
)
- // only karaoke date end
- } else if (!playlistEndDate && karaokeEndDate) {
- if (karaokeEndDate.isAfter()) {
+ // only karaoke date stop
+ } else if (!playlistHasDateEnd && karaokeHasDateStop) {
+ // if the the karaoke date stop is not passed
+ if (dayjs().isBefore(karaokeDateStop)) {
end = (
<>
- Karaoke ends at {formatDate(karaokeEndDate)}
+ Karaoke ends at{' '}
+
+
+
- {dayjs().to(karaokeEndDate, true)} remaining
+
+
+ {' '}
+ remaining
>
)
+ // otherwise the karaoke is finished
} else {
end =
Karaoke ended
}
- // both playlist date end and karaoke date end
- } else if (playlistEndDate && karaokeEndDate) {
- // karaoke date end is after playlist date end
- if (karaokeEndDate.isAfter(playlistEndDate)) {
+ // both playlist date end and karaoke date stop
+ } else if (playlistHasDateEnd && karaokeHasDateStop) {
+ // karaoke date stop is after playlist date end
+ if (dayjs(playlistDateEnd).isBefore(karaokeDateStop)) {
end = (
<>
- Karaoke ends at {formatDate(karaokeEndDate)}
+ Karaoke ends at{' '}
+
+
+
- {dayjs().to(karaokeEndDate, true)} remaining
+
+
+ {' '}
+ remaining in playlist
>
)
- // playlist date end is after karaoke date end
+ // playlist date end is after karaoke date stop
} else {
end = (
<>
Playlist should end after karaoke at{' '}
- {formatDate(playlistEndDate)}
+
+
+
Playlist exceeds karaoke scheduled end!
>
diff --git a/src/components/library/status/InPlaylist.jsx b/src/components/library/status/InPlaylist.jsx
index 3a8718af..9fbb39e5 100644
--- a/src/components/library/status/InPlaylist.jsx
+++ b/src/components/library/status/InPlaylist.jsx
@@ -6,7 +6,8 @@ import { Link } from 'react-router'
import UserWidget from 'components/user/widgets/User'
import { playlistEntryPropType } from 'serverPropTypes/playlist'
-import { formatDate, formatDateRelative, getMostPertinentEntry } from 'utils'
+import { getMostPertinentEntry } from 'utils'
+import { Time, TimeRelative } from 'components/generics/Timing'
function Playing({ entry }) {
const playerStatus = useSelector((state) => state.playlist.playerStatus.data)
@@ -35,7 +36,7 @@ function Queuing({ entry }) {
-
{formatDate(entry.date_play)}
+
)
}
@@ -50,7 +51,7 @@ function Played({ entry }) {
- {formatDate(entry.date_play)}
+
)
}
@@ -114,7 +115,7 @@ export default function InPlaylist({
>
will play
{' '}
- {formatDateRelative(entry.date_play)}
+
)
}
@@ -137,7 +138,7 @@ export default function InPlaylist({
>
played
{' '}
- {formatDateRelative(entry.date_play)}
+
)
}
diff --git a/src/components/library/widgets/Song.jsx b/src/components/library/widgets/Song.jsx
index 96877bb8..4d33dddf 100644
--- a/src/components/library/widgets/Song.jsx
+++ b/src/components/library/widgets/Song.jsx
@@ -6,7 +6,8 @@ import SongTagList from 'components/library/SongTagList'
import ArtistWidget from 'components/library/widgets/Artist'
import WorkLinkWidget from 'components/library/widgets/WorkLink'
import { songPropType } from 'serverPropTypes/library'
-import { formatDuration, isDisplayable } from 'utils'
+import { isDisplayable } from 'utils'
+import { Duration } from 'components/generics/Timing'
export default function SongWidget({
song,
@@ -69,7 +70,7 @@ export default function SongWidget({
// song duration
let duration
if (!noDuration) {
- duration = {formatDuration(song.duration)}
+ duration =
}
// song tags
diff --git a/src/components/playlist/played/Entry.jsx b/src/components/playlist/played/Entry.jsx
index 737e3025..c7b5d449 100644
--- a/src/components/playlist/played/Entry.jsx
+++ b/src/components/playlist/played/Entry.jsx
@@ -10,7 +10,7 @@ import {
import HasError from 'components/playlist/status/HasError'
import PlaylistEntryWidget from 'components/playlist/widgets/PlaylistEntry'
import { playlistEntryPropType } from 'serverPropTypes/playlist'
-import { formatDateLong } from 'utils'
+import { DateTime } from 'components/generics/Timing'
export default function PlayedEntry({ entry, ...rest }) {
const query = useSelector((state) => state.playlist.played.data.query)
@@ -65,10 +65,10 @@ export default function PlayedEntry({ entry, ...rest }) {
)}
- {formatDateLong(entry.date_created)}
+
- {formatDateLong(entry.date_play)}
+
diff --git a/src/components/playlist/playerErrors/Entry.jsx b/src/components/playlist/playerErrors/Entry.jsx
index 2ff9873b..5c2a6587 100644
--- a/src/components/playlist/playerErrors/Entry.jsx
+++ b/src/components/playlist/playerErrors/Entry.jsx
@@ -14,7 +14,7 @@ import {
} from 'components/generics/listing/Entry'
import PlaylistEntryWidget from 'components/playlist/widgets/PlaylistEntry'
import { playerErrorPropType } from 'serverPropTypes/playlist'
-import { formatDateLong } from 'utils'
+import { DateTime } from 'components/generics/Timing'
export default function PlayerErrorsEntry({ playerError, ...rest }) {
const query = useSelector((state) => state.playlist.playerErrors.data.query)
@@ -69,7 +69,7 @@ export default function PlayerErrorsEntry({ playerError, ...rest }) {
- {formatDateLong(date, /* seconds = */ true)}
+
)}
- {formatDateLong(entry.date_created)}
+
{queuingEntryDigest && (
- {formatDateLong(queuingEntryDigest.date_play)}
+
)}
diff --git a/src/components/playlist/widgets/PlaylistEntry.jsx b/src/components/playlist/widgets/PlaylistEntry.jsx
index 930cea34..7c4e180a 100644
--- a/src/components/playlist/widgets/PlaylistEntry.jsx
+++ b/src/components/playlist/widgets/PlaylistEntry.jsx
@@ -4,7 +4,7 @@ import { useSelector } from 'react-redux'
import SongWidget from 'components/library/widgets/Song'
import UserWidget from 'components/user/widgets/User'
-import { formatDateRelative } from 'utils'
+import { TimeRelative } from 'components/generics/Timing'
export default function PlaylistEntryWidget({
entry,
@@ -46,11 +46,7 @@ export default function PlaylistEntryWidget({
- {playlistEntry && (
-
- {formatDateRelative(playlistEntry.date_play)}
-
- )}
+ {playlistEntry && }
)
}
diff --git a/src/style/components/generics/_index.scss b/src/style/components/generics/_index.scss
index 0c783967..db42f219 100644
--- a/src/style/components/generics/_index.scss
+++ b/src/style/components/generics/_index.scss
@@ -14,4 +14,5 @@
@use 'searchbox';
@use 'shapes';
@use 'tab_bar';
+@use 'timing';
@use 'token_widget';
diff --git a/src/style/components/generics/_timing.scss b/src/style/components/generics/_timing.scss
new file mode 100644
index 00000000..ec9e676b
--- /dev/null
+++ b/src/style/components/generics/_timing.scss
@@ -0,0 +1,5 @@
+.timing {
+ .seconds {
+ font-size: 0.8em;
+ }
+}
diff --git a/src/style/components/karaoke/player/_player.scss b/src/style/components/karaoke/player/_player.scss
index c3ddfff2..7306f220 100644
--- a/src/style/components/karaoke/player/_player.scss
+++ b/src/style/components/karaoke/player/_player.scss
@@ -16,7 +16,7 @@
// player sizes
$player-controls-height: 6rem;
$player-controls-height-smartphone: sizes.$row-height;
-$player-timing-height: 5.5rem;
+$player-timer-height: 5.5rem;
$player-progressbar-height: 0.4rem;
// `player` id:
@@ -254,8 +254,8 @@ $player-progressbar-height: 0.4rem;
display: flex;
overflow: hidden;
- .timing {
- // shrink the timing class element first when resizing, up to
+ .timer {
+ // shrink the timer class element first when resizing, up to
// the width of the duration (4 digits plus one colon)
font-feature-settings: 'tnum';
margin-left: auto;
@@ -263,26 +263,26 @@ $player-progressbar-height: 0.4rem;
overflow: hidden;
text-align: right;
- @mixin make-timing($factor) {
- font-size: $player-timing-height * $factor;
- line-height: $player-timing-height * $factor;
+ @mixin make-timer($factor) {
+ font-size: $player-timer-height * $factor;
+ line-height: $player-timer-height * $factor;
@include support.make-smartphone {
- font-size: $player-timing-height * $factor * 0.7;
- line-height: $player-timing-height * $factor * 0.7;
+ font-size: $player-timer-height * $factor * 0.7;
+ line-height: $player-timer-height * $factor * 0.7;
}
}
- .current {
+ > .current {
font-weight: 200;
- @include make-timing(0.7);
+ @include make-timer(0.7);
}
- .duration {
+ > .duration {
letter-spacing: 0.25rem;
- @include make-timing(0.3);
+ @include make-timer(0.3);
}
}
}
diff --git a/src/style/components/library/status/_in_playlist.scss b/src/style/components/library/status/_in_playlist.scss
index 74843af9..497ddc3c 100644
--- a/src/style/components/library/status/_in_playlist.scss
+++ b/src/style/components/library/status/_in_playlist.scss
@@ -25,7 +25,7 @@
font-size: 1em;
}
- .date {
+ .time {
font-size: x-small;
text-align: center;
white-space: nowrap;
diff --git a/src/utils/index.js b/src/utils/index.js
index da183678..ad4bc7cb 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -32,7 +32,8 @@ export function updateData(newData, resultsKey) {
* Will format a duration less than one hour as `m:ss`, and more than one hour
* as `h:mm:ss`.
* @param seconds Duration in seconds.
- * @returns Formatted duration.
+ * @returns Array of 3 elements: the ISO duration representation, the hours (if
+ * any) and minutes, and the seconds.
*/
export function formatDuration(seconds) {
const duration = dayjs.duration(seconds, 'seconds')
@@ -40,27 +41,35 @@ export function formatDuration(seconds) {
// for very long durations exceeding one day, express it in hours
if (duration.days() > 0) {
const hours = duration.asHours().toFixed()
- return duration.format(`${hours}:mm:ss`)
+ return [
+ duration.toISOString(),
+ duration.format(`${hours}:mm`),
+ duration.format(':ss'),
+ ]
}
// display hours only if needed
if (duration.hours() > 0) {
- return duration.format('H:mm:ss')
+ return [
+ duration.toISOString(),
+ duration.format('H:mm'),
+ duration.format(':ss'),
+ ]
}
// default to minutes and seconds
- return duration.format('m:ss')
+ return [duration.toISOString(), duration.format('m'), duration.format(':ss')]
}
/**
- * Smart formatting for a date.
+ * Smart formatting for a date and a time.
* Formats a date before 6 hours or after 12 hours in long form (date + time),
* otherwise in short form (time only).
* @param dateIso Date as a string in ISO format.
- * @param seconds If true, also display seconds.
+ * @param showSeconds If true, also display seconds.
* @returns Formatted date.
*/
-export function formatDateLong(dateIso, seconds) {
+export function formatDateTime(dateIso, showSeconds) {
const date = dayjs(dateIso)
const now = dayjs()
@@ -69,27 +78,30 @@ export function formatDateLong(dateIso, seconds) {
date.isBefore(now.subtract(6, 'hour')) ||
date.isAfter(now.add(12, 'hour'))
) {
- if (seconds) {
- return date.format('YYYY-MM-DD HH:mm:ss')
+ const format = date.format('YYYY-MM-DD HH:mm')
+ if (showSeconds) {
+ return [format, date.format(':ss')]
}
- return date.format('YYYY-MM-DD HH:mm')
+
+ return [format, null]
}
// short format otherwise
- if (seconds) {
- return date.format('HH:mm:ss')
+ const format = date.format('HH:mm')
+ if (showSeconds) {
+ return [format, date.format(':ss')]
}
- return date.format('HH:mm')
+ return [format, null]
}
/**
- * Smart formatting for a date.
+ * Smart formatting for a time.
* Formats a date before 6 hours or after 12 hours as "long ago" or "not soon",
* otherwise in short form.
* @param dateIso Date as a string in ISO format.
* @returns Formatted date.
*/
-export function formatDate(dateIso) {
+export function formatTime(dateIso) {
const date = dayjs(dateIso)
const now = dayjs()
@@ -112,25 +124,35 @@ export function formatDate(dateIso) {
* Formats a date before 6 hours or after 12 hours as "long ago" or "not soon",
* otherwise in relative form.
* @param dateIso Date as a string in ISO format.
+ * @param relativeToDateIso Reference date as a string in ISO format.
+ * @param withoutSuffix If true, Dayjs will not display the suffix.
+ * @param withoutTimeTruncate If true, always display date in relative form.
* @returns Formatted date.
*/
-export function formatDateRelative(dateIso) {
+export function formatTimeRelative(
+ dateIso,
+ relativeToDateIso,
+ withoutSuffix,
+ withoutTimeTruncate
+) {
const date = dayjs(dateIso)
- const now = dayjs()
+ const now = dayjs(relativeToDateIso)
- // long ago if date is before one day
- if (date.isBefore(now.subtract(6, 'hour'))) {
- return 'long ago'
- }
+ if (!withoutTimeTruncate) {
+ // long ago if date is before one day
+ if (date.isBefore(now.subtract(6, 'hour'))) {
+ return 'long ago'
+ }
- // not soon if date is after one day
- if (date.isAfter(now.add(12, 'hour'))) {
- return 'not soon'
+ // not soon if date is after one day
+ if (date.isAfter(now.add(12, 'hour'))) {
+ return 'not soon'
+ }
}
// add 5 seconds to avoid displaying "will play in a few second ago" when
// the date is within one minute
- return date.add(5, 'second').fromNow()
+ return date.add(5, 'second').from(now, withoutSuffix)
}
/**
diff --git a/src/utils/index.test.js b/src/utils/index.test.js
index 334b9897..9b8baae8 100644
--- a/src/utils/index.test.js
+++ b/src/utils/index.test.js
@@ -2,9 +2,9 @@ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
import {
differentiateEntries,
- formatDate,
- formatDateLong,
- formatDateRelative,
+ formatTime,
+ formatDateTime,
+ formatTimeRelative,
formatDuration,
getEntriesHash,
getMostPertinentEntry,
@@ -13,19 +13,19 @@ import {
describe('format duration', () => {
test('more than one day', () => {
- expect(formatDuration(25 * 3600)).toBe('25:00:00')
+ expect(formatDuration(25 * 3600)).toStrictEqual(['P1DT1H', '25:00', ':00'])
})
test('more than one hour', () => {
- expect(formatDuration(3600 + 20)).toBe('1:00:20')
+ expect(formatDuration(3600 + 20)).toStrictEqual(['PT1H20S', '1:00', ':20'])
})
test('less than one hour', () => {
- expect(formatDuration(2 * 60 + 40)).toBe('2:40')
+ expect(formatDuration(2 * 60 + 40)).toStrictEqual(['PT2M40S', '2', ':40'])
})
test('less than one minute', () => {
- expect(formatDuration(40)).toBe('0:40')
+ expect(formatDuration(40)).toStrictEqual(['PT40S', '0', ':40'])
})
})
@@ -42,20 +42,64 @@ describe('format date long', () => {
})
test('before more than 6 hours', () => {
- expect(formatDateLong('1970-01-03T00:00:00')).toBe('1970-01-03 00:00')
- expect(formatDateLong('1970-01-04T18:29:00')).toBe('1970-01-04 18:29')
+ expect(formatDateTime('1970-01-03T00:00:10')).toStrictEqual([
+ '1970-01-03 00:00',
+ null,
+ ])
+ expect(formatDateTime('1970-01-04T18:29:10')).toStrictEqual([
+ '1970-01-04 18:29',
+ null,
+ ])
+ expect(formatDateTime('1970-01-03T00:00:10', true)).toStrictEqual([
+ '1970-01-03 00:00',
+ ':10',
+ ])
+ expect(formatDateTime('1970-01-04T18:29:10', true)).toStrictEqual([
+ '1970-01-04 18:29',
+ ':10',
+ ])
})
test('after more than 12 hours', () => {
- expect(formatDateLong('1970-01-07T00:00:00')).toBe('1970-01-07 00:00')
- expect(formatDateLong('1970-01-05T12:31:00')).toBe('1970-01-05 12:31')
+ expect(formatDateTime('1970-01-07T00:00:10')).toStrictEqual([
+ '1970-01-07 00:00',
+ null,
+ ])
+ expect(formatDateTime('1970-01-05T12:31:10')).toStrictEqual([
+ '1970-01-05 12:31',
+ null,
+ ])
+ expect(formatDateTime('1970-01-07T00:00:10', true)).toStrictEqual([
+ '1970-01-07 00:00',
+ ':10',
+ ])
+ expect(formatDateTime('1970-01-05T12:31:10', true)).toStrictEqual([
+ '1970-01-05 12:31',
+ ':10',
+ ])
})
test('before less than 6 hours and after less than 12 hours', () => {
- expect(formatDateLong('1970-01-05T00:35:00')).toBe('00:35')
- expect(formatDateLong('1970-01-05T00:25:00')).toBe('00:25')
- expect(formatDateLong('1970-01-04T18:30:00')).toBe('18:30')
- expect(formatDateLong('1970-01-05T12:29:00')).toBe('12:29')
+ expect(formatDateTime('1970-01-05T00:35:10')).toStrictEqual(['00:35', null])
+ expect(formatDateTime('1970-01-05T00:25:10')).toStrictEqual(['00:25', null])
+ expect(formatDateTime('1970-01-04T18:30:10')).toStrictEqual(['18:30', null])
+ expect(formatDateTime('1970-01-05T12:29:10')).toStrictEqual(['12:29', null])
+ expect(formatDateTime('1970-01-05T00:35:10', true)).toStrictEqual([
+ '00:35',
+ ':10',
+ ])
+ expect(formatDateTime('1970-01-05T00:25:10', true)).toStrictEqual([
+ '00:25',
+ ':10',
+ ])
+ expect(formatDateTime('1970-01-04T18:30:10', true)).toStrictEqual([
+ '18:30',
+ ':10',
+ ])
+ expect(formatDateTime('1970-01-05T12:29:10', true)).toStrictEqual([
+ '12:29',
+ ':10',
+ ])
})
})
@@ -72,20 +116,20 @@ describe('format date', () => {
})
test('before more than 6 hours', () => {
- expect(formatDate('1970-01-03T00:00:00')).toBe('long ago')
- expect(formatDate('1970-01-04T18:29:00')).toBe('long ago')
+ expect(formatTime('1970-01-03T00:00:00')).toBe('long ago')
+ expect(formatTime('1970-01-04T18:29:00')).toBe('long ago')
})
test('after more than 12 hours', () => {
- expect(formatDate('1970-01-07T00:00:00')).toBe('not soon')
- expect(formatDate('1970-01-05T12:31:00')).toBe('not soon')
+ expect(formatTime('1970-01-07T00:00:00')).toBe('not soon')
+ expect(formatTime('1970-01-05T12:31:00')).toBe('not soon')
})
test('before less than 6 hours and after less than 12 hours', () => {
- expect(formatDate('1970-01-05T00:35:00')).toBe('00:35')
- expect(formatDate('1970-01-05T00:25:00')).toBe('00:25')
- expect(formatDate('1970-01-04T18:30:00')).toBe('18:30')
- expect(formatDate('1970-01-05T12:29:00')).toBe('12:29')
+ expect(formatTime('1970-01-05T00:35:00')).toBe('00:35')
+ expect(formatTime('1970-01-05T00:25:00')).toBe('00:25')
+ expect(formatTime('1970-01-04T18:30:00')).toBe('18:30')
+ expect(formatTime('1970-01-05T12:29:00')).toBe('12:29')
})
})
@@ -101,23 +145,97 @@ describe('format date relative', () => {
vi.useRealTimers()
})
- test('before more than 6 hours', () => {
- expect(formatDateRelative('1970-01-03T00:00:00')).toBe('long ago')
- expect(formatDateRelative('1970-01-04T18:29:00')).toBe('long ago')
+ describe('default', () => {
+ test('before more than 6 hours', () => {
+ expect(formatTimeRelative('1970-01-03T00:00:00')).toBe('long ago')
+ expect(formatTimeRelative('1970-01-04T18:29:00')).toBe('long ago')
+ })
+
+ test('after more than 12 hours', () => {
+ expect(formatTimeRelative('1970-01-07T00:00:00')).toBe('not soon')
+ expect(formatTimeRelative('1970-01-05T12:31:00')).toBe('not soon')
+ })
+
+ test('before less than 6 hours and after less than 12 hours', () => {
+ expect(formatTimeRelative('1970-01-05T00:35:00')).toBe('in 5 minutes')
+ expect(formatTimeRelative('1970-01-05T00:25:00')).toBe('5 minutes ago')
+ })
+
+ test('after less than 5 seconds', () => {
+ expect(formatTimeRelative('1970-01-05T00:30:00')).toBe('in a few seconds')
+ })
})
- test('after more than 12 hours', () => {
- expect(formatDateRelative('1970-01-07T00:00:00')).toBe('not soon')
- expect(formatDateRelative('1970-01-05T12:31:00')).toBe('not soon')
+ describe('relative to', () => {
+ test('before more than 6 hours', () => {
+ expect(
+ formatTimeRelative('1970-01-03T00:00:00', '1970-01-05T00:30:00')
+ ).toBe('long ago')
+ expect(
+ formatTimeRelative('1970-01-04T18:29:00', '1970-01-05T00:30:00')
+ ).toBe('long ago')
+ })
+
+ test('after more than 12 hours', () => {
+ expect(
+ formatTimeRelative('1970-01-07T00:00:00', '1970-01-05T00:30:00')
+ ).toBe('not soon')
+ expect(
+ formatTimeRelative('1970-01-05T12:31:00', '1970-01-05T00:30:00')
+ ).toBe('not soon')
+ })
+
+ test('before less than 6 hours and after less than 12 hours', () => {
+ expect(
+ formatTimeRelative('1970-01-05T00:35:00', '1970-01-05T00:30:00')
+ ).toBe('in 5 minutes')
+ expect(
+ formatTimeRelative('1970-01-05T00:25:00', '1970-01-05T00:30:00')
+ ).toBe('5 minutes ago')
+ })
+
+ test('after less than 5 seconds', () => {
+ expect(
+ formatTimeRelative('1970-01-05T00:30:00', '1970-01-05T00:30:00')
+ ).toBe('in a few seconds')
+ })
})
- test('before less than 6 hours and after less than 12 hours', () => {
- expect(formatDateRelative('1970-01-05T00:35:00')).toBe('in 5 minutes')
- expect(formatDateRelative('1970-01-05T00:25:00')).toBe('5 minutes ago')
+ describe('without suffix', () => {
+ test('before less than 6 hours and after less than 12 hours', () => {
+ expect(formatTimeRelative('1970-01-05T00:35:00', undefined, true)).toBe(
+ '5 minutes'
+ )
+ expect(formatTimeRelative('1970-01-05T00:25:00', undefined, true)).toBe(
+ '5 minutes'
+ )
+ })
+
+ test('after less than 5 seconds', () => {
+ expect(formatTimeRelative('1970-01-05T00:30:00', undefined, true)).toBe(
+ 'a few seconds'
+ )
+ })
})
- test('after less than 5 seconds', () => {
- expect(formatDateRelative('1970-01-05T00:30:00')).toBe('in a few seconds')
+ describe('without time truncate', () => {
+ test('before more than 6 hours', () => {
+ expect(
+ formatTimeRelative('1970-01-03T00:00:00', undefined, undefined, true)
+ ).toBe('2 days ago')
+ expect(
+ formatTimeRelative('1970-01-04T18:29:00', undefined, undefined, true)
+ ).toBe('6 hours ago')
+ })
+
+ test('after more than 12 hours', () => {
+ expect(
+ formatTimeRelative('1970-01-07T00:00:00', undefined, undefined, true)
+ ).toBe('in 2 days')
+ expect(
+ formatTimeRelative('1970-01-05T12:31:00', undefined, undefined, true)
+ ).toBe('in 12 hours')
+ })
})
})