凡人も語りたい

VBAに関すことや日々考えている事柄について投稿しようと思っています。

「労働基準法」がDXを阻む ~序章・労働基準法の歴史~

どうも、こんぺです。普段はExcelVBAのことについてをちょくちょく書いております。ですが、今回は趣向を変えて「業務改善の私見について書こう!」と思い立ち、すったもんだ色々調べた結果、「労働基準法最低賃金の変遷」についてまとめることにしました。
自分もまさかこんな記事書くことになるとは思わなかった(´・ω・`)

この記事ができた経緯

タイトルの通り、ある種の「労働基準法に対する批評」を今後数回にわたって書いていこおうと思っているわけですが、「そもそもどうして労働基準法ができたのか?」ということを知らずにする批評はただの「文句」にしかならない、と思い労働基準法の歴史を調べました。なぜ「現行法ではなく歴史なのか?」というと、法改正は「当初の想定と現実の問題のずれを調整するため」に行われるからです。言い換えるならば、労働基準法の変遷を追うと「その当時の労働環境の問題点の変化」が浮き彫りになる、ということです。そして時代背景と共に調べてみると、なかなか面白かったので個人的な感想と共にまとめることにしました。
ちなみに厚生労働省がこの記事よりずっとわかりやすい資料を公開しておりますので、正確なソースに興味がある方は以下のリンクをご覧ください。
労働時間法制の主な改正経緯について

労働基準法の歴史

労働基準法の歴史は古く、2021年で施行から74年になります。そのため数多くの法改正がありますが、今回は「労働時間と賃金」に関わる部分にフォーカスして、時代背景と共に変遷を追っていきたいと思います。

昭和22年(1947年)制定

この頃の時代背景は、第2次世界大戦終戦後2年しかたっておらず、日本はまだGHQによる統治がされている状況、戦後復興真っ只中の世相です。
そしてこの年に日本で起きた出来事として一番重要なことは日本国憲法の施行」でしょう。
昭和22年(1947)4月|労働基準法が制定される:日本のあゆみ
このサイトによると、「日本国憲法に『法律で定める』と規定したため、それにあたる法律を作った」と読み解けます。実際、1946年11月に日本国憲法公布から「たった5カ月後に公布」というところが、この法律の重要性を物語っていると思います。
当時の労働基準法に盛り込まれた事項の概要は以下のような感じです。

  • 労働時間は週48時間
  • 女子・年少者の深夜就業禁止
  • 労災補償など労働条件の最低基準の設定
  • 割増賃金は2割5分以上
  • 変形労働時間制

GHQからの「戦時中は人権を無視した不当労働をさせていたに違いない!不眠不休を強いる無制限の不当労働は許しません!」という建前と、日本政府の「戦後復興真っ只中、復興遅れるのも困るから割高の対価支払えば(いくらでも)働かせてOKにして」という本音を考慮したような法律だと感じます。

昭和34年(1959年)

この頃の時代背景としては炭鉱、鉄鋼業界などでストライキが頻発している世相であり、「国家体制VS市民」の構図から移行して「使用者VS労働者」という構図が成立していた時代です。
「使用者が不当に安価な賃金で労働者を雇用することを国が制限する」ことで「国家は市民(労働者)の味方」をアピールする目的もあったかな…と感じます。

昭和62年(1987年)改正

調べてびっくりしましたが、労働基準法制定から40年、労働時間に関わる改正はありませんでした!
(40年の間は安全衛生や労災保険職業訓練などの労使契約に付帯する事項に関する法改正がメインでした)

  • 週法定労働時間を48時間→40時間への段階的短縮
  • 変形労働時間制の拡大(フレックスタイム制の導入、3か月単位の変形労働時間制の導入など)
  • 事業場外および裁量労働についての労働時間の算定に関する規定

この頃の時代背景としてはバブル景気真っ只中、「働くば働くほど稼げる」という状況だったようです…生まれてないから知らんけど…(´・ω・`)
しかし、男女雇用機会均等法の施行やグローバル化が進んだことで「いままでの生活様式」が成り立たなくなっていった時代だと言うことも想像できます。
営業、企画などの「ホワイトカラー」に応募が集中し、製造業における「ブルーカラー」の人材不足が問題になり始めた時期でもあるそうです。

