javascript – How to create a "countdown" clock so that it ends in the time of a specific country?

Question:

I am trying to create a countdown and I want it to end in a specific country time, in this case I want it to end on October 31, 2020 at 00:00:00 local time in Japan

This is my code:

var countDownDate = new Date("Oct 31, 2020 12:00:00").getTime();
var x = setInterval(function() {
  var now = new Date().getTime();

  var distance = countDownDate - now;
  var days = Math.floor(distance / (1000 * 60 * 60 * 24));
  var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
  var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
  var seconds = Math.floor((distance % (1000 * 60)) / 1000);
  if (days === 60){//Si ya pasaron 60 días se muestra el contador 
   $('.text').remove();//elimina un div en especifico que muestra un texto para mostrar la cuenta atrás
   document.getElementById('days').innerHTML = days;
   document.getElementById('hors').innerHTML = hours;
   document.getElementById('minutes').innerHTML = minutes;
   document.getElementById('seconds').innerHTML = seconds;
  }else{ //esta parte es para pruebas 
  }
  if (distance < 0) {
    clearInterval(x);
    //si finaliza la cuenta atras aqui se puede ocultar el contador 
  }
}, 2000);

Does anyone know how to do it?

Answer:

To achieve this, you have to take into account the basic concepts of handling data of type Date in Javascript.

From the documentation we have:

Creates an instance of the Date Object that represents an instant in time in a platform-independent format. Date objects contain a Number that represents the milliseconds that have elapsed since January 1, 1970 UTC.

This means that regardless of the platform and its time zone, a Date object will always have the same stored value, whether created in Japan, or in Mexico, or elsewhere.

However, when we display its value, it will be shown in the time zone and in the format of the platform on which it is displayed.

Let's see an example:

let fecha = new Date('December 17, 1995 03:24:00');
console.log(fecha);
console.log(fecha.toString());
console.log(fecha.toUTCString()); // Sun, 17 Dec 1995 02:24:00 GMT
.as-console-wrapper { max-height: 100% !important; top: 0; }

Depending on the time zone the client running this script is in, the displayed values ​​will be different. I have placed the value that it shows me in my computer for the last exit, and it is that my current time zone is GMT + 1. Therefore the returned toUTCString() value will subtract one time from the one generated in my system when the date is created.

Now you want to generate a Date object that corresponds to the date:

October 31, 2020 at 00:00:00 local time in Japan

But in your code you write:

var countDownDate = new Date("Oct 31, 2020 12:00:00").getTime();
var fecha = new Date("Oct 31, 2020 12:00:00");

console.log(countDownDate);
console.log(fecha.toUTCString()); // Sat, 31 Oct 2020 11:00:00 GMT
.as-console-wrapper { max-height: 100% !important; top: 0; }

Again I have commented out the return value in my system of the returned date using toUTCString() . You can see that the date is October 31, 2020, but the time is 11:00:00 GMT.

Since the time zone of Japan is GMT + 9, we must add 9 hours to this value to find the time in Japan that corresponds to 11 hours GMT. Which tells us that the created date corresponds to 20:00:00 Japan time. Which is different from what you want.

How do I generate a date with local time in country X?

The constructor of the Date object receives different parameters:

  • No parameters: the created object represents the local system date and time.
  • Time value or number of timestamp : an integer value representing the number of milliseconds elapsed since January 1, 1970 at 00:00:00 UTC (GMT)
  • timestamp string – a string representing a date, specified in a format recognized by the Date.parse() method.
  • Date and time values ​​as individual components: Given at least the year and month, this way of using Date() , generates an object that represents the date and times passed as individual components, if any are omitted (other than year and month ), the default values ​​will be all 0, except the day that will take the value of 1.

We already know the possible parameters that the Date() constructor receives, and of these we are specifically interested in the timestamp String .

We can use one of the following 2 standard formats:

  1. IETF-compliant RFC 2822
  2. ISO8601

If we read carefully the documentation of both, we see that the time zone can be indicated in the chain.

Since Japan uses the GMT + 9 time zone, one way we can write the string indicating Japan's time zone would be the following:

  1. IETF-compliant RFC 2822: 'October 31, 2020 00:00:00 GMT+09:00'
  2. ISO8601: '2020-10-31T00:00:00.000+09:00'

Let's see an example:

//IETF-compliant RFC 2822: `'October 31, 2020 00:00:00 GMT+09:00'`
const rfc2822Date = new Date('October 31, 2020 00:00:00 GMT+09:00');
//ISO8601: `'2020-10-31T00:00:00.000+09:00'`
const iso8601Date = new Date('2020-10-31T00:00:00.000+09:00');

console.log('Fecha usando RFC2822:');
console.log(rfc2822Date.toString());
console.log('Fecha usando ISO8601:');
console.log(iso8601Date.toString());

console.log('¿Son la misma fecha?');
console.log(rfc2822Date.getTime() === iso8601Date.getTime());
.as-console-wrapper { max-height: 100% !important; top: 0; }

Now we know how to set a date and time according to a specific time zone, we need to do the countdown clock.

