週末業務を楽にするべく綺麗な1週間分の
日付、曜日、Memo(私の場合出勤時間)を出す
PowerShellスクリプトを作りたい。
今までは出力だけに満足してきたが
それだと技術が身についていかないので
なんでそのコードが使われているか
今回からじっくりと見ていくことにした
# 現在の日付を取得
$startDate = Get-Date
# 英語の曜日名を日本語の漢字表記に変換するハッシュテーブル
$dayOfWeekMap = @{
"Sunday" = "日曜日"
"Monday" = "月曜日"
"Tuesday" = "火曜日"
"Wednesday" = "水曜日"
"Thursday" = "木曜日"
"Friday" = "金曜日"
"Saturday" = "土曜日"
}
# 1週間前の日付、曜日、メモをコンソールに出力
for ($i = -7; $i -lt 0; $i++) {
$date = $startDate.AddDays($i)
$formattedDate = $date.ToString("yyyy/MM/dd")
$englishDayOfWeek = $date.DayOfWeek
$japaneseDayOfWeek = $dayOfWeekMap[$englishDayOfWeek]
$memo = "8:30〜17:15"
$line = "$formattedDate ($japaneseDayOfWeek) | $memo"
# コンソールに出力
Write-Host $line
}
ChatGPT様に出力してもらったスクリプトである
ただこれだと曜日の部分が空欄になってしまってうまくいかない
スクリプトを理解しながらどうすればいいのか検証していく
♡自分が理解するためのスクリプトメモ
$startDate = Get-Date
現在の日付と時刻を習得
このスクリプトだとこの値を基準として1週間前の日付を計算
# 英語の曜日名を日本語の漢字表記に変換するハッシュテーブル
$dayOfWeekMap = @{
"Sunday" = "日曜日"
"Monday" = "月曜日"
"Tuesday" = "火曜日"
"Wednesday" = "水曜日"
"Thursday" = "木曜日"
"Friday" = "金曜日"
"Saturday" = "土曜日"
}
DayOfWeekは曜日を示すもの
ただ英語表記になってしまうため日本語に変換している
@{}はハッシュテーブル、または連想配列といい
データ構造を作成するために使われる
以下のような場面で役に立つ
❤︎複数のデータを1つの変数で管理したい場合
❤︎英語→日本語のマッピングなど対応表を作成する場合
❤︎配列やオブジェクトと組み合わせて柔軟なデータ構造を作りたい場合
つまり沢山のデータを整理できるしカスタマイズも楽になるもの!ただしこの子だけでは画面には出ないよ!って事らしい
その@{}を画面に出してくれるのが次からのやつ
# 1週間前の日付、曜日、メモをコンソールに出力
for ($i = -7; $i -lt 0; $i++) {
$date = $startDate.AddDays($i)
$formattedDate = $date.ToString("yyyy/MM/dd")
$englishDayOfWeek = $date.DayOfWeek
$japaneseDayOfWeek = $dayOfWeekMap[$englishDayOfWeek]
$memo = "8:30〜17:15"
$line = "$formattedDate ($japaneseDayOfWeek) | $memo"
# コンソールに出力
Write-Host $line
}
うん、長いし細かい。
1つずつ見ていこうと思う。
for ($i = -7; $i -lt 0; $i++) {
これはループ処理nの開始。
forループを使って1週間前から昨日までの日付を順番に処理。
$i = -7
ループ初期値-7で1週間前の日付を指す
最初これ見た時絶対バグってる記号だろって思ってた(おい
$i -lt 0
ループ$iが0(今日)になる前に終了する値
つまり昨日まで実行される
ややこしいな〜なんか出力おかしいなって思ってた
つまり今日も出したい時は1にすればいいってことか
あとこれltのところIだと思って何度も間違えました(罠だよぉ
$i++
ループ毎に$iの値を1ずつ増やす
(例:-7,-6,-5....-1)
これがあるお陰でズラーっと並べれるのか
ただの変な記号じゃなかったゴメンナサイ
$date = $startDate.AddDays($i)
次にいこう。
これは日付を計算している
$startDate(基準となる現在の日付)に対してi日を加算
(なんかiの前にドルサインを入れるとバグる)
今日が2024/12/18で-7の時2024/12/11が計算される
これで日付の軸を決めてるのかなるほど
$formattedDate = $date.ToString("yyyy/MM/dd")
日付を指定フォーマットに変換している
計算された日付をyyyy/MM/dd(例:2024/12/24)の文字列に今回はしてる
ToStringメソッドというものが使われており数字や日時など元の形式では扱いにくいデータを簡単に文字列化できるし特定のフォーマットで文字列化できたりする便利な子。他のプログラミング言語でも使われるらしい、人気な子なのね。どんなデータでも「文字列」にしてくれるならそりゃそうか。普通にするとさっきの-7みたいにデータとして見られちゃうもんね、納得。
$englishDayOfWeek = $date.DayOfWeek
曜日を取得している。
$dateからその日の曜日を英語表記で出力。
DayOfWeekプロパティは英語の曜日名
なんでこんな表記なんだって思ってよーく見たらイングリッシュって最初に書いてあったわ
$japaneseDayOfWeek = $dayOfWeekMap[$englishDayOfWeek]
曜日を日本語に変換している。
$englishDayOfWeek(英語表記の曜日)をdayOfWeekMapハッシュテーブルで日本語に変換。dayOfWeekMapは英語の曜日を日本語の漢字表記に対応付けたデータ。
日本語にするのって一苦労なんだなって、でもこの1文のお陰で私の目に優しくなってる、ありがとう。
$memo = "8:30〜17:15"
固定メモを変数に設定。
これよこれ、本当に神機能。ただのメモだけどされどメモ。普通に入力するの面倒臭い、メモって大事(小並感)
$line = "$formattedDate ($japaneseDayOfWeek) | $memo"
出力内容を1行にまとめるもの。
今回で言うと日付・曜日(日本語表記)・メモを1つの文字列にしている(例:2024/12/11(水曜日)| 8:30〜17:15)
当たり前かと思ってたけどコレがあるから1行にまとまるのか〜!よく見たら今まで使ってきたものが使われてる。なるほどなあ。
# コンソールに出力
Write-Host $line
$line(整形された文字列)をコンソール(画面)に表示するもの。あなたのお陰で視覚情報として出力されてたのね、ホワイトってなんやねんって思ってた
♡結局どこが違ってたの?
正直言って分からない(おい
スペルミスはないし実行ポリシーかなとも思ったけどそうでもなさそう。曜日周りのプログラムがうまくいってないのかなって
調べてみることにした。
そしたらどうやら
$date.DayOfWeekは文字列ではなく「列拳型」らしい
拳?殴るの??(絶対違う
列拳型(れっきょがた)とは
プログラミングにおいて名前付きの定数の集合を定義するデータ型
日本語でお願いします。。
どうやら列挙型はコードが読みやすくなり値を誤って扱うリスクをえらせるらしい。特定の値を管理・操作する時に便利なツールとのこと。私はその恩恵をまだ感じれないなあ〜
もっと調べてみると文字列は自由にできる分、間違った時にそのまま反映されてしまうリスクがあるらしい。
列挙型は予め決められてる型を表示するため間違っていたら教えてくれるし決められたものなら強いし安全性が高いらしい。
つまり今回みたいに「曜日」という型にはめて出力したいなら列挙型を使う方が安全みたい。
ただ列挙型は文字列ではなく数値として内部で処理されてしまうため今回のようなエラーが出てしまったと考える。なので列挙型を文字列にしなければならない。
ここで出てくるのが
何でも文字列にしてくれるあの子
「.ToString( )」メソッドだ!!!お前ここでも!!
確かに日付にはメソッド使ってたけど曜日には使ってなかった
早速入れてみよう
♡修正スクリプト
# 現在の日付を取得
$startDate = Get-Date
# 英語の曜日名を日本語の漢字表記に変換するハッシュテーブル
$dayOfWeekMap = @{
"Sunday" = "日曜日"
"Monday" = "月曜日"
"Tuesday" = "火曜日"
"Wednesday" = "水曜日"
"Thursday" = "木曜日"
"Friday" = "金曜日"
"Saturday" = "土曜日"
}
# 1週間前の日付、曜日、メモをコンソールに出力
for ($i = -4; $i -lt 1; $i++) {
$date = $startDate.AddDays($i)
$formattedDate = $date.ToString("yyyy/MM/dd")
$englishDayOfWeek = $date.DayOfWeek.ToString( ) #列挙型を文字列に変換
$japaneseDayOfWeek = $dayOfWeekMap[$englishDayOfWeek]
$memo = "8:30〜17:15"
$line = "$formattedDate ($japaneseDayOfWeek) | $memo"
# コンソールに出力
Write-Host $line
}
実行したら・・・・
2024/12/12(木曜日)| 8:30〜17:15
2024/12/13(金曜日)| 8:30〜17:15
2024/12/14(土曜日)| 8:30〜17:15
2024/12/15(日曜日)| 8:30〜17:15
2024/12/16(月曜日)| 8:30〜17:15
2024/12/17(火曜日)| 8:30〜17:15
2024/12/18(水曜日)| 8:30〜17:15
できたーーーーーー!!
コレよコレ、私が求めてたやつ。
まあ土日はいらなかったりしたり今日の日付(19日)はなかったりするけど仕組みはわかったので修正すればよろし
すっきりしました。
今回で学んだことは
①ToStringメソッドは偉大
②列挙型という真面目ツールもある
1つ1つ紐解いてくと面白いからコレからもやっていこうと思う
ただなんかもっと効率のいい書き方とか
なんかできないかなあっとも思うわたくしなのであった・・・・