平成5年(1993年)改正
  • 週法定労働時間40時間制の施行
  • 最長1年単位の変形労働時間制の導入
  • 時間外労働、休日労働についての割増賃金率の政令事項化
  • 休日労働についての割増賃金率引上げ(25%→35%)
  • 裁量労働制の規定の整備(対象業務を労働省令で規定)

この頃の時代背景としてはバブル崩壊直後。日本経済の停滞、「失われた30年」のはじまりです(´・ω・`)
1987年改正で段階的に短縮した週法定労働時間を40時間に固定することが目玉ですね。
穿った見方かもしれませんが休日労働賃金割増の政令化と、最長1年間変形労働時間制がセットというのが「飴と鞭」を使った「いかにも日本の政策」って感じです。
時代背景を遡ると、休日割増はバブル景気の時休日返上で働いた労働者の人気取りのため、要は「バブル景気の名残」。
一方、変形労働時間制はバブルが崩壊し「休日割増なんて払う余裕ない!けど稼働日減らしたくない!」という企業(雇用主)に対する助け舟…という見方もできなくない、と感じます。

平成10年(1998年)改正

この頃の時代背景としては住専問題、拓殖銀行の破綻、山一證券の廃業などバブル崩壊後の金融問題が顕在化している時代で、終身雇用制や年功序列制といった「日本型雇用」が崩壊し始めたころです。そのような世相の中「裁量労働制の拡大」を図ったところを見るに、「年功序列型から成果報酬型に変革したい(人件費削減を図りたい)」という思惑が見え隠れします。

平成15年(2003年)改正
  • 企画業務型裁量労働制の拡大、導入・運用の要件・手続きについて緩和
  • 解雇権濫用法理の明文化(解雇権濫用の無効の明文化)

この頃の時代背景は、小泉内閣による郵政民営化規制緩和三位一体の改革が行われた時期になります。労働基準法の「企画業務型裁量労働制の拡大」だけではなく「労働派遣法改正による規制緩和」も行われ、後々の日本の労働環境へ大きな影響を与えた結果となっています。
一方で「解雇権濫用の無効」が労働基準法に明文化(現在は労働契約法に移行)されたことも大きな変化だと思います。しかし、

  1. 「解雇は、客観的に合理的な理由を欠き、社会通念上相当と認められない場合、無効とする」という曖昧な表現のブラックリスト方式採用
  2. 「労働者派遣法改正」による派遣労働の規制緩和

という「直接雇用のリスク増加」と「派遣労働の低コスト化」というコンボ技により正規雇用から非正規雇用へのシフト」が一気に加速したとも捉えられます。

平成20年(2008年)改正
  • 60時間/月を超える時間外労働についての割増賃金率を25%→50%へ引上げ(中小企業は猶予)
  • 上記割増賃金の支払いに代えて代替休暇付与を認可

この頃の時代背景は、なんといっても世界金融危機リーマンショック」が起きた年です。国内の労働事情にフォーカスすると「みなし管理職」問題が明るみになり、東京地裁で「みなし管理職」への残業代支払い命令の判決が下されたり、リーマンショックの影響により所謂「派遣切り」が横行し、年末には「年越し派遣村」が開設されました。
世間一般に「名ばかり管理職」「みなし残業」「雇用の正規、非正規」という考え方が根付き始めた時代だと思います。

平成30年(2018年)改正
  • 時間外労働の上限規制の導入
  • 中小企業における割増賃金率引上げの施行(平成20年改正における猶予の廃止)
  • 有給休暇の消化義務の導入(10日以上の有給休暇の権利を有する労働者について、最低5日の消化をさせること)
  • フレックスタイム制における最長清算期間の1か月から3か月への延長
  • 特定高度専門業務・成果型労働制(「高度プロフェッショナル制度」)の創設

最も直近の改正であり、読んでいる方々の記憶にも新しいと思います。5年スパンで改正が行われていましたが、民主党政権への政権交代もあってか、実は10年ぶりの改正となっております。
2015年の電通の女性新卒社員自殺というショッキングな一件から長時間労働」や「パワハラが社会問題として改めて大きく取り上げられました。
そのような世論を背景に「時間外労働への上限規制導入」が為されたことが非常に大きなポイントとなります。
事実上青天井だった労働時間にデッドラインが引かれたことで、今までなぁなぁにできた「労働時間管理の責任所在」を雇用主が明確にするよう迫られた点は大きな変化だと感じます。
その一方で「高度プロフェッショナル制度」を創設して多少のガス抜きするあたりは70年経っても日本の組織体質なのか「変化がないなぁ」と感じてしまいます。

最低賃金法について

最低賃金制度の歴史についてもまとめようと思いましたが、なかなか長くなりそうなため割愛(´・ω・`)
興味がある方は 以下の論文の「Ⅴ日本の最低賃金制度について」という部分で非常に丁寧にまとめられておりましたのでご紹介。(結構長い文です)
日本の最低賃金制度について-欧米の実態と議論を踏まえて

