給与計算で利用する年月週目指定で日数を割り出す関数
中小企業ではあまり採用していないと思いますが、割と大企業の場合、フレックスといったような月単位の変形労働時間制を導入している企業の場合、残業時間の計算といっても、1日に8時間を超える部分を集計して「残業代」として支給ではなく、月単位で見て計算する必要があります。
月の1日目が日曜日であるならば面倒ではないのですが、普通は週の途中から始まるわけで、この時、週40時間を超過している部分を計算する際に、月初・月末は月を跨ぐ事になります。この場合、その週の日数による日割りな計算もする必要があります。今回は、これを実現する為の関数をNode.jsで作る必要があったので、ここに記しておきます。
月跨ぎの場合の週40時間超過の計算法
例えば、2021年9月の場合、第一週の1日目は水曜日から始まります。よって、土曜日までの4日間に於ける労働時間の合計が計算対象になりますが、この時の計算法は以下の通り。
1 2 |
//月初・月末の週40時間超過計算式 40時間 * 端日数 / 7 |
まず、通常の週の場合、週40時間なので、1日労働時間が8時間であるならば、5日間がリミットとなります。これを超えて働いた場合には、その部分が週40時間超過の割増賃金支払いの対象となる。当然これには土日祝日などの法定・所定休日での労働時間も含まれる事になります。
しかし、月跨ぎの場合には毎月計算時に前の月の労働時間を再度ピックアップしてきて、超過してるかな?という計算を人数分行うのはなかなか骨が折れます。
- 4日間が端日数となるので、この月の第一週に於ける週40時間超過の簡便な計算では、4日/7*40にて上限を計算すると最大22.85時間(分換算で1371分)となります。
- 当然最終週も7日に満たない事があるので、同様に計算を行います。
- 第一週に於いて、水木金を7時間の所定労働時間で働いた場合、合計で21時間となりこの場合は超過がないという事になります。
- 同様に、3日を8時間で働いた場合、合計で24時間となり、1.15時間(69分)が超過時間となります。この部分が法定外つまり割増賃金の支払いとなります。(25%割増)
- 最終週の計算分も含めて、割増賃金としてその月の給与計算の割増額合計として計算することに
これを機械的に計算するには、週目の算出と週目毎の端日数を割り出す必要があります。
図:月跨ぎの労働時間上限の計算方法
ソースコード
指定の日がその月の何週目か?
1 2 3 4 5 6 |
//週目を演算する関数 function getWeeks(dateman) { var chkdate = new Date(dateman); var msg = Math.floor((chkdate.getDate() - chkdate.getDay() + 12 ) / 7); return msg; } |
例えば、2021年11月16日は、11月の3週目になるので、日付を渡すと、3が返ってくる関数です。
これを元に集計時に週目毎の労働時間を集計する為のフィールドとして利用します。週毎に40時間超過を計算する必要があるため、この週目の算出は必須項目となります。
指定年月と週目でその週の日数を調べる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
//指定年月と週番号からその週の日数を割り出す関数 function weeknum2daycnt(year, month, weekNumber,flg){ //指定週番号の頭の日付・曜日を取得 let start = new Date(year, month - 1, (weekNumber - 1) * 7 + 1); let day = start.getDay(); //日付の修正 if(weekNumber == 1){ if(day == 0){ start.setDate(start.getDate() + (day ? 0 - day : -6)); } }else{ if(day != 0){ start.setDate(start.getDate() - day); } } //startの日付が指定月なのかチェック var startmonth = start.getMonth() + 1; if(startmonth == month){ //指定月内なので何もしない }else{ //前月になってるので、今月の1日にする start = new Date(year + "/" + month + "/01"); } //endの日付が指定月なのかチェック(週末の日付を算出するために6を加算) let end = new Date(start); if(weekNumber == 1){ //途中から始まるので、 if(day == 0){ //日曜から始まるので+6 end.setDate(end.getDate() + 6); }else{ //途中から始まるので土曜日までの日数を足す end.setDate(end.getDate() + Number(6 - day)); } }else{ //日曜から始まるので+6 end.setDate(end.getDate() + 6); } var endmonth = end.getMonth() + 1; if(endmonth == month){ //指定月内なので何もしない }else{ //翌月になってるので今月末にする end = new Date(year,month,0); } //startとendの間の日数を算出 var termDay = ((end - start) / 86400000) + 1 ; //flgで返り値を分岐 if(flg == true){ //日付の期間を返す return { start: start, end: end } }else{ //その週の日数を返す return termDay; } } |
- 1年を通しての週番号を出す関数はウェブ上でもいろいろ公開されていますが、その月の中での週番号(1~6週)が給与計算では必要になります。
- また、その場合の第1週と最終週では「端数日」が出るので(7日ではない)、それを算出するのが今回の関数の目的です
- 通常の週では、7日間合計が40時間以上の労働部分は法定外時間として125%の支払いとして計算します。
- 端数日のある週では、前述計算式で出した上限値を超えた部分を法定外時間として計算します。
- 実際の週40時間超過では、実労働時間 - 労働上限時間 - 残業時間で計算し、差がプラスで出た分が、週40時間超過の法定外時間となります。
- この関数は、年、月、週番号、フラグを引数で受け取り、フラグがtrueならばその週の期間を返し、falseならばその週の日数を算出して返します
- 開始日および終了日が前月・翌月の場合には、それぞれ1日の日付、月末の日付に変換するようにしています。
- ISO8601の規格による週番号は、週の始まりが「月曜日」からになってしまうので、給与計算等ではちょっと使えません。