時間計算で困ったときの確実な対処方法
Excelで非常に多い質問の一つが時間計算です。
特に時間計算は面倒で対処方法も書籍・ネットでもあまりみかけません。
なにより、1日が数値の1(これをシリアル値と言います)で表されているので、大抵はなんとかなっているようです。
まずは、その前に、事前知識が必要になります。
ちょっと難しい話になりますが、さくっと読み流してみてください。
日付・時刻のシリアル値とは
つまり、日付のシリアル値とは、1900/1/1の何日後かの数値ということになります。
雑学話としては、「エクセル雑感.エクセルの日付のお話」をご覧ください。
年月の表記においては各種問題もありますが、これらに対する関数は豊富に存在しています。
つまり、1時は1/24、2時は2/24です。
同様に分は、さらに1/60となります。
つまり、1分は1/24/60、2分は2/24/60です。
1900/1/1の41765日後なので、=41765+14/24+30/24/60=41765.6041666667
となります。
そして、Excelは整数部分を日付、小数以下を時刻として認識します。
整数部分の日付も含めて時刻に(つまり24hを超えて表示)する場合は、
「[hh]」といった書式が必要になります。
決して時間(時刻と時刻の間隔)ではないということです。
したがって、マイナスは決して扱えません、この事を理解していない場合が非常に多く見受けられます。
数式.DATE関数(年,月,日を日付に)
数式.DATEVALUE関数(日付を表す文字列を日付に)
数式.YEAR関数(日付を年に)
数式.MONTH関数(日付を月に)
数式.DAY関数(日付を日に)
数式.TIME関数(時,分,秒を時刻に)
数式.TIMEVALUE関数(時刻を表す文字列を時刻に)
数式.HOUR関数(時刻を時に)
数式.MINUTE関数(時刻を分に)
数式.SECOND関数(時刻を秒に)
数式.TODAY関数(現在の日付)
数式.NOW関数(現在の日付と時刻)
数式.WORKDAY関数(稼動日数だけ前後の日付)
数式.NETWORKDAYS関数(稼動日の日数)
数式.DATEDIF関数(年齢・勤続年数)
Excelにおける小数の問題
詳しい解説は、ここでは省きますが、
コンピューターが全て2進数で表現されているため、表現できない小数点数があったり、
計算過程で誤差が生じてしまうというものです。
VBAの小数以下の演算誤差について
これらの事は、Microsoftの各種ページでも解説されていますので、興味があれば読んでみてください。
Excel で浮動小数点演算の結果が正しくない場合がある
浮動小数点演算で丸め誤差を修正する方法
よくある(かどうかは別にして)出退勤の計算を例に話を進めます。
どんな時に問題が発生するか
・退勤時刻
・休憩時間
・所定時間
まあ遅刻・早退は、望ましくないので(笑)、残業時間の算出を例にとりましょう。
・退勤時刻 17:15
・休憩時間 1:00
・所定時間 8:00
シート上で計算してみてください、正しく計算できています。
出勤時刻 | 退勤時刻 | 休憩時間 | 所定時間 | 残業時間 |
8:15 | 17:15 | 1:00 | 8:00 | 0:00 |
そう、普通は何も問題ないように思えます。
では、その下に以下のようにいれて、さらにドラッグコピーをします。
出勤時刻 | 退勤時刻 | 休憩時間 | 所定時間 | 残業時間 |
8:15 | 17:15 | 1:00 | 8:00 | 0:00 |
8:16 | 17:16 | 1:00 | 8:00 | 0:00 |
この2行分のセル範囲を選択しドラッグコピーすると、
出勤時刻 | 退勤時刻 | 休憩時間 | 所定時間 | 残業時間 |
8:15 | 17:15 | 1:00 | 8:00 | 0:00 |
8:16 | 17:16 | 1:00 | 8:00 | 0:00 |
8:17 | 17:17 | 1:00 | 8:00 | 0:00 |
8:18 | 17:18 | 1:00 | 8:00 | 0:00 |
8:19 | 17:19 | 1:00 | 8:00 | 0:00 |
8:20 | 17:20 | 1:00 | 8:00 | 0:00 |
8:21 | 17:21 | 1:00 | 8:00 | 0:00 |
8:22 | 17:22 | 1:00 | 8:00 | 0:00 |
8:23 | 17:23 | 1:00 | 8:00 | 0:00 |
8:24 | 17:24 | 1:00 | 8:00 | 0:00 |
8:25 | 17:25 | 1:00 | 8:00 | ######## |
8:26 | 17:26 | 1:00 | 8:00 | 0:00 |
8:27 | 17:27 | 1:00 | 8:00 | ######## |
8:28 | 17:28 | 1:00 | 8:00 | 0:00 |
8:29 | 17:29 | 1:00 | 8:00 | ######## |
8:30 | 17:30 | 1:00 | 8:00 | ######## |
8:25のところから、なにやらおかしくなっています。
手入力で、8:25と入れなおすと、正しく0:00となります。
これは、ドラッグコピーで作成された時刻が、手入力の時刻とわずかに違いがあるということです。
手入力する前の8:25のシリアル値は、0.350694444444445
手入力した後の8:25のシリアル値は、0.350694444444444
わずかに、最後で違いがあります。
この違いは、秒まで表示しても時刻形式では差異が見て取れません。
全て手入力し直していたのでは、何のためのExcelだかわからなまなってしまいます。
この問題は、何もドラッグコピー時だけの問題ではなく、
何らかの計算結果を時刻表示しているときには、常に付きまとう問題となっています。
ここでは、簡単に再現でき、かつ、理解しやすいようにドラッグコピーで説明しました。
開始時刻 | 0:08:25 | 0:23:43 | |
終了時刻 | 0:17:25 | 0:32:43 | |
経過時間 | 0:09:00 | 0:09:00 | FALSE |
右下のFALSEは、2つ左の0:09:00と、1つ左の0:09:00をEXACT関数で比較した結果です。
同じ数値ではないということになります。
秒までの計算式では、むしろ一致することの方が少ないくらいに違いが発生します。
このような問題を解決するための確実な方法です。
確実な時間計算方法
したがって、要は人間が頭のなかで行っているのと同様に、10進計算すればよいのです。
そのためには、まずは10進計算できる数値に変換してから計算します。
つまり、小数点以下のシリアル値ではなく、整数としての独自シリアル値として扱うのです。
話を分かりやすくするために、分単位で話を進めます。
8:25
とあるなら、これをそのまま1分を1とした数値に変換します。
つまり、8*60+25=505にします。
その方法としては、何通りかありますが、
元のシリアル値が、1日=24時間=1であることから、
A1セルに8:25が入っているとして、
A1*60*24=505となります。
※計算結果のセルは表示形式を標準に変更してください。
*24で1時間が1となり、*60で1分が1となります。
また、
少しややこしくなりますが、基本単位で割れば、基本単位を1とした数値になりますので、
これは、
8:25/(1/24/60)=8:25*60*24=505
しかし、小数以下の誤差が問題であるといっているのに、
この計算式では、やはり誤差が出てしまうのではないかと不安があります。
※この計算式で誤差がでてしまうかどうかの検証はしていません、
8:25:58
のように秒数が入ってしまっていて、見た目が8:25となっている場合は、
結果が506となってしまいます。
もちろん、小数以下を表示すれば、
505.983333333
このような数値となっているわけです。
それには、Excelで用意されている関数を使います。
また、こんな計算方法もあります。
ちなみに、TEXT関数で分だけ取り出そうとして、"mm"の指定は月を取り出してしまいます。
(このTEXT関数で、分のみ指定する方法が無いのは、かなり痛い仕様と言えます)
でも、最後は、分かりやすいように時間表示にしたくなります。
計算結果が、75、これでは分かりずらい、やはり、1:15のように表示しておきたいところです。
それには、既に登場している、TIME関数を使えば一発で済みます。
B1セルに1分を1とした数値に変換後の計算結果が入っているとして、
TIME関数の引数には、60を超える分や秒を指定しても、正しく変換してくれます。
ちなみに、秒で計算する場合は、
TIME(0, 0, B1)
(労基署の言い分としては、1分単位でやりなさいとなりますが、その辺は専門家に委ねるとして)
出勤時刻は15分毎に切り上げ、つまり、8:25は8:30
退勤時刻は15分単位に切り捨て、つまり、17:35は17:30
このようにしてから、残業時間を計算するというのは昔からよくあることです。
(これで労基署が許してくれるかは別の話ですよ)
このような場合は、
FLOOR
ちなみに、出勤時刻は15分毎に切り上げた分単位にする場合は、
CEILING(HOUR(A1)*60+MINUTE(A1),15)
このようになります。
元の時刻を15分単位にしてからなら、
CEILING(A1,TIME(0,15,0))
としてから、分に変換しても良いですね。
TIME関数の制限について
ヘルプにも書かれていますが、「0~32767の範囲で指定します。」
つまり、秒数なら概ね9時間以上となる場合は制限値を超えてしまいます。
そのような場合は、時と合わせて計算する工夫が必要になります。
単純に、
=TIME(0,0,A1)
とすると、9時間を超える秒数の場合は、#NUMとなってしまいます。
そこで、
A2=FLOOR(A1,60*60)
これは、数値から、時間部分だけを取り出します。
そして、
A3=A1-A2
これは、時間を引いているので、残りの秒数になります。
上記をTIME関数に入れて、
=TIME(A2/60/60,0,A3)
これで計算できます。
(途中の計算方法は、色々な関数の使い方があります)
24時間以上は、DATE関数の範囲となります。
この場合も、日(24時間)以上は別途取り出す工夫が必要になります。
上記のように、A1セルに秒数が入っているとして、
A2=FLOOR(A1,60*60*24)
これは、数値から、日部分だけを取り出します。
そして、
A3=A1-A2
これは、数値から、残りの24時間未満を計算しています。
=A2/60/60/24
これで、日数に戻せますし、日数に*24で時間、*24*60で分数に戻せます。
24時間未満の部分をTIME関数で処理して、
24時間を超える部分は、別途加算するようにします。
ちなみに、先に書いているように、1日=1ですので、
シリアル値計算としては、日数は単純に加算できます。
単純化した結論
質問のほとんどは、基本関数の組み合わせでなんとかなります。
時間計算なら、
TIMEVALUE
HOUR
MINUTE
SECOND
CEILING
FLOOR
大抵(ほぼ全て)は、これらの関数と、文字列関数の一部を使うだけで解決できます。
いろいろと時間計算が面倒なことはご理解いただけたかと思います。
本当の意味での結論としては、
細かい時間にとらわれない仕事をしたいものだということです。
同じテーマ「エクセル関数応用」の記事
MATCH関数 解説・応用・使用例
選択行の色を変える(条件付き書式,Worksheet_SelectionChange)
他ブックを参照できる関数、他ブックを参照できない関数
時間計算で困ったときの確実な対処方法
VLOOKUP 左側の列を取得(MATCH,INDEX,OFFSET)
SUMIF関数の良くある間違い
論理式とは条件式とは(IF関数,AND関数,OR関数)
先頭の数値、最後の数値を取り出す
最後の空白(や指定文字)以降の文字を取り出す
SUMIFの間違いによるパフォーマンスの低下について
数値範囲で表検索するVLOOKUP近似一致
新着記事NEW ・・・新着記事一覧を見る
TRIMRANGE関数(セル範囲をトリム:端の空白セルを除外)|エクセル入門(2024-08-30)
正規表現関数(REGEXTEST,REGEXREPLACE,REGEXEXTRACT)|エクセル入門(2024-07-02)
エクセルが起動しない、Excelが立ち上がらない|エクセル雑感(2024-04-11)
ブール型(Boolean)のis変数・フラグについて|VBA技術解説(2024-04-05)
テキストの内容によって図形を削除する|VBA技術解説(2024-04-02)
ExcelマクロVBA入門目次|エクセルの神髄(2024-03-20)
VBA10大躓きポイント(初心者が躓きやすいポイント)|VBA技術解説(2024-03-05)
テンキーのスクリーンキーボード作成|ユーザーフォーム入門(2024-02-26)
無効な前方参照か、コンパイルされていない種類への参照です。|エクセル雑感(2024-02-17)
初級脱出10問パック|VBA練習問題(2024-01-24)
アクセスランキング ・・・ ランキング一覧を見る
1.最終行の取得(End,Rows.Count)|VBA入門
2.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
3.繰り返し処理(For Next)|VBA入門
4.変数宣言のDimとデータ型|VBA入門
5.RangeとCellsの使い方|VBA入門
6.ブックを閉じる・保存(Close,Save,SaveAs)|VBA入門
7.メッセージボックス(MsgBox関数)|VBA入門
8.セルのクリア(Clear,ClearContents)|VBA入門
9.ブック・シートの選択(Select,Activate)|VBA入門
10.条件分岐(Select Case)|VBA入門
このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。