How can I format time durations exactly using Moment.js? - javascript

I would like to do the following, given two dates in UTC formatting:
var start = "2014-01-13T06:00:00.0000000Z";
var end = "2014-01-13T14:16:04.0000000Z";
I would like to get the exact time span that passes between these two times, such as
8h 16m
I have tried using the following:
var duration = moment(moment(end) - moment(start)).format('hh[h] mm[m]');
But this does not work with days. Moreover, it does not work with days, since they are always >=1 even if <24 hours pass.
I have also tried twix.js to get the length, but its formatting doesn't support creating the format specified above, or I could not find the way to do so in its documentation. Basically I am looking for an exact version of twix.humanizeLength().
Moment.js's a.diff(b) provides only total durations, it can give me the length of the time span in minutes, hours or days, but not calculated using remainders.
My current solution is to use diff to create the ranges and then use modulo to calculate remainders, but this is not very elegant:
var days = moment(end).diff(start, 'days');
var hours = moment(end).diff(start, 'hours') % 24;
var minutes = moment(end).diff(start, 'minutes') % 60;
var duration = ((days > 0) ? days + 'd ' : '') + ((hours > 0) ? hours + 'h ' : '') + ((minutes > 0) ? minutes + 'm ' : '');
The question: Is there any smarter way to do this in either moment.js or twix.js, or should I take my time and develop my own moment.js plugin?

You can try using Durations, but I'm not sure if those have the capabilities you are looking for http://momentjs.com/docs/#/durations/
Also, you can always user moment's diff to get the difference in milliseconds and then format it to your needs. It is basically the same that you are doing, but you only call diff once.
function convertMilliSecondsIntoLegibleString(milliSecondsIn) {
var secsIn = milliSecondsIn / 1000;
var milliSecs = milliSecondsIn % 1000;
var hours = secsIn / 3600,
remainder = secsIn % 3600,
minutes = remainder / 60,
seconds = remainder % 60;
return ( hours + "h: "
+ minutes + "m: "
+ seconds +"s: " + milliSecs + "ms");
}

There's a plugin for formatting duration in moment.js : moment-duration-format
If it doesn't do what you need, then you should extend moment.duration.fn. If you don't support many locales, it should be easy enough.
In any case, I'd recommend to read the thread of this feature request.

Related

How to get timezone offset in javascript?

In javascript, I want to get my local timezone offset such as -04:00 as a string. How can I do this?
Thanks
You can use Date object for this task.
let offset = new Date().getTimezoneOffset()
Now you got a string like -120 you can format as you like. You can divide by 60 to get hours and then use + or push:
offset = (offset / 60) + ":00";
one line:
new Date().getTimezoneOffset() / 60 + ":00";
Edit: Since you seem having problems, i made you a code example you can test.
<html>
<body>
<script>
let offset = new Date().getTimezoneOffset() / 60;
if (offset >= 0 && offset < 10) {
offset = "0" + offset;
} else if (offset > -10) {
offset = "-0" + offset.toString().substr(1);
} else {
offset = "00";
}
offset += ":00";
alert(offset);
</script>
</body>
</html>
I'm not handling 00:XX in case those exists.
I'd created a function...
function timezone(date=new Date()) {
var timezoneOffset=date.getTimezoneOffset();
var sign=(timezoneOffset<0)?"+":"-";
var minutes=Math.abs(timezoneOffset);
var hours=Math.floor(minutes/60);
minutes=minutes-60*hours;
return sign+("0"+hours).slice(-2)+":"+("0"+minutes).slice(-2);
}
You can pass a Date object, if you don't, one will be created.
timezoneOffset is in integer minutes: East of GMT = negative, West = positive.
sign is the opposite of the offset.
minutes abs = we've already got the sign, let's deal with absolute value.
hours - whole number of multiples of 60 minutes.
minutes - reminder of what it was minus 60 times whole hours. Could be done with %, it's a matter of preference.
return -
sign is a string: "+" or "-"
("0"+hours) is now a string: 7 becomes "07", 11 becomes "011", that's why:
.slice(-2) return the last 2 characters: "07" returns just that, "011" returns "11".
same for minutes.
and a ":" between.
You can test on different timezoneOffset values manually by replacing date.getTimezoneOffset() with a number.
Here's a possible solution:
const date = new Date()
const offset = date.getTimezoneOffset()
const sign = offset >= 0 ? '-' : '+'
const hours = Math.abs(offset / 60)
const minutes = Math.abs(offset % 60)
const hoursStr = `0${hours}`.slice(0, 2)
const minutesStr = `0${minutes}`.slice(0, 2)
console.log(`${sign}${hoursStr}:${minutesStr}`)
Note that not all timezones end at hours. Some countries use half hour timezones, like +03:30.
This seems to work...
function getTimeZoneOffset() {
var t = new Date().toString().match(/[-\+]\d{4}/)[0];
return t.substring(0,3) + ":" + t.substr(3);
}
Here's my solution. Rather then do your own division to get the hours, just use the functionality already in the date object:
const date = new Date();
const tzOffsetNumber = date.getTimezoneOffset();
const tzDate = new Date(0,0,0,0,Math.abs(tzOffsetNumber));
console.log(`${ tzOffsetNumber > 0 ? '-' : '+'}${tzDate.getHours()}:${("" + tzDate.getMinutes()).padStart(2,'0')}`)

