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?
.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 , which by the looks of it, they decided to use LanguagePrimitives.ConvertTo
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);
}