Given int value 1807
, format to 30:07
using date-fns?
Yes, I know this can be achieved with vanilla js, but is this possible using date-fns?
Given int value 1807
, format to 30:07
using date-fns?
Yes, I know this can be achieved with vanilla js, but is this possible using date-fns?
You can do this using date-fns by simple modifying an intermediate helper date. Using new Date( 0 )
you'll get a date set to January 1, 1970, 00:00:00 UTC. You can then use addSeconds
from date-fns to add the relevant seconds (actually you could use the native date setTime( 1000 * seconds )
for this). Formatting the minutes and seconds of this will give you your desired result.
var input = document.getElementById('seconds');
var output = document.getElementById('out');
output.innerText = formattedTime(input.value);
input.addEventListener('input', function() {
output.innerText = formattedTime(input.value);
});
function formattedTime(seconds) {
var helperDate = dateFns.addSeconds(new Date(0), seconds);
return dateFns.format(helperDate, 'mm:ss');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.26.0/date_fns.min.js"></script>
<input type="number" id="seconds" value="1807">
<pre id="out"></pre>
var helperDate = dateFns.addSeconds(new Date(0), seconds)
that adds your timezone offset to the resulting date, ie if you format the result with hh:mm:ss
- 180
seconds will produce 10:03:00
and 240
seconds will produce 10:04:00
if you are in a +10
timezone offset. –
Mitten HH:mm:ss
you will always see 01:00:00
for Europe/Berlin
with new Date(0)
. I solved it by using date-fns-tz
to set a fixed timezone where I know the offset of (e.g. Europe/Berlin == +1 Hour to GMT
), then I subtract that value with the addHour
function of date-fns
javascript const dateHelper: Date = addSeconds(new Date(0), duration); const utcDate = zonedTimeToUtc(dateHelper, TIME_ZONE); this.durationDisplay = format(addHours(utcDate, -1), 'HH:mm:ss');
–
Linger 30:05
for a duration of 5 seconds. timeanddate.com/time/time-zones-interesting.html –
Soldier According to the example code in date-fns/date-fns#229 (comment), we can now use intervalToDuration
to convert seconds (passed as an Interval
) to a Duration
, which can then simplify formatting as desired by the OP:
import { intervalToDuration } from 'date-fns'
const seconds = 10000
intervalToDuration({ start: 0, end: seconds * 1000 })
// { hours: 2, minutes: 46, seconds: 40 }
So for the OP's needs:
import { intervalToDuration } from 'date-fns'
const seconds = 1807
const duration = intervalToDuration({ start: 0, end: seconds * 1000 })
// { minutes: 30, seconds: 7 }
const formatted = `${duration.minutes}:${duration.seconds}`
// 30:7
Edit (2022-08-04): It was pointed out that the above simplistic code won't 0-pad the numbers, so you will end up with 30:7
rather than 30:07
. This padding can be achieved by using String.prototype.padStart()
as follows:
import { intervalToDuration } from 'date-fns'
const seconds = 1807
const duration = intervalToDuration({ start: 0, end: seconds * 1000 })
// { minutes: 30, seconds: 7 }
const zeroPad = (num) => String(num).padStart(2, '0')
const formatted = `${zeroPad(duration.minutes)}:${zeroPad(duration.seconds)}`
// 30:07
It was also pointed out that if the Interval
goes above 60 minutes it will start incrementing the hours
within the Duration
, which the above code wouldn't display. So here is another slightly more complex example that handles this as well as the zeroPad
case:
import { intervalToDuration } from 'date-fns'
const seconds = 1807
const duration = intervalToDuration({ start: 0, end: seconds * 1000 })
// { minutes: 30, seconds: 7 }
const zeroPad = (num) => String(num).padStart(2, '0')
const formatted = [
duration.hours,
duration.minutes,
duration.seconds,
]
.filter(Boolean)
.map(zeroPad)
.join(':')
// 30:07
There is also an issue on GitHub asking how to use a custom format with formatDuration
, which suggest that currently the only way to do so is by providing a custom Locale
. GitHub user @marselmustafin provided an example using this workaround. Following this same pattern, we could implement the OP's desired functionality roughly as follows:
import { intervalToDuration, formatDuration } from "date-fns";
const seconds = 1807;
const duration = intervalToDuration({ start: 0, end: seconds * 1000 });
// { minutes: 30, seconds: 7 }
const zeroPad = (num) => String(num).padStart(2, "0");
const formatted = formatDuration(duration, {
format: ["minutes", "seconds"],
// format: ["hours", "minutes", "seconds"],
zero: true,
delimiter: ":",
locale: {
formatDistance: (_token, count) => zeroPad(count)
}
});
// 30:07
formatted
it'll be incorrect –
Filial String.prototype.padStart()
: String(num).padStart(2, '0')
–
Epileptic .filter(Boolean)
? That filters out any results that are falsy (eg. the 0
's), so if you remove that line they will be included, and would result in a formatted result of 00:30:07
using 1807
seconds as above. You're probably better off using the 'custom format' example below it though, as my original solution is starting to feel more and more hacky as edge cases are found. With the 'custom format' example, the zero: true
boolean controls whether the 0
's are included (eg. 1800
seconds will give 30:00
or 30
depending on this flag) –
Epileptic intervalToDuration
(see here). So you need to adapt accordingly if you want to show zero values, ie to show things like 01:00:01, 00:01:01, 01:01:00 ${zeroPad(hours)}:${zeroPad(minutes)}:${zeroPad(seconds)}
–
Euphorbia Here's the simple implementation:
import { formatDistance } from 'date-fns'
const duration = s => formatDistance(0, s * 1000, { includeSeconds: true })
duration(50) // 'less than a minute'
duration(1000) // '17 minutes'
This is basically the same as:
import moment from 'moment'
const duration = s => moment.duration(s, 'seconds').humanize()
duration(50) // 'a minute'
duration(1000) // '17 minutes'
date-fns
: formatDistanceToNow
/ formatDistanceToNowStrict
–
Epileptic You can do this using date-fns by simple modifying an intermediate helper date. Using new Date( 0 )
you'll get a date set to January 1, 1970, 00:00:00 UTC. You can then use addSeconds
from date-fns to add the relevant seconds (actually you could use the native date setTime( 1000 * seconds )
for this). Formatting the minutes and seconds of this will give you your desired result.
var input = document.getElementById('seconds');
var output = document.getElementById('out');
output.innerText = formattedTime(input.value);
input.addEventListener('input', function() {
output.innerText = formattedTime(input.value);
});
function formattedTime(seconds) {
var helperDate = dateFns.addSeconds(new Date(0), seconds);
return dateFns.format(helperDate, 'mm:ss');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.26.0/date_fns.min.js"></script>
<input type="number" id="seconds" value="1807">
<pre id="out"></pre>
var helperDate = dateFns.addSeconds(new Date(0), seconds)
that adds your timezone offset to the resulting date, ie if you format the result with hh:mm:ss
- 180
seconds will produce 10:03:00
and 240
seconds will produce 10:04:00
if you are in a +10
timezone offset. –
Mitten HH:mm:ss
you will always see 01:00:00
for Europe/Berlin
with new Date(0)
. I solved it by using date-fns-tz
to set a fixed timezone where I know the offset of (e.g. Europe/Berlin == +1 Hour to GMT
), then I subtract that value with the addHour
function of date-fns
javascript const dateHelper: Date = addSeconds(new Date(0), duration); const utcDate = zonedTimeToUtc(dateHelper, TIME_ZONE); this.durationDisplay = format(addHours(utcDate, -1), 'HH:mm:ss');
–
Linger 30:05
for a duration of 5 seconds. timeanddate.com/time/time-zones-interesting.html –
Soldier This function will convert seconds to duration format hh:mm:ss, its analogue duration in moment.js
import { addHours, getMinutes, getHours, getSeconds } from 'date-fns';
export const convertToDuration = (secondsAmount: number) => {
const normalizeTime = (time: string): string =>
time.length === 1 ? `0${time}` : time;
const SECONDS_TO_MILLISECONDS_COEFF = 1000;
const MINUTES_IN_HOUR = 60;
const milliseconds = secondsAmount * SECONDS_TO_MILLISECONDS_COEFF;
const date = new Date(milliseconds);
const timezoneDiff = date.getTimezoneOffset() / MINUTES_IN_HOUR;
const dateWithoutTimezoneDiff = addHours(date, timezoneDiff);
const hours = normalizeTime(String(getHours(dateWithoutTimezoneDiff)));
const minutes = normalizeTime(String(getMinutes(dateWithoutTimezoneDiff)));
const seconds = normalizeTime(String(getSeconds(dateWithoutTimezoneDiff)));
const hoursOutput = hours !== '00' ? `${hours}:` : '';
return `${hoursOutput}${minutes}:${seconds}`;
};
Just use format from date-fns like that:
format((seconds * 1000), 'mm:ss')
if there is a need to remove timezone hours offset as well, getTimezoneOffset (in minutes) can be used:
let dt = new Date((seconds * 1000));
dt = addMinutes(dt, dt.getTimezoneOffset());
return format(dt, 'mm:ss');
1807
seconds to mm:ss
, if you wanted to be able to handle hours as well, it doesn't cope as well. Eg. Changing the format string to hh:mm:ss
will result in an output of 12:30:07
, even though the hours should actually be 0
in this case. –
Epileptic There doesn't seem to be a direct equivalent of moment.duration in date-fns...
This function I wrote might help someone. Date-fns.differenceInSeconds is used to get the total difference in seconds. There are equivalent methods for milliseconds, minutes, etc. Then I use vanilla js math to format that
/**
* calculates the duration between two dates.
* @param {date object} start The start date.
* @param {date object} finish The finish date.
* @return {string} a string of the duration with format 'hh:mm'
*/
export const formatDuration = (start, finish) => {
const diffTime = differenceInSeconds(finish, start);
if (!diffTime) return '00:00'; // divide by 0 protection
const minutes = Math.abs(Math.floor(diffTime / 60) % 60).toString();
const hours = Math.abs(Math.floor(diffTime / 60 / 60)).toString();
return `${hours.length < 2 ? 0 + hours : hours}:${minutes.length < 2 ? 0 + minutes : minutes}`;
};
In case you want an output like "12h 30min" I used this simple function:
import { secondsToMinutes, secondsToHours, format } from "date-fns";
export function convertSecondsToHoursMinutes(seconds: number ){
const hours = secondsToHours(seconds);
const minutes = secondsToMinutes(seconds) - hours * 60;
return `${hours}h ${minutes.toString().padStart(2,"0")}min`;
// e.g. 1h 00min or 300h 12min
}
© 2022 - 2025 — McMap. All rights reserved.