Zenn
🐶

PowerShellで日付書式を統一する

に公開

たまにファイル名の前に日付を付けるライフハック紹介してるじゃないですか?
あれフォルダ名の先頭に統一した日付書式で日付を付けるに直せませんかねー
ファイル・フォルダで泣き別れ&日付書式違いとか最早何の意味もねーのよ
バカがそーいうの喜んでやりやがるからマヂで邪魔

[とあるデータフォルダ]
 ├平成12年5月12日_測定データ一式
 ├◯社2023年12月1日議事録
 ├20120315_測定データ.csv
 └請求書_平成2年10月10日.pdf

ん?そんなコトせずともファイル・フォルダのタイムスタンプ見ればオッケー?
いやいやファイルのタイムスタンプなんて手癖のCtrl+S一発で大体ご破産だし
フォルダなんか環境によっちゃただ開いただけで.ThumbsDBとか自動生成されてアウト

まぁ何にせよ日付書式を統一しないと話になんないよねーというわけで先ずソコだけ

本題

# 和暦(gg)が含まれているとおかしくなる対策
function local:FormatDate([datetime] $Date, [string] $Format) {
    $info = New-Object CultureInfo("ja-jp", $true)
    $info.DateTimeFormat.Calendar = New-Object System.Globalization.JapaneseCalendar
    if ($Format.Contains("g")) {
        $Date.ToString($Format, $info)    
    } else {
        $Date.ToString($Format)    
    }
}

<#
.SYNOPSIS
    ファイル・フォルダ名の日付部分を正規化します
.DESCRIPTION
    入力された文字列中の日付部分を指定されたフォーマットに正規化します。西暦/和暦/2桁年数に対応しています。
.PARAMETER Text
    対象文字列
.PARAMETER Format
    出力する日付のフォーマット (例: yyyyMMdd, dd-MM-yyyy)
.PARAMETER RefDate
    参考日時 (省略可能)
.EXAMPLE
    RestrictDate "2023年12月25日_報告書.docx" "yyyyMMdd"
    結果:"20231225_報告書.docx"
.NOTES
    * 変換可能な日付形式はYYYY-MM-DD/YYYY.MM.DD/YYYY年MM月DD日/和暦YY-MM-DD/和暦YY.MM.DD/和暦YY年MM月DD日です
    * 年号省略の場合は表記年度と参照年度が一致する場合だけ処理します
