Why does implicit date casting to [string] not use current regional settings?

52 views Asked by At

PowerShell does an implicit conversion of a [datetime] to [string] in order to do this concatenation.

Why does using ToString() use the current regional settings while not using it produces a different result?

PS C:\> 'now ' + (Get-Date).AddDays(-3)
now 06/10/2023 12:32:28
PS C:\> 'now ' + (Get-Date).AddDays(-3).ToString()
now 2023-06-10 12:32:47

PS C:\> $PSVersionTable.PSVersion.ToString()
7.3.4

Related question: Why is Powershell Write-Output Date Format not the System Setting?

1

There are 1 answers

3
Santiago Squarzon On BEST ANSWER

.ToString() will call the DateTime.ToString() instance method which uses the current culture, where as casting will use whatever the PowerShell team decided to use for IFormatProvider.

I believe the code in charge of this is LanguagePrimitives.ConvertTo, which by the looks of it, they decided to use InvariantCulture: LanguagePrimitives.cs#L1758C2-L1766.

# Both produce the same DateTime format string
[System.Management.Automation.LanguagePrimitives]::ConvertTo(
    (Get-Date).AddDays(-3),
    [string])

(Get-Date).AddDays(-3).ToString([cultureinfo]::InvariantCulture)

Type casting is actually handled by PSConvertBinder and they're also using InvariantCulture there: Binders.cs#L3765-L3795. ScriptBlockDisassembler Module makes it really easy to understand what internal classes are being used:

PS ..\pwsh> { [string] [datetime]::Now } | Get-ScriptBlockDisassembly -Minimal

// ScriptBlock.EndBlock
try
{
    funcContext._outputPipe.Add(
        Fake.Dynamic<Func<CallSite, DateTime, string>>(PSConvertBinder.Get(typeof(string)))(DateTime.Now));
}
catch (FlowControlException)
{
    throw;
}
catch (Exception exception)
{
    ExceptionHandlingOps.CheckActionPreference(funcContext, exception);
}