Compare 2 ISO 8601 timestamps and output seconds/minutes difference - javascript

I need to write JavaScript that's going to allow me to compare two ISO timestamps and then print out the difference between them, for example: "32 seconds".
Below is a function I found on Stack Overflow, it turns an ordinary date into an ISO formatted one. So, that's the first thing out the way, getting the current time in ISO format.
The next thing I need to do is get another ISO timestamp to compare it with, well, I have that stored in an object. It can be accessed like this: marker.timestamp (as shown in the code below). Now I need to compare those two two timestamps and work out the difference between them. If it's < 60 seconds, it should output in seconds, if it's > 60 seconds, it should output 1 minute and 12 seconds ago for example.
Thanks!
function ISODateString(d){
function pad(n){return n<10 ? '0'+n : n}
return d.getUTCFullYear()+'-'
+ pad(d.getUTCMonth()+1)+'-'
+ pad(d.getUTCDate())+'T'
+ pad(d.getUTCHours())+':'
+ pad(d.getUTCMinutes())+':'
+ pad(d.getUTCSeconds())+'Z'}
var date = new Date();
var currentISODateTime = ISODateString(date);
var ISODateTimeToCompareWith = marker.timestamp;
// Now how do I compare them?

Comparing two dates is as simple as
var differenceInMs = dateNewer - dateOlder;
So, convert the timestamps back into Date instances
var d1 = new Date('2013-08-02T10:09:08Z'), // 10:09 to
d2 = new Date('2013-08-02T10:20:08Z'); // 10:20 is 11 mins
Get the difference
var diff = d2 - d1;
Format this as desired
if (diff > 60e3) console.log(
Math.floor(diff / 60e3), 'minutes ago'
);
else console.log(
Math.floor(diff / 1e3), 'seconds ago'
);
// 11 minutes ago

I would just store the Date object as part of your ISODate class. You can just do the string conversion when you need to display it, say in a toString method. That way you can just use very simple logic with the Date class to determine the difference between two ISODates:
var difference = ISODate.date - ISODateToCompare.date;
if (difference > 60000) {
// display minutes and seconds
} else {
// display seconds
}

I'd recommend getting the time in seconds from both timestamps, like this:
// currentISODateTime and ISODateTimeToCompareWith are ISO 8601 strings as defined in the original post
var firstDate = new Date(currentISODateTime),
secondDate = new Date(ISODateTimeToCompareWith),
firstDateInSeconds = firstDate.getTime() / 1000,
secondDateInSeconds = secondDate.getTime() / 1000,
difference = Math.abs(firstDateInSeconds - secondDateInSeconds);
And then working with the difference. For example:
if (difference < 60) {
alert(difference + ' seconds');
} else if (difference < 3600) {
alert(Math.floor(difference / 60) + ' minutes');
} else {
alert(Math.floor(difference / 3600) + ' hours');
}
Important: I used Math.abs to compare the dates in seconds to obtain the absolute difference between them, regardless of which is earlier.

Related

Subtracting 100s of minutes accurately with Javascript

If I have two values, each representing a date such as YYYYMMDDHHMM (YearMonthDayHourMinute) like:
202012141800
202012141614
What I was trying to convey in the question is that this gives me 186 minutes, but this isn't accurate, however, since the last two digits will never be larger than 59 given 60 minutes in an hour. The 100 in 186 comes from hours 18 (6pm) and 16 (4pm).
How can I subtract these in Javascript to account for the extra 40 minutes tacked on if the two timestamps are more than an hour apart?
I have this, but it's not that efficient since I'd need to know the maximum number of hours two timestamps could be apart:
var end_time = $('#the-agenda li.current time').data('end-time'),
time_now = current_display_number,
timer_duration = end_time - time_now;
if (timer_duration > 200) {
// if more than 2 hours, subtract 80 minutes
timer_duration = timer_duration - 80;
}
else if (timer_duration > 100) {
// if more than 1 hour, subtract 40 minutes
timer_duration = timer_duration - 40;
}
I feel like the answer may somehow be in this question's answer, but I am not sure how to apply that parseInt to this situation.
You wouldn't use parseInt. You would use Date.parse, except that the string has to be in a predefined format. Without using a specialized library, you'll have to parse the parts yourself and then create a new Date with the parts. Fortunately though the incoming strings seem straightforward to parse. Do something like this:
let startTimeStr = '202012141614';
let endTimeStr = '202012141800';
let asDateTime = (d) => new Date(
d.substring(0,4),
d.substring(4,6) - 1,
d.substring(6,8),
d.substring(8,10),
d.substring(10,12)
)
let startTime = asDateTime(startTimeStr);
let endTime = asDateTime(endTimeStr);
let result = (endTime - startTime) / 60000;
console.log(result);
// Different in milliseconds
const difference = (new Date('2020-12-14T18:00:00')) - (new Date('2020-12-14T16:14:00'));
const inMinutes = Math.floor(difference / 60000);
You need to convert the string formats to a date object to get accurate date info.

