How does moment.js handle leap seconds? - javascript

I need a way to always add a whole minute to a timestamp, even if the minute is 61 seconds long due to a planned leap second. Does anyone know if moment().add(1, 'minute') adds a minute regardless of leap seconds? Or does it just always add sixty seconds?
I've found how it handles addition over daylight savings time and leap years, but nothing at all for leap seconds.
To give some background as to why this is important:
I need to create a CSV file with a bunch of minute-by-minute sensor data for various sensors, formatted like:
time,sensor1,sensor2
1491329921800,20,21
1491329981800,22,21
My data is stored with with the timestamp for the start of an hour, then an array of sixty data points for the hour.
{
timestamp: Date(2017,2,24,12,0,0),
temperature: [20, 22, 23, ... <60 elements total>]
}
I turn this into a bunch of timestamp'd data by giving the first data point the hour's timestamp and adding sixty seconds to that value for each subsequent data point (as leap seconds always happen at the end of the hour and I only ever do an hour at a time, this should be fine).
I then will need to build a dictionary mapping each timestamp to the value at that minute. This is necessary so that I can have the right data in the right row of the CSV; sensors may have started at different times or may have been powered off for a certain hour or not reported for a certain part of the hour; I can't just assume that all sensors have the same data.
I'm finding all of the timestamps over which the CSV will be created with the following code:
var date = moment(startDate);
var end = endDate.getTime();
var timestamps = [];
while(date.valueOf() < end) {
timestamps.push(date.valueOf());
date.add(1, 'minute')
}
timestamps.push(date.valueOf());
But I'm not sure if it's safe. If I need to, I could just change date.add(1, 'minute') to date.add(1, 'minute').startOf('minute'), but this could add a lot to the execution time and I'd like to avoid it if possible.

You don't need to worry about this, because JavaScript is unaware of leap-seconds. Consider this piece of code :-
// 1. Initialize date
var newDate = new Date('1 March 1972 11:30:00');
// 2. Convert to milliseconds and add 20 years
var msec = Date.parse(newDate) + 631152000000;
// 3. Convert milliseconds back to normal date format
newDate = new Date(msec);
The big number in step #2 is the number of milliseconds in 20 years, as given by the equation ((15 x 365) + (5 x 366)) x 24 x 60 x 60 x 1000; 15 years # 365 days per year plus 5 years # 366 days per year, 24 hours per day, 60 minutes per hour, 60 seconds per minute, 1000 milliseconds per second.
After execution the answer given is '1 March 1992 11:30:00'. If JavaScript took account of leap-seconds it would be '1 March 1992 11:30:16', because 16 extra seconds had happened (or '1 March 1992 11:29:44' depending how you look at it).
Summarily, if you need to know how many milliseconds have actually passed between two dates, then you need to write some code to do a lookup of how many leap-seconds occurred within the period they span (you can find the raw data for that here), but for normal time logging we can happily ignore this unwelcome little complication.

Related

Javascript: Calculating time duration on ajax response

I am trying to calculate the time duration of a tasks, that I get from an ajax response.
Following are my table values:
Jobid techid, techtype, notes, starttime, stoptime
1 1 Brakes Break disc needed to be changed 2020-07-16 13:00:00 2020-07-16 13:40:00
1 2 Oil Change Replaced oil 2020-07-17 08:00:00 2020-07-17 09:00:00
1 3 Cleaning Cleaned the vehicle 2020-07-17 10:00:00 2020-07-17 10:30:00
On my ajax response, in the above case, I am getting 3 objects each having the start time, and stop time. I want to calculate total time spent in hours and minutes.
Is there an easy way to calculate the total duration?
With a string like 2020-07-16 13:00:00 you can construct a JS Date and get the milliseconds since the UNIX epoch with getTime() like so
new Date('2020-07-16 13:00:00').getTime()
Or, if you prefer, as pointed out by #Yousaf in the comments you can actually just use the - operator with Dates directly and get the millisecond difference
// resolves to 3600000, or 1 hour in milliseconds
new Date('2020-07-16 13:00:00') - new Date('2020-07-16 12:00:00')
Using that, you can get the difference in milliseconds between any two dates, and convert that to hours / minutes / whatever with straightforward arithmetic.
You can simply use Date to construct a date and then minus the start time from the end time.
Here I use getTime to get the millisecond difference, divide by 1000 to get seconds and divide by 60 to get minutes.
You could also use getMonth and such if you have bigger differences.
const starttime = '2020-07-16 13:00:00'
const stoptime = '2020-07-16 13:40:00'
const duration = new Date(stoptime) - new Date(starttime)
console.log(duration / 1000 / 60)
[UPDATE]
I think you can check this answer, but basically you should convert each date to js Date, get the milliseconds and just calculate endtime - startime.
const timelapse = new Date(endtime).getTime() - new Date(startime).getTime();
From there, you transform that in the unit you need (e.g: seconds = milliseconds/1000);
Sorry, my bad for writing fast.

