day.js is not converting UTC to local time - javascript

I am running into an issue trying to convert momentjs over to day.js.
In moment, I converted utc to local time via moment.utc('2020-04-22T14:56:09.388842').local().format('MM/DD/YY h:mm A') which returns 04/22/20 9:56 AM.
When I convert with day.js via dayjs.utc('2020-04-22T14:56:09.388842').local().format('MM/DD/YY h:mm A'), I get 04/22/20 2:56 PM; I am importing the utc plugin.
I put an example in jsfiddle here: https://jsfiddle.net/obdg74sp/2/
Has anyone ran into this issue and if you did, how did you resolve it?
Thank you.

Both Moment and Day.js only support millisecond precision, however they differ in behavior when more than 3 decimals are passed in for parsing.
Moment will ignore the extra decimals, but will still use its own parsing logic
Day.js reverts to the Date.parse function
In the latter case, there is no UTC awareness, so you get local time, despite being passed through the dayjs.utc function.
This was brought up in Day.js issue #544, and closed by the owner of that library without any change.
You can work around this by trimming the string to truncate the extra decimals.
dayjs.utc('2020-04-22T14:56:09.388842'.substring(0, 23))
Then it will parse UTC correctly, and the rest of your logic will work accordingly.
(Alternatively, you could append a Z to the string)

I used:
dayjs(date).utc('z').local().tz(ianaCode).format('ddd, MMM D, H:mm z')
Example:
dayjs('2021-06-08T24:00:00').utc('z').local().tz('America/Detroit').format('ddd, MMM D, H:mm z')

Related

Converting a date, time and offset into an ISO8601 DateTime using moment.js and moment timezone

I am processing some itinerary data where the times and dates are all provided in the local timezone. I am adding this data to a database where I'd like to store all of the dates in UTC, with the proper timezone offset. I'm trying to process these dates with moment.js.
The input string for date/time is formatted like this 2020-07-12 13:00 and the timezone is in this format Europe/Amsterdam.
I want to end up with a string like:
2020-07-12T11:00:00+02:00
The trouble I'm having, is that moment converts my input time to either local time or utc if I use the .utc() method.
This code is getting me the correct result, but I don't understand why and I'm not sure if I can rely on its accuracy:
var offset = moment.tz(`Europe/Amsterdam`).utcOffset();
var m = moment(`2020-07-12 13:00`, 'YYYY-MM-DD HH:mm').utc().subtract(240 + offset + offset, 'minutes').utcOffset(offset); // (240 is my own UTC offset)
How can I simply input a date, time and timezone and end up with a correct ISO8601 DateTime?
If you are already using Moment and Moment-TimeZone in your app, then you can simply do the following:
const m = moment.tz('2020-07-12 13:00', 'YYYY-MM-DD HH:mm', 'Europe/Amsterdam');
m.format() //=> "2020-07-12T13:00:00+02:00"
However, the Moment team recommends using Luxon for new development. The equivalent is:
const dt = luxon.DateTime.fromFormat('2020-07-12 13:00', 'yyyy-MM-dd HH:mm', { zone: 'Europe/Amsterdam'});
dt.toISO() //=> "2020-07-12T13:00:00.000+02:00"
The only difference being that milliseconds are included. You can use a different formatting function if you prefer a different output.
The main benefit of Luxon is that it uses the built-in time zone functionality provided by the ECMAScript Internationalization API, whereas Moment-Timezone bundles its own time zone data - which can be quite large.
Also, note that in your question by asking for 2020-07-12T11:00:00+02:00 you seem to be misunderstanding the ISO 8601 format. In that format, the time presented is the local time. Thus, it should be 13:00, not 11:00. The +02:00 means, "this was the offset from UTC for this local time". (It doesn't mean that you apply the offset to get the local time.)

how to get only time from date in ISO formate

How to extract only time from the date which is present in ISO format?
I tried this:
var d = new Date('1970-01-15T03:32:12.000Z'); //ISO-8601 formatted date returned from server
console.log(d.getTime());// 1222332000
Expected op is : 03:32:12
Since your server returns an ISO-8601 formatted date which has a predefined format, you can convert it to ISO string using toISOString() and then get the substring of the time value:
var d = new Date('1970-01-15T03:32:12.000Z');
console.log(d.toISOString().substr(11,8));
Date.getTime() returns the time in UNIX epoch format.
https://en.wikipedia.org/wiki/Unix_time
To access only the parameters you are interested in, you can use Date.getMinutes(), Date.getMinutes(), etc. See docs on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
Note: Do not forget to spend one thought on time zones when you work with Date
's time, especially when your app runs in different regions.
You have to manually build the time string using Date.prototype methods: getHours, getMinutes and getSeconds
Or use moment.js library.
Date.getTime() gives you the unix timestamp, which is the number of seconds since january 1st 1970;
The getTime() method returns the numeric value corresponding to the time for the specified date according to universal time.
from MDN
You need to format the date yourself, either by concatenating the output of the Date.getHours(), Date.getMinutes() and Date.getSeconds() methods, or by using one of the predefined formatting functions, like Date.toTimeString(). Checkout the docs to pick your choice.
You can use getHours(),getMinutes() and getSecondes(). Then you can use it with strings or objects.
Try the following:
d.toTimeString().split(' ')[0]
You can use moment.js to parse whatever format you like.
If you think moment.js is too big, there's another library call dayjs. The same fashion API but just 2KB. (Unfortunately, you can't do UTC time with dayjs yet.)
Update: Thanks kun for notifying the updates. You can now use UTC with dayjs plugin since v1.8.9.
var d = new Date('1970-01-15T03:32:12.000Z');
console.log(moment(d).utc().format('HH:mm:ss'));
dayjs.extend(dayjs_plugin_utc)
console.log(dayjs(d).utc().format('HH:mm:ss'));
<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/dayjs/1.8.9/dayjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.8.9/plugin/utc.js"></script>

