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!!
Related
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.)
I have a date I want to convert based on their timezone.
For example, I want to set it in EST time (America/New_York)
2019-04-24 12:00:00
and if the user comes across the site from America/Los_Angeles, it will appear:
2019-04-24 09:00:00
I need to be able to return the hour, so in that example: 9.
I tried using https://github.com/iansinnott/jstz to determine their timezone and https://moment.github.io/luxon in hopes of handling the conversion w/o any luck.
I was testing by changing the timezone on my computer w/o any luck.
It sounds like you're asking to convert from a specific time zone to the user's local time zone (whatever it may be). You do not need time zone detection for that, but at present you do need a library. (Answers that suggest using toLocaleString with a time zone parameter are incorrect, as that function converts to a specific time zone, but cannot go the other direction.)
Since you mentioned Luxon, I'll provide a Luxon specific answer:
luxon.DateTime.fromFormat('2019-04-24 12:00:00', // the input string
'yyyy-MM-dd HH:mm:ss', // the format of the input string
{ zone: 'America/New_York'}) // the time zone of the input
.toLocal() // convert to the user's local time
.toFormat('yyyy-MM-dd HH:mm:ss') // return a string in the same format
//=> "2019-04-24 09:00:00"
This capability is also provided by other libraries, such as date-fns-timezone, js-Joda, or Moment-Timezone, but it is not yet something built in to JavaScript.
Converting date based on the time can be done like this. reference convert date to another time zone example snippet is under.
var usaTime = new Date().toLocaleString("en-US", {timeZone: "America/New_York"});
usaTime = new Date(usaTime);
console.log('USA time: '+usaTime.toLocaleString())
var usaTime = new Date().toLocaleString("en-US", {timeZone: "America/Los_Angeles"});
usaTime = new Date(usaTime);
console.log('USA time: '+usaTime.toLocaleString())
You could keep a list of timzeone identifiers and a list of their corresponding +/- number of hours with respect to your local time (which is returned by your time function).
Once you have a user's time zone, and you have extracted the current hour from the local timestamp simply look up the timezone in your list and use it's index to access the second list to find how many hours to add or subtract from the users time.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString
var date = new Date(Date.UTC(2012, 11, 12, 3, 0, 0));
// toLocaleString() without arguments depends on the implementation,
// the default locale, and the default time zone
console.log(date.toLocaleString());
// → "12/11/2012, 7:00:00 PM" if run in en-US locale with time zone America/Los_Angeles
Or you can use getYear, getMonth, getDate, getHours, getMinutes, getSeconds to format your own representation of the date. These methods all return values according to the user's local timezone.
I think the question may need more clarification - my first impression was you refer to a date-time that you already have and serve from the server. Doesn't this problem boil down to the Date object being "user-timezone-aware"? or not? But it is (some methods are, to be exact)
Your date/time is 2019-04-24 12:00:00 EDT (i assume P.M.)
This means the Unix timestamp of this in milliseconds is 1556121600000
(i assume daylight is on for April so not pure EST but EDT and an offset of UTC-4:00)
When you call
console.log(new Date(1556121600000).getHours())
doesn't this return 9 as you suggest, for Javascript executed on a browser from America/Los_Angeles with PDT timezone?
As suggested at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getHours :
The getHours() method returns the hour for the specified date,
according to local time.
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
I have utc date 2017-04-22T21:03:54 (local date is 2017-04-23 00:03:54, offset +3)
I would like to get data from server for 1 day. For this example, local day is:
start: 2017-04-23 00:00:00
end: 2017-04-23 23:59:59
And UTC params for server:
start: 2017-04-22 21:00:00
end: 2017-04-23 20:59:59
How I can receive this dates with moment.js? Local offset may be different
I try:
moment.utc(startTime).format() // 2017-04-22T21:03:54Z, but I need 2017-04-22T21:00:00Z
// for example, if local timezone will be +6, I need 2017-04-22T18:00:00Z
(Putting my comments as answer)
The representation of datetimes in a text encoded transport/protocol (as HTTP) should follow ISO-8601. The time portion should include a timezone designator (for UTC time this is the simple Z, see link). These convention removes any ambiguity between client and server about what moment does the time literal represent.
Back ends should store times in UTC:
This removes any ambiguity when the database moves (failover to standby in different timezone, move of server to new location from east coast to west coats etc).
It removes any ambiguity for literals that fall into the DST time overlaps.
It removes any ambiguity from rushed legislative changes modifying timezones (of which several occur every few years)
Now that being said, if you need to convert an UTC time to local time in JavaScript/Node with MomentJS, use Moment's local().
I have utc date 2017-04-22T21:03:54
A date string without a time zone is treated as local (except for ISO 8601 date-only forms, which ECMAScript treats as UTC, contrary to ISO 8601). If you want to treat a string like "2017-04-22 21:00:00" as UTC then you have to tell the parser (in moment.js you can use the utc method).
You should also always tell the parser the format it's trying to parse, otherwise you're hoping it guesses correctly. If utc is used, moment uses offset +0000 by default (its "UTC mode" * ), not the local offset. If you want the host offset, you can use the local method or convert to a Date object and use built-in methods.
var s = '2017-04-22 21:00:00';
var format = 'YYYY-MM-DD HH:mm:ss';
// Tell parser to treat as UTC and the format
var m = moment.utc(s, format);
// Once the string has been parsed, you can output it in any format you like
console.log(
'Original format, offset +0000 : ' + m.format(format)
+'\nBuilt-in toISOString, offset Z: ' + m.toDate().toISOString()
+'\nBuilt-in toString, host offset: ' + m.toDate().toString()
+'\nOriginal format, host offset : ' + m.local().format(format)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
* I'm not sure this is a good idea as it means the code using the object needs to know it's in UTC mode. If you get a moment.js object from elsewhere, it would be good practice to set it to the "mode" you want. Calling local or utc multiple times has no bad effects.
I am calling an API that returns a date/time string such as "2014-04-30 15:32:01". On top of this, I have a known timezone that this date/time exists in. I can see from the javascript Date() class has a .UTC() call for this, but that does not seem to accept a timezone as far as I can tell.
Given the date/time string + timezone, how can I convert those into a UTC timestamp?
I'd recommend using Moment.js and Moment Timezone.
You can create a timestamp using Date.parse from your local time (RFC2822 date format to include the timezone), create a date from that and use Date.toUTCString to get the UTC time. Not sure if it'll work with day light savings though.
Example: http://jsfiddle.net/3vXV6/ (will alert the date)
References:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toUTCString