Is there anything readily available in JavaScript (i.e. not through "plugins") that allows me to do something like setTimeout, but instead of saying in how many milliseconds something should happen, I give it a date object telling it when to do something?
setToHappen(function () {
alert('Wake up!');
}, new Date("..."));
And yes, I know I can do this by simply subtracting new Date() with my existing date object (or maybe it's the other way around) to get the amount of milliseconds, but I'd still like to know.
You have to compute the number of milliseconds between now and your date object:
function setToHappen(fn, date){
return setTimeout(fn, date - Date.now());
}
NB Please note #calvin's answer: this will not work if the number of milliseconds is greater than 2147483647.
Since people are talking about calculating timeout intervals using date objects, it should be noted that the max value setTimeout() will accept for the interval parameter is 2147483647 (2^31 - 1) as PRIntervalTime is a signed 32-bit integer. That comes out to just under 25 days.
No, but you could easily write your own function. Just calculate the diference between now and the given moment in miliseconds and call setTimeout with that.
Something like this:
setToHappen = function(fn, date){
var now = new Date().getTime();
var diff = date.getTime() - now;
return setTimeout(fn, diff);
}
EDIT: removed the extra multiplication by 1000, thanks chris for pointing that out!
You can simply subtract Date.now() from the date
const myDate = new Date('...');
setTimeout(func, myDate - Date.now());
Related
In my backend (written in Perl), I generate an end date. In the front end, I want to compute the remaining time before this end date. To avoid time zones problems, I want to use UTC
In perl, the end date is encapsulated in a data object:
data => {endTime => $date->epoch()}
And this is the Java Script function that I've written:
updateCounter: function (element){
var now = new Date().getTime();
var endTime = $(element).data("endtime");
var diff = epochEndDealTime - milliseconds;
console (diff, now, endTime);
...
}
I know for a fact that endTime is in the future, so diff should be positive, but when I test it is smaller, e.g.:
-1530397503497 1531929432906 1531929409
What am I doing wrong?
If we organize the numbers differently
now: 1531929432906
endTime: 1531929409
you might notice now is roughly 1000x larger than endTime. That's because JS's new Date().getTime() returns the number of milliseconds since 1970-01-01T00:00:00Z, while Perl's time returns the number of seconds since 1970-01-01T00:00:00Z.
So, simply multiply endTime by 1000, or divide now by 1000.
(You could also use different means of obtaining the time in Perl to obtain more precision, but that doesn't appear to be needed.)
I'm trying to get from a time formatted Cell (hh:mm:ss) the hour value, the values can be bigger 24:00:00 for example 20000:00:00 should give 20000:
Table:
if your read the Value of E1:
var total = sheet.getRange("E1").getValue();
Logger.log(total);
The result is:
Sat Apr 12 07:09:21 GMT+00:09 1902
Now I've tried to convert it to a Date object and get the Unix time stamp of it:
var date = new Date(total);
var milsec = date.getTime();
Logger.log(Utilities.formatString("%11.6f",milsec));
var hours = milsec / 1000 / 60 / 60;
Logger.log(hours)
1374127872020.000000
381702.1866722222
The question is how to get the correct value of 20000 ?
Expanding on what Serge did, I wrote some functions that should be a bit easier to read and take into account timezone differences between the spreadsheet and the script.
function getValueAsSeconds(range) {
var value = range.getValue();
// Get the date value in the spreadsheet's timezone.
var spreadsheetTimezone = range.getSheet().getParent().getSpreadsheetTimeZone();
var dateString = Utilities.formatDate(value, spreadsheetTimezone,
'EEE, d MMM yyyy HH:mm:ss');
var date = new Date(dateString);
// Initialize the date of the epoch.
var epoch = new Date('Dec 30, 1899 00:00:00');
// Calculate the number of milliseconds between the epoch and the value.
var diff = date.getTime() - epoch.getTime();
// Convert the milliseconds to seconds and return.
return Math.round(diff / 1000);
}
function getValueAsMinutes(range) {
return getValueAsSeconds(range) / 60;
}
function getValueAsHours(range) {
return getValueAsMinutes(range) / 60;
}
You can use these functions like so:
var range = SpreadsheetApp.getActiveSheet().getRange('A1');
Logger.log(getValueAsHours(range));
Needless to say, this is a lot of work to get the number of hours from a range. Please star Issue 402 which is a feature request to have the ability to get the literal string value from a cell.
There are two new functions getDisplayValue() and getDisplayValues() that returns the datetime or anything exactly the way it looks to you on a Spreadsheet. Check out the documentation here
The value you see (Sat Apr 12 07:09:21 GMT+00:09 1902) is the equivalent date in Javascript standard time that is 20000 hours later than ref date.
you should simply remove the spreadsheet reference value from your result to get what you want.
This code does the trick :
function getHours(){
var sh = SpreadsheetApp.getActiveSpreadsheet();
var cellValue = sh.getRange('E1').getValue();
var eqDate = new Date(cellValue);// this is the date object corresponding to your cell value in JS standard
Logger.log('Cell Date in JS format '+eqDate)
Logger.log('ref date in JS '+new Date(0,0,0,0,0,0));
var testOnZero = eqDate.getTime();Logger.log('Use this with a cell value = 0 to check the value to use in the next line of code '+testOnZero);
var hours = (eqDate.getTime()+ 2.2091616E12 )/3600000 ; // getTime retrieves the value in milliseconds, 2.2091616E12 is the difference between javascript ref and spreadsheet ref.
Logger.log('Value in hours with offset correction : '+hours); // show result in hours (obtained by dividing by 3600000)
}
note : this code gets only hours , if your going to have minutes and/or seconds then it should be developped to handle that too... let us know if you need it.
EDIT : a word of explanation...
Spreadsheets use a reference date of 12/30/1899 while Javascript is using 01/01/1970, that means there is a difference of 25568 days between both references. All this assuming we use the same time zone in both systems. When we convert a date value in a spreadsheet to a javascript date object the GAS engine automatically adds the difference to keep consistency between dates.
In this case we don't want to know the real date of something but rather an absolute hours value, ie a "duration", so we need to remove the 25568 day offset. This is done using the getTime() method that returns milliseconds counted from the JS reference date, the only thing we have to know is the value in milliseconds of the spreadsheet reference date and substract this value from the actual date object. Then a bit of maths to get hours instead of milliseconds and we're done.
I know this seems a bit complicated and I'm not sure my attempt to explain will really clarify the question but it's always worth trying isn't it ?
Anyway the result is what we needed as long as (as stated in the comments) one adjust the offset value according to the time zone settings of the spreadsheet. It would of course be possible to let the script handle that automatically but it would have make the script more complex, not sure it's really necessary.
For simple spreadsheets you may be able to change your spreadsheet timezone to GMT without daylight saving and use this short conversion function:
function durationToSeconds(value) {
var timezoneName = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
if (timezoneName != "Etc/GMT") {
throw new Error("Timezone must be GMT to handle time durations, found " + timezoneName);
}
return (Number(value) + 2209161600000) / 1000;
}
Eric Koleda's answer is in many ways more general. I wrote this while trying to understand how it handles the corner cases with the spreadsheet timezone, browser timezone and the timezone changes in 1900 in Alaska and Stockholm.
Make a cell somewhere with a duration value of "00:00:00". This cell will be used as a reference. Could be a hidden cell, or a cell in a different sheet with config values. E.g. as below:
then write a function with two parameters - 1) value you want to process, and 2) reference value of "00:00:00". E.g.:
function gethours(val, ref) {
let dv = new Date(val)
let dr = new Date(ref)
return (dv.getTime() - dr.getTime())/(1000*60*60)
}
Since whatever Sheets are doing with the Duration type is exactly the same for both, we can now convert them to Dates and subtract, which gives correct value. In the code example above I used .getTime() which gives number of milliseconds since Jan 1, 1970, ... .
If we tried to compute what is exactly happening to the value, and make corrections, code gets too complicated.
One caveat: if the number of hours is very large say 200,000:00:00 there is substantial fractional value showing up since days/years are not exactly 24hrs/365days (? speculating here). Specifically, 200000:00:00 gives 200,000.16 as a result.
var timeArr = moment().format('HH:mm:ss').split(':');
var timeInMilliseconds = (timeArr[0] * 3600000) + (timeArr[1] * 60000);
This solution works, test it, but I'd rather just use the moment api instead of using my own code.
This code returns TODAYS time in milliseconds. I need it to call another function in milliseconds...Can not use the epoch. Need today's time formated in milliseconds. 9:00am = 3.24e+7 milliseconds 9:00pm = 6.84e+7 milliseconds.
From the docs:
http://momentjs.com/docs/#/parsing/unix-timestamp-milliseconds/
So use either of these:
moment(...).valueOf()
to parse a preexisting date and convert the representation to a unix timestamp
moment().valueOf()
for the current unix timestamp
See this link http://momentjs.com/docs/#/displaying/unix-timestamp-milliseconds/
valueOf() is the function you're looking for.
Editing my answer (OP wants milliseconds of today, not since epoch)
You want the milliseconds() function OR you could go the route of moment().valueOf()
var timeArr = moment().format('x');
returns the Unix Millisecond Timestamp as per the format() documentation.
You could subtract the current time stamp from 12 AM of the same day.
Using current timestamp:
moment().valueOf() - moment().startOf('day').valueOf()
Using arbitrary day:
moment(someDate).valueOf() - moment(someDate).startOf('day').valueOf()
You can just get the individual time components and calculate the total. You seem to be expecting Moment to already have this feature neatly packaged up for you, but it doesn't. I doubt it's something that people have a need for very often.
Example:
var m = moment();
var ms = m.milliseconds() + 1000 * (m.seconds() + 60 * (m.minutes() + 60 * m.hours()));
console.log(ms);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
Since this thread is the first one from Google I found, one accurate and lazy way I found is :
const momentObject = moment().toObject();
// date doesn't exist with duration, but day does so use it instead
// -1 because moment start from date 1, but a duration start from 0
const durationCompatibleObject = { ... momentObject, day: momentObject.date - 1 };
delete durationCompatibleObject.date;
const yourDuration = moment.duration(durationCompatibleObject);
// yourDuration.asMilliseconds()
now just add some prototypes (such as toDuration()) / .asMilliseconds() into moment and you can easily switch to milliseconds() or whatever !
I am having a lot of trouble doing something that seems obvious. I have a date:
Date.now()
I want it in milliseconds from epoch. I cannot get that to work. I have tried:
Date.now().getTime();
(Date.now()).getTime();
Date.now().getMilliseconds();
(Date.now()).getMilliseconds();
var date = Date.now();
var ms = date.getTime();
var ms = date.getMilliseconds();
All of these fail because apparently getTime() and getMilliseconds() (which I don't think is the correct approach anyways) are apparently not functions.
What am I doing wrong here?
Date.now() already returns ms from epoch, not a Date object...
Date.now is a method in the Date namespace1, same as Math.random is for Math.
Date (unlike Math) is also a constructor. Used like new Date(), it will return a Date object.
1. A property of Date, which is a function/object
You already have the value you want.
var numberOfMillisecondsSinceEpoch = Date.now();
You're attempting to call methods on a Date object, such as you'd get for the current date by calling new Date(). That's not necessary or appropriate if you're using Date.now(), which returns a number instead.
For platforms that don't provide Date.now(), you can convert the current Date object to a number to get the same value.
var numberOfMillisecondsSinceEpoch = Number(new Date());
Number(new Date()) === Date.now() // if your system is quick enough
var timeInMs = Date.now();
per MDN
vs.
var timeInMs = new Date(optional).getTime();
per MDN.
Is there any difference between the two, besides the syntax and the ability to set the Date (to not the current) via optional in the second version?
Date.now() is faster - check out the jsperf
These things are the same (edit semantically; performance is a little better with .now()):
var t1 = Date.now();
var t2 = new Date().getTime();
However, the time value from any already-created Date instance is frozen at the time of its construction (or at whatever time/date it's been set to). That is, if you do this:
var now = new Date();
and then wait a while, a subsequent call to now.getTime() will tell the time at the point the variable was set.
They are effectively equivalent, but you should use Date.now(). It's clearer and about twice as fast.
Edit: Source: http://jsperf.com/date-now-vs-new-date
When you do (new Date()).getTime() you are creating a new Date object. If you do this repeatedly, it will be about 2x slower than Date.now()
The same principle should apply for Array.prototype.slice.call(arguments, 0) vs [].slice.call(arguments, 0)
Yes, that is correct; they are effectively equivalent when using the current time.
Sometimes it's preferable to keep some time tracking variable in a Date object format rather than as just a number of milliseconds, to have access to Date's methods without re-instantiating. In that case, Date.now() still wins over new Date() or the like, though only by about 20% on my Chrome and by a tiny amount on IE.
See my JSPERF on
timeStamp2.setTime(Date.now()); // set to current;
vs.
timeStamp1 = new Date(); // set to current;
http://jsperf.com/new-date-vs-settime
I tried to find the extracly answer for your question. I found a page with a benchmark so clearly.
The static Date.now() method returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC.
The getTime() method returns the number of milliseconds since the ECMAScript epoch.
You can use this method to help assign a date and time to another Date object. This method is functionally equivalent to the valueOf() method.
Source: https://developer.mozilla.org/
ex:
const moonLanding = new Date('July 20, 69 20:17:40 GMT+00:00');
console.log('getTime:::', moonLanding.getTime()); // expected output: -14182940000
console.log('valueOf:::', moonLanding.valueOf()); // expected output: -14182940000
Date.now() is calling the static method now() of the class Date.
While new Date().getTime() can be divided into two steps:
new Date(): Call the constructor() method of Date class to initialize an instance of Date class.
Call getTime() method of the instance we just initialize.
MDN web docs classifies Date.now() into static method of Date, and Date.prototype.getTime() into instance method.