#>
function RestrictTextDate {
    param (
        [parameter(Mandatory=$false)] [string]$Text,
        [parameter(Mandatory=$true)]  [string]$Format,
        [parameter(Mandatory=$false)] [datetime]$RefDate
    )
    begin {}
    process {
        # 日本のカレンダー情報を取得
        $info = New-Object CultureInfo("ja-jp", $true)
        $info.DateTimeFormat.Calendar = New-Object System.Globalization.JapaneseCalendar
        ## YYYY-MM-DD or YYYY.MM.DD
        $Text = [regex]::Replace($Text, "(?<![0-9]+)(19|20)(\d\d)([.-])([1-9]|0[1-9]|1[0-2])(\3)([1-9]|0[1-9]|[12][0-9]|3[01])(?![0-9]+)",{
            param($match)
            $name = $match.Value.ToUpper()
            $name = $name.Replace(".","-")
            $date = [DateTime]::ParseExact($name, "yyyy-M-d", $null) 
            if($date){ return (FormatDate $date $Format) }else{ return $match.Value }
        }, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
        ## YYYY年MM月DD日
        $Text = [regex]::Replace($Text, "(?<![0-9]+)(19|20)(\d\d)年([1-9]|0[1-9]|1[0-2])月([1-9]|0[1-9]|[12][0-9]|3[01])日",{
            param($match)
            $name = $match.Value.ToUpper()
            $date = [DateTime]::ParseExact($name, "yyyy年M月d日", $null) 
            if($date){ return (FormatDate $date $Format) }else{ return $match.Value }
        }, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
        ## 和暦YY-MM-DD or 和暦YY.MM.DD 
        $Text = [regex]::Replace($Text, "(令和|\bR|平成|\bH|昭和|\bS|明治|\bM|大正|\bT)(\d{1,2})([.-])([1-9]|0[1-9]|1[0-2])(\3)([1-9]|0[1-9]|[12][0-9]|3[01])(?![0-9]+)",{
            param($match)
            $name = $match.Value.ToUpper()
            $name = $name.Replace(".","-")
            $name = $name.Replace("R","令和")
            $name = $name.Replace("H","平成")
            $name = $name.Replace("S","昭和")
            $name = $name.Replace("M","明治")
            $name = $name.Replace("T","大正")
            $date = [DateTime]::ParseExact($name, "gy-M-d", $info) 
            if($date){ return (FormatDate $date $Format) }else{ return $match.Value }
        }, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
        ## 和暦YY年MM月DD日
        $Text = [regex]::Replace($Text, "(令和|\bR|平成|\bH|昭和|\bS|明治|\bM|大正|\bT)(\d{1,2}|元)年([1-9]|0[1-9]|1[0-2])月([1-9]|0[1-9]|[12][0-9]|3[01])日",{
            param($match)
            $name = $match.Value.ToUpper()
            $name = $name.Replace("R","令和")
            $name = $name.Replace("H","平成")
            $name = $name.Replace("S","昭和")
            $name = $name.Replace("M","明治")
            $name = $name.Replace("T","大正")
            $date = [DateTime]::ParseExact($name, "gy年M月d日", $info) 
            if($date){ return (FormatDate $date $Format) }else{ return $match.Value }
        }, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
        # 年号省略の場合は表記年度と参照年度が一致する場合だけ処理
        if ($RefDate -ne $null) {
            ## YY-MM-DD or YY.MM.DD
            $Text = [regex]::Replace($Text, "(?<![0-9]+)(\d\d)([.-])(0[1-9]|1[0-2])(\2)(0[1-9]|[12][0-9]|3[01])(?![0-9]+)",{
                param($match)
                $name = $match.Value.ToUpper()
                $name = $name.Replace(".","-")
                $nameyy = ($RefDate.Year).ToString().Substring(0,2) + $name
                $dateyy = [DateTime]::ParseExact($nameyy, "yyyy-M-d", $null) 
                $namegg = $RefDate.ToString("ggg", $info) + $name
                $dategg = [DateTime]::ParseExact($namegg, "gggy-M-d", $info) 
                if( ($dateyy) -and ($RefDate.Year -eq $dateyy.Year) ){
                    return (FormatDate $dateyy $Format)
                }elseif( ($dategg) -and ($RefDate.Year -eq $dategg.Year) ){
                    return (FormatDate $dategg $Format)
                }else{
                    return $match.Value
                }
            }, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
            ## YY年MM月DD日
            $Text = [regex]::Replace($Text, "(?<![0-9]+)(\d\d)年([1-9]|0[1-9]|1[0-2])月([1-9]|0[1-9]|[12][0-9]|3[01])日",{
                param($match)
                $name = $match.Value.ToUpper()
                $name = $name.Replace(".","-")
                $nameyy = ($RefDate.Year).ToString().Substring(0,2) + $name
                $dateyy = [DateTime]::ParseExact($nameyy, "yyyy年M月d日", $null) 
                $namegg = $RefDate.ToString("ggg", $info) + $name
                $dategg = [DateTime]::ParseExact($namegg, "gy年M月d日", $info) 
                if( ($dateyy) -and ($RefDate.Year -eq $dateyy.Year) ){
                    return (FormatDate $dateyy $Format)
                }elseif( ($dategg) -and ($RefDate.Year -eq $dategg.Year) ){
                    return (FormatDate $dategg $Format)
                }else{
                    return $match.Value
                }
            }, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
        }
        return $Text
    }
    end {}
}

説明

本命はRestrictTextDateでコレが正規表現で文字列中の日付を指定書式に置き換えます
最初のFormatDateはDateTimeをToStringしたときにggが含まれてると
何故かカルチャーをガン無視で「西暦〇〇年」とかいう謎フォーマットする対策ね

なおYY年MM月DD日とかいう西暦なのか和暦なのかさえわからんアホな記述は
RefDateに最終更新日とか指定してくれればそれっぽいのを自動選択しようとします
これでも微妙な奴は統一せずにスルー一択

蛇足

いやまぁ実はすでにリネームツール一式作ってあるんだけど、長いんでその一部です

Discussion

ログインするとコメントできます