I am getting time from server as "19:30" but it needs to be converted to "Pacific/Easter time zone.
I have tried things like
let t = "19:30:00";
let utc = moment.utc(t);
let z = moment(utc).utcOffset(-300).format('HH:mm');
But I am going wrong somewhere.
I have seen in my dev app version that it is being converted to 14:30 which is like -5:00 hours.
So, how do I get similar result for this?
Here's something else that I tried
let t = "19:30:00";
let tt = moment.tz(t, "UTC");
let nt = tt.clone().tz("Pacific/Easter");
and I am getting nt as "19:30:00" also. so , it's not converting at all
this is the one that seems to be working.
but it's not showing the correct result
let t = "19:30:00";
let utc = moment.utc(t, 'HH:mm:ss');
let z = utc.tz('Pacific/Easter').format('HH:mm');
console.log(z);
it should show the result as 19:30 -5 hours which should be 14:30,
but it shows the result as 13:30. so, anyone knows why this is happening??
You have to use tz() function from moment-timezone.
Since your input (19:30:00) is not in ISO 8601/RFC 2822 recognized format you have to parse it using moment.utc(String, String) passing 'HH:mm:ss' as second parameter.
Then you can convert your moment object to given timezone using tz().
Please note that, even if you are providing only time, you are creating a moment object that includes date. As Default section of the docs states:
You can create a moment object specifying only some of the units, and the rest will be defaulted to the current day, month or year, or 0 for hours, minutes, seconds and milliseconds.
'Pacific/Easter' uses Daylight Saving Time (see full info here) so the conversion depends on date and DST.
If you want to use fixed offset (no DST), you can use utcOffset():
Setting the UTC offset by supplying minutes. Note that once you set an offset, it's fixed and won't change on its own (i.e there are no DST rules).
If the input is less than 16 and greater than -16, it will interpret your input as hours instead.
Here a live sample:
let t = "19:30:00";
let utc = moment.utc(t, 'HH:mm:ss');
let z = utc.tz('Pacific/Easter').format('HH:mm');
console.log(z);
// DST
console.log( moment.utc('2018-09-01 19:30:00').tz('Pacific/Easter').format('HH:mm') );
// No DST
console.log( moment.utc('2018-06-01 19:30:00').tz('Pacific/Easter').format('HH:mm') );
// Fixed offset
console.log( moment.utc('19:30:00', 'HH:mm:ss').utcOffset(-5).format('HH:mm') );
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.17/moment-timezone-with-data-2012-2022.min.js"></script>
You need moment-timezone to get this working.
var newYork = moment.tz("2014-06-01 12:00", "America/New_York");
var losAngeles = newYork.clone().tz("America/Los_Angeles");
Related
Let us consider following example
const date = new Date(0);
date.setSeconds(60*60*24-1);
console.log(date.toISOString().substr(11, 8));
outputs
23:59:59
I am searching for elegant way to have
const date = new Date(0);
date.setSeconds(60*60*24+1);
console.log(date.toISOString().substr(11, 8));
output
24:00:01
instead of
00:00:01
by elegant I mean without implementing my own Date object... Maybe it would be possible to set a custom length of the day? Increase from 24h to 99h?
You can set the hour cycle in the hour cycle option (hc) and the language parameter available in the Intl.DateTimeFormat constructor and toLocaleTimeString, e.g.
console.log(
new Date(2020,7,1,0,5).toLocaleTimeString('en-CA-u-hc-h24')
);
Whether the hour cycle setting "works" or not seems to depend on the language chosen and how it's set, so maybe not that reliable. Test thoroughly in different implementations.
Many thanks to #RobG who understood my question. The hour cycle is what I needed, unfortunately according to the docs it is restricted to values h11, h12, h23, h24 and I would need h99 which is not available.
Eventually I had to make my own ugly solution as it appears such a use case was not predicted in the standard, so here it is
function unfortunatelyWeHadToWriteIt(nbsec) {
// compute numerical values
const nbhours = Math.floor(nbsec/(60*60));
const nbminutes = Math.floor((nbsec - nbhours*60*60)/60)
const nbseconds = Math.floor(nbsec - nbhours*60*60 - nbminutes*60);
// convert them to padded strings
const hours = String(nbhours).padStart(2, '0');
const minutes = String(nbminutes).padStart(2, '0');
const seconds = String(nbseconds).padStart(2, '0');
// format
return `${hours}:${minutes}:${seconds}`;
}
so let's compare it to the Date formatting
// 27 hours, 13 minutes and 6 seconds
const nbsec = 60*60*27+13*60+6;
what Date will give us
const date = new Date(0);
date.setSeconds(nbsec);
console.log(date.toISOString().substr(11, 8));
outputs 03:13:06, it overflows at value of 24 hours. Now let's apply the unfortunatelyWeHadToWriteIt function
console.log(unfortunatelyWeHadToWriteIt(nbsec))
outputs 27:13:06 which does not overflow.
Just to give you guys some context, I am playing games and displaying the playtime. It is more convenient to show number of hours than number of days of gameplay...
I have a date selector and a time selector, and I'm trying to figure out how I can combine their outputs to make a single ISOString so that I can use with the google calendar API.
Here's what I've tried:
//date = 2022-05-18
//time = 14:22
const apptdate = new Date(date)
const timeSplit = time.split(':')
apptDate.setHours(timeSplit[0])
apptDate.setMinutes(timeSplit[1])
What I notice is when I console.log(apptdate) this is the output I get: 2022-05-17T18:22:00.000Z
I'm not sure why it changes the day from May 18 to May 17, and the time from 14:22 to 18:22.
Does anyone have a solution for this? Or even a completely different way of combining date and time to one string (other than using a datetime-local input format, I want to keep the date and time separate in my database).
"2022-05-18" is parsed as UTC but apptDate.setHours(timeSplit[0]) sets the local hour. So if the host has a negative offset, the local date is 17 May and the time is set to the local hour on 17 May, not UTC hour on 18 May.
Instead use setUTCHours and setUTCMinutes.
let date = '2022-05-18';
let time = '14:22';
let apptDate = new Date(date);
let timeSplit = time.split(':');
apptDate.setUTCHours(timeSplit[0]);
apptDate.setUTCMinutes(timeSplit[1]);
// 2022-05-18T14:22:00.000Z
console.log(apptDate.toISOString());
PS. There was also a typo: let apptdate then later apptDate.
I tried looking for an answer but could not find a particular answer which does with Timezone offset. Hence, posting the same really sorry if there are any answer present already.
I have a requirement in the project where I need to convert the time to UTC or GMT based on the time specified by the user and timezone offset value provided by the user. Basically, the user provides his local time and timezone offset value according to his local time. I need to convert that into UTC/GMT time.
I am using the Node.js and following is the data which is available in the Node.js Backend:
Time: 2020-11-05T15:00:00.000Z
Timezone offset value: +02:00
As the timezone offset value is +02:00 I need to subtract it from the time to convert it into the UTC format. so I can get the time as: 2020-11-05T13:00:00.000Z. I using the moment-js as well. Can someone please help me how can achieve this using the Node.js or using the Moment.js?
If the offset takes daylight saving time into account you should be able to do:
const the_date = '2020-11-05T15:00:00.000';
const offset = 2;
const utc_time = moment.utc(the_date).subtract(offset, 'hours');
It's not clear which way you are trying to convert. If you are converting from UTC to a fixed offset, you can use the utcOffset function, like this:
const m = moment.utc('2020-11-05T15:00:00.000Z').utcOffset('+02:00');
m.format(); //=> "2020-11-05T17:00:00+02:00"
Or - if you were trying to convert from +02:00, then you would include that offset in the input instead of the Z (Z means UTC). You would then just call the utc function, like this:
const m = moment('2020-11-05T15:00:00.000+02:00').utc();
m.format(); //=> "2020-11-05T13:00:00Z"
However you should be aware that an offset is not the same as a time zone. A time zone can have more than one offset, one of which will apply at a given point in time. Those offsets can change due to daylight saving time and for changes in standard time. Thus, asking a user to pick "his timezone offset value according to his local time" is problematic - as you may be applying that offset to the wrong point in time. See "Time Zone != Offset" in the timezone tag wiki for further details.
You should also understand Moment's project status, and possibly choose a different library.
After some more research and trying, I was able to convert it. Posting the answer in addition to Christians response (https://stackoverflow.com/a/64701083/7584240) so if anyone is looking for the answer they will have another option:
var moment = require('moment');
var time = "2020-11-05T15:00:00.000Z";
var timeoffset = "+02:00";
time = moment.utc(time).local().format('YYYY-MM-DDTHH:mm:SS.000');
time = moment(time, 'YYYY-MM-DDTHH:mm:ss.000').subtract(timeoffset).format('YYYY-MM-DDTHH:mm:ss.000') + 'Z';
I am having a hard time to calculate the duration (difference in time) of two timestamps.
There is a timestamp I receive from the server in the following format:
start # => "2017-05-31 06:30:10 UTC"
(This is basically rubys DateTime.now.utc)
I want to see how many hours have passed since then until as of right now.
The calculation happens in the angularjs frontend only.
I tried the following:
var start = moment("2017-05-31 06:30:10 UTC", "YYYY-MM-DD HH:mm:ss Z").utc();
var now = moment.utc();
var duration = moment.duration(now.diff(start));
console.log(duration.asHours()); #=> 2 hours even though the point in time was just a couple of minutes ago.
Unfortunately this would always use my devices local time and produce a time that's a few hours off the actual time.
So my approach was to either convert all times to UTC and let momentjs handle all this.
What am I missing?
Since your input is UTC you can use moment.utc method.
By default, moment parses and displays in local time.
If you want to parse or display a moment in UTC, you can use moment.utc() instead of moment().
Here a live example:
var start = moment.utc("2017-05-31 06:30:10 UTC", "YYYY-MM-DD HH:mm:ss Z");
var now = moment.utc();
var duration = moment.duration(now.diff(start));
console.log(duration.asHours());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
In your code sample, you are parsing the input string as local date and then converting it to UTC (with utc() method).
See Local vs UTC vs Offset guide to get more info.
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.