So I was doing some tests where I need to fire some threads and perform some datetime parsings modifying the CurrentCulture and wondered if there is any difference at all between CultureInfo.CurrentCulture
and Thread.CurrentThread.CurrentCulture
For both the intellisense tells me:
Gets or sets the culture for the current thread.
Returns:
An object that represents the culture for the current thread.
My code:
using System.Globalization;
Console.WriteLine("Hello, World!");
string dateValueString = "05/07/2022";
CultureInfo enGB = new CultureInfo("en-GB");
CultureInfo enUS = new CultureInfo("en-US");
DateTime result = DateTime.Now;
DateTime result2 = DateTime.Now;
Console.WriteLine($"CurrentCulture: {CultureInfo.CurrentCulture.Name} - ThreadCulture: {Thread.CurrentThread.CurrentCulture.Name}");
if (DateTime.TryParse(dateValueString, enGB, DateTimeStyles.None, out result))
{
Console.WriteLine($"Original: {dateValueString} Parsed: {result}. Day: {result.Day}. Month: {result.Month}. Year: {result.Year}");
result2 = DateTime.Parse(dateValueString);
Console.WriteLine($"[Parse]Original: {dateValueString} Parsed: {result2}. Day: {result2.Day}. Month: {result2.Month}. Year: {result2.Year}");
}
Console.WriteLine(System.Environment.NewLine);
Thread.CurrentThread.CurrentCulture = enGB;
Console.WriteLine($"CurrentCulture: {CultureInfo.CurrentCulture.Name} - ThreadCulture: {Thread.CurrentThread.CurrentCulture.Name}");
if (DateTime.TryParse(dateValueString, enGB, DateTimeStyles.None, out result))
{
Console.WriteLine($"Original: {dateValueString} Parsed: {result}. Day: {result.Day}. Month: {result.Month}. Year: {result.Year}");
result2 = DateTime.Parse(dateValueString);
Console.WriteLine($"[Parse]Original: {dateValueString} Parsed: {result2}. Day: {result2.Day}. Month: {result2.Month}. Year: {result2.Year}");
}
Console.WriteLine(System.Environment.NewLine);
Thread.CurrentThread.CurrentCulture = enUS;
Console.WriteLine($"CurrentCulture: {CultureInfo.CurrentCulture.Name} - ThreadCulture: {Thread.CurrentThread.CurrentCulture.Name}");
if (DateTime.TryParse(dateValueString, enGB, DateTimeStyles.None, out result))
{
Console.WriteLine($"Original: {dateValueString} Parsed: {result}. Day: {result.Day}. Month: {result.Month}. Year: {result.Year}");
result2 = DateTime.Parse(dateValueString);
Console.WriteLine($"[Parse]Original: {dateValueString} Parsed: {result2}. Day: {result2.Day}. Month: {result2.Month}. Year: {result2.Year}");
}
Console.WriteLine(System.Environment.NewLine);
new Thread(() =>
{
Thread.CurrentThread.CurrentCulture = enGB;
Console.WriteLine($"CurrentCulture: {CultureInfo.CurrentCulture.Name} - ThreadCulture: {Thread.CurrentThread.CurrentCulture.Name}");
if (DateTime.TryParse(dateValueString, enGB, DateTimeStyles.None, out result))
{
Console.WriteLine($"[Thread] Original: {dateValueString} Parsed: {result}. Day: {result.Day}. Month: {result.Month}. Year: {result.Year}");
result2 = DateTime.Parse(dateValueString);
Console.WriteLine($"[Thread][Parse]Original: {dateValueString} Parsed: {result2}. Day: {result2.Day}. Month: {result2.Month}. Year: {result2.Year}");
}
}).Start();
Console.WriteLine(System.Environment.NewLine);
Output:
CurrentCulture: es-ES - ThreadCulture: es-ES
Original: 05/07/2022 Parsed: 05/07/2022 0:00:00. Day: 5. Month: 7. Year: 2022
[Parse]Original: 05/07/2022 Parsed: 05/07/2022 0:00:00. Day: 5. Month: 7. Year: 2022
CurrentCulture: en-GB - ThreadCulture: en-GB
Original: 05/07/2022 Parsed: 05/07/2022 00:00:00. Day: 5. Month: 7. Year: 2022
[Parse]Original: 05/07/2022 Parsed: 05/07/2022 00:00:00. Day: 5. Month: 7. Year: 2022
CurrentCulture: en-US - ThreadCulture: en-US
Original: 05/07/2022 Parsed: 7/5/2022 12:00:00 AM. Day: 5. Month: 7. Year: 2022
[Parse]Original: 05/07/2022 Parsed: 5/7/2022 12:00:00 AM. Day: 7. Month: 5. Year: 2022
CurrentCulture: en-GB - ThreadCulture: en-GB
[Thread] Original: 05/07/2022 Parsed: 05/07/2022 00:00:00. Day: 5. Month: 7. Year: 2022
[Thread][Parse]Original: 05/07/2022 Parsed: 05/07/2022 00:00:00. Day: 5. Month: 7. Year: 2022
CodePudding user response:
Difference between
CultureInfo.CurrentCulture
andThread.CurrentThread.CurrentCulture
Surprisingly, no-one has asked this specific question before, though people have asked about Application.CurrentCulture
instead.
Anyway: Thread.CurrentThread.CurrentCulture
(or Thread.CurrentCulture
to be specific)'s property getter just returns CultureInfo.CurrentCulture
, as can be seen in the source code:
class Thread
{
// ...
public CultureInfo CurrentCulture
{
get
{
RequireCurrentThread();
return CultureInfo.CurrentCulture;
}
set
{
if (this != CurrentThread)
{
SetCultureOnUnstartedThread(value, uiCulture: false);
return;
}
CultureInfo.CurrentCulture = value;
}
}
// ...
}
So as far as you're concerned: there is no difference and your tests are redundant.
And if you're wondering, CultureInfo.CurrentCulture
is a simple property that reads/writes to a \[ThreadStatic\]
field (so the real logic is in the CLR, I suppose):
public partial class CultureInfo : IFormatProvider, ICloneable
{
// ...
[ThreadStatic]
private static CultureInfo? s_currentThreadCulture;
[ThreadStatic]
private static CultureInfo? s_currentThreadUICulture;
// ...
public static CultureInfo CurrentCulture
{
get
{
return s_currentThreadCulture ??
s_DefaultThreadCurrentCulture ??
s_userDefaultCulture ??
InitializeUserDefaultCulture();
}
set
{
ArgumentNullException.ThrowIfNull(value);
if (s_asyncLocalCurrentCulture == null)
{
Interlocked.CompareExchange(ref s_asyncLocalCurrentCulture, new AsyncLocal<CultureInfo>(AsyncLocalSetCurrentCulture), null);
}
s_asyncLocalCurrentCulture!.Value = value;
}
}
// ...
}