【GAS、JavaScript】月末や月またぎも考慮した日付の計算をする

Code

はじまり

リサちゃん
リサちゃん

月またぎの日付の計算がしたいなあ

135ml
135ml

結構、野放しにしていたこの問題。

リサちゃん
リサちゃん

調べても調べても・・・!

135ml
135ml

じゃあ、跨ぐか

基本的な日付の取得

まず、JavaScriptでは、Dateオブジェクトを使用して日付を扱います。新しい日付を作成するには、以下のようにします。

let today = new Date(); // 今日の日付
let specificDate = new Date(2024, 1, 13); // 2024年1月13日

日本時間を考慮した日付の取得

そして、タイムゾーンを考慮した日付の取得はこんな感じで可能です。

まあ、下準備はこんなもんでしょうか。

const timezoneDiffOfTokyo = (new Date().getTimezoneOffset() + (540)) * 60 * 1000;
const today = new Date(Date.now() + timezoneDiffOfTokyo);

日付の成分の取得と設定

日付から年、月、日などを取得または設定するには、getおよびsetメソッドを使用します。

const today = new Date();
let year = today.getFullYear();
let month = today.getMonth(); // 注意: 月は0から始まる
let day = today.getDate();
console.log(today)
console.log(year)
console.log(month)
console.log(day)

today.setFullYear(2025);
today.setMonth(11); // 12月
today.setDate(25);
console.log(today)
console.log(today.getMonth())
console.log(today.getDate())

出力結果はこうなります。 月の部分だけ注意が必要です。

Mon Feb 12 2024 20:29:13 GMT-0500 (Eastern Standard Time)
2024
1
12
Thu Dec 25 2025 20:29:13 GMT-0500 (Eastern Standard Time)
11
25

日付の計算

明日の日付や、1週間前といった日付を取得したければこう書けます。

let tomorrow = new Date();
tomorrow.setDate(today.getDate() + 1);

let lastWeek = new Date();
lastWeek.setDate(today.getDate() - 7);

しかし、これだけだと、月またぎを考慮した日付計算ができません。

例えば、2/13から1/31を引くと、「-18」になってダメダメです。

月またぎで2つの日付の差が分かる関数

そして、本題です。

まずは、コードから見せます。

/**
 * @description Get boolean value whether the difference between formerDay and latterDay is over or not.
 * @param {Date()} formerDay
 * @param {Date()} latterDay
 * @param {number} targetDiff
 * @return {boolean}
*/
function isDateDiffOver(formerDay, latterDay, targetDiff){
  if(Math.abs(latterDay.getMonth() - formerDay.getMonth()) > 2){
    console.log(`isDateDiffOver: 555555555555555555555555555555555555555555555555555555555555555555555`);
    return true;
  }else if(Math.abs(latterDay.getMonth() - formerDay.getMonth()) === 1){
    let diffDates = latterDay.getDate() - formerDay.getDate();
    formerDay.setDate(0); // Get end of month
    diffDates += formerDay.getDate();
    console.log(diffDates);
    console.log(`isDateDiffOver: 666666666666666666666666666666666666666666666666666666666666666666666`);
    if(diffDates <= targetDiff){
      return true;
    }
  }else{
    if(latterDay.getDate() - formerDay.getDate() <= targetDiff){
      console.log(`isDateDiffOver: 77777777777777777777777777777777777777777777777777777777777777777777777`);
      return true;
    }
  }
  return false;
}

この関数は、formerDay(前者の日付)とlatterDay(後者の日付)の差が、targetDiffの数値を超えているかどうかを取得できるものです。

文章で書くとややこしいので、図付きで説明します。

考え方としては、最終的には緑色の範囲と青色の範囲が欲しいので、

  1. latterDay(後者の日付)と、formerDay(前者の日付)に2ヶ月以上の差があれば、trueになります。
  2. diffDatesを宣言するときは、latterDay(後者の日付)からformerDay(前者の日付)を引きます。
  3. そして、formerDay → End of Monthの部分の範囲が取れていないので、formerDay.setDate(0)をします。
  4. formerDay.setDate(0)をすると、前者の月の末日が取得できます。
  5. そして、formerDay.getDate()を足すと、緑色の範囲と青色の範囲が取得できたことになります。
  6. 緑色の範囲と青色の範囲にtargetDiffより大きい差があれば、trueになります。
  7. 緑色の範囲と青色の範囲がtargetDiffより小さかったら、falseになります。(指定した差の中に収まっている。)

