0

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
  • It appears that the PowerShell team is a bit en-us oriented. Being ISO-8601 oriented might be better. Commented Jun 13, 2023 at 17:53

1 Answer 1

1

.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);
}
Sign up to request clarification or add additional context in comments.

3 Comments

It might be helpful it the datetime format in [cultureinfo]::InvariantCulture was ISO-8601.
Nicely done; I assume that Get-ScriptBlockDisassembly is from the third-party ScriptBlockDisassembler module. @lit, to get ISO 8601 format, you can use (Get-Date).ToString('o') for instance, and this format is also recognized by the invariant culture, and therefore in casts; e.g. [datetime] (Get-Date).ToString('o')
@lit, for a (hopefully) comprehensive overview of when string operations in PowerShell are culture-sensitive and when not, see this answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.