ChatGPT4で定型的なコードを自動生成して今日も定時退社をキメよう！

# はじめに

みなさん、ChatGPT4（有料のやつ）使ってますか？
彼（彼女？）は大変優秀な部下であり、同僚です。ChatGPT3.5（無料のやつ）は、ダメです…あいつはダメです…。

GPT4くんは、私が面倒に思ういろんな作業を肩代わりしてくれます。
プログラミングに関して、彼は「創造的な仕事」よりも「**定型的で確実な答えがある作業**」を得意とします。

月額20ドルというのは年間でだいたい3.5万円くらいなので、「えっちょっと高くない？」と思うかもしれませんが、それ以上の余暇を私に与えてくれます。
時給換算では余裕で元が取れます。

人によっては「**どうやって自分の作業に生かしていいかわからない**」という人もいるらしいので、私が日々の業務でどんなふうにChatGPT4くんとの甘い時間を過ごしているか、散文的ではありますが赤裸々にまとめてみます。

きっと「こんな事もできるんか」と思っていただけるでしょうし、「だったらこれも出来るんじゃ？」と、ChatGPT4くんの無限の可能性に気づくきっかけになるかもしれません。

ちなみに、私は彼に何か頼むときはいつも敬語を使っています。みなさんもそうですよね…？

サンプルコードは全て C# ですが、他の言語でも問題なくいけると思います。

# テーブル定義書からSQLのcreate table文を作る

新しくテーブルを作成する時、まず以下のようなテーブル定義書をExcelで作成すると思います。

|コメント|フィールドID|型|桁数|必須|
| - | - | - | - | - |
|ユーザID|userid|varchar|8|◎|
|苗字|familyname|varchar|20|○|
|名前|firstname|varchar|20|○|
|年齢|age|int|||
|職業|occupation_cd|varchar|4||

ここから実際のcreate table文を作る場合、会社によってはマクロで生成してくれるような場合もあると思いますが、oracle専用だったりして、「今作りたいのはPostgreSQL用なんだよなー」みたいなことはあると思います。

人間がやっても機械的にできますが、細かいSQLの文法とか毎回思い出さないといけないしトライアンドエラーに時間をかけたくありません。
こういうものはChatGPTに任せましょう。

上記のセルを選択してコピーし、テキストエディタに無造作にペーストした後、次のプロンプトを冒頭に追加します。

## プロンプト

次のテーブル定義に従ってPostgreSQL用のcreate table文を作成してください。◎はPrimary Key、〇はNOT NULL制約を表します。
また、テーブルとテーブルのフィールドにCOMMENT ON文でコメントを付与してください。

テーブルID: users
テーブル名: ユーザー

コメント	フィールドID	型	桁数	必須
ユーザID	userid	varchar	8	◎
苗字	familyname	varchar	20	○
名前	firstname	varchar	20	○
年齢	age	int		
職業	occupation_cd	varchar	4	

## ChatGPT4の回答

次のSQLスクリプトで指定のテーブルを作成できます。

```sql
CREATE TABLE users
(
    userid varchar(8) PRIMARY KEY,  -- ユーザID
    familyname varchar(20) NOT NULL, -- 苗字
    firstname varchar(20) NOT NULL, -- 名前
    age int, -- 年齢
    occupation_cd varchar(4) -- 職業
);

COMMENT ON TABLE users IS 'ユーザー';
COMMENT ON COLUMN users.userid IS 'ユーザID';
COMMENT ON COLUMN users.familyname IS '苗字';
COMMENT ON COLUMN users.firstname IS '名前';
COMMENT ON COLUMN users.age IS '年齢';
COMMENT ON COLUMN users.occupation_cd IS '職業';
```

このSQLはPostgreSQL用で、テーブル名とフィールドにコメントを追加する`COMMENT ON`構文を利用しています。各フィールドについて、その型、桁数、必須性（NOT NULL制約）に基づいて定義を行なっています。また、ユーザID (userid) は主キー (PRIMARY KEY) として指定されています。

## 私の感想

Excelマクロなんていらんかったんや…。


# create table文からモデルクラスを生成する

生成したテーブルにDapperでアクセスしようとすると、テーブルと同様の定義を持つクラスが欲しくなりますよね。
こういうものもChatGPTに作ってもらうと良いです。

## プロンプト

