見出し画像

経過時間を計算するにあたり、営業時間内だけをカウントしてしたい。GASで。

どうもtmdです。

営業時間内だけをカウントした経過時間、前職でKPI出すのに需要があったんですが、現職でも需要があったのでもしかして世の中に需要がある?と思ったのが今週。

じゃあ、noteにしようとコードを見たら、めちゃんこルー大柴英語で書いた関数名で気持ち悪くて直すつもりがまるっとコードを書き直したのも今週。

私がGoogle翻訳で適当につけた変数名について、同僚(帰国子女)が日本語の意味を教えてくれたのが2日前。

いろんなパターンで稼働させた結果なんかいい感じで数字でるからきっとあってると思ってようやく記事にしたのが今です。

ということで直したコードをここに置いていきます。
なんか変だったら調整してください。

■準備

正しくは準備というより動かなかったら、の説明なのだが、
このGASを承認するアカウントのGoogleカレンダーに「日本の祝日」を入れてない人でエラーになった人がいたので、もしカレンダーを呼ぶ行でエラーが出る場合は以下を追加して欲しい。

  1. Googleカレンダーを開く

  2. 設定を開く

  3. カレンダーを追加を開く

  4. 関心のあるカレンダーを探すを開く

  5. 地域限定の祝日から「日本の祝日」を探してチェックをいれる

    1. なんだかよくわからないけど、日本の祝日 英語varがあるっぽくてそっちだとダメだった。

■関数の呼び方

以下の値をそれぞれいれます。

入れる値

  • date1:計測開始日時

  • date2:計測終了日時

  • hours1:営業開始時間(時間)

  • minutes1:営業開始時間(分)

  • hours2:営業終了時間(時間)

  • minutes2:営業終了時間(分)

呼び方

elapsedHoursOfBusinessHours(date1,date2,hours1,minutes1,hours2,minutes2)

イメージ

date1,date2は計算に使う値(稼働した時間)で、それ以外は会社等の営業時間です。

例えば、2023/5/1 10:30〜現在の日時までの経過時間を、営業時間だけカウントし、結果をconsole.logで経過時間を出したい場合で、営業時間は9:15〜18:00だとこのような感じ。

var date1 = new Date("2023/5/1 10:30:00")
var date2 = new Date()
console.log(elapsedHoursOfBusinessHours(date1,date2,9,15,18,00))

■本体

計測開始日からスタートしてwhileするごとに1日ずつカウントアップ?しながらから計測終了日を超える前までチェックします。
この時、以下の措置を入れてから経過時間を計算しています。

  • 土日祝日は計算しない

  • 計測開始側が営業時間前の場合は営業開始時間にする

  • 計測終了側が営業終了後の場合は営業終了時間にする

これで計測終了時-計測開始した値が0以上ならを足していく感じ。

function elapsedHoursOfBusinessHours(startDate,endDate,bStartH,bStartM,bEndH,bEndM){
  var startdayStartofwork= new Date(startDate)
  var starCheck= new Date(startDate.getFullYear(),(startDate.getMonth()),startDate.getDate(),bStartH,bStartM,0)
  var endCheck= new Date(endDate.getFullYear(),(endDate.getMonth()),endDate.getDate(),bEndH,bEndM,0)
  var exclusion = 0;
  while(startdayStartofwork<=endDate){
    //土日祝以外なら対応
    if(!isHoliday(startdayStartofwork)){
      if(dateChange(startdayStartofwork)==dateChange(startDate) && !((startDate-starCheck)/1000/60/60<0)){
        //ループ1回目で営業開始時間以降の時間を指定している場合
        var startTimeForCalculation= new Date(startDate)
      }else{
        //ループ1回目で営業開始時間以前の時間を指定している場合 もしくはループ2回目以上の場合
        var startTimeForCalculation= new Date(startdayStartofwork.getFullYear(),(startdayStartofwork.getMonth()),startdayStartofwork.getDate(),bStartH,bStartM,0)
      };
      if(dateChange(startdayStartofwork)==dateChange(endDate) && endDate<=endCheck){
        //現在の処理が終了日と同じ日付を見ていて、終了時間が営業終了時間より前の場合
        var endTimeForCalculation= new Date(endDate)
      }else{
        //現在の処理が終了日と同じ日を見ていて、終了時間が営業終了時間より後、もしくは終了日じゃない日を見ている場合
        var endTimeForCalculation= new Date(startdayStartofwork.getFullYear(),(startdayStartofwork.getMonth()),startdayStartofwork.getDate(),bEndH,bEndM,0)
      };
      var calculationData = (endTimeForCalculation-startTimeForCalculation)/1000/60;
      if (calculationData>0){
      exclusion = exclusion + calculationData;
      };
    };
    startdayStartofwork = new Date(startdayStartofwork.getFullYear(), startdayStartofwork.getMonth(), startdayStartofwork.getDate()+1)
  };
return exclusion
};

日付の変換がコード内に書くと長くて心がしんどかったんで関数にしました。
読みやすさ的にどちらが良かったのだろうか。

function dateChange(dateType){
return Utilities.formatDate(dateType,'Asia/Tokyo','yyyy-MM-dd');
};

土日祝日の判定です。

function isHoliday(today){
  //土日を判定
  var weekInt = today.getDay();
  if(weekInt <= 0 || 6 <= weekInt){
    return true;
  };
  //祝日を判定
  var calendarId = "ja.japanese#holiday@group.v.calendar.google.com";
  var calendar = CalendarApp.getCalendarById(calendarId);
  var todayEvents = calendar.getEventsForDay(today);
  if(todayEvents.length > 0){
    return true;
  };
  //年末年始を判定
  var month = today.getMonth()+1;    //月
  var day   = today.getDate();     //日
  if(month===12 && day>=29 || month===1 && day<=3){
      return true;
  };
  return false;
}

繰り返しの案内です。
こちらの検証では数字は出たけれど、なんか変だったら調整してください。

この記事が気に入ったらサポートをしてみませんか?