Search code examples
javascriptmomentjsmoment-timezone

How to update the time every second using "setInterval()" without the time flashing in and out every second?


I'm using a dropdown list that displays different timezones onclick using moment-timezone. For example when you click the dropdown labeled "est" it will display the time in eastern time, when you click "cst" the cst time will display and so on.

Anyways the problem I'm running into is this... I use setInterval(updateTime, 1000); to show the seconds tick up every second, now by doing this when a user clicks on "est" and then another time zone in the dropdown list like "cst" both of those times will appear and disappear every second on top of each other. I want it so when you click on an li element the previous one that was on screen will have the property of display=none. So when u click est for example est time will display and then when u click on cst the est will be display=none and the cst time will display. Man that was a mouthful.

Is there a way to accomplish this and still use the setInterval of 1second?

Here is my code...

<div>
    <li>
        <ul>
        <li id="tmz1">est</li>
        <li id="tmz2">central</li>
        <li>pacific</li>
        </ul>
   </li>

   <div id="output1"></div>
   <div id="output2"></div>
</div>    


$(document).ready(function(){

    var output1 = document.getElementById('output1');
    var output2 = document.getElementById('output2');

    document.getElementById('tmz1').onclick = function updateTime(){

        output2.style.display = "none";
        output1.style.display = "block";

        var now = moment();
        var humanReadable = now.tz("America/Los_Angeles").format('hh:mm:ssA');

        output1.textContent = humanReadable;
        setInterval(updateTime, 1000);

    }

    updateTime();

});


$(document).ready(function(){

    var output2 = document.getElementById('output2');
    var output1 = document.getElementById('output1');

    document.getElementById('tmz2').onclick = function updateTimeX(){

        output1.style.display = "none";
        output2.style.display = "block";

        var now = moment();
        var humanReadable = 
        now.tz("America/New_York").format('hh:mm:ssA');

        output2.textContent = humanReadable;
        setInterval(updateTimeX, 1000);

    }

    updateTimeX();

});

Solution

  • Perhaps this will help. I believe you've overcomplicated this just a bit. I've provided comments in the code for you to review.

    Note: I did not use moment.js as it is unecessary for your task.

    You need:

    1. a time from a Date object
    2. a timezone reference that will change upon click
    3. an interval that will publish the time (with the changing TZ)
    4. Someplace to put the output

    // place to put the output
    const output = document.getElementById('output');
    // starting timezone
    var tz = 'America/New_York';
    // Capture click event on the UL (not the li)
    document.getElementsByTagName('UL')[0].addEventListener('click', changeTZ);
    
    function changeTZ(e) {
      // e.target is the LI that was clicked upon
      tz = e.target.innerText;
      // toggle highlighted selection 
      this.querySelectorAll('li').forEach(el=>el.classList.remove('selected'));
      e.target.classList.add('selected');
    }
    
    // set the output to the time based upon the changing TZ
    // Since this is an entire datetime, remove the date with split()[1] and trim it
    setInterval(() => {
      output.textContent = new Date(Date.now()).toLocaleString('en-US', {timeZone: `${tz}`}).split(',')[1].trim();
    }, 1000);
    .selected {
      background-color: lightblue;
    }
    <div>
      <ul>
        <li class="selected">America/New_York</li>
        <li>America/Chicago</li>
        <li>America/Los_Angeles</li>
      </ul>
    
      <div id="output"></div>
    </div>