先ほど生成したcreate table文に対応するモデルクラスをC#で生成してください。全てのフィールドをプロパティとして実装します。
また、プロパティ名はsnake_caseではなくPascalCaseにしてください。クラス名はテーブル名と同じにしますが、複数形の場合は単数形にし、先頭を大文字にしてください。

クラスやプロパティには、テーブルのコメントをそのままドキュメントコメントとして日本語で付与してください。

## ChatGPT4の回答

以下は、指定されたテーブル定義に基づいて作成したC#のモデルクラスです。プロパティ名はPascalCaseに変換し、テーブルのコメントをそのままドキュメントコメントとして付与しています。

```csharp
/// <summary>
/// ユーザー
/// </summary>
public class User
{
    /// <summary>
    /// ユーザID
    /// </summary>
    public string UserId { get; set; }

    /// <summary>
    /// 苗字
    /// </summary>
    public string FamilyName { get; set; }

    /// <summary>
    /// 名前
    /// </summary>
    public string FirstName { get; set; }

    /// <summary>
    /// 年齢
    /// </summary>
    public int? Age { get; set; }

    /// <summary>
    /// 職業
    /// </summary>
    public string OccupationCd { get; set; }
}
```

このクラスでは、テーブルの各フィールドを表すプロパティを定義しています。また、年齢(`Age`)はNULLが許容されるフィールドであるため、C#のnullable型である`int?`として定義しています。それ以外のフィールドは`string`型として定義し、`UserId`、`FamilyName`、`FirstName`、`OccupationCd`はNULLが許容されないため`NOT NULL`制約が暗示的に適用されています。

## 私の感想

PascalCaseちゃんとわかっててoccupation_cdをOccupationCdってしてくれるのもえらすぎるし、別になんも指定していない「familyname」って文字列を「FamilyName」にしてくれるのえらすぎん？？
こんなん入ってきたばっかりの新人にお願いしても絶対一発ではやってくれんやん…。


# 入力チェックのコードをテーブルから作成する

入力チェック用のコードというのは、必須入力チェックや最大長チェックなど、だらだらと同じようなコードが並ぶ感じになります。
見ていると何らかの定義書から自動生成できそうですが、面倒なので自動生成ツールまで作る気力はありません。

そうだ、ChatGPTならこういうの得意なのでは？

## プロンプト

入力チェックには「必須入力チェック」と「最大長チェック」があり、次のようなC#コードでチェックを行います。

```C#
// 必須入力チェック
if (string.IsNullOrWhiteSpace(model.<プロパティ名>)
{
	return new ErrorResult {
		ErrorCode = ErrorCode.E123,
		Message = _messages.BuildMessage(ErrorCode.E123, <項目名>),
		PropertyName = nameof(model.<プロパティ名>),
	};
}

// 最大長チェック
if (model.<プロパティ名>.Length > そのフィールドの最大長 )
{
	return new ErrorResult {
		ErrorCode = ErrorCode.E456,
		Message = _messages.BuildMessage(ErrorCode.E456, <項目名>),
		PropertyName = nameof(model.<プロパティ名>),
	};
}
```

以下のルールに従って、さきほど生成したモデルクラスの内容をチェックするコードを書いてください。

- 対応するテーブルのフィールドの型がvarchar、且つ、NOT NULL のものは、必須入力チェックと最大長チェックを行います
- varchar だけど NOT NULL ではないものは、最大長チェックのみ行います（その時、nullならばチェックを行わないようにします）
- 各チェック用のコードブロックにはブロックの開始位置に、「項目名：チェック内容」の形式でコメントを付与します

## ChatGPT4の回答

前回生成したモデルクラスを用いて、入力チェックを行うC#コードを以下のように記述します。指定のルールに従い、`UserId`、`FamilyName`、`FirstName`、`OccupationCd`については必須入力チェックと最大長チェックを行い、`Age`についてはチェックを行いません。

また、各チェック用のコードブロックの開始位置に「項目名：チェック内容」の形式でコメントを付与しています。

