Home > Enterprise >  Difference between CultureInfo.CurrentCulture and Thread.CurrentThread.CurrentCulture
Difference between CultureInfo.CurrentCulture and Thread.CurrentThread.CurrentCulture

Time:11-20

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 and Thread.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;
        }
    }

    // ...
}
  • Related