[GAS][JS] Moment 라이브러리의 diff에서 날짜 차이

(추기 2020/09/19) Moment.js의 개발이 종료한 것 같습니다.



↓ 여기 참조
htps : // 모멘 tjs. 이 m/두 cs/

지금 라이브러리를 사용할 수 없게 되는 것은 없다고 생각합니다만, 앞으로, 적극적으로 이 라이브러리를 선택할지 어떨지는 생각이군요.

그리고 GAS 버전의 라이브러리가 어떻게 될지에 대한 정보를 찾을 수 없습니다. (누군가를 알고 싶으면)

GAS로 이야기하지만 Javascript에서도 마찬가지입니다.

GAS 버전 Moment 라이브러리의 ID는 아래와 같습니다.
MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48

하고 싶었던 일



이런 표를 만들고, 매일 아침 8시대에 GAS가 기동해, 「마감까지 3일」이내가 되면 「마감 가깝지만 괜찮아?」라고 하는 리마인드를 해 주는 기능을 만들고 싶다.



그 때문에 Moment 라이브러리를 사용해 「날짜의 차분」을 취하고 싶었다.

좋지 않은 예



단순화를 위해 A2 셀의 날짜만을 대상으로 합니다.

처음에는 이렇게 썼습니다.
function sample1() {
  // 日付のセルからgetValue()したら Dateオブジェクト が取れるのでこう書いてしまいます
  const deadline_date = new Date("2020-09-10");

  const deadline_moment = Moment.moment(deadline_date);
  const now_moment      = Moment.moment();

  const diff = deadline_moment.diff(now_moment, "days");
  console.log(diff);
}

그리고 「오늘은 2020/9/9라고 한다」가 아닙니까.
A2셀은 2020/9/10이므로 1이 출력될 것을 기대하지 않습니까?
그러나 출력 결과는 "0"

좋지 않은 이유



상기에서 「오늘은 2020/9/9라고 한다」라고 썼습니다만,
실제로 이 GAS가 실행되는 시간은 2020/09/09 12:34:56이거나 하는 것입니다.

그리고 deadline 으로 지정하고 있는 것은 「2020-09-10 00:00:00」입니다.

실험해 보면 이렇게 되었습니다 ↓
function sample2() {
  const deadline_date = new Date("2020-09-10 00:00:00");
  const deadline_moment = Moment.moment(deadline_date);

  const now_moment1 = Moment.moment("2020-09-09 00:00:00");
  const diff1 = deadline_moment.diff(now_moment1, "days");
  console.log(diff1); //=> 1 

  const now_moment2 = Moment.moment("2020-09-09 00:00:01");
  const diff2 = deadline_moment.diff(now_moment2, "days");
  console.log(diff2); //=> 0
}

now_moment1과 now_moment2는 "1 초"다릅니다.

diff1 에서는 deadline인 2020-09-10 00:00:00 과 2020-09-09 00:00:00 의 차이가 24:00:00 이므로 하루.
diff2 에서는 deadline인 2020-09-10 00:00:00 과 2020-09-09 00:00:01 의 차이가 23:59:59 이므로 0일.

라는 움직임 같다.

어떻게 해야할까



「날짜」로 비교하고 싶기 때문에 이런 것이라고 하는 것은.

「시분초 밀리 세컨드에 제로를 세트 버린다」작전
function sample3() {
  const deadline_date = new Date("2020-09-10 00:00:00");
  const deadline_moment = Moment.moment(deadline_date);

  // 時分秒ミリ秒にゼロをセットしちゃう
  const today_moment = Moment.moment().hour(0).minutes(0).second(0).millisecond(0);
  const diff = deadline_moment.diff(today_moment, "days");

  console.log(diff);
}

이제 실행 시간이 "2020-09-09 11:11:11"이더라도 "1"이 출력됩니다.

↓ 만약을 위해 실험
function sample4() {
  const deadline_date = new Date("2020-09-10 00:00:00");
  const deadline_moment = Moment.moment(deadline_date);

  const now = new Date("2020-09-09 11:11:11")
  const today_moment = Moment.moment(now).hour(0).minutes(0).second(0).millisecond(0);

  const diff = deadline_moment.diff(today_moment, "days");
  console.log(diff); //=> 1
}

예상대로!

정말 그렇죠?



"days"로 비교할 때, "24시간 미만인지 아닌지로 판정하고 있다"는 것은, 동작시킨 결과를 보고 내가 추측하고 있는 곳입니다만, 실제로 어떤 구현이 되어 있는지 moment 라이브러리 diff.js 소스 코드 를 보았습니다. (이것은 moment.js의 소스 코드이며 GAS 라이브러리의 코드가 아니기 때문에 GAS에서는 다른 구현 일 수 있지만 분명히 동일합니다)
export function diff(input, units, asFloat) {
    var that, zoneDelta, output;

    if (!this.isValid()) {
        return NaN;
    }

    that = cloneWithOffset(input, this);

    if (!that.isValid()) {
        return NaN;
    }

    zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;

    units = normalizeUnits(units);

    switch (units) {
// 略
        case 'day':
            output = (this - that - zoneDelta) / 864e5;
            break; // 1000 * 60 * 60 * 24, negate dst
// 略
    }

    return asFloat ? output : absFloor(output);
}
864e5 는 1 일을 밀리 세컨드로 했을 때의 86400000 의 지수 표기.
따라서 시간의 차이를 하루를 나타내는 밀리 세컨드로 나눕니다.

diff 함수의 세 번째 인수 asFloat는 지정하지 않으므로,
return asFloat ? output : absFloor(output);

그럼 absFloor(output) 가 return 된다.
absFloor() 함수의 정의는 여기
export default function absFloor(number) {
    if (number < 0) {
        // -0 -> 0
        return Math.ceil(number) || 0;
    } else {
        return Math.floor(number);
    }
}

Math.ceil() : 인수로 주어진 숫자 이상의 최소 정수를 반환합니다.
Math.floor() : 인수로 주어진 숫자 이하의 최대 정수를 반환합니다.

그래서 output (시간의 차이를 하루를 나타내는 밀리 초로 나눈 숫자)
  • 0.999이면 0을 반환하고
  • 1.234라면 1을 반환하고
  • -3.55 라면 -3 을 돌려준다.

  • 내 추측은 있었던 것 같습니다! (...라는 여기까지의 흐름이 잘못되면 가르쳐 주었으면 합니다)

    결론



    그렇다고 해서 「날」을 비교하고 싶다면, 「날」(date)보다 작은 단위(hour, minutes, second, millisecond)는 제로로 메워 준다

    보충이지만 밀리 초가 나오면
    const deadline_date = new Date("2020-09-10 00:00:00.000");
    

    하는 편이 입도는 갖추어지네요.
    (밀리 세컨드까지 지정해 Date 객체를 new 한 적이 없기 때문에 힘들다)

    좋은 웹페이지 즐겨찾기