How to use Momentjs to calculate number of hours on Day light savings Day

I would like to know how to use Moment.JS to caluculate the number of hours on a given day.
The reason is that a regular day will be 24 hrs. But the day that daylight savings time starts in the Spring will be 25hrs.
OR how can I use moment.js or even js to calculate if daylight savings date in the spring has been reached bearing in mind that DST starts after 2a.m.
The code I am trying to use is
moment([2017, 2, 12]).isDST();
However how can i used it such that not only does it tell me if its DST but also can check if its after 2 a.m.
Simply get the difference in hours between the start of the day, and the start of the next day.
var m = moment([2017, 2, 12]); // your moment object, however you create it.
var a = moment(m).startOf('day');
var b = moment(m).add(1, 'day').startOf('day');
var h = b.diff(a, 'hours'); // 23, 24, 25, etc.
Note that time zones are different all over the world. Some do DST, some don't. Some do it on different dates and different times. It's even possible to get 23.5 or 24.5 as a result, since there is at least one place that has a 30-minute DST bias instead of the normal 1-hour (Lord Howe Island, Australia). And also there are places that have transitions not related to DST, such as when Venezuela moved their standard time from UTC-04:30 back to UTC-04:00 in May 2016.
Also, you said:
... But the day that daylight savings time starts in the Spring will be 25hrs.
It's actually the Fall that has an extra hour. In the Spring, it would be an hour short (23 hours).

Moment.JS - Change a two digit value to milliseconds using moment

At the moment I have an input field that allows you to choose an hour by entering two digits. for example you could choose 12 for 12 hours.
Is there a way using moment to convert that number into milliseconds using MomentJS?
At the moment I am having to do the below maths. I can't see in the Moment docs that this is doable.
var timeHH = scope.session.timeHH * 3600;
This works out the seconds, then later I mulitply it by 1000 for the milliseconds value.
Is there a way using moment to convert that number into mini milliseconds using moment?
There may be, but there's absolutely no reason to use MomentJS for this, and doing so would be roundabout and inefficient. It's quite straightforward: hours * 3600000 is milliseconds. There are no weird special cases to handle, etc., unless you're handling converting a particular period of hours of a real time (say, the 10 hours from 8 p.m. December 31st 2005 GMT) and want to handle leap second insertions (there was one that night at midnight), but MomentJS doesn't do that anyway.
For this particular use case, the right thing to do is a manual calculation. For the sake of completeness and in the event you needed to do more complicated calculations, to do this with Moment, you would use the duration type. The duration type will allow you to convert from one unit value to another, and if you had to make several unit conversions instead of just this one it would be a good choice.
moment.duration(12, 'hours').asMilliseconds()
43200000
In addition to converting to milliseconds, you could convert to any other unit:
var dur = moment.duration(12, 'hours');
dur.asMilliseconds();
43200000
dur.asDays();
0.5
dur.asYears();
0.001368953503494254
In addition to the as functions, you can get the parts of the duration broken out:
var dur = moment.duration(12.5, 'hours');
dur.hours();
12
dur.minutes();
30
dur.seconds();
0
Or call humanize to get a human readable string that is an estimate of the duration's length:
var dur = moment.duration(42, 'hours');
dur.humanize();
"2 days"
You can also do math with durations. See the docs for more info: http://momentjs.com/docs/#/durations/
You can try the following hack(assuming hours in 24-Hours format) :
var momObj = moment('12', 'HH');
var x = momObj.diff(moment().startOf('day'));
console.log(x) //43200000

Date subtraction in JavaScript