```csharp
// UserId：必須入力チェック
if (string.IsNullOrWhiteSpace(model.UserId))
{
    return new ErrorResult {
        ErrorCode = ErrorCode.E123,
        Message = _messages.BuildMessage(ErrorCode.E123, "ユーザID"),
        PropertyName = nameof(model.UserId),
    };
}

// UserId：最大長チェック
if (model.UserId.Length > 8)
{
    return new ErrorResult {
        ErrorCode = ErrorCode.E456,
        Message = _messages.BuildMessage(ErrorCode.E456, "ユーザID"),
        PropertyName = nameof(model.UserId),
    };
}

// FamilyName：必須入力チェック
if (string.IsNullOrWhiteSpace(model.FamilyName))
{
    return new ErrorResult {
        ErrorCode = ErrorCode.E123,
        Message = _messages.BuildMessage(ErrorCode.E123, "苗字"),
        PropertyName = nameof(model.FamilyName),
    };
}

// FamilyName：最大長チェック
if (model.FamilyName.Length > 20)
{
    return new ErrorResult {
        ErrorCode = ErrorCode.E456,
        Message = _messages.BuildMessage(ErrorCode.E456, "苗字"),
        PropertyName = nameof(model.FamilyName),
    };
}

// FirstName：必須入力チェック
if (string.IsNullOrWhiteSpace(model.FirstName))
{
    return new ErrorResult {
        ErrorCode = ErrorCode.E123,
        Message = _messages.BuildMessage(ErrorCode.E123, "名前"),
        PropertyName = nameof(model.FirstName),
    };
}

// FirstName：最大長チェック
if (model.FirstName.Length > 20)
{
    return new ErrorResult {
        ErrorCode = ErrorCode.E456,
        Message = _messages.BuildMessage(ErrorCode.E456, "名前"),
        PropertyName = nameof(model.FirstName),
    };
}

// OccupationCd：最大長チェック
if (!string.IsNullOrEmpty(model.OccupationCd) && model.OccupationCd.Length > 4)
{
    return new ErrorResult {
        ErrorCode = ErrorCode.E456,
        Message = _messages.BuildMessage(ErrorCode.E456, "職業"),
        PropertyName = nameof(model.OccupationCd),
    };
}
```

ここでの`_messages.BuildMessage`はエラーメッセージを構築するためのメソッドと仮定しています。具体的な挙動はそのメソッドの実装に依存します。

## 私の感想

最初OccupationCdも必須チェック行うって書いてて「おいおい、それはNOT NULLじゃないんですけど？」と一瞬思ったけど、生成されたコード見たら必須チェックしてないし、この子できる子やん・・・！

ていうか、「（その時、nullならばチェックを行わないようにします）」っていう雑な指示でちゃんとやってくれるし最高では。

# SQLを生成しているコードから結果のSQLを取り出す

条件に応じてSQLを組み立てているコードがあるんだけど、ある条件の時にどんな結果になるのかいちいち実行して確かめるのが面倒…今からトレースを仕込むのもなぁ。
そうだ。ChatGPT4なら分かるんじゃ？

## プロンプト

以下のコードは sb.AppendLine("...") を使って SQL を生成しています。
searchParams.age = 0 の時、生成されるSQLを教えてください。
次に、searchParams.age = 5 の時、生成されるSQLを教えてください。
その後、生成された2つのSQLの差異を教えてください。

```C#
public string createSQL(SearchParameters searchParams)
{
	var sb = new StringBuilder();
	
	sb.AppendLine(" SELECT ");
	sb.AppendLine("   userid, ");
	sb.AppendLine("   firstname ");
	sb.AppendLine(" FROM ");
	sb.AppendLine("   user ");
	sb.AppendLine(" WHERE ");
	sb.AppendLine("   userid = @userid ");
	
	if (searchParams.age > 0 )
	{
		sb.AppendLine("   AND age > @age ");
	}
	
	return sb.ToString();
}
```

## ChatGPT4の回答

まずは `searchParams.age = 0` のときのSQLを見てみましょう：

```SQL
SELECT 
   userid, 
   firstname 
FROM 
   user 
WHERE 
   userid = @userid
```

次に、 `searchParams.age = 5` のときのSQLです：

```SQL
SELECT 
   userid, 
   firstname 
FROM 
   user 
WHERE 
   userid = @userid
   AND age > @age 
```

これら二つのSQLの主な違いは `age > @age` の条件が追加されているかどうかです。この部分は `searchParams.age` の値が0より大きい場合のみ追加されます。この条件が追加されると、ユーザーIDが `@userid` に等しく、かつ、年齢が `@age` より大きいレコードのみが検索結果に含まれます。この条件が存在しない場合は、年齢に関係なくユーザーIDが `@userid` に等しいレコードが検索結果に含まれます。

