I've got a variable that holds a number of miliseconds which represents the timespan from now to a specified point in the future.
I want to convert this milisecond figure into a timespan value I can display to users.
I know I can do this the naive way with modulo arithmetic and manually displaying the result to the user, but I want to do this using the Date() API built-in to Javascript/ECMAScript.
This is how I generate it:
var timespanInMS = timeInFuture.getTime() - now.getTime();
var diff = new Date( timespanInMS );
alert( "Hours: " + diff.getHours() + " Minutes: " + diff.getMinutes() );
However this only works when the user's computer is in the UTC timezone. If they're in Pacific (UTC-8) then the value of 'diff' is off by 16 hours (even though the timespanInMS figure is the same).
Thanks
Perhaps getUTCHours and getUTCMinutes might work? See https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Date for more information.
Related
new Date(Date.now()).toLocaleString(
"en-US",
{
timeZone: "Asia/Calcutta"
}
)
Works for my timezone. But when I try to get for another timezone, it doesn't help. I tried using Date.parse() and moment, no luck. Would be helpful if there is some other way. I am trying to work on time setting feature for different timezones. Hence I need a function to return current time in that timezone.
Time returned by Date.now() will be the same for any time zone, because it returns how many ms have passed since 01-01-1970
What you need is to calculate GMT offset for your desired time zone
var offset = new Date().getTimezoneOffset();
console.log(offset);
The time-zone offset is the difference, in minutes, between UTC and local time. Note that this means that the offset is positive if the local timezone is behind UTC and negative if it is ahead. For example, if your time zone is UTC+10 (Australian Eastern Standard Time), -600 will be returned. Daylight savings time prevents this value from being a constant even for a given locale
ECMAScript Dates are simply a time value that is an offset from 1970-01-01T00:00:00Z (the ECMAScript epoch, which is the same as the Java and UNIX epoch).
If a system's clock is accurately set to the current time, then Date.now() and new Date().getTime() for a particular instant will return exactly the same value regardless of the timezone offset of the host system. In practice there will however be minor variations due to clock inaccuracies and lack of syncrhonisation.
The host timezone offset comes from the host system and is only used for calculations involving local values, it's not an attribute of the Date itself.
If you want to get the time value for a particular date and time for a particular timezone offset, you can build a string that should be parsable by the built–in parser and use that. E.g. the Line Islands have an offset of +14:00 and don't observe daylight saving, so to get the time value for Christmas morning use a supported string format1 and the built–in parser:
// Christmas morning in Line Islands
let s = '2019-12-25T00:00:00+14:00';
// Get time value
let ms = Date.parse(s);
let d = new Date(ms);
let optsLocal = {weekday:'short', day:'numeric', month:'short', year:'numeric', hour:'numeric', hour12:false, minute:'numeric'};
let optsHK = Object.assign({},optsLocal,{timeZone:'Asia/Hong_Kong'});
let optsNY = Object.assign({},optsLocal,{timeZone:'America/New_York'});
let optsHW = Object.assign({},optsLocal,{timeZone:'Pacific/Honolulu'});
console.log('Start string: ' + s +
'\nTime value : ' + ms +
'\nLocal date : ' + d.toLocaleString('en-GB', optsLocal) +
'\nHong Kong : ' + d.toLocaleString('en-GB', optsHK) +
'\nNew York USA: ' + d.toLocaleString('en-GB', optsNY) +
'\nHawaii USA : ' + d.toLocaleString('en-GB', optsHW)
);
Where "supported string format" is one of the two formats specified in ECMA-262, also see Why does Date.parse give incorrect results?
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.
How we can add minutes to time, I want to add:
time = 21:36:13 and minutes 21:33
and want to get result 21:57:46
A JavaScript Date object stores time as the number of milliseconds since 1970/01/01 00:00:00 (in what should be UTC if the rest of your application is written properly). To add minutes and seconds, simply multiply te values to get the equivalent number of milliseconds, something like this: newDate = new Date(oldDate.getTime() + (((minutesToAdd * 60) + secondsToAdd) * 1000))
You should think about what you expect to happen during daylight saving time transitions. If the application is designed properly, the value in the Date object will be UTC, so the calculation above will always work correctly, but obviously the displayed value will be formatted as local time.
You may find a library such as Datejs useful.
What are you using to represent time? if you are using a native Date object, you can do something like this:
var addTime = function (baseDate, hours, minutes, seconds) {
return new Date(baseDate.getTime() + hours*3600000 + minutes*60000 + seconds*1000);
}
This is basically creating a new Date object adding a series of hours, minutes and seconds to the base Date provided (all of it in milliseconds). Here's the reference to work with Date objects.
You can use Date object with only taking interest in time. Here is your example:
function Foo()
{
time = new Date();
time.setHours(21);
time.setMinutes(36);
time.setSeconds(13);
time.setMinutes(time.getMinutes() + 21);
time.setSeconds(time.getSeconds() + 33);
alert(time.getHours() + ":" + time.getMinutes() + ":" + time.getSeconds());
}
Hope it helps :D
I have a function in which I am calculating the current user location time based on the Australian NSW timezone minus the local offset. So for example I want to compare an event starting time in Australian (NSW) local time vs my local time I am getting the correct value if I open the website on my localhost. However I am getting 1 hour different if I visit the website on the uploaded server (test environment). So if the correct time is 04:00 on localhost I am getting 05:00 on the test environment.
Here is my function:
var date = {
formatFullDate: function(date, gmtTimeOffset) {
var localDate = this.getLocalTimeFromAustraliaTime(date, gmtTimeOffset),
month = this.addZeroToFront(localDate.getMonth() + 1),
hour = this.addZeroToFront(localDate.getHours()),
minute = this.addZeroToFront(localDate.getMinutes());
return localDate.getDate() + '/' + month + '/' + localDate.getFullYear() + ' ' + hour + ':' + minute;
},
formatTime: function(date, gmtTimeOffset) {
var localDate = this.getLocalTimeFromAustraliaTime(date, gmtTimeOffset),
hour = this.addZeroToFront(localDate.getHours()),
minute = this.addZeroToFront(localDate.getMinutes());
return hour + ':' + minute;
},
addZeroToFront: function(whatever) {
if (whatever < 10) whatever = "0" + whatever;
return whatever;
},
getUTCtimeOffset: function() {
var date = new Date();
return date.getTimezoneOffset();
},
getLocalTimeFromAustraliaTime: function (date, gmtTimeOffset) {
var gmtTime = new Date(date.getTime() - gmtTimeOffset*1000),
localOffset = new Date().getTimezoneOffset(),
localDate = new Date(gmtTime - localOffset*60*1000);
return localDate;
}
}
Some general details for my specific case:
Aus/NSQ time zone: UTC/GMT +10 hours
Finnish timezone: UTC/GMT +3 hours
So there is 7 hours different between AUS/NSW and Finland and the result is correctly displayed on localhost but not on the test environment. I am not sure why there is 1 hour different between these 2 cases.
EDIT: 1
This is how I am displaying the current local time
var tr = $('<tr style="cursor:pointer; color: #000000" id="' + categoryId + '_' + raceNumber + '_nextRaceTr"/>')
.append($('<td/>')
.append($('<p/>')
.html(date.formatTime(new Date(value.time), value.timezoneOffset))))
Where as time and timezoneOffset are the JSON response.
P.S - Dont pay attention if I am missing enclosing brackets or any other syntax error. I have only copied a small piece of code just to show how I am displaying the time on HTML.
The JavaScript Date object is always influenced by the time zone settings of the environment where it is running. In most cases, that's the user's browser. Users of different time zones will get different results running your code.
In general, you should beware of any code that follows a pattern like this:
var adjustedDate = new Date(someOtherDate.getTime() - someOffset);
You might think you're cleverly adjusting the behavior of the Date object to a different time zone, but in reality you're changing the referenced point in time and leaving the time zone the same!
Also, consider where you have:
var localOffset = new Date().getTimezoneOffset();
You might think you're getting the time zone offset for the user, but actually you are just getting the current time zone offset for the user. Remember, new Date() initializes to the current moment in time. The moment you're working with might have a completely different offset, depending on if the user happens to be in a time zone with daylight saving time or not and whether it was in effect at that time.
As far as your code goes, it's a bit difficult to tell what you're after since you didn't give examples of your input. You might want to take a look at moment.js, which has most of the formatting functions you might be looking for.
BTW - I don't see anything in your code that would actually bind it to any of the Australian time zones.
I recommend that you convert all times to UTC and store in that format. When you display a time for a user, you can convert to their local time from UTC. Just make sure that you do all calculations/conversions on the same machine on which you are going to display the time (e.g. if you are displaying dates in a webpage, don't calculate the local time on the server, send down an epoch timestamp to the browser and then convert it to local time using JavaScript).
var d = new Date(1413409549000);
alert(d.toString());
How do I use a different time zone time in a JavaScript?
I already know how to get the current system time but I am confused how to display different time zone time. This one is displaying as an alert, but I need it as a usual displayer not as an alert.
function calcTime(city, offset) {
d = new Date();
utc = d.getTime() + (d.getTimezoneOffset() * 60000);
nd = new Date(utc + (3600000*offset));
return "The local time in " + city + " is " + nd.toLocaleString();
}
alert(calcTime('U.S.A', '-5.0'));
The "time" is absolute.
How you display the time (including time zone) is representational.
So the key thing to understand is that you DON'T want to modify the time VALUE - you just need to alter your FORMAT statement to use one or another time zone.
For example, this uses the Moment.js timezone plugin:
moment().tz("America/Los_Angeles").format("h:mm a")
Here is a great reference:
Stack Overflow 'Timezone' tag wiki