はじめに
給与計算で 地味だけど絶対に間違えてはいけない 領域があります。
中途入退社の日割り計算です。
毎月の基本給は、まるまる 1 ヶ月在籍した従業員にはそのまま支給します。問題は、月途中で入社した人、月途中で退社した人、そして両方が同じ月に起きるレアケースです。
「20 日入社で、月給 30 万円。今月の給与はいくらにする?」
この問いに、給与計算ソフトはどう答えるかで、お客様の従業員の生活が左右されます。本記事では、niyase が日割り計算をどう実装したか、そして検証で確認した 26 ケースをご紹介します。
「日割り」と一口に言っても、複数の方式がある
まず、日割りには大きく分けて以下の選択肢があります。
| 方式 | 計算式 | 特徴 |
|---|---|---|
| 暦日基準 | 月給 × (在籍日数 ÷ 月の暦日数) | 2 月は 28 日、1 月は 31 日で割る |
| 営業日基準 | 月給 × (在籍営業日数 ÷ 月の営業日数) | 土日祝を除いて計算 |
| 所定労働日基準 | 月給 × (在籍所定労働日数 ÷ 月の所定労働日数) | 会社カレンダーで定めた所定日のみ |
niyase では 暦日基準 をデフォルトとしています。月給の支給単位 (= 「1 ヶ月という単位」) に対応する考え方として、最もシンプルで予想しやすいためです。会社の規程によって他の方式が指定されているお客様には、設定で切替可能な構造にしています。
よくある「うっかり間違える」5 つのパターン
パターン 1: 月の日数違いを忘れる
2 月入社の月給 30 万円の従業員と、3 月入社の同条件の従業員。両方とも「20 日入社」だった場合、初月給与は同じになるでしょうか。
- 2 月 (28 日) で 20 日に入社 → 在籍日数 9 日 → 9/28 × 30 万円 = 96,428 円
- 3 月 (31 日) で 20 日に入社 → 在籍日数 12 日 → 12/31 × 30 万円 = 116,129 円
同じ「20 日入社」でも、月の日数で結果がかなり違います。「自社の規程の式」と「ソフトの計算結果」が、月によって違って見える原因はこれです。
パターン 2: 月初入社 (= 1 日入社) は日割りなし
「3 月 1 日入社」の場合、その月は 満額 の月給を支給するのが一般的です。日割り係数は 1.0 (= 全額)。
これを「3 月 1 日入社 → 3 月の在籍 31 日 / 月の暦日 31 日 = 100%」と計算すれば結果は同じですが、「1 日入社だから日割りしない」と「1 日入社の日割り係数は 1.0」が、コードの分岐として違って見えるとバグの温床になります。
niyase では「日割り係数 = min(在籍日数, 月の暦日数) ÷ 月の暦日数」という統一式にして、入社日や退社日に関わらず同じ式が走るようにしました。
パターン 3: 月末退社 (= 月の末日退社) は満額
「3 月 31 日退社」の場合、その月は満額。3 月 30 日退社なら 30/31。
「末日退社」と「最終日退社」の表現はそれぞれの会社の規程で扱いが違うので、niyase では「退社日まで在籍とみなす」(退社日も日数に含める) を採用しています。
パターン 4: 同月内の入社 → 退社
非常に稀ですが、例えば 3 月 10 日入社 → 3 月 25 日退社、というケース。
- 在籍日数 = 25 - 10 + 1 = 16 日 (両端を含む)
- 日割り係数 = 16 / 31
niyase では入社日も退社日も両方在籍日数に含めるルールにしているため、上記の式がそのまま使えます。
パターン 5: 入社月と退社月が違う場合の中間月
入社月と退社月の 間の月 は、当然満額です。
「2 月 15 日入社、4 月 20 日退社」の従業員の 3 月給与は、3 月まるまる在籍なので満額。これは日割り計算ロジックに「月単位の判定」を入れて、対象月が在籍期間に完全に含まれているなら係数 1.0 を返す、という分岐です。
niyase の実装方針 — 純粋関数として切り出し
これらの計算ロジックを、niyase では 純粋関数 として共通パッケージに切り出しました。
function calculateProration({
joinDate, // 入社日 (なければ undefined = 期初から在籍)
leaveDate, // 退社日 (なければ undefined = 期末まで在籍)
periodStart, // 給与計算期間の開始日 (e.g. 2026/03/01)
periodEnd, // 給与計算期間の終了日 (e.g. 2026/03/31)
}): ProrationResult;
この関数は、入社日 / 退社日 / 計算期間 の組み合わせを入力として、日割り係数 (0.0〜1.0) と在籍日数を返します。給与計算サービス側では、この係数を基本給などに掛け算するだけで日割りが完了します。
Vitest で 26 ケースを通す
純粋関数として切り出したことで、テストが書きやすくなりました。実装時には以下の 26 ケースをテストとして用意しました。
月の日数違い (4 ケース)
- 28 日月 (2 月、うるう年なし)
- 29 日月 (2 月、うるう年)
- 30 日月 (4 月 / 6 月 / 9 月 / 11 月)
- 31 日月 (1 月 / 3 月 / 5 月 / 7 月 / 8 月 / 10 月 / 12 月)
入社パターン (7 ケース)
- 月初 (1 日) 入社 → 日割りなし
- 月途中入社 (5 日 / 15 日 / 25 日)
- 月末 (末日) 入社 → 1 日分
- 期初前入社 (前月以前) → 満額
- 期末後入社 (翌月以降) → 0
退社パターン (7 ケース)
- 月初 (1 日) 退社 → 1 日分
- 月途中退社 (10 日 / 20 日)
- 月末 (末日) 退社 → 満額
- 期末後退社 (翌月以降) → 満額
- 期初前退社 (前月以前) → 0
入退社が同月のケース (4 ケース)
- 月初入社 + 月末退社 → 満額
- 月途中入社 + 月途中退社
- 同日入退社 (極稀)
- 入社日 > 退社日 (データ不整合、エラー扱い)
計算期間ずれ (4 ケース)
- 計算期間が 1 ヶ月より長い (補正期間)
- 計算期間が 1 ヶ月より短い (締日変更月など)
- 入社日が計算期間外
- 退社日が計算期間外
すべてのケースで期待値どおりの結果が返ることを CI で継続的に検証しています。テストケース数を訴求するつもりはなく、「こういう罠があるとわかっているから、漏れがないように網羅している」という姿勢の現れだと思っていただければ。
おわりに
中途入退社の日割り計算は、給与計算の中でも「事故が起きると従業員から信頼を失う」領域です。1 円ズレるだけで「うちの会社の給与計算は大丈夫か」と疑念が生まれます。
niyase クラウド (認証取得を準備中) では、上記のロジックがバックエンドで自動適用されます。お客様側で「うちの会社の場合、日割りはどうするんだっけ?」と毎月考える必要のない作りにしています。
派手な機能ではありません。でも、お客様の従業員 1 人ひとりの信頼が積み上がる場所だと考えて、地味に作り込んでいます。