Localize UTC time/date - javascript

i have a timestamp which comes from server (utc). I now want to transform this timestamp to my local time.
Transform UTC:
2016-08-11 12:19:14
To local time:
2016-08-11 14:19:14
This is what i have used:
localizeTime = function (timeToLocalize = "2016-08-11 12:19:14") {
return moment(timeToLocalize).locale(deviceLocale = "de").format('LLL');
};
I am working with react-native and moment.js

If the input time is UTC, and you don't have anything in the string to indicate such, then you need to parse it with moment.utc instead of just with moment. You can then convert it to local time with the local function.
moment.utc("2016-08-11 12:19:14").local().format("YYYY-MM-DD HH:mm:ss")
You don't need to involve locales (like de) unless you really want a locale-specific string format. Locale has to do with language and culture, not with time zones. "local" != "locale"

Related

How to format a string in UTC to the configured timezone on Moment

I have the following string, which is in UTC:
2022-02-01T00:00:00Z
I have already configured my timezone, so I do not want to mess/call .tz()
I know that this string is in UTC, but I am not managing to convert from UTC to the defined timezone, which in this example is pacific/wallis.
I have tried many things, as
const utc = moment.utc('2022-02-01T00:00:00Z').toDate()
const inConfiguredTimeZone = utc.format()
My desire is to get this timestamp 2022-02-01T00:00:00Z and have converted to the defined timezone on Moment
I need to tell moment that "This string is in UTC, please give me the converted timestamp in the defined time zone"
If you just want to format a UTC timestamp in your current timezone (determined by your computer's time settings) just use
let s = moment("2022-02-01T00:00:00Z").format();
This will produce a string like 2022-02-01T12:00:00+12:00 if you are currently in a timezone that has a UTC offset of +12 hours (like pacific/wallis) or 2022-02-01T01:00:00+01:00 if you are currently in a timezone that has a UTC offset of +1 hours (like europe/berlin)
If you want it converted to a specific timezone use
let s = moment("2022-02-01T00:00:00Z").tz("pacific/wallis").format();
This will produce 2022-02-01T12:00:00+12:00, regardless of your current timezone.

Alternative to casting UTC Date in Javascript?

I wish to create a new Date in JS, but have it be cast as UTC time. For example, suppose castAsUTC() produces the following desired effect:
var x = new Date('2019-01-01T00:00:00') // In local time (PST)
castAsUTC(x).toISOString(); // => '2019-01-01T00:00:00Z'
// x.toISOString() gives us '2019-01-01T08:00:00Z', which is undesired
Currently, my function looks like this:
function castAsUTC(date) {
return new Date(x.toLocaleString() + '+00:00');
}
Is there a cleaner/nicer way of producing the same effect? Thanks in advance!
EDIT: To be more specific, I'm interested in transforming the date's timezone, without changing its actual value with as little arithmetic as possible. So calling .toISOString() will produce the same date as it is in local time.
I am currently using the moment-timezone library, but I can't seem to get the desired effect using that, either. I would definitely accept an answer that uses Moment.js
You can switch a Moment instance to UTC using the utc function. Then just use format to get whatever the specific output you want from it.
If indeed the string you have is like the one shown, then the easiest thing to do would be to append a Z to indicate UTC.
var input = '2019-01-01T00:00:00';
var date = new Date(input + 'Z');
var output = date.toISOString();
Or, if you would like to use Moment.js, then do this:
var input = '2019-01-01T00:00:00';
var m = moment.utc(input);
var output = m.format();
You do not need moment-timezone for this.
tl;dr;
You formatted the date wrong. Add the letter "Z" to the end of your date string and it will be treated as UTC.
var x = new Date('2019-01-01T00:00:00Z') // Jan 1, 2019 12 AM UTC
These formatting issues are easier to manage with a library like momentjs (utc and format functions) as described in other answers. If you want to use vanilla javascript, you'll need to subtract out the timezone offset before calling toISOString (see warnings in the longer answer below).
Details
Date in javascript deals with timezones in a somewhat counter intuitive way. Internally, the date is stored as the number of milliseconds since the Unix epoch (Jan 1, 1970). That's the number you get when you call getTime() and it's the number that's used for math and comparisons.
However - when you use the standard string formatting functions (toString, toTimeString, toDateString, etc) javascript automatically applies the timezone offset for the local computers timezone before formatting. In a browser, that means it will apply the offset for the end users computer, not the server. The toISOString and toUTCString functions will not apply the offset - they print the actual UTC value stored in the Date. This will probably still look "wrong" to you because it won't match the value you see in the console or when calling toString.
Here's where things really get interesting. You can create Date's in javascript by specifying the number of milliseconds since the Unix epoch using new Date(milliseconds) or by using a parser with either new Date(dateString). With the milliseconds method, there's no timezone to worry about - it's defined as UTC. The question is, with the parse method, how does javascript determine which timezone you intended? Before ES5 (released 2009) the answer was different depending on the browser! Post ES5, the answer depends on how you format the string! If you use a simplified version of ISO 8601 (with only the date, no time), javascript considers the date to be UTC. Otherwise, if you specify the time in ISO 8601 format, or you use a "human readable" format, it considers the date to be local timezone. Check out MDN for more.
Some examples. I've indicated for each if javascript treats it as a UTC or a local date. In UTC, the value would be Jan 1, 1970 at midnight. In local it depends on the timezone. For OP in pacfic time (UTC-8), the UTC value would be Jan 1, 1970 at 8 AM.
new Date(0) // UTC (milliseconds is always UTC)
new Date("1/1/1970"); // Local - (human readable string)
new Date("1970-1-1"); // Local (invalid ISO 8601 - missing leading zeros on the month and day)
new Date("1970-01-01"); // UTC (valid simplified ISO 8601)
new Date("1970-01-01T00:00"); // Local (valid ISO 8601 with time and no timezone)
new Date("1970-01-01T00:00Z"); // UTC (valid ISO 8601 with UTC specified)
You cannot change this behavior - but you can be pedantic about the formats you use to parse dates. In your case, the problem was you provided an ISO-8601 string with the time component but no timezone. Adding the letter "Z" to the end of your string, or removing the time would both work for you.
Or, always use a library like momentjs to avoid these complexities.
Vanilla JS Workaround
As discussed, the real issue here is knowing whether a date will be treated as local or UTC. You can't "cast" from local to UTC because all Date's are UTC already - it's just formatting. However, if you're sure a date was parsed as local and it should really be UTC, you can work around it by manually adjusting the timezone offset. This is referred to as "epoch shifting" (thanks #MattJohnson for the term!) and it's dangerous. You actually create a brand new Date that refers to a different point in time! If you use it in other parts of your code, you can end up with incorrect values!
Here's a sample epoch shift method (renamed from castAsUtc for clarity). First get the timezone offset from the object, then subtract it and create a new date with the new value. If you combine this with toISOString you'll get a date formatted as you wanted.
function epochShiftToUtc(date) {
var timezoneOffsetMinutes = date.getTimezoneOffset();
var timezoneOffsetMill = timezoneOffsetMinutes * 1000 * 60;
var buffer = new Date(date.getTime() - timezoneOffsetMill);
return buffer;
}
epochShiftToUtc(date).toUTCString();

How to guess user's timezone using date-fns?

I have a requirement, where I need to show a user's time in their local time zone. This needs to be done using date-fns.
The following code checks the current time and then given a timezone converts it into local time as per the time zone.
const { formatToTimeZone } = require('date-fns-timezone')
let date = new Date()
const format = 'D.M.YYYY HH:mm:ss [GMT]Z (z)'
const output = formatToTimeZone(date, format, { timeZone: 'Asia/Calcutta' })
However, how do I guess the user's timezone on the fly?
In moment.js, you can get it with moment.tz.guess(). But how can I do it without moment.js and by using date-fns?
https://runkit.com/embed/835tsn9a87so
UPDATE: I will be using this inside a VueJS application. So, if there are any other related solutions, those are welcomed as well. Thanks.
To get the user's IANA time zone identifier, most modern browsers now support the following:
Intl.DateTimeFormat().resolvedOptions().timeZone
That said, the usual reason you would need to use formatToTimeZone from date-fns-timezone is when you need to use a different time zone other than the user's local zone. Otherwise, you can usually just use the format function from date-fns.
However, in your case, you are also trying to use the z format specifier to display the user's time zone abbreviation. This isn't provided by date-fns directly, so if that is critical then you will indeed need to get the user's time zone with the Intl api shown above and use formatToTimeZone.
Do keep in mind though that these abbreviations are whatever the IANA data has recorded, which are in English only, and it doesn't have abbreviations for every time zone. For those that don't, you will see a numeric value instead, such as -02.
Also, many abbreviations can be ambiguous (such as the I in IST possibly meaning India, Israel, or Ireland, and many others...). Thus, in most cases, if you don't need the abbreviation, you're often better off without it.
Just solved a similar problem myself. The trick is to use the format function from date-fns-tz instead of the one from date-fns.
import { format } from "date-fns";
console.log(format(new Date(), "yyyy-MM-dd HH:mm z"));
// 2021-11-29 13:55 GMT-8
import { format } from "date-fns-tz";
console.log(format(new Date(), "yyyy-MM-dd HH:mm z"));
// 2021-11-29 13:55 PST
See documentation here:
https://date-fns.org/v2.27.0/docs/Time-Zones

Return date and time in ("YYYY-MM-DD HH:mm") format when using moment.js (timezone)

I am using moment-timezone so I can convert from selected timezone to timezone of a client.
I wasn't able to implement it in a better way than this:
convertSelectedTimeZoneToClients() {
let timeZoneInfo = {
usersTimeZone: this.$rootScope.mtz.tz.guess(),
utcOffset: this.formData.timeZone.offset,
selectedDateTime: this.toJSONLocal(this.formData.sessionDate) + " " + this.formData.sessionTime
};
let utcTime = this.$rootScope.mtz.utc(timeZoneInfo.selectedDateTime).utcOffset(timeZoneInfo.utcOffset).format("YYYY-MM-DD HH:mm");
let convertedTime = this.$rootScope.mtz.tz(utcTime, timeZoneInfo.usersTimeZone).format("Z");
return convertedTime;
}
So basically I am using usersTimeZone: this.$rootScope.mtz.tz.guess(), guess() function to find out timezone from the browser.
Then I get values from datetime picker and dropdown and convert them to UTC value by using utcOffset.
At the end I want to convert that utc value to user timezone value.
I get object like this:
_d represent correct value after conversion. I have tried adding bunch of different .format() paterns on convertedTime variable, but I am not able to retrive time in this format: "YYYY-MM-DD HH:mm". I guess it works differentlly than when using .utcOffset() function.
Can anybody help me with this?
You don't need to guess the client time zone to convert to local time. Just use the local function.
For example:
moment.tz('2016-01-01 00:00', 'America/New_York').local().format('YYYY-MM-DD HH:mm')
For users located in the Pacific time zone, this converts from Eastern to Pacific and you get an output string of "2015-12-31 21:00". For users in other time zones, the output would be different, as expected.
You don't need to format to a string and re-parse it, or manually manipulate the UTC offset either. That is almost never warranted.

Date parsed with gmt + 2 hours

I always get the wrong date when I use var date = new Date(timestring), there is always +2 GMT hours.
var unsortedPlayTimes =
[{date:'2014-08-11T09:30:00'},
{date:'2014-08-11T08:30:00'},
{date:'2014-08-11T08:15:00'},
{date:'2014-08-11T08:45:00'},
{date:'2014-08-11T12:30:00'},
{date:'2014-08-11T10:30:00'},
{date:'2014-08-11T11:30:00'},
{date:'2014-08-11T07:30:00'},
{date:'2014-08-11T13:00:00'},
{date:'2014-08-11T23:00:00'},
{date:'2014-08-12T00:00:00'},
{date:'2014-08-12T01:00:00'},
{date:'2014-08-12T05:00:00'},
{date:'2014-08-12T09:00:00'},
{date:'2014-08-11T14:00:00'},
{date:'2014-08-11T18:30:00'},
{date:'2014-08-11T13:00:00'}];
function SortandFilterPlayTimes (allPlayTimes) {
var filteredPlayTimes = [];
$.each(allPlayTimes, function(index, value) {
var date = new Date(value.date);
if ($.inArray(date,filteredPlayTimes) === -1) {
filteredPlayTimes.push(date);
}
});
};
Why is JavaScript always adding this +2 hours ?
You're using the ISO-8601 formatting of dates while omitting the timezone, this makes the parsing consider the timezone as UTC in ES5 (this will be different in ES6 : strings in ISO format will be considered as local too when the timezone isn't provided).
If you want the date to be parsed with your local timezone in ES5, you might change the format to a not ISO one :
var date = new Date(value.date.replace(/T/,' '));
But you might also want to check you really want the date to be parsed depending on the user's timezone, this is most often a bad idea. The usual good solution is to send the timezone or to send the date as a unix timestamp (what you get with date.getTime()).
You are parsing ISO-8601 timestamps without timezone information, thus a UTC timezone is assumed, but Date.prototype.toString() will provide a string representation of this timestamp in your current timezone which means that if you are in the UTC+2 timezone you will notice a shift by two hours.
I'm guessing your project is hosted on a server that has a +2 hours time difference with your local system, thus giving you a time you are not expecting. Is your server in a different country?

Categories

Resources