I have two text boxes which accept Start Date and End Date respectively, in format YYYY/MM/DD.
I need to alert the user if he selects an end date that exceeds the start date by 50 days.
Here's what I have so far:
var startDate = new Date(document.getElementsByName('MYSTARTDATE').value);
var endDate = new Date(document.getElementsByName('MYENDDATE').value);
if ((endDate - startDate) > 50)
{
alert('End date exceeds specification');
return false;
}
Just as an example, when I select Start Date as 2012/01/22 and End Date as 2012/02/29
startDate = 'Sun Jan 22 00:00:00 UTC +0530 2012'
endDate = 'Wed Feb 29 00:00:00 UTC +0530 2012'
And the result for endDate - startDate is 3283200000, instead of 38.What am I doing wrong?
3283200000 is 38 days in milliseconds.
38 days x 24 hours x 60 minutes x 60 seconds x 1000 milliseconds
Also, there are 38 days between those two dates, not 39.
An easy solution is to have a variable (constant really) defined as the number of milliseconds in a day:
var days = 24*60*60*1000;
And use that variable as a "unit" in your comparison:
if ((endDate - startDate) > 50*days) {
...
}
The solution by Jeff B is incorrect, because of daylight savings time. If the the startDate is, say, on October 31, and the endDate is on December 20, the amount of time that has actually elapsed between those two times is 50 days plus 1 hour, not 50 days. This is especially bad if your program doesn't care about the time of day and sets all times at midnight - in that case, all calculations would be off by one for the entire winter.
Part of the correct way to subtract dates is to instantiate a new Date object for each of the times, and then use an Array with the number of days in each month to compute how many days have actually passed.
But to make things worse, the dates that Europe changes the clocks are different than the dates that the clocks are changed in New York. Therefore, timezone alone is not sufficient to determine how many days have elapsed; location is also necessary.
Daylight savings time adds significant complexity to date handling. In my website, the function needed to accurately compute the number of days passed is nearly a hundred lines. The actual complexity is dependent on whether the calculations are client side or server side or both and who is viewing the data.

How to determine if it is day or night in Javascript? [duplicate]

This question already has answers here:
Calculating sunrise/sunset times in Javascript
(4 answers)
Closed 1 year ago.
Im wanting to apply different CSS sheets to my site depending on the time of the browser. e.g if its day time, display day.css or night.css for night.
I can do this with PHP but it is based on the server time, not the browsers local time.
Is there a way to tell the time in javascript? I'm probably going to use jQuery to simply initiate the css once its worked out.
var hr = (new Date()).getHours(); //get hours of the day in 24Hr format (0-23)
Depending on your definition of day/night, perform your magic :)
PS: If your day/night starts not at the exact hour, you can try getMinutes().
I use this logic:
const hours = new Date().getHours()
const isDayTime = hours > 6 && hours < 20
(new Date).getHours()
will get the local hour of the time (0-23) of the client. Based on that value, swap the stylesheet for the page. I would set the day stylesheet as the default and swap it out when necessary.
My initial thought is that you would want to perform this operation as soon as possible on the client to avoid any potential browser reflow.
For this to work you’ll need to know the location of the client, the local sunrise and sunset time and the day of the year. Only locations at the equator have an almost constant 12 hour of day light all the year around.
This other answer on StackOverflow provides a good answer:
Calculating sunrise/sunset times in Javascript
Fun question. I wanted to give it a try and come up with something totally different than what was proposed so far. This is what I got:
function isDay() {
return (Date.now() + 60000 * new Date().getTimezoneOffset() + 21600000) % 86400000 / 3600000 > 12;
}
It will return true if it's between 6 AM and 6 PM, or false otherwise.
Breaking down into parts:
Date.now() returns UTC epoch in milliseconds;
new Date().getTimezoneOffset() gets local time zone, in minutes, and 60000 just converts it to milliseconds;
21600000 represents 6 hours in milliseconds. This is a hack to pretend each day starts at 6 AM (will be explained in the end);
86400000 is how many milliseconds there is in a day, so X % 86400000 will return how many milliseconds have passed since the current day begun; since we added 6 hours in the previous step, this is actually counting millis since 6 AM;
we divide that result by 3600000 (number of milliseconds in an hour) to find out how many hours have passed since the day begun;
since we added 6 hours to our clock, 6 AM is now 12 PM, and 6 PM is actually midnight. This is why the function checks to see if the value is greater than 12; if it is, it must be between 6 AM and 6 PM right now. Anything earlier than 6 AM or later than 6 PM becomes less than 12, according to that formula.
Of course, the same can be accomplished with:
function isDay() {
const hours = (new Date()).getHours();
return (hours >= 6 && hours < 18);
}
But that is not even half as fun :-D

Categories