アルゴリズム：5分, 15分, 30分区切りでタイムカードのスタンプ時刻を刻む考え方

> 勤怠表などで打刻する場合、四捨五入でなく 15 分区切り／30 分区切りといった**区切り時刻で打刻**する必要があります。どうすればいいですか？


```text:タイムカードの15分区切りの打刻例（08時〜18時勤務）
例）  8:01 出社 → 勤怠打刻時間：08:15 （14分間の 切り上げ）
例） 11:32 出社 → 勤怠打刻時間：11:45 （13分間の 切り上げ）
例） 18:42 退社 → 勤怠打刻時間：18:30 （12分間の 切り下げ）
例） 22:02 退社 → 勤怠打刻時間：22:00 （02分間の 切り下げ）
```

## 実は「禁断の計算術」です

勤怠、つまり毎日の勤労時間を記録する際に、5 分や 15 分単位で切り捨てる計算は「切り捨て御免」と呼ばれる古くからの計算術です。

しかし、この計算術は **Qiita では禁断の術式**とされており、しかも**日本国内では違法**になります。そのため、禁断の術を暴露したこの記事も、書いた私も消されるかもしれません。

あなたが総務の方で上司に頼まれたり、従来からの勤怠ルールで効率化を図るために訪れた場合、「計算方法は簡単らしいが、勤怠に利用するには上司の承諾が必要である」旨をメールで伝え、下記の「理由」を上司の方にお見せください。

<details><summary>禁断の計算術／違法な計算式である理由</summary><div>

## 違法だと言っているのに労働局から叱られないとわからない企業はまだまだ多いのです

アルバイト・派遣社員・社員と言った「自社株を持たない労働者」つまり、法的に言う「従業員」の労働時間における勤怠記録は「１分単位で記録する」か「切り上げのみ」が許されています。