Format a date with MomentJS, without local time adjustment

I want to display a unix timestamp (which is in UTC) as a formatted date.
I also want to keep it in the UTC timezone (so no change to the hours based on TZ). How can I do this?
Example:
moment(unix_timestamp).format('MMMM D, YYYY - H:mm:SS.SSSS') converts the output into the computer's local time.
Moment Docs:
Found this section in the docs, but none of the options seem to work:
https://momentjs.com/guides/#/parsing/local-utc-zone/
As far as documentation states:
Note that if you use moment() or moment.utc() to parse a date with a specified offset, the date will be converted from that offset to either local or UTC:
moment('2016-01-01T00:00:00+02:00').format() //converted to local
moment.utc('2016-01-01T00:00:00+02:00').format() //treated as UTC

moment js, converting EST string to UTC

I'm a new developer and I have been stuck on this for a while, how would I convert the following date to it's UTC version (no utc prefix/suffix needed) in moment JS?
05/03/2016 16:00
I tried:
var b = "05/03/2016 16:00";
moment.utc(b).format();
"2016-05-03T16:00:00Z"
I would like the final result to be exactly as b, but its UTC equivalent. What am I missing?
You're missing the input format and the output format.
Without an input format, your date could be interpreted as either May 3rd, or March 5th, depending on the culture.
Without an output format, moment has no way to know what kind of string you want, so it defaults to the full ISO8601 extended format.
You're also missing the conversion. If the input is local time and you want UTC, then you should parse it with moment(...) then convert it to UTC with the .utc() function.
In summary:
moment(b, 'MM/DD/YYYY HH:mm').utc().format('MM/DD/YYYY HH:mm')
Also note that it's converting from the local time where the code is running. in your question you asked about EST. If your local time zone is something else, then EST will not apply to the above. You would instead need to use the moment-timezone add-on to do the following:
moment(b, 'MM/DD/YYYY HH:mm', 'America/New_York').utc().format('MM/DD/YYYY HH:mm')
moment(b).utc();
Will change it to a utc time, you might still need to add parameters to format() to make sure it displays the way you originally wrote it.
moment(b).utc().format("MM/DD/YYYY HH:mm");

