relativeTime outputs day value but month as unit (eg. 28d -> 28mo)
- Dominant language
- JavaScript
- Stars
- 48.7k
- Forks
- 2.5k
- PR merge metrics
- No merged PRs in 30d
Description
**Describe the bug**
We're customizing `relativeTime` from fromNow/toNow in a dayjs service we're using site-wide.
If we _don't_ override the relativeTime config, the relativeTime outputs are correct but with more verbose output than desired.
The issue we're seeing is that once a date crosses the month threshold, it's outputting months as the unit but still outputting the day value as opposed to the month value. In a separate use case, it's outputting years as the unit while outputting the month value, eg. 15y as opposed to 15mo. Here are some example inputs / outputs:
**Input / Output:**
```ts
{createdAt: '2025-10-29T20:01:41.002Z', createdAgo: '6d'}
{createdAt: '2025-10-30T16:41:50.258Z', createdAgo: '5d'}
{createdAt: '2025-10-29T20:01:41.002Z', createdAgo: '6d'}
{createdAt: '2025-10-23T22:13:14.470Z', createdAgo: '12d'}
{createdAt: '2025-10-22T19:56:02.664Z', createdAgo: '13d'}
{createdAt: '2025-10-21T22:55:42.414Z', createdAgo: '14d'}
{createdAt: '2025-10-21T18:00:05.745Z', createdAgo: '14d'}
{createdAt: '2025-10-10T21:07:17.747Z', createdAgo: '25d'}
{createdAt: '2025-10-10T19:22:07.387Z', createdAgo: '25d'}
{createdAt: '2025-10-07T20:55:07.274Z', createdAgo: '28mo'}
{createdAt: '2025-10-07T20:52:15.052Z', createdAgo: '28mo'}
{createdAt: '2025-10-07T20:14:19.170Z', createdAgo: '28mo'}
{createdAt: '2025-10-07T20:11:37.432Z', createdAgo: '28mo'}
{createdAt: '2025-10-07T20:09:50.188Z', createdAgo: '28mo'}
{createdAt: '2025-10-07T20:05:29.522Z', createdAgo: '28mo'}
{createdAt: '2025-10-07T20:02:37.296Z', createdAgo: '28mo'}
{createdAt: '2025-10-07T17:18:36.854Z', createdAgo: '28mo'}
{createdAt: '2025-10-07T17:00:28.519Z', createdAgo: '28mo'}
{createdAt: '2025-10-07T16:57:51.514Z', createdAgo: '28mo'}
{createdAt: '2025-10-07T16:39:52.905Z', createdAgo: '28mo'}
{createdAt: '2025-10-03T19:50:11.902Z', createdAgo: '32mo'}
{createdAt: '2025-10-03T19:43:51.780Z', createdAgo: '32mo'}
{createdAt: '2025-10-03T16:50:07.937Z', createdAgo: '32mo'}
{createdAt: '2025-10-02T20:03:07.614Z', createdAgo: '33mo'}
{createdAt: '2025-10-02T19:41:41.399Z', createdAgo: '33mo'}
```
**dayjs config:**
```ts
import dayjs from "dayjs"
import relativeTime from "dayjs/plugin/relativeTime"
import updateLocale from "dayjs/plugin/updateLocale"
import utc from "dayjs/plugin/utc"
import "dayjs/locale/en"
dayjs.extend(relativeTime)
dayjs.extend(updateLocale)
dayjs.extend(utc)
dayjs.updateLocale("en", {
relativeTime: {
...dayjs.Ls.en.relativeTime,
future: "in %s",
past: "%s ago",
s: "%d s",
m: "%d m",
mm: "%d m",
h: "%d h",
hh: "%d h",
d: "%d d",
dd: "%d d",
M: "%d mo",
MM: "%d mo",
y: "%d y",
yy: "%d y",
},
})
export { dayjs }
```
```ts
interface GetRelativeTimeProps {
relativeTo?: "past" | "future"
useSuffix?: boolean
addSpace?: boolean
}
/**
* Utility used to format relative datetime to now.
* Falsy `time` values will return null.
*/
export function getRelativeTime(
time: dayjs.Dayjs | string | number | null | undefined,
{
relativeTo = "past",
useSuffix = false,
addSpace = false,
}: GetRelativeTimeProps = {
relativeTo: "past",
useSuffix: false,
addSpace: false,
},
) {
if (!time) {
return null
}
try {
const date = dayjs(time).utc()
const formattedDate =
relativeTo === "past" ? date.fromNow(!useSuffix) : date.toNow(!useSuffix)
return addSpace ? formattedDate : formattedDate.replace(" ", "")
} catch {
return null
}
}
```
**Expected behavior**
If the # of days exceeds the 1 month threshold, the output should be `1mo` (or 28 days), not `28mo`
**Information**
- Day.js Version 1.11.19
- OS: MacOS
- Browser Version 141.0.7390.77 (Official Build) (arm64)
- Time zone: Vancouver / Pacific Time
Contributor guide
Assessment
This issue has not been assessed yet.