## 私の感想

なんかもう、あんたすげえよ！ 脳にでっかいコンピュータ積んでんのかい！（正解）
いつもありがとう！


# HTMLのテーブルをモデルクラスから生成する

## プロンプト

以下のクラスの内容を表示する為のHTMLのtableを作成してください。
tableは固定幅とし、各列にはプロパティ名を全て小文字にしたCSSクラス名を付与します。
列のタイトルとして、プロパティのコメントを表示してください。
また、それらの列幅を指定するスタイル定義を作成してください。幅はremで仮に指定してください。

```csharp
/// <summary>
/// ユーザー
/// </summary>
public class User
{
    /// <summary>
    /// ユーザID
    /// </summary>
    public string UserId { get; set; }

    /// <summary>
    /// 苗字
    /// </summary>
    public string FamilyName { get; set; }

    /// <summary>
    /// 名前
    /// </summary>
    public string FirstName { get; set; }

    /// <summary>
    /// 年齢
    /// </summary>
    public int? Age { get; set; }

    /// <summary>
    /// 職業
    /// </summary>
    public string OccupationCd { get; set; }
}
```

## ChatGPT4の回答

以下に、指定された "User" クラスのプロパティに基づくHTMLのtableを生成します。各列にはCSSクラス名として、プロパティ名を小文字にしたものを割り当てます。また、各列の幅を設定するスタイル定義を作成します。列のタイトルはプロパティのコメントを使用します。

まず、"User" クラスのプロパティ名を小文字にしたCSSクラス名を持つHTMLテーブルです：

```HTML
<table>
    <thead>
        <tr>
            <th class="userid">ユーザID</th>
            <th class="familyname">苗字</th>
            <th class="firstname">名前</th>
            <th class="age">年齢</th>
            <th class="occupationcd">職業</th>
        </tr>
    </thead>
    <tbody>
        <!-- Repeat this for each User in your dataset -->
        <tr>
            <td class="userid">{User.UserId}</td>
            <td class="familyname">{User.FamilyName}</td>
            <td class="firstname">{User.FirstName}</td>
            <td class="age">{User.Age}</td>
            <td class="occupationcd">{User.OccupationCd}</td>
        </tr>
    </tbody>
</table>
```

次に、各列幅を指定するスタイル定義です。ここではrem単位での指定を行います。具体的な幅の値は適宜調整してください：

```CSS
<style>
    .userid { width: 4rem; }
    .familyname { width: 5rem; }
    .firstname { width: 5rem; }
    .age { width: 2rem; }
    .occupationcd { width: 3rem; }
</style>
```

上記のCSSのスタイル定義は、適用したいHTMLファイルの `<head>` 内や、外部CSSファイルに配置することができます。


## 私の感想

プログラマーはついに単純作業から解放されたのです…！

# C# のソースコードを VB.NET に変換する

例えば次のような C# 拡張メソッドを見つけて、これは便利なのでVB.NETのプロジェクトで使いたいと思ったとします。

https://www.extensionmethod.net/csharp/list-string/datareader-to-csv

C#からVB.NETへの変換は人間がやっても機械的な置き換えになりますが、それなりに気を遣う、なかなか面倒な作業です。
こういう「機械的な置き換え」はChatGPTが得意なのでは？


## プロンプト

次の C# の拡張メソッドをVB.NETに変換してください。適切なコメントを日本語で付与してください。

```C#
public static List<string> ToCSV(this IDataReader dataReader, bool includeHeaderAsFirstRow, string separator)
{
    List<string> csvRows = new List<string>();
    StringBuilder sb = null;

    if (includeHeaderAsFirstRow)
    {
        sb = new StringBuilder();
        for (int index = 0; index < dataReader.FieldCount; index++)
        {
            if (dataReader.GetName(index) != null)
                sb.Append(dataReader.GetName(index));

            if (index < dataReader.FieldCount - 1)
                sb.Append(separator);
        }
        csvRows.Add(sb.ToString());
    }

    while (dataReader.Read())
    {
        sb = new StringBuilder();
        for (int index = 0; index < dataReader.FieldCount - 1; index++)
        {
            if (!dataReader.IsDBNull(index))
            {
                string value = dataReader.GetValue(index).ToString();
                if (dataReader.GetFieldType(index) == typeof(String))
                {
                    //If double quotes are used in value, ensure each are replaced but 2.
                    if (value.IndexOf("\"") >= 0)
                        value = value.Replace("\"", "\"\"");

                    //If separtor are is in value, ensure it is put in double quotes.
                    if (value.IndexOf(separator) >= 0)
                        value = "\"" + value + "\"";
                }
                sb.Append(value);
            }

            if (index < dataReader.FieldCount - 1)
                sb.Append(separator);
        }

        if (!dataReader.IsDBNull(dataReader.FieldCount - 1))
            sb.Append(dataReader.GetValue(dataReader.FieldCount - 1).ToString().Replace(separator, " "));

        csvRows.Add(sb.ToString());
    }
    dataReader.Close();
    sb = null;
    return csvRows;
}
```