ここで言いたかったことは2つです。

(定義)
第二条 この法律において、次の各号に掲げる用語の意義は、当該各号に定めるところによる。
三 賃金 労働基準法第十一条に規定する賃金をいう。

  • 賃金の最低限基準である最低賃金「時間基準で支給すること」が義務付けられている

最低賃金額)
第三条 最低賃金額(最低賃金において定める賃金の額をいう。以下同じ。)は、時間によつて定めるものとする。

労働人口推移との比較

人口のデータについては以下のサイトを参考にしました。
統計情報|労働政策研究・研修機構(JILPT)


人口推移のグラフを見ると、1990年あたりから15~65歳以下の人口「生産年齢人口」が下降曲線に入り、現在まで減少の一途をたどっています。
www.jil.go.jp
その頃はちょうど、40年続いた「48時間労働の短縮」という大きな改正が行われた1987年改正にあたります。男女雇用機会均等法の施行もこのあたりというのは、世界的な風潮に押された点も多分にあったと思いますが、バブル景気も相まって「労働力の頭数確保」が当時から喫緊課題だったからだと考えられます。しかし男女雇用機会均等法は「男はとにかく仕事一本、女は家を守る」といった戦後40年以上続いた生活様式、価値観をひっくり返す法律であり、従来の労働時間では「生活が成り立たない」ということで労働時間の短縮に繋がったのかもしれません。

しかし、そんな配慮もむなしく1990年以降、労働力人口も緩やかな減少傾向のまま回復の兆しもない状況が現在まで続いています。
www.jil.go.jp
それもあってか1990年以降は「働き方のバリエーションを増やす」ための法改正が繰り返されています。「画一的な労働」から「多種多様な労働」を容認せざるを得ない労働市場の状況になったといえます。しかし2005年の「出生率1.26」という数字をたたき出し、いよいよ「日本の将来」すら危ういという状況に現在進行形でなっています。「いかに多く働かせるか」という「経営者・企業側」の視点だけでは破綻する、ということを歴史が証明してしまったと言えるかもしれません。
それもあってか、「割増賃金の一部増加」「割増賃金に変えての代替休暇付与の容認」という「労働者寄りの改正」がなされています。
そして直近の2018年改正になります。これらの経緯を知ってからだと、「働き方改革」でついに「働かせない≒休ませる」という「労働者側」の視点を重視した法改正がなされたのではないかと個人的に感じます。

今回の感想と次回について