というのも、**日々の勤怠記録において実際の労働時間を切り捨てる行為は労働基準法[第24条](https://ja.wikibooks.org/wiki/%E5%8A%B4%E5%83%8D%E5%9F%BA%E6%BA%96%E6%B3%95%E7%AC%AC24%E6%9D%A1)および[第37条](https://ja.wikibooks.org/wiki/%E5%8A%B4%E5%83%8D%E5%9F%BA%E6%BA%96%E6%B3%95%E7%AC%AC37%E6%9D%A1)に違反し違法**となるからです。（月締めの集計時の端数処理でなく「毎日の勤怠記録」の時点での切り捨てを指しています）

つまり、体勢的に「実際の労働時間をなかったことにするのは１分でも違法」と言うことです。逆に「18:25 に退社して 18:30 に退社したことにする」のは問題ありません。会社側からすると理不尽ですが、労働者を守る法律ではそうなっているそうです。

```text:タイムカードの15分区切りの打刻例
勤務時間 8:00 〜 18:00（10 分前出社強制）
例）  7:59 出社 → 勤怠打刻時間：08:00 （01分間の 切り上げ => 01分間の実務時間の切り捨て）
例）  8:00 出社 → 勤怠打刻時間：08:15 （15分間の 切り上げ => 15分間の実務時間の切り捨て）
例）  8:01 出社 → 勤怠打刻時間：08:15 （14分間の 切り上げ => 14分間の実務時間の切り捨て）
例） 11:32 出社 → 勤怠打刻時間：11:45 （13分間の 切り上げ => 13分間の実務時間の切り捨て）
例） 18:42 退社 → 勤怠打刻時間：18:30 （12分間の 切り下げ => 12分間の実務時間の切り捨て）
例） 22:02 退社 → 勤怠打刻時間：22:00 （02分間の 切り下げ => 02分間の実務時間の切り捨て）
```

そのため、ここをお読みになった時点で禁断の計算術である旨を知った以上、あなたが**違法を承知でこの計算式を勤怠の計算に組み込むのであれば幇助の疑いを持たれる**可能性があります。いや、ほんとに。

従来からの習慣で手の付けようがない／わからないという場合は、[所在地を管轄する労働基準監督署](https://www.mhlw.go.jp/stf/seisakunitsuite/bunya/koyou_roudou/roudoukijun/location.html)に相談することをおすすめします。労働局による抜き打ちや査察などが入ると、過去にまたがって不足分の支払いが命じられる可能性もあります。

また「遅刻ばかりする」「退勤しろと言ったのに勝手に仕事をしていた」などの、ペナルティや勤務態度は勤怠の集計とは別問題です。労務士の方に相談いただく必要があります。

### 参考文献

- [福井県庁 労働委員会事務局 職場のトラブルＱ＆Ａ ～時間外労働の端数処理～](http://www.pref.fukui.jp/doc/roudouiinkaijimukyoku/qa/qa57.html)
- [東京労働局 労働基準法しっかりマスター P.6](http://www.roumu.or.jp/data/pdf/20090310_roudou_warimashi.pdf#page=6)

---

</div></details>

## 禁断の計算術

>「現在の時刻」を「区切り時間」で割った整数の値に「区切り時間」を掛ける

```text:15分区切りの場合（切り捨て）
（現在の分 割る 15分） 掛ける 15分
```

このように、勤怠の計算においては禁断の計算術ではあるものの、**計算自体は簡単**です。

```python:切り捨て
min   = minute(time())       # 現在時刻から分を取得
step  = 15                   # 15分区切り
stamp = (min // step) * step # // は整数の割り算とする

print(stamp)
```

また、切り上げは「１」を掛ける前に加えます。

```text:15分区切りの場合（切り上げ）
（（現在の分 割る 15分） 足す 1） 掛ける 15分
```

```python:切り上げ
min   = minute(time())           # 現在時刻から分を取得
step  = 15                       # 15分区切り
stamp = (min // step + 1) * step # // は整数の割り算とする

print(stamp)
```

:::note info
<sub><sup>鋭い方<sup><a href="#comment-33c27a12fb865f395bcc">^1</a></sup>はお気付きかもしれません。切り上げ時の <code>+1</code> をすると <code>0</code> 分ピッタリに出社しても遅刻扱いとなる<strong>「<code>10</code> 分前出社」を強制する<ruby>黒魔術の術式<rt>ブラック・マジック</rt></ruby></strong>となります。</sup></sub>
:::


- [オンラインで Python3 の場合の動作例をみる](https://paiza.io/projects/cFe82driQU1CeP6VJROm7g) @ paiza.IO

### 禁断の秘術の使い所

n 分区切りが好まれるのは、タイムスタンプや手書きを勤怠ソフトに手打ちしたり、月締めで手計算するのが大変だったりすることから[ポカをする](https://ja.wikipedia.org/wiki/%E3%83%9D%E3%82%AB%E3%83%A8%E3%82%B1)可能性があった時代の名残りなのです。つまり「総務のリスクを減らすために n 分区切りにする」という習慣が大半なのです。

では「勤怠の計算以外での活用方法」といえば、**細かすぎて伝わらないデータをわかりやすくする**などに使われます。

```text:どこらへんの時間帯が多いかわかりやすくなる
// ポットのお湯が使われた時間のログ
// 詳細な時間 → 5分区切り → 15分区切り
08:06 → 08:05 → 08:00
08:11 → 08:10 → 08:00
08:16 → 08:15 → 08:15
08:10 → 08:10 → 08:00
09:13 → 09:10 → 09:00
08:30 → 08:30 → 08:30
```

例えば、センサーで集計した莫大なデータから機械学習用の教材（教師データ）などにも使われます。具体的には、詳細なデータ以外にも大雑把なくくりでデータを荒くして教材を増やすなどです。

グラフィックなどでは RGB などの色情報を荒くして画像サイズを落とすのにも使われたり、サウンド・ソフトでは解像度を荒くしてプレビューに使われたりします。

データ（の集計結果）の処理以外では**集計のタイミングといった時間を扱った「インターバル」処理にも使われます**。

上記の「ポットのお湯が使われた時間のログ」のサンプルを見ると、時間がキリ番（キリの良い番号）になっていると思います。この「キリの良いところでの区切り」を「インターバル」と言い、インターバル（区切り）で何か処理を行うことを「インターバル処理」などと呼びます。

身近なところでは「タイマー」であったり、「定例処理」（定期的な処理）などがあります。このような**ループさせる秘術を極めたい**方は以下のキーワードで調べてみてはいかがでしょう。

- 剰余, MOD
    - お使いのプログラム言語で [0〜99 までの数値を任意の値で割った余りの変化](https://paiza.io/projects/HuuzdXucMGzbB_dPohSDVw)をみてください。ゲームの画面で左に消えたキャラクターが右から出てくるような仕組みにも使われています。
- [Timer Event](https://qiita.com/search?utf8=%E2%9C%93&sort=created&q=user%3A7of9+tag%3AtimerEvent)

## 禁断の呪文集

他の言語の呪文があれば遠慮なく[編集リクエストください](https://qiita.com/KEINOS/items/5723ee3b626b98aec08e/edit)。

---

```vb:VB
public class compiler

  shared function Main as integer
    Dim minute As Integer      '現在時刻（分）
    Dim steps  As Integer = 15 '15分区切り
    Dim stamp  As Integer = 0  '打刻時間

    ' 0分〜59分までをテスト
    for minute = 0 to 59
      stamp = (minute \ steps) * steps ' バックスラッシュ(\)は整数の除算
      Console.WriteLine (minute & " = " & stamp)
    next minute

    return 0
  End function

end class

```
- [オンラインで動作確認する](https://paiza.io/projects/uiOfCTlbohUsC3VLmA6kxA) @ paiza.IO

---

```php:PHP
<?php

$minute =  0; //現在時刻（分）
$steps  = 15; //15分区切り
$stamp  =  0; //打刻時間

// 0分〜59分のテスト
for ($minute = 0; $minute < 60; ++$minute) {
    $stamp = intdiv($minute, $steps) * $steps; // `intdiv`は整数の除算

    echo $minute, ' = ', $stamp, PHP_EOL;
}

```
- [オンラインで動作確認する](https://paiza.io/projects/p79rUYSsi8nEahCKSFr-ig) @ paiza.IO

---

```python:Python3
minute =  0  # 現在時刻（分）
steps  = 15  # 15分区切り
stamp  =  0  # 打刻時間

for minute in range(60):
   stamp = (minute // steps ) * steps  # // は整数の除算
   print(str(minute) + ' = ' + str(stamp))

```
- [オンラインで動作確認する](https://paiza.io/projects/caTP5RM6Yry327TwzwUxSw) @ paiza.IO

---

```go:Go
package main

import (
	"testing"
)

func Test15MinInterval(t *testing.T) {
	const interval = 15

	for _, data := range []struct {
		input  int // minute
		expect int // minute
	}{
		{50, 0},  // 50分出社 -> 00分打刻（10分前出社）
		{59, 0},  // 59分出社 -> 00分打刻
		{0, 15},  // 00分出社 -> 15分打刻
		{1, 15},  // 01分出社 -> 15分打刻
		{15, 30}, // 15分出社 -> 30分打刻
		{29, 30}, // 29分出社 -> 30分打刻
		{30, 45}, // 30分出社 -> 45分打刻
		{45, 0},  // 45分出社 -> 00分打刻（1時間遅刻）
	} {
		actual := ((data.input / interval) + 1) * interval % 60

		if data.expect != actual {
			t.Errorf("Input: %v, Expect: %v, Actual: %v\n", data.input, data.expect, actual)
		}
	}
}

```
- [オンラインで動作確認する](https://play.golang.org/p/TImkBQSbiAh) @ Go Playground

## 履歴

- 2018/07/26 [@​7of9​ さんのコメント](https://qiita.com/KEINOS/items/5723ee3b626b98aec08e#comment-295a0bddf7b52afa874e)よりインターバルについて追記 THX!

## 所感

本件に限らず、プログラム的な問い合わせを受けた際に「まずは [Qiita の記事に絞ってググる](https://qiita.com/KEINOS/items/63c5f9b1c1f70f1ff531)」ように案内しています。

しかし、ネットにはエクセル向けの本記事のような情報は多いものの、当然すぎるのか、意外にも Qiita にはありませんでした。

何を調べたかったのか聞いてみたところ、「早く出社したら遅い方に打刻、遅く退社したら早い方に打刻したい」というのです。そんな[ブラックブラック](https://www.lotte.co.jp/products/brand/blackblack/)を噛み締めながら仕事をするようなことの手助けはしたくありませんし、Qiita ないことはよくありません。

そこで、「Qiita では禁断の計算術」という名のもとに「これは遺憾」と書いた次第であります。