According to the API of Openweather, the field timezone
contains the difference from UTC in seconds.
Thus, one way to get the local time in the indicated Timezone would be to use toLocaleTimeString
, passing Timezone in the options.
But there is one detail: this option accepts timezone identifiers defined by IANA, which are in the format "Continent/Region" (such as America/Sao_Paulo
, Europe/Berlin
, Asia/Tokyo
, etc). But there is an alternative to fixed values such as "-3 hours", which is to use timezones in the "Etc/GMT[offset] format, in which offset
is the difference in hours with respect to UTC, but with the reversed signal (yes, if the difference is 3 hours after UTC, the corresponding would be "Etc/GMT-3").
Another important detail is that not all places in the world adopt "full-hour time zones". For example, India is currently in UTC+05:30
(yes, 5 and a half hours ahead of UTC), and Nepal is in UTC+05:45
(5 hours and 45 minutes ahead of UTC). Not counting some regions of Australia, which during daylight saving time set the clock at just half an hour.
That is, the approach I will show below is limited, because it only works when the difference with UTC is full hour (since timezones in "Etc/GMT" format only support full hours):
const data = { timezone: -10820 };
// valor das horas arredondado (invertendo o sinal)
const horasTz = (-Math.sign(data.timezone)) * Math.floor(Math.abs(data.timezone) / 3600);
const sign = horasTz >= 0 ? '+' : ''; // se for negativo, o próprio número já terá o sinal "-"
// exibir a hora atual no timezone indicado
const agora = new Date();
console.log(agora.toLocaleTimeString('pt-BR', { timeZone: `Etc/GMT${sign}${horasTz}`}));
The boring part is rounding up the value and keeping the sign. Rounding is important for the cases mentioned above ("broken time zones"), and attention should be paid to the case of negative values (when rounding up -3.5
, the result would be -4
, then the above adjustment is for it to be -3
), and also to reverse the signal (because the "Etc/GMT" timezones must have the inverted signal).
If it is to work even with the "broken hours" zones, the way is to do it manually:
const data = { timezone: -10800 };
const agora = new Date();
function mod(x, y) {
return x - (y * Math.floor(x / y));
}
let n = mod((agora.getUTCHours() * 3600) + (agora.getUTCMinutes() * 60) + agora.getUTCSeconds() + data.timezone, 86400);
let hour = Math.floor(n / 3600);
n %= 3600;
let min = Math.floor(n / 60);
let sec = n % 60;
// função para retornar o valor com zero à esquerda, caso necessário
function pad(val) {
return val.toString().padStart(2, '0');
}
console.log(`${pad(hour)}:${pad(min)}:${pad(sec)}`);
So it works for any value that data.timezone
has, even if it is of one of the zones already mentioned (of "broken hours"). It is worth remembering that you need to use the getters UTC (getUTCHours
to get the time in UTC, since the difference is in relation to UTC). To use getHours
, the time will be returned according to the time zone of the environment (be it the browser or what is in the Node configuration, etc).
I made a simplified calculation because we are only interested in the schedule, without caring about the day, month and year (because then the calculation would be a little more complicated). The point that is a little more complicated is the rest of the division, which I had to do a separate function to deal with the negative numbers cases (for example, if the UTC time was midnight and Timezone was -10800
, the result would be negative (-3:00:00
), so I made an adjustment so that he becomes 21:00:00
).
In the comments suggested to change the timestamp value:
const data = { timezone: -10800 };
function pad(val) {
return val.toString().padStart(2, '0');
}
const date = new Date();
// mudar o valor do timestamp
date.setTime(date.getTime() + data.timezone * 1000);
let h = date.getUTCHours();
let m = date.getUTCMinutes();
let s = date.getUTCSeconds();
console.log(`${pad(h)}:${pad(m)}:${pad(s)}`);
Although "working", you should use with caution, because by changing the value of timestamp, you are actually creating a Date
for an instant other than the current one. If you will not use the Date
for nothing else, it’s not that serious, but if you’re going to use it later, be aware that it now has a modified value that no longer matches the current date/time. Read here (in the "Gambiarra" section) to better understand, and to learn more about the Date
javascript, read here and here.
Another alternative is to use some external lib (while the Temporal
is not approved), such as Moment Timezone:
const data = { timezone: -10800 };
console.log(moment().utcOffset(data.timezone / 60).format('HH:mm:ss'));
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data.min.js"></script>
You can create a new
Date
with the current timestamp plus the value ofdata.timezone
converted into milliseconds:new Date(Date.now() + (data.timezone * 1000));
, then you use the object methods to for example get to hours, minutes etc. But it is important to use the methodsgetUTC...
. See also this reply for details on JS dates– suriyel