8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

c#の非同期処理時のDateTimeFormat

Last updated at Posted at 2025-01-07

C#で日付のフォーマットを変更していた際に、思い通りの挙動にならず
仕様について調べたのでそれの備忘録です

発生した問題

test.cs
using System.Globalization;
using System.Threading;
// 2025/01/06
CultureInfo originalCulture = new CultureInfo("ja-JP");
originalCulture.DateTimeFormat.Calendar = new JapaneseCalendar();
originalCulture.DateTimeFormat.ShortDatePattern = "ggy年M月d日";
Thread.CurrentThread.CurrentCulture = originalCulture;
DateTime.Today.ToString();
// 令和7年1月6日 0:00:00

Thread.CurrentThread.CurrentCultureで和暦で日付を表示させるようにしていましたが...

test.cs
using System.Globalization;
using System.Threading;
// 2025/01/06
CultureInfo originalCulture = new CultureInfo("ja-JP");
originalCulture.DateTimeFormat.Calendar = new JapaneseCalendar();
originalCulture.DateTimeFormat.ShortDatePattern = "ggy年M月d日";
Thread.CurrentThread.CurrentCulture = originalCulture;
// 非同期で実行
Task.Run(() => {
    DateTime.Today.ToString();
});  
// 2025/01/06 0:00:00

非同期処理だと日付のフォーマットがデフォルトのままでした

問題の原因

Thread.CurrentThread.CurrentCultureは設定したスレッドでのみ有効で、非同期処理は別のスレッドで実行されるため日付のフォーマットがデフォルトになっていました。

問題の解決策

解決策 (2025/01/08追記)

1.非同期処理の中でDateTimeFormatを設定

test.cs
using System.Globalization;
using System.Threading;
// 2025/01/06
CultureInfo originalCulture = new CultureInfo("ja-JP");
originalCulture.DateTimeFormat.Calendar = new JapaneseCalendar();
originalCulture.DateTimeFormat.ShortDatePattern = "ggy年M月d日";
// 非同期で実行
Task.Run(() => {
    // 非同期処理の中でDateTimeFormatを設定
    Thread.CurrentThread.CurrentCulture = originalCulture;
    DateTime.Today.ToString();
});  
// 令和7年1月6日 0:00:00
  • 良い点:どこで日付のフォーマットが変更されたか見やすい
  • 悪い点:非同期処理をするたび(スレッドが変わるたび)に設定しないといけない

2.CultureInfo.DefaultThreadCurrentCultureで全体のフォーマットを設定

test.cs
CultureInfo originalCulture = new CultureInfo("ja-JP");
originalCulture.DateTimeFormat.Calendar = new JapaneseCalendar();
originalCulture.DateTimeFormat.ShortDatePattern = "ggy年M月d日";
CultureInfo.DefaultThreadCurrentCulture = originalCulture;
// 非同期で実行
Task.Run(() => {
    DateTime.Today.ToString();
});  
// 令和7年1月6日 0:00:00
  • 良い点:設定されていない全ての非同期処理のフォーマットが切り替わる
  • 悪い点:全てのフォーマットが切り替わるので、個別でフォーマットを変えたいときに不便

2025/01/08追記

コメントでアドバイスをいただいたので、追記させていただきます(ありがとうございます!)
1.2の合わせ技やStringの書式指定で個別のFormatを綺麗に設定できそうです

日付フォーマットの適用順
CultureInfo.DefaultThreadCurrentCulture

Thread.CurrentThread.CurrentCulture

String.FormatToString

上に行くほど範囲が広くなり、下に行くほど優先度が高くなります

test.cs
using System.Globalization;
using System.Threading;
// 2025/01/06
CultureInfo originalCulture = new CultureInfo("ja-JP");
originalCulture.DateTimeFormat.Calendar = new JapaneseCalendar();
originalCulture.DateTimeFormat.ShortDatePattern = "ggy年M月d日";
// 全体のデフォルトFormatを設定
CultureInfo.DefaultThreadCurrentCulture = originalCulture;
// 非同期で実行
Task.Run(() => {
    DateTime.Today.ToString();
    DateTime.Today.ToString();
    DateTime.Today.ToString();
});  
// 令和7年1月6日 0:00:00
// 令和7年1月6日 0:00:00
// 令和7年1月6日 0:00:00

// 非同期で実行(非同期処理内全部に設定 和暦→西暦)
Task.Run(() => {
    // 西暦のカレンダーでフォーマットを設定
    CultureInfo asyncCulture = new CultureInfo("ja-JP");
    asyncCulture.DateTimeFormat.Calendar = new GregorianCalendar();
    asyncCulture.DateTimeFormat.ShortDatePattern = "yyyy年MM月dd日";
    Thread.CurrentThread.CurrentCulture = asyncCulture;
    
    DateTime.Today.ToString();
    DateTime.Today.ToString();
    DateTime.Today.ToString();
});  
// 2025/01/06 0:00:00
// 2025/01/06 0:00:00
// 2025/01/06 0:00:00

// 非同期で実行(個別に設定 和暦→西暦)
Task.Run(() => {
    // 西暦のカレンダーを設定
    CultureInfo gregorianCulture = new CultureInfo("ja-JP");
    gregorianCulture.DateTimeFormat.Calendar = new GregorianCalendar();
    
    // デフォルト
    DateTime.Today.ToString();
    // ToStringのカスタム日時書式指定子で変換
    DateTime.Today.ToString("yyyy年M月d日", gregorianCulture);
    // String.Formatで変換
    string.Format(gregorianCulture, "{0:yyyy年MM月dd日}", DateTime.Today); 
});  
// 令和7年1月6日 0:00:00
// 2025年1月6日
// 2025年01月06日

実行環境 (2025/01/10追記)

.NET Framework 4.5

.NET Frameworkのバージョンによって非同期処理時のCurrentCultureの挙動が異なるようです
↓こちらの記事で、詳しく解説されています。

おわりに

今回の問題は、同期処理を非同期処理に変更する時(逆もしかり)などに、よく起こりそうなので、そういった修正をする際には日付のフォーマットに注意しておこうと思いました。

参考にさせていただいた記事、サイト

8
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?