Display my var as HH:mm (javascript)

I'm writing code that will allow me to log my hours worked a little easier. I can get the minutes past a defined time to display but I can't seem to get the format on the output to be HH:mm, here's my code;
<html>
<head>
<title>Time Past Since 08:30</title>
<meta http-equiv="Refresh" content="60">
<script language="JavaScript">
var sd = new Date(); // Get system date (sd)
var sh = sd.getHours(); // Get system hour (sh)
var sm = sd.getMinutes(); // Get system minutes (sm)
wh = (08); // Specify work start hour (wh)
wm =(30); // Specify work start minute (wh)
var vctime = ((sh *60 + sm) - (wh *60 + wm)); // Get differnece for system and work start, this needs to display in hh:mm but isn't
document.write(vctime); // output
</script>
</head>
<body>
</body>
</html>
Since your result is in minutes, why not just use division to convert minutes elapsed into hours and then apply a modulus to extract the remaining minutes?
hours_since = Math.floor(vctime/60);
minutes_since = Math.round((vctime/60 % 1) * 60); // Use num % 1 to extract the decimal and convert it to minutes.
console.log(hours_since + ":" + minutes_since);
If you need the leading "0"s in your result, just write a simple conditional to check if the values are less than 10:
hours_zero_prefix = hours_since < 10 ? "0" : ""
minutes_zero_prefix = minutes_since < 10 ? "0" : ""
console.log(hours_zero_prefix + hours_since + ":" + minutes_zero_prefix + minutes_since);
I would suggest using diff in the Moment.js library to handle this calculation. The library will clean up the daylight saving time issues you would have by trying to do this by calculating the difference between the start and end hours. It looks like you want the difference in minutes between a start time and now. To do this with moment:
//returns number of minutes, accounting for DST based on the time zone of the local machine
var min = moment().diff(moment(yourStartDateTimeInIsoString), 'minutes');
//converts minutes to hours, then adds remaining minutes
return Math.floor(min/60) + ':' + min%60

Get times in 15 minute increments up to a specific time

I'm using moment.js and would like to create an array that contains all of the times in 15 minute intervals from the current time. So for example:
Current time is 1:35pm. The next time would be 1:45pm, then 2:00, 2:15, 2:30, 2:45, etc. up until a certain point.
I'm really not sure how to this. Would anyone be able to point me in the right direction?
Try this:
function calculate(endTime) {
var timeStops = [];
var startTime = moment().add('m', 15 - moment().minute() % 15);
while(startTime <= endTime){
timeStops.push(new moment(startTime));
startTime.add('m', 15);
}
return timeStops;
}
usage:
calculate(moment().add('h', 1));
This will return time intervals of every quarter of hour (like you said) h:15, h:30, h:45, h+1:00... It also contains seconds, so you might set seconds to 0, since I was not sure if you need them or not.
You also can see working example on FIDDLE
I'm not as familiar with momentjs but this is relatively easy to do in pure Javascript. To get the closest 15 minutes you can use this solution here. Then if you put that in a date variable you can just add 15 minutes as many times as you want! So the resulting Javascript is:
var d = new Date();
var result = "";
for (var idx = 0; idx < 3; idx++)
{
var m = (((d.getMinutes() + 7.5)/15 | 0) * 15) % 60;
var h = ((((d.getMinutes()/105) + .5) | 0) + d.getHours()) % 24;
d = new Date(d.getYear(), d.getMonth(), d.getDay(), h, m, 0, 0);
if (idx > 0) result += ", ";
result += ("0" + h).slice(-2) + ":" + ("0" + m).slice(-2);
d = addMinutes(d, 15);
}
SEE THIS IN A FIDDLE
Notes - I just added 15 minutes 3 times arbitrarily. You could calculate the difference between the time you want and now if you need a different number of intervals. Also note that I don't know exactly what this would do if it is almost midnight, though that would be easy enough to test and code around.
Best of luck!

Javascript time difference via timepicker

