I am really struggling to solve human readable duration format algorithm. I have solved the most of it, but there are some mistakes anyway which I cannot solve for a while. Some tests pass, while others don't. Please help me it solve it.
The code
function formatDuration (seconds) {
// Complete this function
var minutes = Math.round(seconds / 60);
var thisSeconds = Math.round(seconds % 60);
var hours = Math.round(seconds / 3600);
var days = Math.round(seconds / 86400);
var years = Math.round(seconds / 31536000);
var stringYear = "year";
var stringDay = "day";
var stringHour = "hour";
var stringMinute = "minute";
var stringSecond = "second";
if (years > 1) {
stringYear = "years";
} else if (days > 1) {
stringDay = "days";
} else if (hours > 1) {
stringHour = "hours";
} else if (thisSeconds > 1) {
stringSecond = "seconds";
} else if (minutes > 1) {
stringMinute = "minutes";
}
if (minutes >= 60) {
hours = Math.round(minutes/60);
minutes = Math.abs(minutes - hours*60);
if (minutes > 1) {
stringMinute = "minutes";
}
}
if (hours >= 24) {
days = Math.round(hours/24);
if (days > 1) {
stringDay = "days";
}
hours = hours - days*24;
stringHour = "hours";
}
if (days > 365) {
days = Math.abs(days - years*365);
stringDay = "days";
}
var obj = new Map();
obj.set(stringYear, years);
obj.set(stringDay, days);
obj.set(stringHour, hours);
obj.set(stringMinute, minutes);
obj.set(stringSecond, thisSeconds);
var empArr = [];
obj.forEach(function (value, key, mapObj) {
if (value == 0) {
obj.delete(key);
}
var res = value + " " + key;
if (value > 0) {
empArr.push(res);
formatStrings(empArr);
}
});
return formatStrings(empArr);
}
function formatStrings(arr) {
return arr.length == 1 ? arr[0] : arr.slice(0, arr.length - 1).join(", ") + " and " + arr[arr.length - 1];
//console.log(str);
}
formatDuration(3600);
Test results
Math.round performs rounding (rounding up if the value would be above .5).
use Math.floor everywhere to take the truncated part.
I would also use modulo to avoid all the complicated logic you've added.
So
var minutes = Math.round(seconds / 60);
would become
var minutes = Math.floor(seconds / 60) % 60;
and so on.
I have a count of seconds stored in variable seconds. I want to convert for example 1439 seconds to 23 minutes and 59 seconds. And if the time is greater than 1 hour (for example 9432 seconds), to 2 hours, 37 minutes and 12 seconds.
How can I achieve this?
I'm thinking of:
var sec, min, hour;
if(seconds<3600){
var a = Math.floor(seconds/60); //minutes
var b = seconds%60; //seconds
if (b!=1){
sec = "seconds";
}else{
sec = "second";
}
if(a!=1){
min = "minutes";
}else{
min = "minute";
}
$('span').text("You have played "+a+" "+min+" and "+b+" "+sec+".");
}else{
var a = Math.floor(seconds/3600); //hours
var x = seconds%3600;
var b = Math.floor(x/60); //minutes
var c = seconds%60; //seconds
if (c!=1){
sec = "seconds";
}else{
sec = "second";
}
if(b!=1){
min = "minutes";
}else{
min = "minute";
}
if(c!=1){
hour = "hours";
}else{
hour = "hour";
}
$('span').text("You have played "+a+" "+hour+", "+b+" "+min+" and "+c+" "+sec+".");
}
But that's a lot of code, and it has to be calculated each second. How can I shrink this up?
I think you would find this solution very helpful.
You modify the display format to fit your needs with something like this -
function secondsToHms(d) {
d = Number(d);
var h = Math.floor(d / 3600);
var m = Math.floor(d % 3600 / 60);
var s = Math.floor(d % 3600 % 60);
var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : "";
var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : "";
var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : "";
return hDisplay + mDisplay + sDisplay;
}
The builtin JavaScript Date object can simplify the required code
toTime(seconds) {
var date = new Date(null);
date.setSeconds(seconds);
return date.toISOString().substr(11, 8);
}
You can try this, i have used this successfully in the past
You should be able to add the minutes and seconds on easily
function secondsToTime(secs)
{
var hours = Math.floor(secs / (60 * 60));
var divisor_for_minutes = secs % (60 * 60);
var minutes = Math.floor(divisor_for_minutes / 60);
var divisor_for_seconds = divisor_for_minutes % 60;
var seconds = Math.ceil(divisor_for_seconds);
var obj = {
"h": hours,
"m": minutes,
"s": seconds
};
return obj;
}
Fiddle
You can change the object to
var obj = {
"h": hours + " hours",
"m": minutes + " minutes",
"s": seconds + " seconds"
};
I'm probably a bit late but you can achieve this kind of things using
https://momentjs.com/
myVar = moment(myVar).format('HH:mm');
moment provides A LOT of format for hours / dates etc.
A low fat way to do this is:
function seconds_to_days_hours_mins_secs_str(seconds)
{ // day, h, m and s
var days = Math.floor(seconds / (24*60*60));
seconds -= days * (24*60*60);
var hours = Math.floor(seconds / (60*60));
seconds -= hours * (60*60);
var minutes = Math.floor(seconds / (60));
seconds -= minutes * (60);
return ((0<days)?(days+" day, "):"")+hours+"h, "+minutes+"m and "+seconds+"s";
}
Thus
> seconds_to_days_hours_mins_secs_str(9432+60*60*24)
'1 days, 2h, 37m and 12s'
This is easy to understand and extend as needed.
Try this, Convert SEC to H:M:S.
function convertTime(sec) {
var hours = Math.floor(sec/3600);
(hours >= 1) ? sec = sec - (hours*3600) : hours = '00';
var min = Math.floor(sec/60);
(min >= 1) ? sec = sec - (min*60) : min = '00';
(sec < 1) ? sec='00' : void 0;
(min.toString().length == 1) ? min = '0'+min : void 0;
(sec.toString().length == 1) ? sec = '0'+sec : void 0;
return hours+':'+min+':'+sec;
}
I found Wilson Lee's and Brian's code super useful! Here is how I adapted their code:
function formatTime(serverTimeinSeconds, elementId)
{ /* This converts seconds into days, hours, minutes and seconds timestring.
Requires JQuery if elementId argument is provided */
seconds = Math.floor(Number(serverTimeinSeconds));
days = Math.floor(seconds / (24*60*60));
seconds -= Math.floor(days * (24*60*60));
hours = Math.floor(seconds / (60*60));
seconds -= Math.floor(hours * (60*60));
minutes = Math.floor(seconds / (60));
seconds -= Math.floor(minutes * (60));
dDisplay = days > 0 ? days + (days == 1 ? ' day, ' : ' days, ') : '';
hDisplay = hours > 0 ? hours + (hours == 1 ? ' hour, ' : ' hours, ') : '';
mDisplay = minutes > 0 ? minutes + (minutes == 1 ? ' minute, ' : ' minutes, ') : '';
sDisplay = seconds > 0 ? seconds + (seconds == 1 ? ' second' : ' seconds') : '';
if (elementId != null) {
if (serverTimeinSeconds < 60) {
$(elementId).css('font-size', '15px');
$(elementId).html(sDisplay);
}
if (serverTimeinSeconds >= 60 && serverTimeinSeconds < 3600) {
$(elementId).css('font-size', '15px');
$(elementId).html(mDisplay + sDisplay);
}
if (serverTimeinSeconds >= 3600 && serverTimeinSeconds < 86400) {
$(elementId).css('font-size', '12px');
$(elementId).html(hDisplay + mDisplay + sDisplay);
}
if (serverTimeinSeconds >= 86400 && serverTimeinSeconds !== Infinity) {
$(elementId).css('font-size', '8px');
$(elementId).html(dDisplay + hDisplay + mDisplay + sDisplay);
}
}
return dDisplay + hDisplay + mDisplay + sDisplay;
}
Please install moment js after that import it,
import moment from 'moment'
let dateForm = (arg) => {
return moment.unix(arg).utc().format('H [hours,] m [minutes and] s [seconds]');
}
console.log(dateForm(11));
// 0 hours, 0 minutes and 11 seconds
console.log(dateForm(16060));
// 1 hours, 0 minutes and 0 seconds
const formatter = (seconds = 0) => {
const d = Number(secondsAmount);
const h = Math.floor(d / 3600);
const m = Math.floor((d % 3600) / 60);
const s = Math.floor((d % 3600) % 60);
const hDisplay = h > 0 ? `${h.toString().length > 1 ? `${h}` : `${0}${h}`}` : '00';
const mDisplay = m > 0 ? `${m.toString().length > 1 ? `${m}` : `${0}${m}`}` : '00';
const sDisplay = s > 0 ? `${s.toString().length > 1 ? `${s}` : `${0}${s}`}` : '00';
return `${hDisplay}:${mDisplay}:${sDisplay}`;
};
Will return this format human readable format 00:00:00
Built off R4nc1d's answer:
function secondsToTime(secs){
var h = Math.floor(secs / (60 * 60));
var divisor_for_minutes = secs % (60 * 60);
var m = Math.floor(divisor_for_minutes / 60);
var divisor_for_seconds = divisor_for_minutes % 60;
var s = Math.ceil(divisor_for_seconds);
return `${h?`${h}:`:""}${m?`${m}:${s}`:`${s}s`}`
}
This will return a human readable answer which looks like this. I used this for displaying the length of music tracks
time = secondsToTime(5)
console.log(time) // 5s
time = secondsToTime(50)
console.log(time) // 50s
time = secondsToTime(500)
console.log(time) // 8:20
time = secondsToTime(5000)
console.log(time) // 1:23:20
#pkerckhove has already mentioned moment as a great library to work with dates and times, and you can also use moment to directly format the seconds into OP's desired format, i.e.:
import moment from 'moment'
const myVar = 1439
console.log(
moment.unix(myVar).utc().format('H [hours,] m [minutes and] s [seconds]')
)
Will result in: 0 hours, 23 minutes and 59 seconds and,
import moment from 'moment'
const myVar = 9432
console.log(
moment.unix(myVar).utc().format('H [hours,] m [minutes and] s [seconds]')
)
Will result in: 2 hours, 37 minutes and 12 seconds
One way of doing it:
const formatDuration = totalSeconds => {
const hours = Math.floor(totalSeconds / 3600)
const minutes = Math.floor((totalSeconds % 3600) / 60)
const seconds = totalSeconds - hours * 3600 - minutes * 60
return [`${hours}h`, `${minutes}m`, `${seconds}s`]
.filter(item => item[0] !== '0')
.join(' ')
}
This method also works with a negative amount of time:
function CalculateTime(sec){
if(sec >= 0){
var h = Math.floor(sec / 3600);
var m = Math.floor(sec % 3600 / 60);
var s = Math.floor(sec % 3600 % 60);
}
else{
var h = Math.ceil(sec / 3600);
var m = Math.ceil(sec % 3600 / 60);
var s = Math.ceil(sec % 3600 % 60);
}
var hDisplay = h !== 0 ? h + (h == 1 ? " hour, " : " hours") + (m != 0 || s > 0 ? ", ":"") : "";
var mDisplay = m !== 0 ? m + (m == 1 ? " minute, " : " minutes") + (s != 0 ? " ":""): "";
var sDisplay = s !== 0 ? s + (s == 1 ? " second" : " seconds") : "";
return hDisplay + mDisplay + sDisplay;
}
for having the result with the time format " 00:00:00 " I added some changes to it.
function secondsToHms(seconds) {
let d = Number(seconds);
if(d <= 0){
return '00:00:00'
}else{
let h = Math.floor(d / 3600);
let m = Math.floor(d % 3600 / 60);
let s = Math.floor(d % 3600 % 60);
let hDisplay = h <= 9 ? '0'+ h+':' : h+ ":";
let mDisplay = m <= 9 ? '0'+ m+':' : m+ ":";
let sDisplay = s <= 9 ? '0'+ s : s;
return hDisplay + mDisplay + sDisplay;
}}
Try this :D
secondsToHms(d) {
d = Number(d);
var h = Math.floor(d / 3600);
var m = Math.floor(d % 3600 / 60);
var s = Math.floor(d % 3600 % 60);
var hDisplay = h > 0 ? h + (h == 1 ? "" : "") : "";
var mDisplay = m > 0 ? m + (m == 1 ? "" : "") : "";
var sDisplay = s > 0 ? s + (s == 1 ? "" : "") : "";
if (hDisplay != "") {
return (hDisplay.length > 1 ? hDisplay : '0' + hDisplay) + ":" + (mDisplay.length > 1 ? mDisplay : '0' + mDisplay) + ":" + (sDisplay.length > 1 ? sDisplay : '0' + sDisplay);
}
else if (mDisplay != "") {
return (mDisplay.length > 1 ? mDisplay : '0' + mDisplay) + ":" + (sDisplay.length > 1 ? sDisplay : '0' + sDisplay);
}
else if (sDisplay != "") {
return "00:" + (sDisplay.length > 1 ? sDisplay : '0' + sDisplay);
}
return "00:00"
}
Using the popular date-fns library
import { format, setSeconds, startOfDay } from 'date-fns'
export const hourMinSec = (secs: number, showHour = false): string => {
const tmpDate: Date = startOfDay(new Date())
const date: Date = setSeconds(tmpDate, secs)
const hour: number = date.getHours()
const hasHour: boolean = !!hour
if (hasHour && !showHour) console.warn('hourMinSec is hiding a non zero hour')
const strFormat: string = showHour ? 'H:mm:ss' : 'm:ss'
return format(date, strFormat)
}
OR the same code with a more functional approach (adding lodash flow in the mix)
import { setSeconds, startOfDay } from 'date-fns/fp'
import { format } from 'date-fns'
import { flow } from 'lodash-es'
export const hourMinSec = (secs: number, showHour = false): string => {
const date: Date = flow(startOfDay, setSeconds(secs))(new Date())
const hour: number = date.getHours()
const hasHour: boolean = !!hour
if (hasHour && !showHour) console.warn('hourMinSec is hiding a non zero hour')
const strFormat: string = showHour ? 'H:mm:ss' : 'm:ss'
return format(date, strFormat)
}
Usage:
hourMinSec(100) // 1:40
hourMinSec(3700) // 1:40 // will warn in logs that a non zero hour is hidden
hourMinSec(100, true) // 0:01:40
hourMinSec(3700, true) // 1:01:40
This met my needs but you could adapt this by changing the showHour = false parameter to be a strFormat = 'm:ss' parameter instead to support more flexible formatting.
const minutes = Math.floor(duration / 60);
const seconds = Math.floor(duration - minutes * 60);
const time = `${minutes < 10 ? `0${minutes}` : minutes}
:${seconds < 10 ? `0${seconds}` : seconds}`; // result: 02:23
useCountDown Hook
// useCountDown.js
import { useEffect, useState } from "react"
const useCountDown = (minutes) => {
const [seconds, setSeconds] = useState(minutes * 60)
useEffect(() => {
const interval = setInterval(() => {
setSeconds(seconds - 1)
}, 1000)
return () => clearInterval(interval)
}, [seconds])
return getReturnValues2(seconds)
}
const getReturnValues2 = (countDown) => {
const minutes = Math.floor(countDown / 60)
const seconds = countDown % 60
return `${padTo2Digits(minutes)}:${padTo2Digits(seconds)}`
}
function padTo2Digits(num) {
return num.toString().padStart(2, "0")
}
export default useCountDown
How to use?
//React Component
import useCountDown from '../hooks/useCountDown'
function App() {
const countDown = useCountDown(5) // 5 Minutes
return (
<h1> {countDown} </h1> // MM:SS
)
}
You can tweak as per your needs.
Convert to H:M
Number(moment.duration(Number(37320), 'seconds').hours()+'.'+moment.duration(Number(37320),'seconds').minutes())
I am making a online quiz system and i want to convert my timer from seconds to minutes and seconds. Please help me to solve this problem here is my code
<div id="divCounter"></div>
<script type="text/javascript">
if(localStorage.getItem("counter")){
if(localStorage.getItem("counter") <= 0){
var value = 110;
}
else{
var value = localStorage.getItem("counter");
}
}
else{
var value = 10;
}
var counter = function (){
document.getElementById('divCounter').innerHTML = localStorage.getItem("counter");
if(value <= 0){
window.location="http://www.google.com"
}else{
value = parseInt(value)-1;
localStorage.setItem("counter", value);
}
};
var interval = setInterval(function (){counter(value);}, 1000);
Try something like this:
function convert(value) {
return Math.floor(value / 60) + ":" + (value % 60 ? value % 60 : '00')
}
DEMO
value/60 + ":" + value%60, formats to (m)m:ss figure out the right padding
I would suggest you simply use this function (taken from here) which transforms a number of seconds into an string representing the hours, minutes and seconds in format HH:MM:SS:
function secondsToTimeString(seconds) {
var minutes = 0, hours = 0;
if (seconds / 60 > 0) {
minutes = parseInt(seconds / 60, 10);
seconds = seconds % 60;
}
if (minutes / 60 > 0) {
hours = parseInt(minutes / 60, 10);
minutes = minutes % 60;
}
return ('0' + hours).slice(-2) + ':' + ('0' + minutes).slice(-2) + ':' + ('0' + seconds).slice(-2);
}
My script is OK in Chrome, but in FireFox and IE the result is: NaN:NaN.
This is my script: Anyone knows whats wrong?
Output of $db[time] is : 2013-10-07 14:28:35 (Timestamp database)
<script>
var end = new Date('<?=$db[time]?>');
var _second = 1000;
var _minute = _second * 60;
var _hour = _minute * 60;
var _day = _hour * 24;
var timer;
function showRemaining() {
var now = new Date();
var distance = end - now;
if (distance < 0) {
clearInterval(timer);
document.getElementById('countdown').innerHTML = 'ITS NOW TIME!</font><BR><BR>';
return;
}
var days = Math.floor(distance / _day);
var hours = Math.floor((distance % _day) / _hour);
var minutes = Math.floor((distance % _hour) / _minute);
var seconds = Math.floor((distance % _minute) / _second);
document.getElementById('countdown').innerHTML = '<font color="orange">' + minutes + ':';
document.getElementById('countdown').innerHTML += '<font color="orange">' + seconds + ' minutes</font>';
}
timer = setInterval(showRemaining, 1000);
</script>
This is because of the value of $db[time].
You said in a comment the format of the date/time is 2013-10-07 14:28:35 which is the default DATETIME output for MySQL, when it needs to be 2013-10-07T14:28:35.
Chrome supports the 2013-10-07 14:28:35 format as a convenience however it's not in the Javascript spec, so not all other browsers do.
Try this:
<? echo str_replace(' ', 'T', $db['time']); ?>
javascript time format different from php so firefox will display NaN:NaN:NaN. you should covert time as below:
PHP date format
$yourDate = date("M d, Y H:i:s", strtotime($db['time'])));
get time like this
date = new date("<?=$yourDate?>").getTime();
You could parse the date string yourself rather than relying on a modern browsers with modern methods, something like the following should be cross-browser friendly. Countdown is in milliseconds, you can format it as you wish.
HTML
<div id="countdown"></div>
Javascript
function isGregorianLeapYear(year) {
return year % 400 === 0 || year % 100 !== 0 && year % 4 === 0;
}
function daysInGregorianMonth(year, month) {
var days;
if (month == 2) {
days = 28;
if (isGregorianLeapYear(year)) {
days += 1;
}
} else {
days = 31 - ((month - 1) % 7 % 2);
}
return days;
}
function timeStampToDate(timeStamp) {
var dateObject,
dateTime,
date,
time,
value;
if (typeof timeStamp === "string") {
dateTime = timeStamp.split(" ");
if (dateTime.length === 2) {
date = dateTime[0].split("-");
if (date.length === 3) {
value = +date[0];
if (date[0].length === 4 && value >= -9999 && value <= 9999) {
value = +date[1];
if (date[1].length === 2 && value >= 1 && value <= 12) {
date[1] = value - 1;
value = +date[2];
if (date[2].length === 2 && value >= 1 && value <= daysInGregorianMonth(+date[0], date[1])) {
time = dateTime[1].split(":");
if (time.length === 3) {
value = +time[0];
if (time[0].length === 2 && value >= 0 && value <= 23) {
value = +time[1];
if (time[1].length === 2 && value >= 0 && value <= 59) {
value = +time[2];
if (time[2].length === 2 && value >= 0 && value <= 59) {
dateObject = new Date(Date.UTC.apply(Date, date.concat(time)));
}
}
}
}
}
}
}
}
}
}
if (typeof dateObject === "undefined") {
dateObject = new Date(NaN);
}
return dateObject;
}
function emptyNode(node) {
while (node.firstChild) {
node.removeChild(node.firstChild);
}
}
var countdown = document.getElementById("countdown"),
end = timeStampToDate("2013-10-07 16:57:00"),
intervalId;
end = end.getTime() + end.getTimezoneOffset() * 60000;
function showRemaining() {
var now = new Date().getTime();
if (isNaN(end) || isNaN(now)) {
clearInterval(intervalId);
emptyNode(countdown);
countdown.appendChild(document.createTextNode("Error"));
} else if (now < end) {
emptyNode(countdown);
countdown.appendChild(document.createTextNode(end - now));
} else {
clearInterval(intervalId);
emptyNode(countdown);
countdown.appendChild(document.createTextNode("ITS NOW TIME!"));
}
}
intervalId = setInterval(showRemaining, 1000);
jsFiddle
function TimeConvert(num) {
for (i = 0; i < num; i+= 60) {
if (num % 60 < 60) {
var hours = Math.floor(i / 60);
if (hours == 0) {
var minutes = num % 60;
} else {
minutes = num % (60 * hours);
}
}
}
return hours + ":" + minutes;
}
When I call TimeConvert(60), it returns 0:0 instead of 1:0... why? Do I have to add a conditional to check whether num % 60 == 0 in such cases?
Why would you need to iterate ?
function TimeConvert(num) {
var hours = Math.floor( num / 60 );
var minutes = num % 60;
//minutes = minutes < 10 ? '0'+minutes:minutes
return hours + ":" + minutes;
}
FIDDLE
The problem is with i < num it should be i <= num instead.
Your for is only executed once with i=0, because on the very next step i gets +60 and i < num becomes false.
And, anyway, the whole function should just be:
function TimeConvert(num) {
var hours = Math.floor(num / 60);
var minutes = num % 60;
return hours + ":" + minutes;
}