労働基準法の変遷を調べて稚拙な観点からではありますが、考えたことや感じたことを書きました。変遷を調べることは「日本の労働観」を振り返るという点で正解でした。
しかし書いた後、働き方改革までの労働基準法、延いては日本の労働観は第一次産業革命後のイギリスと大差ない労働価値観」だったのかもしれない、と感じました…
要は「成果を多く出すには頭数と時間をたくさん注ぎ込めばいい」という労働生産性皆無の価値観、「労働者の生活という観点がすっぽり抜けている」とも言えます。
半世紀以上、人口の大半を占める労働者の生活を無下にしたら、そりゃ国全体衰退するわな(´・ω・`)
そんな弱り目の中、コロナ禍により今までの生活様式から一変を余儀なくされ、大変な思いをされている方も多く出ています。その一方、「日本の労働観の強制アップデート」ができるまたとない機会が到来しているのも事実だと思います。この機会を逃したら、冗談抜きで「失われた1世紀」になりかねないと感じます。
そして、その機会をもしかしたら「労働基準法」「最低賃金法」が阻む原因になるのでは?という内容を次回に書きたいと思います。

長文失礼しましたm(_ _)m

ExcelVBAの一工夫:配列の繰り返し処理について

どうも、こんぺです。
今回、VBAの配列について小技とも言えないような「ちょっとした一工夫」をご紹介します

配列の繰り返し処理について

VBAにおける配列の使い方や書き方は様々なサイトで取り扱われていると思われますので、割愛させていただきます。
配列と繰り返し処理の組み合わせ技は強力ですが、慣れないうちは、

  • Do Loopの終わりがわかりにくい
  • For Next は繰り返し処理後イテレーター変数は「繰り返した回数+1」になっている
  • カウンタ変数をカウントアップ(ダウン)するタイミングがいまいちわからない

とロジックエラーが起きやすい部分でもあると思います。
しかし、ちょっとしたひと工夫で「一気にわかりやすいコードに変わった」経験をしたのでご紹介します。

テストコード

  1. 1~20までの整数rndをランダムで決め、
  2. 1~rnd まで順に2乗し、配列に格納、
  3. 最後に配列の内容をイミディエイトウィンドウに表示

という処理をしています。

Sub test()
'cnt(=ループ処理の回数)を1~20までの整数からランダムで選出
    Dim rnd As Long
    rnd = Int(WorksheetFunction.RandBetween(1, 20))
'カウンタ変数とDoLoopを用いた動的配列の処理
    Dim arr() As String
    Dim cnt As Long
    Dim i As Long
    Do
        cnt = cnt + 1
        ReDim Preserve arr(1 To cnt) As String
        arr(cnt) = Str(cnt ^ 2)
    Loop Until cnt = rnd
'配列内数値の確認
    Debug.Print "要素数:" & cnt, Join(arr, ",")
End Sub

解説

今回の工夫した箇所は以下の部分

    Do
        cnt = cnt + 1
        ReDim Preserve arr(1 To cnt) As String
        繰り返し行いたい処理
    Loop Until cnt = 繰り返したい回数

非常に短いですが、工夫としては

  • 処理の「前」にカウンタ変数をカウントアップする
  • 配列に動的配列を用いる
  • 「ReDim Preserve」で処理結果を格納する要素を直前に「追加」する
  • 素数は「必ず『1』から要素が始まる」ようにする
  • 条件分岐に「Until」を使う

といったことが挙げられます。

これにより

  1. 「配列の要素数が足りない」というエラーを除去できる
  2. ループを抜けたタイミングは「カウンタ変数=繰り返し処理回数」でわかりやすく、繰り返し処理後のロジックエラーを起こしにくい
  3. 素数が「1」から始めることでめインデックス「0」を考慮しなくてよいため、後々Rangeに転記しやすい

など、「後々エラーの原因になりやすいポイント」を未然に解消してくれます。

おわりに

簡単ではございますが、「コーディングにおける一工夫」をご紹介させていただきました。
この書き方のアイディアを知るまで、私は「処理後にカウントアップ」していました。そのため、繰り返し処理後にロジックエラーを起こして予期しない動作になることが度々あり、「エラー回避するためのコード」を頭をひねって追加していました。しかし、この一工夫でその労力は「ほぼ0」になりました…
業務効率だけではなく、リーダブルコーディングで「コーディング効率」も上げていかねば…と思った次第です。


最後にお詫びです
以前、VBA勉強会に登壇させていただいたときに行ったリファクタリングをしたコードをすっかりアップし忘れていました。
しかし、動作確認をしたところバグが見つかってしまったので修正したのちアップします(;´・ω・)

セルコメントがあるセル番地とコメント内容を抽出するサブルーチン

セルコメントを別シートセル番地と内容を抽出し、セルコメントを削除するコード作ったので、備忘録ついでに投稿します。
※補足※サブルーチンのためこのコードのみでは動作しません。万が一コピペして利用するようなことがあればご注意ください。

コメントのセル番地と内容を抽出し、新規シートへ転記する
Sub CommentOut(wsInput As Worksheet)
    Dim trg As Range
    Dim arr() As Variant
    Dim cnt As Long
    ReDim arr(1 To 2, 1 To 1) As Variant

'    コメントセルに関する情報を二次元配列へ格納
    For Each trg In wsInput.Range("A1").CurrentRegion
        If TypeName(trg.Comment) = "Comment" Then
            cnt = cnt + 1
            ReDim Preserve arr(1 To 2, 1 To cnt)
            arr(1, cnt) = trg.Address
            arr(2, cnt) = trg.Comment.Text
'            trg.Comment.Delete
        End If
    Next
'    コメント抽出用シートの作成
    Worksheets.Add after:=Sheets(Sheets.Count)
    Dim wsOutput As Worksheet
    Set wsOutput = Sheets(Sheets.Count)
    wsOutput.Name = "抽出コメント"
    wsOutput.Range("A1:B" & cnt) = WorksheetFunction.Transpose(arr)
End Sub
メッセージボックスで検索セル数、コメント付きセル数、セルコメント割合を集計・表示する
Sub CommentsCounter(wsInput As Worksheet)
    Dim trg As Range, cnt(1) As Long, Ans As Long
    For Each trg In wsInput.Range("A1").CurrentRegion
        cnt(0) = cnt(0) + 1
        If TypeName(trg.Comment) = "Comment" Then
            cnt(1) = cnt(1) + 1
        End If
    Next
    Ans = cnt(1) * 100 / cnt(0)
    
    MsgBox " 全検索セル数:" & cnt(0) & vbLf & "内 コメント付:" & cnt(1) & vbLf & "  コメント率:" & Ans & "%"
End Sub

VBA 100本ノックNo91

お題

解答コード

Class1 コード(クラスモジュール)

Option Explicit
Private rest As Integer
Private St1_ As Double
Private fin1_ As Double
Private WT_ As Long
Private Ded_ As Long
Private NT_ As Long
Private Ovt_ As Integer
'Letプロパティの一括設定
Sub SetProp(ByVal new_st1 As Double, ByVal new_fin1 As Double)
    rest = 60 '休憩時間 60分
    If new_st1 < TimeSerial(9, 0, 0) Then
        St1_ = 9 / 24 '9時のシリアル値
    Else
        St1_ = new_st1
    End If
    fin1_ = new_fin1
    WT_ = WorkTime
    Ovt_ = OverTime
    NT_ = Night
End Sub
'労働時間の計算
Private Function WorkTime() As Long
    Dim WT As Double
    WT = fin1_ - St1_
    WorkTime = WorksheetFunction.RoundDown((WT) * 1440, 0) - rest
End Function
'残業時間の計算
Private Function OverTime() As Integer
    If WT_ > 480 Then
        OverTime = WT_ - 480
    Else
        OverTime = 0
    End If
End Function
'深夜時間の計算
Private Function Night() As Long
    Dim i As Long, dbStr As Double, dbFin As Double, dbNT As Long
    dbStr = St1_
    If fin1_ >= 1 Then
        dbFin = fin1_ - 1
    Else
        dbFin = fin1_
    End If
'始業時刻の条件分岐
'始業時刻が0時~5時までかつ、
    If dbStr < TimeSerial(5, 0, 0) Then
'終業時刻が0時~5時までの場合
        If dbFin < TimeSerial(5, 0, 0) Then
            dbNT = WorksheetFunction.RoundDown((dbFin - dbStr) * 1440, 0)
'終業時刻が22時~24時までの場合
        ElseIf dbFin > TimeSerial(22, 0, 0) Then
            dbNT = WorksheetFunction.RoundDown(((5 / 24 - dbStr) + dbFin - 22 / 24) * 1440, 0)
'終業時刻が5時~24時までの場合
        Else
            dbNT = WorksheetFunction.RoundDown((5 / 24 - dbStr) * 1440, 0)
        End If
'始業時刻が22時~24時までかつ、
    ElseIf dbStr >= TimeSerial(22, 0, 0) Then
'終業時刻が0時~5時までの場合
        If dbFin < TimeSerial(5, 0, 0) Then
            dbNT = WorksheetFunction.RoundDown((dbFin + (1 - dbStr)) * 1440, 0)
'終業時刻が22時~24時までの場合
        ElseIf dbFin > TimeSerial(22, 0, 0) Then
            dbNT = WorksheetFunction.RoundDown(((dbFin - dbStr) + dbFin - 22 / 24) * 1440, 0)
'終業時刻が5時~24時までの場合
        Else
            dbNT = WorksheetFunction.RoundDown((5 / 24 + (1 - dbStr)) * 1440, 0)
        End If
'始業時刻が8時~22時までかつ、
    Else
'終業時刻が0時~5時までの場合
        If dbFin < TimeSerial(5, 0, 0) Then
            dbNT = WorksheetFunction.RoundDown((dbFin + 2 / 24) * 1440, 0)
'終業時刻が22時~24時までの場合
        ElseIf dbFin > TimeSerial(22, 0, 0) Then
            dbNT = WorksheetFunction.RoundDown((dbFin - 22 / 24) * 1440, 0)
'終業時刻が翌日5時~8時までの場合
        ElseIf dbFin < dbStr Then
            dbNT = 420
'終業時刻が8時~24時までの場合
        Else
            dbNT = 0
        End If
    End If
    Night = dbNT
End Function
’プロパティ取得の設定
Property Get 勤務時間() As Double
    勤務時間 = WT_
End Property
Property Get 深夜時間() As Double
    深夜時間 = NT_
End Property
Property Get 始業時刻() As Double
    始業時刻 = St1_
End Property
Property Get 終業時刻() As Double
    終業時刻 = fin1_
End Property
Property Get 残業時間() As Integer
    残業時間 = Ovt_
End Property

Module1 コード(標準モジュール)

Sub ノック91本目()
    Dim ID As Integer
    Dim Dic_ID As Object: Set Dic_ID = CreateObject("Scripting.Dictionary")
    Dim cnt_ID As Long
    Dim y As Integer, m As Integer
    Dim 年月 As String
    Dim Dic_年月 As Object: Set Dic_年月 = CreateObject("Scripting.Dictionary")
    Dim cnt_年月 As Long
    Dim i As Long
'ID,年月に関する連想配列生成と二次元配列の要素数決定
    For i = 2 To Sheet1.Cells(Rows.Count, 1).End(xlUp).Row
        ID = Sheet1.Cells(i, 1).Value
        年月 = Nengetsu(Sheet1.Cells(i, 2).Value)
        If Not (Dic_ID.exists(ID)) Then
            cnt_ID = cnt_ID + 1
            Dic_ID.Add ID, cnt_ID
        End If
        If Not (Dic_年月.exists(年月)) Then
            cnt_年月 = cnt_年月 + 1
            Dic_年月.Add 年月, cnt_年月
        End If
    Next
'ID,年月ごとの残業時間集計
    Dim obj As Class1
    Dim StartTime As Double, FinishTime As Double
    Dim arr() As Variant
    ReDim arr(1 To cnt_ID, 1 To cnt_年月) As Variant
    For i = 2 To Sheet1.Cells(Rows.Count, 1).End(xlUp).Row
        ID = Sheet1.Cells(i, 1).Value
        年月 = Nengetsu(Sheet1.Cells(i, 2).Value)
        StartTime = Sheet1.Cells(i, 3).Value
        FinishTime = Sheet1.Cells(i, 4).Value
        Set obj = New Class1
        obj.SetProp StartTime, FinishTime
        arr(Dic_ID(ID), Dic_年月(年月)) = arr(Dic_ID(ID), Dic_年月(年月)) + obj.残業時間
        Set obj = Nothing
    Next

'残業シートへの転記
    Dim j As Long, k As Long, r As Long
    Dim Keys_ID As Variant: Keys_ID = Dic_ID.keys
    Dim Keys_年月 As Variant: Keys_年月 = Dic_年月.keys
    r = 1
    For j = 1 To cnt_ID
        For k = 1 To cnt_年月
            r = r + 1
            Sheet2.Cells(r, 1).Value = Keys_ID(j - 1)
            Sheet2.Cells(r, 2).Value = Keys_年月(k - 1)
            If arr(j, k) Mod 60 < 30 Then
                Sheet2.Cells(r, 3).Value = "'" & arr(j, k) \ 60 & ":00"
            Else
                Sheet2.Cells(r, 3).Value = "'" & arr(j, k) \ 60 & ":30"
            End If
        Next
    Next
End Sub

'年月文字列を生成する関数
Function Nengetsu(ByVal d As Date) As String
    Nengetsu = Year(d) & Month(d)
    If Month(d) > 9 Then
        Nengetsu = Year(d) & Month(d)
    Else
        Nengetsu = Year(d) & "0" & Month(d)
    End If
End Function

振り返りと感想

完成まで3時間。以前に近いものを作った経験があったのでそのノウハウを応用。
表記は文字列で扱っており手抜き…本来はFormat関数やNunberFormat関数で整形するのが理想だと思います。
始業時刻、終業時刻から様々なデータを生成できるのでクラスを活用しています。
そのため、インスタンスのプロパティを変更するだけで、総労働時間や深夜時間を切り替えて集計できます。

個人的な時間計算における時刻データの取り回しは

  1. 日付型ではなくシリアル値(Double型)で取得
  2. シリアル値のまま時刻計算
  3. 端数処理は分単位に変換してから取り回し([シリアル値] ×1440)
  4. 最後に時刻表記に変換

という方法で基本的に行っています。

回りくどい方法ですが、日付型はシリアル値が1以上になると「時刻のみ」から「日付+時刻」で取り扱われるので直感的に扱いづらいためこのような変換を行っています。
マスタ上の時刻標記が[h]:mm:ss型であるため、労働時間の算出は非常にやりやすかったです。マスタの記述ルールの重要性を実感しました。
日付をまたぐ条件分岐(出題違反以外ですが、今回でいえば深夜時間の算出)はh:mm:ss型にも対応できるように、かなり面倒な処理をしています。

VBAの悩みはVBAerに聞け! 第7回 1次会 話題のメモ帳

関数について

やまとさんが関数(Function)を使う理由

  1. コーディングで楽をしたいため
  2. メインのプロシージャが何やっているかがわかりやすい
関数を作るとは?
Worksheet関数を作れる?

条件があるものの、標準モジュールで作成したFunctionプロシージャ
ADD2とするとエラー→ADD列2行目の参照と認識してしまった
参照とみなせる関数は作れない

FunctionとSubの違い

sub:プロシージャ名は値を返さない
Function:プロシージャ名自体が値を返す

「:=」とは?

:= :関数の名前付き引数を指定して値を代入する。引数の順番を入れ替えても関数が機能する
= :変数へ値を代入する

引数のヒントを出すショートカット

Ctrl+i (りゅうりゅうさん)

  • 引数のヒントをコピペするショートカットなかった?
ワークシート関数の引数入力ショートカット

Ctrl+Shift+A
→自作関数も同じく出る

ByVal、ByRef

ByVal:引数で渡した変数が呼び出し先の影響を受けない、省略不可

  • ByValでしかできないこと

分割した先のプロシージャ内で引数を変数に代入しなくてもよい

ByRef:引数で渡した変数が呼び出し先の影響を受ける、省略可

  • ByRefでしかできないこと

一つの関数で渡した複数の引数に対して複数の値を返してほしいとき

その他

変数日本語派?
  • やまとさんの考え

業務で使うものは日本語、自分で使うものは英語
→以前モジュール名日本語でバグったことがある

goto gosubの違い

gotoは戻る場所を自分で管理する必要がある
→どこに戻るかわかりくい

gosubはreturnで元の処理に戻れる

  • エラー処理の共通化、特定の計算値算出にjika便利(ほえほえさん)
  • 「変数を共有して他から呼べない処理」という意味でスーパーPrivate sub と思っていい(和風スパゲティさん)

VBA 100本ノックNo11~14

Sub ノック11本目()
With Worksheets("セル結合")
Dim r As Long: r = .Cells(Rows.Count, 1).End(xlUp).Row
Dim c As Long: c = .Cells(1, Columns.Count).End(xlToLeft).Column

Dim i As Long, j As Long
For i = 1 To r
    For j = 1 To c
        If .Cells(i, j).MergeCells Then .Cells(i, j).AddComment.Text "セル結合…しましたね…(´・ω|"
    Next
Next
End With
End Sub

Sub ノック12本目()
With Worksheets("セル結合")
Dim r As Long: r = .Cells(Rows.Count, 1).End(xlUp).Row
Dim c As Long: c = .Cells(1, Columns.Count).End(xlToLeft).Column

Dim i As Long, j As Long, k As Long, md As Integer
Dim trg As Range
Dim amount As Long '金額
For j = 1 To c
    For i = 1 To r
        If .Cells(i, j).MergeCells Then                                                          'セルの結合判定
            Set trg = .Cells(i, j).MergeArea
            trg.UnMerge
            md = .Cells(i, j).Value Mod trg.Rows.Count                                              '余りの計算
            If md = 0 Then                                                                          '割り切れる場合
                amount = .Cells(i, j).Value / trg.Rows.Count
                For k = 1 To trg.Rows.Count                                                             '結合範囲のループ処理
                    .Cells(i + k - 1, j).Value = amount
                Next
            Else                                                                                    '端数が出る場合
                amount = WorksheetFunction.RoundDown(.Cells(i, j).Value / trg.Rows.Count, 0)
                For k = 1 To trg.Rows.Count                                                             '結合範囲のループ処理
                    Select Case k
                    Case Is <= md                                                                       '余りの配賦
                        .Cells(i + k - 1, j).Value = amount + 1
                    Case Else
                        .Cells(i + k - 1, j).Value = amount
                    End Select
                Next
            End If
        End If
    Next
Next
End With

End Sub

Sub ノック13本目()
Dim arr As Variant, Target As Range
If TypeName(Selection) = "Range" Then
    Set Target = Selection
    For Each arr In Target
        Dim i As Long
        Dim start As Integer: start = 1
        
        Do
        If Not (InStr(start, arr.Value, "注意") = 0) Then
            arr.Characters(InStr(start, arr.Value, "注意"), 2).Font.Color = RGB(255, 0, 0)
            start = InStr(start, arr.Value, "注意") + 2
        End If
        Loop Until InStr(start, arr.Value, "注意") = 0
    Next
End If
End Sub

Sub ノック14本目()
Dim wsName As String
Dim ws As Worksheet
Dim cnt As Long
For Each ws In Worksheets
    wsName = ws.Name
    If Not (InStr(wsName, "社外秘") = 0) Then
        Application.DisplayAlerts = False
        Worksheets(wsName).Delete
        Application.DisplayAlerts = True
        cnt = cnt + 1
    End If
Next
MsgBox cnt & "枚のコードを削除しました"
End Sub

振り返りと反省

  • セル結合に関わるメソッド(MergeCells、MergeAreaなど)をうまく使いこなせていない
  • 結合セルのカウントと端数処理が回りくどい気がする
  • Charactersプロパティ使ったのが久々。Value(値)とCharacters(文字列オブジェクト)の違いをしっかり理解する
  • InStrは便利なので使いこなせるように意識して使ってみる

VBAの悩みはVBAerに聞け! 第6回 話題のメモ帳

2021/2/12 20時から行われた VBAの悩みはVBAerに聞け! に今回も参加しました。

主催者のしゃあさんも議事録を作っております。
今回の登壇者である「あこ」さんが作成したマクロもダウンロード可能ですので、コイらもぜひご覧ください。
note.com

聞き取れた範囲ですが以下にまとめました。

話題抜粋

SheetsコレクションとWorksheetsコレクションの違い

Worksheets:ワークシートのみのコレクション。インデックスで指定してもワークシートのみ指定される。
Sheets:ワークシート、グラフシート、Excel4.0マクロなども含むコレクション。
SheetsコレクションからWorksheetオブジェクトを指定する場合、インデックスで指定するとワークシート以外のシートも指定される
→グラフシートなどが挿入されていると想定外の挙動になる可能性あり

sleep、wait、doevents の違い

ループ処理の際、一時停止の方法として利用される手法として上記の3つがあるが、その違いは何なのか?という質問から

ほえほえ先生の回答

sleep: プロセスが停止→バックグランドも停止
wait:VBAスレッドが停止→バックグラウンドは動作する
doevent: 実行権の放棄

フォームコントロールActiveXコントロールフォームの違い

  • 宗教の違い
  • ActiveXの方はWindouwアップデートに影響されてバグが発生する可能性がある
  • ActiveXコントロールはワークシートモジュールのメンバになるため、標準モジュールから直接コントロールできない

Shell,VBSの使い方

Shell関数:Shell で起動したプログラムが、他のプログラムが非同期に実行させる関数

(VBSは聞き逃しました…すみません)

VBEからMicrsoftDocsの開き方

キーワード上にマウスカーソルを置き、F1キー(ヘルプ)を押す

「””」と「Null」の違い

””:空文字。
Null:有効な数値ではないことを示す値

チャットで挙げられていた例え
  • 「””」はトイレットペーパーの紙がない状態
  • 「Null」はそもそもトイレがない

感想

今回も非常に勉強になりました!
Shell関数やVBSは触れたことがまだないので、もっと勉強が必要だなぁ…と実感。
しっかり理解できていないことが多いから、ブログでアウトプットしながら整理したいです。