Show current date in a particular Timezone

Asked

Viewed 92 times

1

I am trying to put on my site the local time of another city, through the data.timezone returned by the Open Weather API.

This value is in seconds, for example, if the country has an extra 3 hours difference compared to UTC, what appears in the API is 10800, and if it is 3 hours less, -10800.

So to convert to minutes, I did:

const timezone = data.timezone / 3600

And to show on the screen:

let currentHour = new Date().getHours()
let currentMinutes = new Date().getMinutes()
let currentSeconds = new Date().getSeconds()
let currentHourZone = currentHour + timezone
let dateTimezone = `${currentHourZone}:${currentMinutes}:${currentSeconds}` // (essa variável que está sendo mostrada)

However, what is happening is this: In giving 24 hours or more, he instead of going back to midnight (00), he is adding, and in the minute, when it goes to 60, instead of going back to 00 and adding 1 to the hours, he also does not go, and the same thing with the seconds, that is, is not validating as in the standard of new Date().toLocaleTimeString().

What I tried to:

if (currentHour === 60) {
        currentHour = '00'
     }

     if (currentMinutes < 10) {
        currentMinutes = '0' + currentMinutes
     }
     if (currentSeconds < 10) {
        currentSeconds = '0' + currentSeconds
     }

And even more:

if (dateTimezone = 24 + ':' + currentMinutes + ':' + currentSeconds) {
         dateTimezone = '00' + ':' + currentMinutes + ':' + currentSeconds
     }
     if (dateTimezone = currentHourZone + ':' + 60 + ':' + currentSeconds) {
         dateTimezone = currentHourZone + 1 + ':' + '00' + ':' + currentSeconds
     }
     if (dateTimezone = currentHourZone + ':' + currentMinutes + ':' + 60) {
         dateTimezone = currentHourZone + ':' + currentMinutes + 1 + ':' + '00'
     }

And last but not least, the closest you’ve come to validating:

const pastTime = `${24}:${currentMinutes}:${currentSeconds - 1}`
    const midNightTime = `00:${currentMinutes.toString()}:${currentSeconds.toString()}`

    if (dateTimezone > pastTime) {
        dateTimezone = midNightTime
    }
  • You can create a new Date with the current timestamp plus the value of data.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 methods getUTC.... See also this reply for details on JS dates

1 answer

5


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>

  • 1

    Thank you very much. I thank you so much for your attention and help.

Browser other questions tagged

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