## ChatGPT4の回答

以下に、指定されたC#の拡張メソッドをVB.NETに変換したものを提供します。各行には適切な日本語のコメントを付与しています。

```vb
Imports System.Data
Imports System.Text
Imports System.Collections.Generic

Public Module DataReaderExtensions

    ''' <summary>
    ''' IDataReaderからCSV形式のリストを生成します。
    ''' ヘッダーを最初の行として含めるかどうかを指定し、フィールドのセパレータも指定できます。
    ''' </summary>
    ''' <param name="dataReader">元のIDataReader</param>
    ''' <param name="includeHeaderAsFirstRow">ヘッダーを最初の行として含めるかどうか</param>
    ''' <param name="separator">フィールドのセパレータ</param>
    ''' <returns>CSV形式の文字列のリスト</returns>
    <System.Runtime.CompilerServices.Extension()>
    Public Function ToCSV(ByVal dataReader As IDataReader, ByVal includeHeaderAsFirstRow As Boolean, ByVal separator As String) As List(Of String)
        Dim csvRows As New List(Of String)
        Dim sb As StringBuilder = Nothing

        If includeHeaderAsFirstRow Then
            sb = New StringBuilder()
            For index As Integer = 0 To dataReader.FieldCount - 1
                If dataReader.GetName(index) IsNot Nothing Then
                    sb.Append(dataReader.GetName(index))
                End If

                If index < dataReader.FieldCount - 1 Then
                    sb.Append(separator)
                End If
            Next
            csvRows.Add(sb.ToString())
        End If

        While dataReader.Read()
            sb = New StringBuilder()
            For index As Integer = 0 To dataReader.FieldCount - 1
                If Not dataReader.IsDBNull(index) Then
                    Dim value As String = dataReader.GetValue(index).ToString()
                    If dataReader.GetFieldType(index) Is GetType(String) Then
                        ' 値内で二重引用符が使用されている場合、各引用符を二つに置き換えます
                        If value.IndexOf("""") >= 0 Then
                            value = value.Replace("""", """""")
                        End If

                        ' 値内にセパレータが存在する場合、値を二重引用符で囲みます
                        If value.IndexOf(separator) >= 0 Then
                            value = """" & value & """"
                        End If
                    End If
                    sb.Append(value)
                End If

                If index < dataReader.FieldCount - 1 Then
                    sb.Append(separator)
                End If
            Next

            If Not dataReader.IsDBNull(dataReader.FieldCount - 1) Then
                sb.Append(dataReader.GetValue(dataReader.FieldCount - 1).ToString().Replace(separator, " "))
            End If

            csvRows.Add(sb.ToString())
        End While
        dataReader.Close()
        sb = Nothing
        Return csvRows
    End Function
End Module
```

なお、VB.NETでは拡張メソッドはモジュール内で定義する必要があります。そのため、ここでは`DataReaderExtensions`という名前のモジュールを新たに定義しています。

## 私の感想

ええぇ…ちゃんとしすぎてて逆に怖い…。でもありがとう！
とりあえず目視で確認は必要だけど、見る限り問題なさそう…あとは軽くテストですね。


# 調べるのが面倒な単純なコードを書いてもらう

yyyy/MM 形式の文字列を扱うことが多いものの、DBでは対応するフィールドはyyyyMM形式になっており、その変換コードがいちいち面倒です。yyyy/MM/dd 形式の文字列も、DBに格納する時はDateTime型にします。

そこで、datestring.ToDate() でDateTime型に変換したり、date.ToYYYYMM() でyyyyMM形式の文字列に、date.ToSlashYYYYMM() で yyyy/MM形式の文字列にする拡張メソッドを作ろうと考えました。まぁよくあるやるなんですが、細かい部分で業務的な仕様を盛り込まないといけないので、ありものを使うわけにもいきません。