Typescript : find date difference in dates/hours/minutes

I am working on a date comparison and I am trying to calculate and display the difference between two dates in a format of dates, hours, minutes...
Date values are stored in the DB like:
EndDate : 2018-11-29 10:49:49.9396033
PurchaseDate: 2018-11-29 10:49:07.4154497
And in my Angular component, I have:
let result = new Date(res.endDate).valueOf() - new Date(res.purchaseDate).valueOf();
This leads to: 42524 which I am not sure what it represents.
I wonder what is the proper way to calculate the time difference between two dates and also how can I display the result in a proper and readable way.
Any help is welcome
Working Example in codepen
let endDate = new Date("2018-11-29 10:49:07.4154497");
let purchaseDate = new Date("2018-11-29 10:49:49.9396033");
let diffMs = (purchaseDate - endDate); // milliseconds
let diffDays = Math.floor(diffMs / 86400000); // days
let diffHrs = Math.floor((diffMs % 86400000) / 3600000); // hours
let diffMins = Math.round(((diffMs % 86400000) % 3600000) / 60000); // minutes
console.log(diffDays + " days, " + diffHrs + " hours, " + diffMins + "
minutes");
You can use the getTime() method to get the difference time in milliseconds
let time = purchaseDate.getTime() - endDate.getTime();
You can then format the date as you want with the DatePipe librairy : https://angular.io/api/common/DatePipe
Well, there are pure javascript way of doing it like in Check time difference in Javascript
or you can reuse the efforts put in by engineers who delevloped moment.js. In moment.js, there is a concept called duration whose link is - https://momentjs.com/docs/#/durations/
and you can even find the difference in duration by referencing docs here - https://momentjs.com/docs/#/durations/diffing/

Formatting seconds duration into DD:HH:mm format by using moment.js

I'm trying to count calculate a duration from seconds into a DD-HH-mm format.
My javascript code:
var seconds = 120;
var result = moment.utc(seconds*1000).format('DD:HH:mm');
My code should return something like this: 00:00:02 (DD:HH:MM) but it returns that: 01:00:02 (DD:HH:MM)!
I'm sure that's because of my local time, but how to fix the 1 hour interval in general?
moment.utc creates a moment.js object with a timezone set to GMT/UTC. When using a date for a duration, you need to allow for the date starting from 1, not zero. Also, if the duration is 32 days or longer, the "days" will reset to 1.
Moment.js also has durations, however, they don't support formatting other than "humanize" or converting to particular units.
If your durations are less than 32 days, you can use a date starting from 1 January in any year provided you deal with the day number not being zero indexed (i.e. subtract 1 from the day).
So getting your required format with moment.js is a bit more work than just formatting a date, you'll need a sequence of steps so consider writing a function. A plain JS function is no more work than a moment one in this case, it will handle durations 32 days or longer and is not affected by Date vagaries like daylight saving and timezones.
var secs = 120;
// Using a duration
var m = moment.duration(secs * 1000);
console.log(m);
console.log(m.humanize());
console.log(m.asMinutes());
// Using a date and seconds value
var x = moment.utc(secs*1000);
// Generated date
console.log(x.format());
// Get the days separately
var dayNum = x.format('D') - 1;
// Format with hours and minutes
console.log(('0'+dayNum).slice(-2) + x.format(':HH:mm'))
// Function using moment.js
function myFormat(secs) {
var x = moment.utc(secs*1000);
var dayNum = x.format('D') - 1;
return ('0'+dayNum).slice(-2) + x.format(':HH:mm');
}
// Function without using a Date
function duration(secs) {
function z(n){return ('0'+n).slice(-2)}
return z((secs/8.64e4|0))
+ ':' + z((secs%8.64e4)/3.6e3|0)
+ ':' + z((secs%3.6e3)/60|0)
// + ':' + z(secs%60);
}
console.log(duration(secs));
// Some other tests
var min = 60;
var hr = 60*min; // 3,600
var day = 24*hr; // 86,400
//2 days 17 hours 53 minutes and 08 seconds
var d = 2*day + 17*hr + 53*min + 8;
//0 days 1 hour 2 minutes and 1 second
var e = 0*day + 1*hr + 2*min + 1;
// 48 days 21 hours 15 minutes
var f = 48*day + 21*hr + 15*min;
[120, d, e, f].forEach(function(d) {
console.log(d + ' seconds');
console.log('Plain js: ' + duration(d));
console.log('Moment fn: ' + myFormat(d));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.1/moment.min.js"></script>
The format seems ambiguous, I think many would interpret it as HH:mm:ss rather than DD:HH:mm.

How do I get the number of days for a duration where the number of hours exceeds 24 in google sheets?

I am using google sheets where there is a duration value of 69:41:00 where it's 69 hours, 41 minutes, 0 secs. There doesn't seem to be a function to convert this to days, hours and minutes so I did some searching and some had suggested a custom function. Not sure exactly how it works but made some changes from the original to fit what I needed. The code below:
/**
* Format Duration to Days,Hours,Minutes
*
* #param {duration} input value.
* #return Days,Hours,Minutes.
* #customfunction
*/
function FormatDuration(duration) {
// Retrieve the hours and minutes
var hrs = duration.getHours();
var days = Math.floor(hrs/24);
var hours = hrs % 24;
var mins = duration.getMinutes();
// Convert the result to a number to use in calculations
var result = days + 'd ' + hours + ' h '+ mins+' min';
return result;
}
The result should be 2d 21h 44 min but instead I got 0d 21 h 35 min. Am I doing something wrong here?
I was going to add, why don't you just use a custom format of
ʺd\d hh\h mm\mʺ ?
This works fine in Excel but not in GS because it uses a different base for dates so duration like 69:41:00 would be interpreted as 1/1/1900 21:41 and the days are not correct. So you would have to break it down into days (whole numbers) and hours+minutes (fractions of a day) like this
=text(int(A1),ʺ#0\d ʺ)&text(mod(A1,1),ʺHH\h MM\mʺ)
You can make it work in Google Scripts if you want to by adjusting the date - should work OK for durations up to 1 month.
The reason for adding 2 to the date is that a time like 03:21:00 (less than a day) is seen as a date - namely 30th December 1899 ! So I add 2 to it to make it 1st January 1900. However, now the day part of the date is 1 and I want it to be zero. So I have to subtract 1 from the day further down.
This strange behaviour is probably why you're advised to do it the other way and work in milliseconds, but I was just interested to see if there was a way of making the original code work.
/**
* Format Duration to Days,Hours,Minutes
*
* #param {duration} input value.
* #return Days,Hours,Minutes.
* #customfunction
*/
function FormatDuration(duration) {
// Add 2 days to the date
var date=new Date(duration.setDate(duration.getDate()+2));
Logger.log(date.getDate());
var hours = duration.getHours();
// Take 1 off the day part of the date
var days = date.getDate()-1;
var mins = duration.getMinutes();
// Convert the result to a number to use in calculations
var result = days + 'd ' + hours + ' h '+ mins+' min';
return result;
}
function(durations){
var timeArr = durations.split(':'); //["69","41","00"]
//your code
}
getHours is a method of object Date.
var t = new Date;
t.getHours();
How do you expect to get more than 24hours from a Date object? It is not the same as what you expect as Duration. Date is for points of time in calendar, so at most you'd get the 23:59:59 of any day. You can get date2 - date1 = milliseconds diff, and work on it, as following;
function FormatDuration(date1, date2) {
var milliseconds = date2 - date1;
var mins = Math.floor((milliseconds / (1000*60)) % 60);
var hours = Math.floor((milliseconds / (1000*60*60)) % 24);
var days = Math.floor(milliseconds / (1000*60*60*24));
var result = days + ' d ' + hours + ' h '+ mins + ' min';
console.log(result);
}
FormatDuration(new Date(2000, 5, 1, 5, 13, 0, 0),
new Date(2000, 5, 2, 15, 31, 0, 0))
You can find more details here

jQuery Format Time

I have a jQuery script that receives a string in milliseconds inside a parameter, like this:
params.tweetDate='77771564221';
What I need to do is to create a jQuery function that will be able to format this milliseconds string in a USA time, like 10.00 AM or 10.00 PM.
Is there a jQuery function that is able to do this?
Please help.
Thanks
There is Date object in pure javascript, no jQuery needed.
http://www.javascriptkit.com/jsref/date.shtml
Example:
var time = new Date(params.tweetDate),
h = time.getHours(), // 0-24 format
m = time.getMinutes();
// next just convert to AM/PM format (check if h > 12)
No, there's no jQuery function for this. You can use
JavaScript's own Date object, using the getHours() and getMinutes() functions, handling the AM/PM thing yourself (e.g., hours >= 12 is PM), padding out the minutes with a leading 0 if minutes is less than 10, etc. Also note that if hours is 0, you want to make it 12 (because when using the AM/PM style, you write midnight as "12:00 AM", not "0:00 AM").
DateJS, an add-on library that does a huge amount of date stuff (although sadly it's not actively maintained)
PrettyDate from John Resig (the creator of jQuery)
To use just about any of those, first you have to turn that "milliseconds" value into a Date object. If it's really a "milliseconds" value, then first you parse the string into a number via parseInt(str, 10) and then use new Date(num) to create the Date object representing that point in time. So:
var dt = new Date (parseInt(params.tweetDate, 10));
However, the value you've quoted, which you said is a milliseconds value, seems a bit odd — normally it's milliseconds since The Epoch (Jan 1, 1970), which is what JavaScript uses, but new Date(parseInt("77771564221", 10)) gives us a date in June 1972, long before Twitter. It's not seconds since The Epoch either (a fairly common Unix convention), because new Date(parseInt("77771564221", 10) * 1000) gives us a date in June 4434. So the first thing to find out is what that value actually represents, milliseconds since when. Then adjust it so it's milliseconds since The Epoch, and feed it into new Date() to get the object.
Here is a function for you:
function timeFormatter(dateTime){
var date = new Date(dateTime);
if (date.getHours()>=12){
var hour = parseInt(date.getHours()) - 12;
var amPm = "PM";
} else {
var hour = date.getHours();
var amPm = "AM";
}
var time = hour + ":" + date.getMinutes() + " " + amPm;
console.log(time);
return time;
}
You may call the function in any approach like:
var time = timeFormatter(parseInt("2345678998765"));
take a look at timeago: this is a jquery plugin used exactly for this purposes.
Using T.J.'s solution this is what I ended up with.
var date = new Date(parseInt("77771564221", 10));
var result = new Array();
result[0] = $.datepicker.formatDate('DD, M, d, yy', date);
result[1] = ' ';
if (date.getHours() > 12) {
result[2] = date.getHours() - 12;
} else if (date.getHours() == 0 ) {
result[2] = "12";
} else {
result[2] = date.getHours();
}
result[3] = ":"
result[4] = date.getMinutes();
if (date.getHours() > 12) {
result[5] = " pm";
} else {
result[5] = " am";
}
console.log(result.join(''));

Categories

Resources