I am attempting to show the time using milliseconds. I'm using the toLocaleTimeString since it supports the locale.
var milliseconds = 10000;
var date = new Date(milliseconds);
console.log(date.toLocaleTimeString('en',milliseconds));
// expected result - 0:0:10 AM
// actual result - 5:30:10 AM
The result is not what I'm expected. How can get the expected result using toLocaleTimeString
The normal behaviour of the .toLocaleTimeString() method is to display the time in a string representation based on the local time zone of your environment, that's why you got a different result.
And you were passing a wrong argument milliseconds to it in:
date.toLocaleTimeString('en',milliseconds);
Actually the Date.prototype.toLocaleTimeString() method takes an options object as a second argument, where you can specify several options including the timeZone which specifies the desired time zone for the output.
So call it with {"timeZone": "UTC"} to display it in UTC, like this:
date.toLocaleTimeString('en',{"timeZone": "UTC"})
Demo:
var milliseconds = 10000;
var date = new Date(milliseconds);
console.log(date.toLocaleTimeString('en',{"timeZone": "UTC"}));
// expected result - 0:0:10 AM
// actual result - 5:30:10 AM
In var date = new Date(10000);, the "10000" unit is always relative to 1970-01-01 00:00:00 in UTC timezone (i.e. add 10000ms from it). Thus, the corresponding time is equivalent to 1970-01-01 00:00:10 UTC.
date.toLocaleTimeString('en') output the time in your system timezone, thus gives the difference you found.
One way to fix is to set date variable to system timezone by adding the timezone difference in milliseconds, as the following:
var date = new Date(10000 + new Date().getTimezoneOffset()*60000); (new Date().getTimezoneOffset() is timezone difference in minutes)
Related
I'm quite new (and confused) with time in JavaScript..
I currently have time data to work with, and they are in the format of DD-MMM-YYYY, meaning it would be 23-Feb-2021. This time is already in its own timezone, GMT-10. I'm trying to initialize it as GMT-10 so that I could get its appropriate epoch time.
I've done this:
date = new Date("23-Feb-2021") // This results in 2021-02-23T00:00:00.000Z
But what I'm trying to achieve is to get the time to be 2021-02-23T10:00:00.000Z, which I could then do a getTime() to get its epoch in ms. I understand I could probably hard code to +10 to the time I have, but the data I work with might vary so I'd like to figure a way to initialize the date with a specific timezone.
EDIT:
Here's an example of an outcome I'd want:
date = ("23-Feb-2021")
date = moment(date).format(); // 2021-02-23T00:00:00+00:00
date = date.replace("+00","+10");
date = new Date(msg.date); // 2021-02-22T14:00:00.000Z
date = date.getTime(); // 1614002400000 (2021-02-22T14:00:00.000Z)
In the end, 2021-02-22T14:00:00.000Z is what I'm trying to get, without having to iterate it a bunch of times like above and adding +10
You can add the timezone offset to your input string, and use an explicit string format to parse it:
let date = "23-Feb-2021"
date = moment(date + "-10:00", "D-MMM-YYYYZ")
console.log(date.format()) // 2021-02-23T11:00:00+01:00 (if local is GMT+1)
console.log(date.utc().format()) // 2021-02-23T10:00:00+00:00
It seems you're already using moment.js, so add moment–timezone so you can parse timestamps in whatever IANA timezone you want. You can either choose a location with the offset rules you want (e.g. Pacific/Honolulu or Pacific/Tahiti for -10) or just a fixed offset like etc/GMT+10.
You can then format the value in any timezone, as UTC, or as a time value, e.g.
// Timestamp
let d = "23-Feb-2021";
// Parse in specific IANA timezone
let m = moment.tz(d, 'D-MMM-YYYY', 'Pacific/Honolulu');
// Trigger UTC mode
m.utc()
// Show result
console.log(m.format())
// Get time value (ms since epoch)
console.log(m.valueOf());
// Parse using generic timezone/fixed offset
let g = moment.tz(d, 'D-MMM-YYYY', 'etc/GMT+10');
console.log(g.utc().format());
// Display timestamp for another timezone
console.log(moment.tz(g, 'Asia/Riyadh').format());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data-10-year-range.js"></script>
Note that for fixed offset timezones like etc/GMT+10, the sign is the opposite of the common offset (e.g. etc/GMT+10 is UTC-10) to be consistent with POSIX notation. However, moment.tz only has limited POSIX support in that it only recognises one hour offsets, not the full POSIX timezone notation, so you can't do say "etc/GMT-530" instead of Asia/Kolkata.
I'm trying to get the same value as 1502755200000 using momentjs
console.log(Date.UTC(2017, (8-1), 15));//1502755200000
var newDate = moment();
newDate.set('year', 2017);
newDate.set('month', 7); // April
newDate.set('date', 15);
console.log(newDate.format('X'));//1502818350
However when I try to get the miliseconds I get 1502818350 Any idea how to get the exact same timestamp as above?
Here is the fiddle https://jsfiddle.net/cdvzoezb/1/
Firstly, .format('X') gives you the unix timestamp in seconds, not milliseconds.
To get milliseconds, you must use .format('x') (lowercase x).
Secondly, when you use moment(), it gives you a moment date object at your current local time, not UTC time. So when you modify it with .set('date', 15) etc, you're setting it to 15 April 2017 in your local time. This is why you're getting the vastly different value.
To get a moment date object for current UTC time, use moment.utc().
Thirdly, the Date object you created will be at time 00:00:00.000, while the moment object will be for current time. So when you set the year/month/date, time still remains at what it was when you created the object. You need to set the moment object's time to 00:00:00.000.
This can be done with the .startOf('day') function.
In conclusion:
console.log(Date.UTC(2017, (8-1), 15)); //1502755200000
var newDate = moment.utc();
newDate.set('year', 2017);
newDate.set('month', 7);
newDate.set('date', 15);
newDate.startOf('day');
console.log(newDate.format('x')); //1502755200000
Or, much shorter:
var newDate = moment.utc('2017-07-15 00:00:00.000');
Well you can simply create a moment object out of a Date instance and then using the utc() to convert the timestamp to UTC. After that, we can use moments method format() to get milliseconds using the x display option like so:
console.log("==============");
console.log(Date.UTC(2017, (8-1), 15));
var base = Date.UTC(2017, (8-1), 15)
var newDate = moment(base);
console.log('a', newDate.utc().format('x')); //1502755200000
I'm passing back a UTC date from the server, and I need some JS to find the difference in seconds between "now" and the date passed back from the server.
I'm currently trying moment, with something like
var lastUpdatedDate = moment(utcStringFromServer);
var currentDate = moment();
var diff = currentDate - lastUpdatedDate;
problem is, this gives a very invalid answer, because UTC is coming down from the server, and creating a new moment() makes it local. How can I do a calculation with respect to full UTC so it's agnostic of any local timing?
What you aren't quite understanding is that Dates are stored as the number of milliseconds since midnight, Jan 1, 1970 in UTC time. When determining the date/time in the local timezone of the browser, it first works out what the date/time would be in UTC time, then adds/subtracts the local timezone offset.
When you turn a Date back into a number, using +dateVar or dateVar.valueOf() or similar, it is back to the number of milliseconds since 01/01/1970T00:00:00Z.
The nice part about this is that whenever you serialise dates in UTC (either as a number, or as ISO String format), when it gets automatically converted to local time by Javascript's Date object, it is exactly the same point in time as the original value, just represented in local time.
So in your case, when you convert a local date to a number, you get a value of milliseconds in UTC that you are subtracting a value in milliseconds in UTC from. The result will be the number of milliseconds that has passed between the time from the server and the time the new Date() call is made.
Where it gets tricky is when you want a timestamp from the server to not be translated to local time, because you want to show the hours and minutes the same regardless of timezone. But that is not what you need in this case.
Try this way hope it may help:
var lastUpdatedDate = moment(utcStringFromServer);
var date = Date.UTC();
var currentDate = moment(date);
var diff = currentDate - lastUpdatedDate;
I'm assuming that utcStringFromServer is something like this:
Fri, 19 Aug 2016 04:27:27 GMT
If that's the case, you don't really need Moment.js at all. If you pass that string to Date.parse(), it'll return the number of milliseconds since Jan. 1, 1970. You can then use the .toISOString() method to get the same info about right now (converted to UTC) and parse it the same way to get milliseconds since 1970. Then, you can subtract the former from the latter and divide it by 1000 to convert back to seconds.
All in all, it would look something like this:
var lastUpdatedDate = Date.parse(utcStringFromServer);
var currentDate = Date.parse((new Date()).toISOString())
var diff = (currentDate - lastUpdatedDate) / 1000.0; // Convert from milliseconds
on my UI, I try to display a date based on a specific timezone. In this example, I will use Americas/New_York as the timezone. This is how I did it.
$scope.getStartTime = function(){
var date = new Date();
return moment(date).tz("Americas/New_York").format('YYYY-MM-DD HH:mm:ss');
};
Afterwards, I want to send this data and send it to my server. In my server however, I want it so that it is always serialized into UTC time instead of in the New York Timezone (EST).
For example, if the time was 12:00 P.M. in New York, then the time would be serialized to 4:00 P.M. in UTC time before it was sent to the backend. This was my attempt:
var date = getStartTime();
....
// Display the date in the UI
....
$scope.revertStartTime(date);
$scope.revertStartTime = function(startTime) {
console.log("Start time: ", startTime);
console.log("Moment: ", moment(startTime).format());
console.log("Converted to utc time: ", moment().utc(startTime).format());
return moment.utc(startTime).format("YYYY-MM-DD'T'HH:mm:ss.SSSZ");
}
I tried to revert the start time by using the moment().utc() function and hoped that the date would change to a UTC based date but unfortunately it keeps turning my date into the localized date instead of UTC date and I'm not sure why. Any help would be appreciated. Thanks!
Edit:
Tried to follow the below method and here is what I did:
$scope.getStartTime = function(){
var date = new Date();
var startTime = new moment(date).tz($rootScope.userinfo.timeZone).format('YYYY-MM-DD HH:mm:ss');
$rootScope.offset = moment().utcOffset(startTime);
console.log("offset: ", $rootScope.offset);
return startTime;
};
$scope.revertStartTime = function(startTime) {
console.log("User Selected Time: ", moment().utcOffset(startTime).format('YYYY-MM-DD HH:mm:ss'));
return moment().utcOffset(startTime).format('YYYY-MM-DD HH:mm:ss');
}
But all I get is an error saying that revertStartTime returns an Invalid Date.
A few things:
Hoping it's a typo, but just to point out, the zone ID is America/New_York, not Americas/New_York.
You can pass a value as moment.utc(foo), or moment(foo).utc(), but not moment().utc(foo). The difference is that one interprets the input as UTC and stays in UTC mode, while they other just switches to UTC mode. You can also think of this as "converting to UTC", but really the underlying timestamp value doesn't change.
Yes, you can switch to UTC mode and call format, but you can also just call .toISOString() regardless of what mode you're in. That's already in the ISO format you're looking for.
Note that if you start with a unique point in time, and you end with converting to UTC, no amount of switching time zones or offsets in the middle will change the result. In other words, these are all equivalent:
moment().toISOString()
moment.utc().toISOString()
moment(new Date()).toISOString()
moment.utc(new Date()).toISOString()
moment(new Date()).utc().toISOString()
moment().tz('America/New_York').toISOString()
moment.tz('America/New_York').toISOString()
moment().utcOffset(1234).toISOString()
moment.utc().format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]')
moment().utc().format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]')
Only the last two even need to be in UTC mode, because the format function would produce different output if in local mode or in a particular time zone.
In order to accomplish this you'd want to use .utcOffset(). It is the preferred method as of Moment 2.9.0. This function uses the real offset from UTC, not the reverse offset (e.g., -240 for New York during DST). Offset strings like "+0400" work the same as before:
// always "2013-05-23 00:55"
moment(1369266934311).utcOffset(60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).utcOffset('+0100').format('YYYY-MM-DD HH:mm')
The older .zone() as a setter was deprecated in Moment.js 2.9.0. It accepted a string containing a timezone identifier (e.g., "-0400" or "-04:00" for -4 hours) or a number representing minutes behind UTC (e.g., 240 for New York during DST).
// always "2013-05-23 00:55"
moment(1369266934311).zone(-60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).zone('+0100').format('YYYY-MM-DD HH:mm')
To work with named timezones instead of numeric offsets, include Moment Timezone and use .tz() instead:
// determines the correct offset for America/Phoenix at the given moment
// always "2013-05-22 16:55"
moment(1369266934311).tz('America/Phoenix').format('YYYY-MM-DD HH:mm')
I am storing a UTC date time in a SharePoint list and fetching it's value in c#, converting into milliseconds from 1 Jan 1970 and passing those milliseconds to JavaScript to get date object.
But when I create a date object, its value remains same as UTC date, I want that value to be in users local time zone and reflecting their daylight saving status.
You can use the TimezoneOffset in javascript, check the following code,
var d = new Date()
var n = d.getTimezoneOffset();
In this way you can calculate the time as you want.
Let me know if you need more details :)
When you create a new date in Javascript i assume you create it on the client side / client machine:
var d = new Date(millis);
The notion that the value remains the same in UTC no matter where you construct the Date object is correct, it's only a matter of how you display the date: in UTC or in the user's local timezone:
You can run this code to see the difference:
var local = date.toDateString() + ' ' + date.toTimeString();
var utc = date.toUTCString();
alert(local);
alert(utc);
Note that the value of millis is the milliseconds passed since 1970-01-01 00:00:00 UTC no matter where you are in this world. Calling new Date().getTime() on 2 opposite sides of the globe should return the same number of milliseconds.