作ろうと思えば簡単だと思いますが、なんか日付の正しいパーズ処理とか調べるのが面倒です。考えてみたら、入力される日付文字列も、yyyy/MM/ddだったりyyyy/M/d だったりします。あー面倒。

そうだ、こういう「確実な正解」があるシンプルな作業は、ChatGPTならやってくれるのでは？

## プロンプト

あなたは凄腕のC#プログラマーです。
以下の拡張メソッドを定義する DateTimeExtensionsクラス、DateTimeStringExtensionsクラスを定義してください。
各メソッドには適切なドキュメントコメントを日本語で付与してください。

DateTimeExtensions

- string ToYYYYMM(this DateTime date)
	- DateTimeを "yyyyMM" 形式の文字列にします

- string ToSlashYYYYMM(this DateTime date)
	- DateTimeを "yyyy/MM" 形式の文字列にします

- string ToSlashYMD(this DateTime date)
	- DateTimeを "yyyy/MM/dd" 形式の文字列にします

DateTimeStringExtensions

- DateTime ToDate(this string datestring)
	- yyyy/MM, yyyy/M, yyyyMM, yyyy/MM/dd, yyyy/M/d, yyyyMMdd 形式の日付文字列をDateTime型に変換します
	- 文字列が空、空白、又は null の場合は例外をスローします

- bool IsValidDate(this string datestring)
	- yyyy/MM, yyyy/M, yyyyMM, yyyy/MM/dd, yyyy/M/d, yyyyMMdd  形式の日付文字列の場合にtrueを返します
	- 文字列が空、空白、又は null の場合は falseを返します

- string ToYYYYMM(this string datestring)
	- 日付文字列を yyyyMM形式の文字列に変換します
	- 内部的には、ToDate().ToYYYYMM()を利用します
	- 文字列が空、空白、又は null の場合は 空文字を返します

- string ToSlashYYYYMM(this string datestring)
	- 日付文字列を yyyy/MM形式の文字列に変換します
	- 内部的には、ToDate().ToSlashYYYYMM()を利用します
	- 文字列が空、空白、又は null の場合は 空文字を返します

## ChatGPT4の回答

ご指定いただいた仕様に基づいて、`DateTimeExtensions`クラスと`DateTimeStringExtensions`クラスを定義します。なお、この実装では日付文字列の解析に`DateTime.TryParseExact`メソッドを用い、さまざまな形式に対応しています。

