[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『作業時間と休憩時間』(FA)
いつもお世話になっております。 また行き詰りましたので皆様のお力をお借りしたくご質問させて頂きます。
現在作業工数の割出しを検討中です。 下記のような表があります。 A B C D E F G H I J K L 1 開始 開始 終了 終了 2 社員番号 作業者 シフト 作業 日付 時間 日付 時間 作業時間 顧客名 製品名 数量 3 001 AAA C 111 2010/12/21 22:00 2010/12/22 2:00 A社 AKSS-1 100 4 015 BBB A 111 2010/12/21 8:30 2010/12/21 17:00 B社 XKS1111 10000 別のシートで、シフト別のタイムテーブルがあります。
A B C D E F G H I J K L M N O
1 シフトA 開始 終了 時間 シフトB 開始 終了 時間 シフトC 開始 終了 時間
2 朝礼 8:00 8:15 0:15 作業 16:00 20:00 4:00 作業 20:00 0:00 4:00
3 掃除 8:15 8:30 0:15 休憩 20:00 21:00 1:00 休憩 0:00 1:00 1:00
4 作業 8:30 12:00 3:30 作業 21:00 0:00 3:00 作業 1:00 5:00 4:00
5 休憩 12:00 13:00 1:00 残業1H 0:00 1:15 1:15 残業1H 5:00 6:15 1:15
6 作業 13:00 15:00 2:00 残業2H 1:15 2:15 1:00 残業2H 6:15 7:15 1:00
7 休憩 15:00 15:10 0:10 残業3H 2:15 3:15 1:00 残業3H 7:15 8:15 1:00
8 作業 15:10 17:00 1:50
9 休憩 17:00 17:30 0:30
10 残業1H 17:30 18:15 0:45
11 残業2H 18:15 19:15 1:00
12 残業3H 19:15 20:00 0:45
13 掃除 20:00 20:15 0:15
やりたいことは、作業開始日、時間、作業終了日、時間を入力するとタイムテーブルから各シフトの休憩時間を差し引いた作業時間をI列に表示したいのです。 例:表の1行目の場合3:00、2行目の場合7:20
どうかご教授宜しくお願い致します。
製作中のエクセル2007(日本語版) 使用想定、Excel2000、Excel2003、Excel2007(各英語、タイ語版) 製作中のOS、XP(日本語版) 使用想定OS、XP(各英語、タイ語版)
時間の計算で変換誤差(倍精度実数の為)が出るのが怖いので シリアル値を分(Minute)に変換して整数計算をしています 時間の計算が、今一自信が無いので善く検証して見て下さい
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim i As Long
Dim lngRow As Long
Dim vntData As Variant
Dim vntColumn As Variant
Dim vntTime As Variant
'シフト、開始日付、開始時間、終了日付、終了時間の位置を列挙
vntColumn = Array(3, 5, 6, 7, 8)
With Target
If .Count > 1 Then
Exit Sub
End If
If .Row <= 2 Then
Exit Sub
End If
'シフト、開始日付、開始時間、終了日付、終了時間の何れかが入力された場合
For i = 0 To UBound(vntColumn)
If .Column = vntColumn(i) Then
Exit For
End If
Next i
If i > UBound(vntColumn) Then
Exit Sub
End If
'入力行位置を取得
lngRow = .Row
End With
'社員番号、作業者、シフト、開始日付、開始時間、終了日付、終了時間迄を配列として取得
vntData = Me.Cells(lngRow, "A").Resize(, 8).Value
'入力されたシフト、開始日付、開始時間、終了日付、終了時間を検査
For i = 0 To UBound(vntColumn)
Select Case i
Case 0 'シフト
If IsEmpty(vntData(1, vntColumn(i))) Then
Exit Sub
End If
Case 1, 3 '日付
If Not IsDate(vntData(1, vntColumn(i))) Then
Exit Sub
End If
Case Else '時刻
If VarType(vntData(1, vntColumn(i))) <> vbDouble Then
Exit Sub
End If
End Select
Next i
'作業時間を分で計算
vntTime = TimeCalc(vntData, vntColumn)
'作業時間が有るなら
If vntTime <> -1 Then
Application.EnableEvents = False
With Me.Cells(lngRow, "I")
'セルの書式を変更
.NumberFormat = "h:mm"
'分をシリアル値に変換してI列に代入
.Value = TimeSerial(vntTime \ 60, vntTime Mod 60, 0)
End With
Application.EnableEvents = True
End If
End Sub
Private Function TimeCalc(vntData As Variant, vntColumn As Variant) As Long
Dim i As Long
Dim lngRows As Long
Dim vntTabl As Variant
Dim lngNumb As Long
Dim lngStart As Long
Dim lngEnd As Long
Dim lngSum As Long
'タイムテーブルの位置を取得
lngNumb = (Asc(StrConv(vntData(1, vntColumn(0)), vbNarrow + vbUpperCase)) - 65) * 5 + 2
'作業開始時間を午前0時からの経過分に変換
lngStart = ConvMinute(vntData(1, vntColumn(2)))
'作業終了時間を午前0時からの経過分に変換
lngEnd = ConvMinute(vntData(1, vntColumn(4)) _
+ vntData(1, vntColumn(3)) - vntData(1, vntColumn(1)))
'タイムテーブルの先頭セル位置を基準とする(先頭列の列見出しのセル位置)
With Worksheets("Sheet2").Cells(1, lngNumb)
'行数の取得
lngRows = .Offset(Rows.Count - .Row).End(xlUp).Row - .Row
If lngRows <= 0 Then
TimeCalc = -1
Exit Function
End If
'タイムテーブルを配列に取得
vntTabl = .Offset(1).Resize(lngRows, 4).Value
End With
'タイムテーブルに就いて繰り返し
For i = 1 To lngRows
If vntTabl(i, 1) = "作業" Or vntTabl(i, 1) Like "残業*" Then
'タイムテーブルの開始を午前0時からの経過分に変換
'開始がタイムテーブル開始先頭時刻より小さい場合、
'翌日とする為、1日を加算
If vntTabl(i, 2) < vntTabl(1, 2) Then
vntTabl(i, 2) = vntTabl(i, 2) + 1
End If
'経過分に変換
vntTabl(i, 2) = ConvMinute(vntTabl(i, 2))
'タイムテーブルの終了を午前0時からの経過分に変換
If vntTabl(i, 3) < vntTabl(1, 2) Then
vntTabl(i, 3) = vntTabl(i, 3) + 1
End If
'経過分に変換
vntTabl(i, 3) = ConvMinute(vntTabl(i, 3))
'タイムテーブルの開始、終了が作業時間内に在るなら
If lngStart <= vntTabl(i, 3) And vntTabl(i, 2) <= lngEnd Then
'タイムテーブルの開始が作業開始時刻より前なら
'タイムテーブルの開始を作業開始時刻に
If lngStart > vntTabl(i, 2) Then
vntTabl(i, 2) = lngStart
End If
'タイムテーブルの終了が作業終了時刻より後なら
'タイムテーブルの終了を作業終了時刻に
If vntTabl(i, 3) > lngEnd Then
vntTabl(i, 3) = lngEnd
End If
'作業時間を加算
lngSum = lngSum + (vntTabl(i, 3) - vntTabl(i, 2))
End If
End If
Next i
TimeCalc = lngSum
End Function
Private Function ConvMinute(vntValue As Variant) As Long
'シリアル値を午前0時からの経過分に変換
ConvMinute = Int(vntValue) * 24 * 60 + Hour(vntValue) * 60 + Minute(vntValue)
End Function
(Bun)
後、以下の★印を追加した方が善いかも
Case Else '時刻
If VarType(vntData(1, vntColumn(i))) <> vbDouble Then
Exit Sub
Else '★追加
If vntData(1, vntColumn(i)) < 0 Or 1 <= vntData(1, vntColumn(i)) Then '★追加
Exit Sub '★追加
End If '★追加
End If
End Select
(Bun)
Bun様
いつもお世話になっております。ご回答ありがとうございます。 ご丁寧なコメントを書いて頂きとても勉強になります。
早速、マクロの方ご確認させて頂きました。 シフトAは問題ないのですが、シフトBとCの休憩時間が反映されません。 再度ご教授お願い致します。
(FA)
ごめん、タイムテーブルの先頭データを変数に退避するのを忘れていました ★印を変更して下さい
後、計算は、シフト1回分で善いのですよね? もし、泊まり込みでシフト2回分、3回分と成る場合が有るならコードは変わります
Private Function TimeCalc(vntData As Variant, vntColumn As Variant) As Long
Dim i As Long
Dim lngRows As Long
Dim vntTabl As Variant
Dim lngNumb As Long
Dim lngStart As Long
Dim lngEnd As Long
Dim lngSum As Long
Dim vntTop As Variant '★追加
'タイムテーブルの位置を取得
lngNumb = (Asc(StrConv(vntData(1, vntColumn(0)), vbNarrow + vbUpperCase)) - 65) * 5 + 2
'作業開始時間を午前0時からの経過分に変換
lngStart = ConvMinute(vntData(1, vntColumn(2)))
'作業終了時間を午前0時からの経過分に変換
lngEnd = ConvMinute(vntData(1, vntColumn(4)) _
+ vntData(1, vntColumn(3)) - vntData(1, vntColumn(1)))
'タイムテーブルの先頭セル位置を基準とする(先頭列の列見出しのセル位置)
With Worksheets("Sheet2").Cells(1, lngNumb)
'行数の取得
lngRows = .Offset(Rows.Count - .Row).End(xlUp).Row - .Row
If lngRows <= 0 Then
TimeCalc = -1
Exit Function
End If
'タイムテーブルを配列に取得
vntTabl = .Offset(1).Resize(lngRows, 4).Value
End With
'先頭データを変数に退避
vntTop = vntTabl(1, 2) '★追加
'タイムテーブルに就いて繰り返し
For i = 1 To lngRows
If vntTabl(i, 1) = "作業" Or vntTabl(i, 1) Like "残業*" Then
'タイムテーブルの開始を午前0時からの経過分に変換
'開始がタイムテーブル開始先頭時刻より小さい場合、
'翌日とする為、1日を加算
' If vntTabl(i, 2) < vntTabl(1, 2) Then
If vntTabl(i, 2) < vntTop Then '★変更
vntTabl(i, 2) = vntTabl(i, 2) + 1
End If
'経過分に変換
vntTabl(i, 2) = ConvMinute(vntTabl(i, 2))
'タイムテーブルの終了を午前0時からの経過分に変換
' If vntTabl(i, 3) < vntTabl(1, 2) Then
If vntTabl(i, 3) < vntTop Then '★変更
vntTabl(i, 3) = vntTabl(i, 3) + 1
End If
'経過分に変換
vntTabl(i, 3) = ConvMinute(vntTabl(i, 3))
'タイムテーブルの開始、終了が作業時間内に在るなら
If lngStart <= vntTabl(i, 3) And vntTabl(i, 2) <= lngEnd Then
'タイムテーブルの開始が作業開始時刻より前なら
'タイムテーブルの開始を作業開始時刻に
If lngStart > vntTabl(i, 2) Then
vntTabl(i, 2) = lngStart
End If
'タイムテーブルの終了が作業終了時刻より後なら
'タイムテーブルの終了を作業終了時刻に
If vntTabl(i, 3) > lngEnd Then
vntTabl(i, 3) = lngEnd
End If
'作業時間を加算
lngSum = lngSum + (vntTabl(i, 3) - vntTabl(i, 2))
End If
End If
Next i
TimeCalc = lngSum
End Function
(Bun)
Bun様
早速のご返答とご教授恐縮です。 マクロの方、ご確認させて頂きました。 理想道理のマクロとなりました!ありがとうございます。
>後、計算は、シフト1回分で善いのですよね? >もし、泊まり込みでシフト2回分、3回分と成る場合が有るならコードは変わります 上記に関しては可能性がありますが、今の段階ではハッキリとどのような仕様になるか決められないのと イレギラーなことなので別管理とする予定です。
まだ課題を抱えているので、また行き詰ることがあればご教授お願い致します。
(FA)
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.