In the code of your question you can see that you want to show days, hours, minutes and seconds, so we must calculate these values ​​and update every certain interval.

We are going to choose the interval of 1 second to perform the update, that is, every 1 second we perform the calculation of days, hours, minutes and seconds.

For this we are going to create a function that performs these calculations, we updateClock() call it updateClock() .

Our function will receive the date, which we created previously, as a parameter and it will calculate the number of days, hours, minutes and seconds remaining for the system on which the script is run to reach that date.

The calculation is simple, using the getTime() method of the Date Object, we can calculate the difference between the current system date and the date that we have calculated as future.

This difference is expressed in milliseconds, therefore we must calculate how many milliseconds are equivalent to a day, an hour, a minute and a second.

  • One day equals 86400000 milliseconds.
  • One hour equals 3600000 milliseconds.
  • One minute equals 60000 milliseconds.
  • One second equals 1000 milliseconds.

Therefore, to start our clock, we must calculate these values ​​from the difference between milliseconds of the current system date and the deadline.

Thus:

const topDate = new Date('October 31, 2020 00:00:00 GMT+09:00');

const updateClock = (date) => {
  if(!date) return;
  let end = date.getTime();
  let now = Date.now();
  let diff = end - now;
  let days = Math.floor(diff / 86400000);
  diff = diff % 86400000
  let hours = Math.floor(diff / 3600000);
  diff = diff % 3600000;
  let minutes = Math.floor(diff / 60000);
  diff = diff % 60000;
  let seconds = Math.floor(diff / 1000);
  console.log(`Tiempo estimado: ${days} días, ${hours} horas, ${minutes} minutos, ${seconds} segundos.`);
}

updateClock(topDate);
.as-console-wrapper { max-height: 100% !important; top: 0; }

We already have our function, now we only have to create the appropriate interval and every time the page loads, our function is executed and updates the fields, for this we must create the HTML structure that our clock will contain.

const topDate = new Date('October 31, 2020 00:00:00 GMT+09:00');

const updateClock = (date) => {
  if(!date) return;
  let end = date.getTime();
  let now = Date.now();
  let diff = end - now;
  let days = Math.floor(diff / 86400000);
  diff = diff % 86400000
  let hours = Math.floor(diff / 3600000);
  diff = diff % 3600000;
  let minutes = Math.floor(diff / 60000);
  diff = diff % 60000;
  let seconds = Math.floor(diff / 1000);
  document.getElementById('days').innerHTML = days;
  document.getElementById('hours').innerHTML = hours;
  document.getElementById('minutes').innerHTML = minutes;
  document.getElementById('seconds').innerHTML = seconds;
}

// se llama a la función una vez para que pinte el resultado inmediatamente
updateClock(topDate);
// se hace uso de setInterval para cambiar el contador cada 1 segundo
setInterval(updateClock, 1000, topDate)
.container {
  text-align: center;
  }
<div id="clock" class="clock">
  <div class="container">
    Días: <span id="days"></span>, Horas: <span id="hours"></span>, Minutos: <span id="minutes"></span>, Segundos: <span id="seconds"></span>
  </div>
</div>

With this, you already have a way to calculate the time until the deadline is met.

It would only be necessary to verify when the date is fulfilled to hide the clock.

We can do this using a CSS class to hide it or we can even remove it from the DOM: a countdown clock is only valid as long as there is something to count.

To remove it from the DOM, we will use the Node.removeChild() method, and with that we will finish.

I'll use a basic example and a 6 second counter to show how the element is removed from the DOM:

const topDate = new Date(Date.now() + 6000);

const updateClock = (date) => {
  if(!date) return;
  let end = date.getTime();
  let now = Date.now();
  let diff = end - now;
  if(diff < 0) { // <- si el reloj ya mostró todo en cero, lo remuevo del DOM
    clearInterval(interval);
    let visor = document.getElementById('visor');
    document.getElementById('clock').removeChild(visor);
  } else {
    let days = Math.floor(diff / 86400000);
    diff = diff % 86400000
    let hours = Math.floor(diff / 3600000);
    diff = diff % 3600000;
    let minutes = Math.floor(diff / 60000);
    diff = diff % 60000;
    let seconds = Math.floor(diff / 1000);
    document.getElementById('days').innerHTML = days;
    document.getElementById('hours').innerHTML = hours;
    document.getElementById('minutes').innerHTML = minutes;
    document.getElementById('seconds').innerHTML = seconds;
  }
}

// se llama a la función una vez para que pinte el resultado inmediatamente
updateClock(topDate);
// se hace uso de setInterval para cambiar el contador cada 1 segundo
const interval = setInterval(updateClock, 1000, topDate)
.container {
  text-align: center;
  }
.visor {
  
}
<div id="clock" class="clock">
  <div id="visor" class="container">
    Días: <span id="days"></span>, Horas: <span id="hours"></span>, Minutos: <span id="minutes"></span>, Segundos: <span id="seconds"></span>
  </div>
</div>

I hope that with this you have a little clearer how to achieve the goal.

Scroll to Top