How to change time zone (GMT) date and time in JS

Asked

Viewed 22,159 times

7

I need to update the

// data e hora atual a região
let data = new Date();
console.log(data); 
// Está retornando Fri Nov 16 2018 17:04:08 GMT-0200 (Horário brasileiro de verão)

var dataBase = data.toISOString().replace(/\.\d{3}Z$/, '');
console.log(dataBase);
// Está retornando 2018-11-16T19:04:08

The first return is in current time zone (correct), but the second is +0300 and with daylight saving time. How do I keep the same format as the second return, but with the time zone as the first example?

2 answers

7

First let’s understand what represents a Date in Javascript. According to the documentation, is an object representing the amount of milliseconds since 1 January 1970 at midnight, in UTC (this date is also called Unix Epoch). In other words, it is the numerical value of Unix Timestamp.

You can get this value using the methods getTime() or valueOf(). And the great detail of this value is that he is the same all over the world.

For example, right now, if I turn new Date().getTime(), the result will be 1542471749270. That is, this exact moment corresponds to 1542471749270 milliseconds after the Unix Epoch. And any computer anywhere in the world that would have run this code the same instant I would have gotten this same result. The timestamp (and consequently the Date Javascript) represents a specific point in the timeline, a single instant.

Only this same value can correspond to a different date and time, depending on the time zone you are in:

  • in São Paulo, corresponds to 11/17/2018, at 14:22:29.270 (2 pm of 17)
  • in Tokyo, corresponds to 18/11/2018, at 01:22:29.270 (1 am on the 18th)
  • in Los Angeles, 17/11/2018, at 08:22:29.270 (8 am on the 17th)
  • and in UTC, 17/11/2018, at 16:22:29.270

The value of timestamp (and therefore of Date) is the same, only the corresponding date and time varies according to Timezone.


That’s why the same date produces 2 different results. When I do console.log(data), the result is the same as the method toString(), that produces the string in the format Fri Nov 16..., and with the date and time values converted to the Timezone the browser is using.

You can check the Timezone of your browser using Intl.DateTimeFormat().resolvedOptions().timeZone, just check your browser supports the Intl API.

Already the method toISOString() returns the date on ISO 8601 format, but with the date and time values adjusted for UTC. Hence the time difference you noticed.


How to solve?

Unfortunately Javascript does not provide a native way to return a date in ISO 8601 format and at the same time with the date and time values in the browser Timezone (or any other you want, other than UTC).

One way to solve this is to build the string manually. You can use the getters of the object, which return the numeric values of date and time according to the browser Timezone.

In the example below I am using a date with timestamp 1542471749270, just so that the output does not change all the time. But in your case, to use the current date, just change to new Date().

// data: troque por "new Date()" para a data atual
let d = new Date(1542471749270);

// formatar data no formato ISO 8601
var iso = d.getFullYear().toString() + "-";
iso += d.getMonth().toString().padStart(2, '0') + "-";
iso += d.getDate().toString().padStart(2, '0') + "T";
iso += d.getHours().toString().padStart(2, '0') + ":";
iso += d.getMinutes().toString().padStart(2, '0') + ":";
iso += d.getSeconds().toString().padStart(2, '0');
console.log(iso); // 2018-10-17T14:22:29

The exit is 2018-10-17T14:22:29.

Attention to use getFullYear() (returning 2018), instead of getYear(), that returns the year value indexed in 1900 (ie in this case would return 118).

I also used the function padStart to complete the values below 10 with zero on the left (thus, 5 is shown as 05). Unfortunately that does not work in IE, but you can replace by this function:

function pad(valor) {
    if (valor < 10) {
        return "0" + valor;
    }
    return valor.toString();
}

And if I use another timestamp?

To sam’s response suggests creating another date with the modified timestamp value. In fact it shows the value you want, but be aware of a detail.

Remember what timestamp is: a value that represents a single instant, and that is the same all over the world. When creating a date with another timestamp value, you are creating an object that refers to a different instant.

To better understand, an analogy: suppose my computer is configured with the wrong time zone (I am in Brazil, but the operating system time zone is configured for London).

