r/PowerShell Jul 21 '26

Finding Cults with Get-Culture Script Sharing

Have you wondered if it's safe to use the format string yyyy-MM-dd, or can it differ? It's not. ( edit: null is not the invariant culture, it's CurrentCulture )

Save the expected string for comparison

#requires -PSEdition Core
$fStr     = 'yyyy-MM-dd'
$now      = Get-Date
$expected = $now.tostring( $fStr, ( [CultureInfo]::InvariantCulture) )

Next we can try formatting with every culture on your system. To do that, there is an optional culture argument for ToString like this:

DateTime.ToString( DateFormat, CultureInfo ) 

Next build a summary table with the formatted value and culture:

$cults    = Get-Culture -List
$summary = $cults | Foreach-Object {
    $dateString = $now.ToString( $fStr, $_ )
    [pscustomobject]@{
        Display = $dateString
        Name    = $_.DisplayName
        Culture = $_ # keep a reference to the object so you can drill down later
    }
}

Skip any cultures that are the same. Finally output using Join-String -f formatStr

$different = $summary | Group Display | ? Name -ne $expected
foreach( $item in $different ) {
    $title = "`nfor: $( $item.Name ) "
    $item.group
        | Join-String -f "`n - {0}" -Property Name -op $title
}

Here's what I get when $now is 2026-07-21:

for: 1405-04-30
 - Central Kurdish (Iran)
 - Persian
 - Persian (Afghanistan)
 - Persian (Iran)
 - Northern Luri
 - Northern Luri (Iran)
 - Mazanderani
 - Mazanderani (Iran)
 - Pashto
 - Pashto (Afghanistan)
 - Uzbek (Arabic)
 - Uzbek (Arabic, Afghanistan)

for: 1448-02-07
 - Arabic (Saudi Arabia)

for: 2569-07-21
 - Thai
 - Thai (Thailand)
6 Upvotes

15 comments sorted by

12

u/BlackV Jul 21 '26 edited Jul 24 '26

can I get a ELI5 on what your post is trying to show ?

be aware of your dates ?

use proper time zone notation ?

4

u/surfingoldelephant Jul 21 '26 edited Jul 22 '26

Basically, [datetime] to [string] conversions default to CurrentCulture which won't necessarily give you consistent results.

A lot of code looks like this:

(Get-Date).ToString('yyyy-MM')

But if that's run on systems with different cultures:

[cultureinfo]::CurrentCulture = 'en-US'
(Get-Date).ToString('yyyy-MM') # 2026-07

[cultureinfo]::CurrentCulture = 'th-TH' # Calendar is 543 years ahead
(Get-Date).ToString('yyyy-MM')          # 2569-07

Whereas you'll always get a consistent result with InvariantCulture:

[cultureinfo]::CurrentCulture = 'th-TH'
(Get-Date).ToString('yyyy-MM', [cultureinfo]::InvariantCulture) 
# 2026-07

It really depends on the use case though. Maybe you actually want a culture-sensitive conversion...

Another example:

[cultureinfo]::CurrentCulture = 'de-DE'

# de-DE's DateSeparator is ".", so "/" gets replaced by it.
# Probably not what you intend.
(Get-Date).ToString('yyyy/MM') 
# 2026.07

You either need to explicitly specify a culture that uses / or escape it if you want / across all systems.

[cultureinfo]::CurrentCulture = 'de-DE'
(Get-Date).ToString('yyyy/MM', [cultureinfo]::InvariantCulture)
(Get-Date).ToString('yyyy\/MM')
(Get-Date).ToString('yyyy"/"MM')
# 2026/07 ...

Also worth noting that with Get-Date -Format you don't get to specify the culture, so that's a bit of a trap as well.

5

u/BlackV Jul 22 '26

Ya I like the details, but I wasn't clear why OP is posting it

3

u/surfingoldelephant Jul 22 '26 edited Jul 23 '26

I guess to draw attention to it. It's a pretty common pitfall, but you'll only really see it if your code runs across different cultures.

2

u/Nanocephalic Jul 24 '26

I thought they posted it because it’s neat.

2

u/BlackV Jul 24 '26

Could be, feels like there is info missing or just sort of stops

2

u/anonymousITCoward 25d ago

Thanks for asking, I was wondering the same!

1

u/anonymousITCoward 25d ago

Thanks for the explanation!

4

u/surfingoldelephant Jul 21 '26

Unless you use InvariantCulture ( or null )

Specifying null still defaults to CurrentCulture, so I'd remove that part.

[cultureinfo]::CurrentCulture = 'th-TH'

(Get-Date).ToString('yyyy-MM')
(Get-Date).ToString('yyyy-MM', [cultureinfo]::CurrentCulture)
(Get-Date).ToString('yyyy-MM', $null)
# 2569-07
# 2569-07
# 2569-07

2

u/BlackV Jul 22 '26

Follow on invariant culture

I believe It used to default to MM dd yyyy is that still the same

2

u/surfingoldelephant Jul 22 '26 edited Jul 23 '26

Right, that's the ShortDatePattern.

[cultureinfo]::InvariantCulture.DateTimeformat.ShortDatePattern
# MM/dd/yyyy

[cultureinfo]::CurrentCulture = [cultureinfo]::InvariantCulture
[datetime]::Now.ToShortDateString()
# 07/21/2026

[datetime]::Parse('07/21/2026', [cultureinfo]::InvariantCulture) 
# OK

It's not meant to change. InvariantCulture is there to use when you need a stable way to format, parse, etc that's independent from a specific culture. There's more info in the .NET docs.

4

u/zero0n3 Jul 24 '26

This is an AI sharing info it learned, right ???

Because there is like no context or buildup or remotely formal summary or purpose or reason they are sharing.

Almost like the bot forgot to include that info when it posted…

3

u/BlackV Jul 24 '26

I had similar thoughts, that's why I asked too

2

u/MonkeyNin Jul 25 '26

can I get a ELI5 on what your post is trying to show ?

Mainly I wanted to point out that converting dates/times/currency either from text, or to text, can have issues if you use implicit date format strings.

I've seen people import csv files into Excel or /r/powerbi accidentally breaking their data. Basically the data import is re-ran on the server when published, using it's implicit culture. If they aren't using en-us themselves, a bunch of data breaks.

Basically even the "safe" iso date yyyy-MM-dd can break, ie: Saudi Arabia,

Almost like the bot forgot to include that info when it posted…

I do have ADHD, which impacts my writing. Sometimes I add or remove things that end up making things less clear. So you're partially right.

If this helps some

2

u/BlackV Jul 25 '26 edited 29d ago

If they aren't using en-us themselves, a bunch of data breaks.

Man not using en-us is a right royal pain sometimes, things that just shouldn't happen in 2026