Format date in a specific timezone

I'm using Moment.js to parse and format dates in my web app. As part of a JSON object, my backend server sends dates as a number of milliseconds from the UTC epoch (Unix offset).
Parsing dates in a specific timezone is easy -- just append the RFC 822 timezone identifier to the end of the string before parsing:
// response varies according to your timezone
const m1 = moment('3/11/2012 13:00').utc().format("MM/DD HH:mm")
// problem solved, always "03/11 17:00"
const m2 = moment('3/11/2012 13:00 -0400').utc().format("MM/DD HH:mm")
console.log({ m1, m2 })
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
But how do I format a date in a specifc timezone?
I want consistent results regardless of the browser's current time, but I don't want to display dates in UTC.
As pointed out in Manto's answer, .utcOffset() 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')
A couple of answers already mention that moment-timezone is the way to go with named timezone. I just want to clarify something about this library that was pretty confusing to me. There is a difference between these two statements:
moment.tz(date, format, timezone)
moment(date, format).tz(timezone)
Assuming that a timezone is not specified in the date passed in:
The first code takes in the date and assumes the timezone is the one passed in.
The second one will take date, assume the timezone from the browser and then change the time and timezone according to the timezone passed in.
Example:
moment.tz('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss', 'UTC').format() // "2018-07-17T19:00:00Z"
moment('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss').tz('UTC').format() // "2018-07-18T00:00:00Z"
My timezone is +5 from utc. So in the first case it does not change and it sets the date and time to have utc timezone.
In the second case, it assumes the date passed in is in -5, then turns it into UTC, and that's why it spits out the date "2018-07-18T00:00:00Z"
NOTE: The format parameter is really important. If omitted moment might fall back to the Date class which can unpredictable behaviors
Assuming the timezone is specified in the date passed in:
In this case they both behave equally
Even though now I understand why it works that way, I thought this was a pretty confusing feature and worth explaining.
Use moment-timezone
moment(date).tz('Europe/Berlin').format(format)
Before being able to access a particular timezone, you will need to load it like so (or using alternative methods described here)
moment.tz.add('Europe/Berlin|CET CEST CEMT|-10 -20 -30')
.zone() has been deprecated, and you should use utcOffset instead:
// for a timezone that is +7 UTC hours
moment(1369266934311).utcOffset(420).format('YYYY-MM-DD HH:mm')
I was having the same issue with Moment.js. I've installed moment-timezone, but the issue wasn't resolved. Then, I did just what here it's exposed, set the timezone and it works like a charm:
moment(new Date({your_date})).zone("+08:00")
Thanks a lot!
Just came acreoss this, and since I had the same issue, I'd just post the results I came up with
when parsing, you could update the offset (ie I am parsing a data (1.1.2014) and I only want the date, 1st Jan 2014. On GMT+1 I'd get 31.12.2013. So I offset the value first.
moment(moment.utc('1.1.2014').format());
Well, came in handy for me to support across timezones
B
If you pass the timestamp as the parameter to moment() (e.g if the timezone is Asia/Hong_kong which is +08:00), what I do is:
const localDateTime = moment((item.createdAt.seconds + 8 * 3600) * 1000).format('YYYY-MM-DD HH:mm:ss');
You can Try this ,
Here you can get the date based on the Client Timezone (Browser).
moment(new Date().getTime()).zone(new Date().toString().match(/([-\+][0-9]+)\s/)[1]).format('YYYY-MM-DD HH:mm:ss')
The regex basically gets you the offset value.
Cheers!!

Categories