Now in Brazil it’s 2 in the afternoon, but in London it’s 4 in the afternoon, so my computer is showing it’s 4 in the afternoon. What can I do to tidy up? There are two options:

  1. enter the time zone settings and switch to Brazil, or
  2. delay the clock by two hours

Both will cause the clock to show "2 pm", but the second option is actually showing me a time corresponding to 2 hours in the past: it shows me that it is 2 pm, but in London time zone. Only now in London it’s 4 in the afternoon (in Brazil it’s still 2 in the afternoon). Who looks only at the numbers of the clock thinks that everything is right, not knowing that in fact my clock is delayed 2 hours.

This is what happens when you subtract a timestamp value: the date created is in the past, but as you are looking at it from the point of view of another Timezone, it seems to be right (the numbers shown are "right").

Using as example the date above:

let d = new Date(1542471749270);

We have seen that it corresponds to a different date and time in each Timezone:

  • in São Paulo, corresponds to 11/17/2018, at 14:22:29.270 (2 pm of 17)
  • in Tokyo, corresponds to 18/11/2018, at 01:22:29.270 (1 am on the 18th)
  • in Los Angeles, 17/11/2018, at 08:22:29.270 (8 am on the 17th)
  • and in UTC, 17/11/2018, at 16:22:29.270

If I do what has been proposed:

let d = new Date(1542471749270);
let d2 = new Date(d.valueOf() - d.getTimezoneOffset() * 60000);

console.log(d.toISOString());  // 2018-11-17T16:22:29.270Z
console.log(d2.toISOString()); // 2018-11-17T14:22:29.270Z
console.log(d.getTime());  // 1542471749270
console.log(d2.getTime()); // 1542464549270

Notice that d2 corresponds to an instant "in the past", if compared to d. You have created a date that corresponds to a completely different instant. Thanks to the method getTimezoneOffset(), it was possible to obtain the exact value to be subtracted so that the date and time values of d2 in UTC the date and time values of d in Brazilian time zone. But anyway, d and d2 correspond to different instants.

Is that wrong? Well, it goes from each one. If you won’t use d2 for nothing else, it is not so problematic. But if you use it later, beware, because it does not represent the same instant that d. In doing so, you just "delayed the clock", when the correct one would be to use the Timezone you need (and that’s what I did when using the getters, because they return the values in the browser Timezone, which is what you want).


Moment js.

If you want, you can use the library Moment js., which in my opinion is "everything Javascript should have natively to handle dates" (a little exaggerated, but finally).

With it it is a little easier to get the desired format:

// use "moment()" para a data/hora atual
let d = moment(1542471749270);

// por padrão, já usa o timezone do browser (em vez de UTC)
console.log(d.format('YYYY-MM-DD[T]HH:mm:ss')); // 2018-11-17T14:22:29
<script src="https://momentjs.com/downloads/moment.min.js"></script>

The method format will use the date and time values corresponding to the browser Timezone, which is what you need, without the need to "juggle" with the value of the timestamp.

It may seem like overkill to add a library just for that, but if you’re going to do more operations with dates, it’s highly recommended (take a look at documentation and try to do all those operations with native Javascript ).

If you need to convert between timezones, you can use in conjunction with the Moment Timezone.


See more about dates and timezones in Javascript here and here.

6


Create a new date by subtracting the GMT. Using data.getTimezoneOffset() you can catch the GMT in minutes (e.g. 0200 = 2 hours = 120 minutes).

The data.valueOf() will return the date on ms (milliseconds). Then you need to convert the GMT also in milliseconds: data.getTimezoneOffset() * 60000.

Now just subtract the second from the first:

let data2 = new Date(data.valueOf() - data.getTimezoneOffset() * 60000);

Will stay like this:

// data e hora atual a região
let data = new Date();
// Fri Nov 16 2018 18:36:40 GMT-0200 (Horário de Verão de Brasília)

let data2 = new Date(data.valueOf() - data.getTimezoneOffset() * 60000);
var dataBase = data2.toISOString().replace(/\.\d{3}Z$/, '');
// 2018-11-16T18:36:40

See on Jsfiddle

  • here in the Trecho de código I think it looks different right?

  • Yeah. There’s things in the snippet that don’t funnel right.

  • @Sam, the code snippet worked perfectly. Thank you!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.