Date conversion issue in pipeline

96 views Asked by At

I encountered a bizarre issue with date conversion. Everything is working as expected in my local PowerShell, but something goes wrong when the same code is running in a pipeline. The goal is to capture the date from the title and convert it to a different format.

I have a title like:

$title = "Update 11-02-2024"

I am extracting the date from the title:

$date = ([regex]::Matches($title, '(\d{2}-\d{2}-\d{4})')).Value

Converting the old date to a new format:

$newDate = Get-Date $date -UFormat "%B %d, %Y"

The new date is:

February 11, 2024

This is the right format for me, looks like it is working. When the code is running via the pipeline the result is:

Update November 02, 2024

This is what the pipeline runs:

if ($itemTitle -match 'Update') {
                $date = ([regex]::Matches($itemTitle, '(\d{2}-\d{2}-\d{4})')).Value
                $newDate = Get-Date $date -UFormat "%B %d, %Y"
                $newTitle = $itemTitle.Replace($Matches[0],"Dictionaries Update").Replace($date,$newDate)
                Write-host "The new title is: $newTitle"
            }

The pipeline runs a task that runs the script with the same code. What am I missing?

2

There are 2 answers

6
Mathias R. Jessen On BEST ANSWER

This difference in parsing behavior likely occurs because the pipeline is being executed on a runner machine with en-US default locale, so the default date format is MM-dd-yyyy.

Use [datetime]::ParseExact to always use a specific format when parsing dates:

$newDate = [datetime]::ParseExact($date, 'dd-MM-yyyy', $null) |Get-Date -UFormat "%B %d, %Y"
2
mklement0 On

Mathias' helpful answer explains your problem and shows how to parse a fixed date format.

If you want to parse the date based on the culture currently in effect (as reported by Get-Culture, for instance), simply use the single-argument [dateTime]::Parse() overload.

That is, if <date> in your "Update <date>" input string was created based on the current culture, say with "Update " + (Get-Date -Format d),[1] you can parse and reformat it as follows:

[datetime]::Parse(
  (-split $title)[-1]
).ToString('MMMM dd, yyyy')

Or, if you prefer to format the resulting date via Get-Date -UFormat, preferring Unix-style formatting over .NET's custom date and time format strings (which you can pass to -Format):

# Alternatively: ... -Format 'MMMM dd, yyyy' 
Get-Date ([datetime]::Parse((-split $title)[-1])) -UFormat '%B %d, %Y'

Note:

  • (-split $title)[-1] extracts the last (-1) whitespace-separated token from your string, assumed to be the date string.

  • In cases where you do have to specify the format explicitly, using [datetime]::ParseExact(), pass $null to the 3rd parameter (provider) to request current-culture parsing, and [cultureinfo]::InvariantCulture for culture-invariant parsing;[2] e.g.:

     # Parse based on the current culture.
     # Works in the US-English culture (en-US)
     # but not in the UK-English one (en-GB), for instance.
     [datetime]::ParseExact('November 02', 'M', $null)
    
     # Parse based on the invariant culture.
     # Always works, irrespective of what culture is in effect.
     [datetime]::ParseExact('November 02', 'M', [cultureinfo]::InvariantCulture)
    
  • As an aside:

    • In contrast with a single-argument [datetime]::Parse() call, using a [datetime] PowerShell cast would perform culture-invariant parsing, in which case a US-style month-first date is assumed; e.g. [datetime] '11-02-2024' becomes 2 November 2024.
      In fact, such a cast is translated into the following call behind the scenes:

      # Equivalent of:
      #      [datetime] '11-02-2024'
      [datetime]::Parse('11-02-2024', [cultureinfo]::InvariantCulture)
      
    • For cross-culture scripting, PowerShell uses the invariant culture (which is based on, but distinct from the US-English culture) in many contexts - see this answer for background information.


[1] However, note that "Update $(Get-Date -Format d)", i.e. using PowerShell's string interpolation would result in a culture-invariant representation. See the last bullet point in this answer for background information.

[2] To request the rules of a specific culture (other than the current one), cast its name to [cultureinfo]; the following examples use fr-FR, the French culture as used in France:
[datetime]::ParseExact('1 novembre', 'M', [cultureinfo] 'fr-FR'). For a list of all available cultures, use Get-Culture -ListAvailable in PowerShell (Core) 7+, and [cultureinfo]::GetCultures('SpecificCultures') in Windows PowerShell.