I'm working on a web timesheet where users use timepicker to determine start & end times and I'd like to have the form automatically find the difference between the two times and place it in a 3rd input box. I understand that I need to get the values, convert them to milliseconds, then subtract the first number from the second, convert the difference back to human time and display that in the third box. But I can't seem to wrap my head around time conversion in javascript. Here's what I have so far:
function date1math(){
var date1in = document.getElementById("date-1-in").value;
var date1out = document.getElementById("date-1-out").value;
date1in = date1in.split(":");
date1out = date1out.split(":");
var date1inDate = new Date(0, 0, 0, date1in[0], date1in[1], 0);
var date1outDate = new Date(0, 0, 0, date1out[0], date1out[1], 0);
var date1math = date1outDate.getTime() - date1inDate.getTime();
var hours = Math.floor(date1math / 1000 / 60 / 60);
date1math -= hours * 1000 * 60 * 60;
var minutes = Math.floor(date1math / 1000 / 60);
return (hours < 9 ? "0" : "") + hours + ":" + (minutes < 9 ? "0" : "") + minutes;
document.getElementById("date-1-subtotal").value = date1math(date1in, date1out);
}
I want to take the timepicker result (say 9:00am) from the input date-1-in, the timepicker result (say 5:00pm) from the input date-1-out, and then place the difference as a number in date-1-subtotal.
Presumably the input is a string in the format hh:mm (e.g. 09:54) and that the two strings represent a time on the same day. You don't mention whether an am/pm suffix is included, but it's there in the text so I'll assume it might be.
If daylight saving changes can be ignored, the simplest method is to convert the string to minutes, find the difference, then convert back to hours and minutes, e.g.:
// Convert hh:mm[am/pm] to minutes
function timeStringToMins(s) {
s = s.split(':');
s[0] = /m$/i.test(s[1]) && s[0] == 12? 0 : s[0];
return s[0]*60 + parseInt(s[1]) + (/pm$/i.test(s[1])? 720 : 0);
}
// Return difference between two times in hh:mm[am/pm] format as hh:mm
function getTimeDifference(t0, t1) {
// Small helper function to padd single digits
function z(n){return (n<10?'0':'') + n;}
// Get difference in minutes
var diff = timeStringToMins(t1) - timeStringToMins(t0);
// Format difference as hh:mm and return
return z(diff/60 | 0) + ':' + z(diff % 60);
}
var t0 = '09:15am';
var t1 = '05:00pm';
console.log(getTimeDifference('09:15am', '05:00pm')); // 07:45
console.log(getTimeDifference('09:15', '17:00')); // 07:45
If daylight saving is to be incorporated, you'll need to include the date so that date objects can be created and used for the time difference. The above can use either 12 or 24 hr time format.

Jquery time difference in hours from two fields

I have two fields in my form where users select an input time (start_time, end_time) I would like to, on the change of these fields, recalcuate the value for another field.
What I would like to do is get the amount of hours between 2 times. So for instance if I have a start_time of 5:30 and an end time of 7:50, I would like to put the result 2:33 into another field.
My inputted form times are in the format HH:MM:SS
So far I have tried...
$('#start_time,#end_time').on('change',function()
{
var start_time = $('#start_time').val();
var end_time = $('#end_time').val();
var diff = new Date(end_time) - new Date( start_time);
$('#setup_hours').val(diff);
try
var diff = ( new Date("1970-1-1 " + end_time) - new Date("1970-1-1 " + start_time) ) / 1000 / 60 / 60;
have a fiddle
It depends on what format you want your output in. When doing math with Date objects, it converts them into milliseconds since Epoch time (January 1, 1970, 00:00:00 UTC). By subtracting the two (and taking absolute value if you don't know which is greater) you get the raw number of milliseconds between the two.
From there, you can convert it into whatever format you want. To get the number of seconds, just divide that number by 1000. To get hours, minutes, and seconds:
var diff = Math.abs(new Date(end_time) - new Date(start_time));
var seconds = Math.floor(diff/1000); //ignore any left over units smaller than a second
var minutes = Math.floor(seconds/60);
seconds = seconds % 60;
var hours = Math.floor(minutes/60);
minutes = minutes % 60;
alert("Diff = " + hours + ":" + minutes + ":" + seconds);
You could of course make this smarter with some conditionals, but this is just to show you that using math you can format it in whatever form you want. Just keep in mind that a Date object always has a date, not just a time, so you can store this in a Date object but if it is greater than 24 hours you will end up with information not really representing a "distance" between the two.
var start = '5:30';
var end = '7:50';
s = start.split(':');
e = end.split(':');
min = e[1]-s[1];
hour_carry = 0;
if(min < 0){
min += 60;
hour_carry += 1;
}
hour = e[0]-s[0]-hour_carry;
min = ((min/60)*100).toString()
diff = hour + ":" + min.substring(0,2);
alert(diff);
try this :
var diff = new Date("Aug 08 2012 9:30") - new Date("Aug 08 2012 5:30");
diff_time = diff/(60*60*1000);

Categories