やっぱりタイムスタンプが最強なのかもしれない

とまあ、年月日のパラメータを使ってこねていきますが・・・

この考え方で計算すると、じゃあ12月と1月の場合はどうするの?とか、formerDayがlatterDayより新しい日付だったらどうするの?とか、何だか色々と面倒くさいことが残ってしまいます。

そこで、日付同士を計算する時は、「UNIXタイムスタンプ」を使うのが最善策なのかもしれません。

(JavaScriptのDate型でググっても、あんまりUNIXタイムスタンプで計算する方法がヒットしませんよね・・・)

UNIXタイムスタンプとは、巷で有名なわわわさんから引用すると・・・

時間の表現方法だよ。「1970年1月1日午前0時0分0秒(UTC)」からの経過秒数で表現するよ。

「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

だそうです。

まあ、時刻を表す絶対的な指標ということですかね。

それでは、UNIXタイムスタンプを活用した関数です。これが本命。

/**
 * @description Get boolean value whether the difference between formerDay and latterDay is over or not.
 * @param {Date()} formerDay
 * @param {Date()} latterDay
 * @param {number} targetDiff
 * @return {boolean}
 * @example
 * formerDay = 2022/01/23; latterDay = 2022/01/24; targetDiff = 1; return false;
 * formerDay = 2022/01/23; latterDay = 2022/01/24; targetDiff = 0; return true;
*/
function isDateDiffOver(formerDay, latterDay, targetDiff){
  
  let timestamp1 = Math.floor(formerDay.getTime() / 1000);
  let timestamp2 = Math.floor(latterDay.getTime() / 1000);
  const margin = 10 * 1000;
  console.log(formerDay)
  console.log(latterDay)
  console.log(targetDiff)
  console.log(`isDateDiffOver: 11111111111111111111111111111111111111111111111111111111111111111`);
  console.log(timestamp2 - timestamp1)
  console.log(60 * 60 * 24 * (targetDiff + 1) - 1)
  if(Math.abs(timestamp2 - timestamp1) >= 60 * 60 * 24 * targetDiff - margin){
    console.log(`isDateDiffOver: 44444444444444444444444444444444444444444444444444444444444444444`);
    return true;
  }
  console.log(`isDateDiffOver: 999999999999999999999999999999999999999999999999999999999999999999999`);
  return false;
}

UNIXタイムスタンプは、日付ではなく整数型の値なので、比較をするのが物凄く楽です。もう、こんなにコードが短くなってしまいました。

UNIXタイムスタンプはミリ秒単位で記録されるものなので、秒間や日にちの比較をする際には1000で割ってあげると良いでしょう。

これで、じゃあ12月と1月の場合はどうするの?とかの問題が解消されます。しかし、「formerDayがlatterDayより新しい日付だったらどうするの?」とかの問題が残っています。

そこで、もう一つ関数を用意します。

/**
 * @description Get boolean value whether latterDay is later than formerDay or not.
 * @param {Date()} formerDay
 * @param {Date()} latterDay
 * @return {boolean}
 * @example
 * formerDay = 2022/01/25; latterDay = 2022/01/24; return false;
 * formerDay = 2022/01/23; latterDay = 2022/01/24; return true;
*/
function isLatterDayLater(formerDay, latterDay){
  let timestamp1 = Math.floor(formerDay.getTime() / 1000);
  let timestamp2 = Math.floor(latterDay.getTime() / 1000);
  if(timestamp2 - timestamp1 > 0){
    console.log(`isLatterDayLater: 88888888888888888888888888888888888888888888888888888888888888888888888888`);
    return true
  }
  console.log(`isLatterDayLater: 999999999999999999999999999999999999999999999999999999999999999999999`);
  return false;
}

この関数を使うことで、formerDayとlatterDayの前後関係を判定することが出来ます。

なので、この節で紹介した、isDateDiffOver()isLatterDayLater()で論理演算すれば日付に関する計算は問題ないのではないでしょうか。(1970年1月1日午前0時0分0秒が基準なのをお忘れなく。)

おしまい

リサちゃん
リサちゃん

よし、日付の差が取れたぞ

135ml
135ml

日付の操作って、本当に面倒くさいよな

以上になります!

コメント

タイトルとURLをコピーしました