1

I have a live clock working pretty good except in the morning hours, it displays 1:2:3 when it should display 01:02:03

How can I modify this to work in a ReactJS component? I'm very new at React and the ways to implement a javascript function are not quite the same so I can't really use any of the regular JS answer I find. Here is the code in my class:

class SidebarContent extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            date: new Date()
        };
    }

    componentWillUnmount() {
        clearInterval(this.timerID);
    }

    tick() {
        this.setState({date: new Date()});
    }

    getHours() {
        return this.state.date.getHours();
    }
    getMinutes() {
        return this.state.date.getMinutes();
    }

    getSeconds() {
        return this.state.date.getSeconds();
    }


    componentDidMount() {

       this.timerID = setInterval(() => this.tick(), 1000);
    }

    render() {

    return (
        <ul className="nav" ref={(c) => {this.nav = c; }}>
            <li className="today">
                <Row className="clock" center="xs">
                    <Row center="xs">
                        <span className="hours">{this.getHours()}</span>
                        <span>:</span>
                        <span className="min">{this.getMinutes()}</span>

                        <span className="sec">{this.getSeconds()}</span>
                    </Row>
                </Row>
                <Row className="date" center="xs">
                    <p className="today-is">{this.state.date.toDateString()}</p>
                </Row>
            </li>
        </ul>
      );
   }
}

Thanks in advance

Sulthan
  • 128,090
  • 22
  • 218
  • 270
LOTUSMS
  • 10,317
  • 15
  • 71
  • 140

5 Answers5

3

Padding time is essentially this:

if (seconds < 10) {
   return '0' + seconds;
} else {
   return '' + seconds;
}

or

const pad = (seconds < 10) ? '0' : '';
return pad + seconds;

In total:

getFormattedTime() {
    const {date} = this.state;
    const timeComponents = [date.getHours(), date.getMinutes(), date.getSeconds()];
    return timeComponents
        .map(component => {
            const pad = (component < 10) ? '0' : '';
            return pad + component;
        })
        .join(':');
}
Sulthan
  • 128,090
  • 22
  • 218
  • 270
2

If you wish you can you momentjs and forget about formatting stuff. momentjs will take care of that. You'll only need to specify the format. I believe It will look a lot cleaner than padding stuff.

class SidebarContent extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            date: moment()
        };
    }

    componentWillUnmount() {
        clearInterval(this.timerID);
    }

    tick() {
        this.setState({date: moment()});
    }

    getTime() {
        return this.state.date.format('HH:mm:ss')
    }

    componentDidMount() {
        this.timerID = setInterval(() => this.tick(), 1000);
    }

    render() {

    return (
        <ul className="nav" ref={(c) => {this.nav = c; }}>
            <li className="today">
                <div className="clock" center="xs">
                    <div center="xs">
                        <span className="hours">{this.getTime()}</span>
                    </div>
                </div>
                <div className="date" center="xs">
                    <p className="today-is">
                    {this.state.date.format('ddd MMM DD YYYY')}</p>
                </div>
            </li>
        </ul>
      );
   }
}

Here is the Fiddle for the same. JSFiddle

Hardik Modha
  • 12,098
  • 3
  • 36
  • 40
1

You can use the function padStart from lodash. You can install the entire lodash library or the standalone package lodash.padstart.

To display the leading 0, you can do this:

// here you will import the function from the lodash package
// import padStart from 'lodash.padstart';
// OR
// import padStart from 'lodash/padstart';
const padStart = _.padStart;

class SidebarContent extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      date: new Date()
    };
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  getHours() {
    return padStart(this.state.date.getHours(), 2, '0');
  }
  getMinutes() {
    return padStart(this.state.date.getMinutes(), 2, '0');
  }

  getSeconds() {
    return padStart(this.state.date.getSeconds(), 2, '0');
  }


  componentDidMount() {

    this.timerID = setInterval(() => this.tick(), 1000);
  }

  render() {

    return ( <
      ul className = "nav"
      ref = {
        (c) => {
          this.nav = c;
        }
      } >
      <
      li className = "today" >
      <
      div className = "clock"
      center = "xs" >
      <
      div center = "xs" >
      <
      span className = "hours" > {
        this.getHours()
      } < /span> <
      span >: < /span> <
      span className = "min" > {
        this.getMinutes()
      } < /span> <
      span >: < /span> <
      span className = "sec" > {
        this.getSeconds()
      } < /span> <
      /div> <
      /div> <
      div className = "date"
      center = "xs" >
      <
      p className = "today-is" > {
        this.state.date.toDateString()
      } < /p> <
      /div> <
      /li> <
      /ul>
    );
  }
}


ReactDOM.render( < SidebarContent / > , document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>

<div id="app" />
Julio Betta
  • 2,275
  • 1
  • 25
  • 25
  • This is really great! I am getting a duplicate declaration "padStart" however. But I am only importing it once. :/ – LOTUSMS May 07 '17 at 05:09
  • you're not declaring `const padStart = _.padStart;`, right? It was to get the code to run inside the snippet. – Julio Betta May 07 '17 at 12:01
  • Ah, sorry. I was. But I think I commented it and it still gave me issues. Either way, I liked the moment() solution above. It was a little simpler and cleaner. Your solution is also great +1 for that! – LOTUSMS May 07 '17 at 17:54
-1

This is how I did it in my count down timer app some time back. Here given the time in seconds it returns you a JSON object which represents hours, minutes and seconds in two digit format.

  secondsToTime(secs) {
    let hours = `${constants.ZERO}${Math.floor(secs / (60 * 60))}`.slice(-2);

    let divisorForMinutes = secs % (60 * 60);
    let minutes = `${constants.ZERO}${Math.floor(divisorForMinutes / 60)}`.slice(-2);

    let divisorForSeconds = divisorForMinutes % 60;
    let seconds = `${constants.ZERO}${Math.ceil(divisorForSeconds)}`.slice(-2);

    let obj = {
      "h": hours,
      "m": minutes,
      "s": seconds
    };
    return obj;
  }

You may access the values like this.

var remainingTime = this.secondsToTime(timeInSeconds);
remainingTime["h"] // gives you hours
remainingTime["m"] // gives you minutes
remainingTime["s"] // gives you seconds

This approach is far more better than calling 3 functions to get the hours, minutes and seconds separately which is a bit awkward for me. Hope this helps. Happy Coding !

Ravindra Ranwala
  • 20,744
  • 6
  • 45
  • 63
-2

React is plain javascript. You absolutely can use any plain javascript in there. Your issue has nothing to do with react and everything to do with javascript. Date()'s methods return a single digit. You're going to need to somehow pad the output. See How to output integers with leading zeros in JavaScript

Community
  • 1
  • 1
shayac
  • 584
  • 3
  • 10