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?
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
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>
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'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With