```csharp
using System;

public static class DateTimeExtensions
{
    /// <summary>
    /// DateTimeを "yyyyMM" 形式の文字列に変換します。
    /// </summary>
    /// <param name="date">変換するDateTime。</param>
    /// <returns>"yyyyMM" 形式の文字列。</returns>
    public static string ToYYYYMM(this DateTime date)
    {
        return date.ToString("yyyyMM");
    }

    /// <summary>
    /// DateTimeを "yyyy/MM" 形式の文字列に変換します。
    /// </summary>
    /// <param name="date">変換するDateTime。</param>
    /// <returns>"yyyy/MM" 形式の文字列。</returns>
    public static string ToSlashYYYYMM(this DateTime date)
    {
        return date.ToString("yyyy/MM");
    }

    /// <summary>
    /// DateTimeを "yyyy/MM/dd" 形式の文字列に変換します。
    /// </summary>
    /// <param name="date">変換するDateTime。</param>
    /// <returns>"yyyy/MM/dd" 形式の文字列。</returns>
    public static string ToSlashYMD(this DateTime date)
    {
        return date.ToString("yyyy/MM/dd");
    }
}

public static class DateTimeStringExtensions
{
    private static string[] formats = { "yyyyMM", "yyyy/M", "yyyy/MM", "yyyyMMdd", "yyyy/M/d", "yyyy/MM/dd" };

    /// <summary>
    /// yyyy/MM, yyyy/M, yyyyMM, yyyy/MM/dd, yyyy/M/d, yyyyMMdd 形式の日付文字列をDateTime型に変換します。
    /// 文字列が空、空白、又は null の場合は例外をスローします。
    /// </summary>
    /// <param name="datestring">変換する文字列。</param>
    /// <returns>変換後のDateTime。</returns>
    public static DateTime ToDate(this string datestring)
    {
        if (string.IsNullOrWhiteSpace(datestring))
            throw new ArgumentException("日付文字列が null、空白、または空です。");

        if (DateTime.TryParseExact(datestring, formats, null, System.Globalization.DateTimeStyles.None, out DateTime result))
            return result;
        
        throw new ArgumentException("日付文字列の形式が正しくありません。");
    }

    /// <summary>
    /// yyyy/MM, yyyy/M, yyyyMM, yyyy/MM/dd, yyyy/M/d, yyyyMMdd 形式の日付文字列の場合にtrueを返します。
    /// 文字列が空、空白、又は null の場合は falseを返します。
    /// </summary>
    /// <param name="datestring">チェックする文字列。</param>
    /// <returns>日付文字列が有効な場合はtrue、そうでない場合はfalse。</returns>
    public static bool IsValidDate(this string datestring)
    {
        if (string.IsNullOrWhiteSpace(datestring))
            return false;



        return DateTime.TryParseExact(datestring, formats, null, System.Globalization.DateTimeStyles.None, out _);
    }

    /// <summary>
    /// 日付文字列を yyyyMM形式の文字列に変換します。
    /// 文字列が空、空白、又は null の場合は 空文字を返します。
    /// </summary>
    /// <param name="datestring">変換する文字列。</param>
    /// <returns>"yyyyMM" 形式の文字列。変換不可能な場合は空文字。</returns>
    public static string ToYYYYMM(this string datestring)
    {
        if (string.IsNullOrWhiteSpace(datestring))
            return "";

        return datestring.IsValidDate() ? datestring.ToDate().ToYYYYMM() : "";
    }

    /// <summary>
    /// 日付文字列を yyyy/MM形式の文字列に変換します。
    /// 文字列が空、空白、又は null の場合は 空文字を返します。
    /// </summary>
    /// <param name="datestring">変換する文字列。</param>
    /// <returns>"yyyy/MM" 形式の文字列。変換不可能な場合は空文字。</returns>
    public static string ToSlashYYYYMM(this string datestring)
    {
        if (string.IsNullOrWhiteSpace(datestring))
            return "";

        return datestring.IsValidDate() ? datestring.ToDate().ToSlashYYYYMM() : "";
    }
}
```
これにより、`DateTime`オブジェクトから特定の文字列形式への変換、また特定の文字列形式から`DateTime`オブジェクトへの変換が可能になります。

## 私の感想

え、DateTime.TryParseExactって、複数のフォーマットをまとめて指定できたん？？
めっちゃ便利やし、自分じゃ気づかなかった・・・ChatGPT4ありがとう！
いちおう目視でコードレビューはしないとダメだけど、見る限りほぼ問題なさそう！
ありがとう！

# その他

それ以外にも、いろんな「面倒な作業」をお願いできます。可能性は無限大です。

- このソースコードに日本語でコメントを付けてください
- 以下のソースコード中の tabindex="number" について、number を再度割り当ててください。1から開始し、あとは連番とします。
- 以下のHTML中のinput要素について、idが付与されていないものについて全てidを付与してください。idの値はそのinput要素にbindされているVueのv-modelのプロパティ名と同一にしてください。
- 以下のSQLを sb.AppendLine("...") を使って1行ずつStringBuilderにApppendするC#コードに置き換えてください。また、SQL中のパラメータをSqlParameterのリストに追加してください。

# まとめ

私はChatGPT4によって、少なく見積もっても週に4時間程度の時間を節約できています。
これがたったの20ドル/月！

- ChatGPTは「機械的」で「定型作業」が得意です
- あんまり創造的な事をやらせようとすると間違うので逆に面倒です
- 丁寧で明確な指示が大切です
- これ正規表現での置換でできそうだけど面倒だなーと思ったらChatGPTに頼んでみましょう
- Excelに項目名リストアップしてChatGPTに流すとコードが生成される、という思考で考えてみましょう

ChatGPT4が作ってくれた余裕時間で好きなコードを書きましょう。
それもChatGPT4に手伝ってもらいましょう。
（そしてどんどん堕落していく）

# 注意事項

- あまり企業秘密になりそうなコードをChatGPTに投げないようにしましょう。
- フィールド名やテーブル名などは適当にボカして依頼し、結果を文字列置換するなどして防衛しましょう。