fffo

javascript로 d-day 만들 때 Math.floor를 쓰면 안되는 이유 본문

Programming/Javascript

javascript로 d-day 만들 때 Math.floor를 쓰면 안되는 이유

gggs 2021. 10. 27. 19:03

자바스크립트로 d-day를 표시하는 시계를 만들다가 헷갈리는 부분이 있어서 포스팅하겠습니다.

 

d-day를 만들기 위해서는 현재 시간을 불러오는 new Date() 생성자 함수, 그리고 d-day에 현재 시간을 빼고 남은 시간을 일, 시, 분, 초 단위로 나타낼 코드가 필요합니다. Date생성자 함수를 통해 얻어진 Date 객체끼리 뺄셈을 하면 시간을 ms단위로 반환하기 때문에 남은시간 역시 ms단위로 얻을 수 있습니다. 물론 Date객체 각각의 연월일 시분초를 얻어서 뺄셈할 수 있지만 이는 월의 마지막 날이 30일인지, 31일인지, 혹은 28일인지 29일인지를 구분하는 별도의 로직이 필요하기 때문에 더 복잡한 것 같습니다.

 

d-day의 Date객체와 현재 시간의 Date객체의 뺄셈으로 구해진 ms을 시간의 단위에 따라 나타낼 때 나누기 연산이 필요합니다. 예를 들어 3231ms 은 초로 환산하면 3231 / 1000으로 3.231초가 나옵니다.

 

이 때 소수점 뒤의 수를 버릴 필요가 있는데 두 가지 방법이 있습니다. 하나는 Math.floor()를 이용해 버림연산을 하는 것이고, 하나는 parseInt()를 통해 소수점 뒤의 수를 버리는 것입니다. 둘의 차이는 음수에서 나타납니다. 예를 들어 -1.123를 각각의 방법에 적용시키면 전자는 버림 연산이기 때문에 -2가 되고 후자는 단순히 소수점 뒤의 숫자를 날리는 것이기 때문에 -1이 됩니다.

 

일반적인 시계에서는 음수가 나오지 않지만 d-day를 계산하는 시계는 현재 날짜가 d-day를 지나면 음수가 되면서 d-day로부터 얼마나 지났는지를 알려줄 수 있습니다. 그렇다면 여기서 -1.12는 -2이 되어야 할까 -1이 되어야 할까요? 

 

예를 들어보겠습니다. d-day의 시간이 되면 시계는 00일 00시 00분 00초가 됩니다. 이 때 1ms 후의 상황을 생각해 봅시다. 1ms 후는 남은 시간이 -1ms이고 이를 초로 나타내기 위해 1000으로 나누고 버림을 하면 -0.001에서 -1이 되어버립니다.

Math.floor의 버림 연산

이는 사소해 보이지만 일, 시, 분 또한 같은 원리로 1ms 만 지나도  -1일 -1시 -1분이 되어버리기 때문에 큰 오차를 불러일으킵니다. 

 

끝으로 제가 만든 d-day 시계 코드를 올리겠습니다. js-clock이라는 클래스를 가진 html요소의 innerText로 시계를 추가하는 코드입니다. 

const clockTitle = document.querySelector(".js-clock");
const christmasEve = new Date("2021-12-24");
makeDDayCounter(clockTitle, christmasEve);

function makeDDayCounter (clock, dDay) {
  printDDayCount(clock, dDay);
  setInterval(()=> printDDayCount(clock, dDay), 1000);
}

function printDDayCount(clock, dDay) {
  const nowDay = new Date();
  const timeDiff = dDay - nowDay;

  const SECOND_TIMES = 1000;
  const MINUET_TIMES = SECOND_TIMES * 60;
  const HOUR_TIMES = MINUET_TIMES * 60;
  const DATE_TIMES = HOUR_TIMES * 24;

  let restTime = 0;
  const date = timeDiff === 0 ? 0 : parseInt(timeDiff / DATE_TIMES);
  restTime += date * DATE_TIMES;
  const hour =
    restTime === 0
      ? parseInt(timeDiff / HOUR_TIMES)
      : parseInt((timeDiff % restTime) / HOUR_TIMES);
  restTime += hour * HOUR_TIMES;
  const minute =
    restTime === 0
      ? parseInt(timeDiff / MINUET_TIMES)
      : parseInt((timeDiff % restTime) / MINUET_TIMES);
  restTime += minute * MINUET_TIMES;
  const second =
    restTime === 0
      ? parseInt(timeDiff / SECOND_TIMES)
      : parseInt((timeDiff % restTime) / SECOND_TIMES);
  const [h, m, s] = [hour, minute, second].map(formatting);
  const time = `${date}d ${h}h ${m}m ${s}s`;
  clock.innerText = time;
}

function formatting(time) {
  return time < 10 && time >= 0
    ? "0" + time
    : time < 0 && time > -10
    ? `-0${Math.abs(time)}`
    : time;
}
Comments