I am using PowerShell to try and convert a string to a datetime. It should be easy, right?
I am getting the string from a CSV import, and it comes in the format of Jul-16. I have tried multiple ways of getting it into the format I want which is yyyy-MM-dd and I am currently at the following.
$invoice = $object.'Invoice Month'
$invoice = "01-" + $invoice
$invoice = [datetime]::parseexact($invoice, 'yyyy-MM-dd', $null)
But I get the error:
String was not recognized as a valid DateTime.
Am I missing something?
ParseExact is told the format of the date it is expected to parse, not the format you wish to get out.
$invoice = '01-Jul-16'
[datetime]::parseexact($invoice, 'dd-MMM-yy', $null)
If you then wish to output a date string:
[datetime]::parseexact($invoice, 'dd-MMM-yy', $null).ToString('yyyy-MM-dd')
You can simply cast strings to DateTime:
[DateTime]"2020-7-16"
or
[DateTime]"Jul-16"
or
$myDate = [DateTime]"Jul-16";
And you can format the resulting DateTime variable by doing something like this:
'{0:yyyy-MM-dd}' -f [DateTime]'Jul-16'
or
([DateTime]"Jul-16").ToString('yyyy-MM-dd')
or
$myDate = [DateTime]"Jul-16";
'{0:yyyy-MM-dd}' -f $myDate
You need to specify the format it already has, in order to parse it:
$InvoiceDate = [datetime]::ParseExact($invoice, "dd-MMM-yy", $null)
Now you can output it in the format you need:
$InvoiceDate.ToString('yyyy-MM-dd')
or
'{0:yyyy-MM-dd}' -f $InvoiceDate
Chris Dents' answer has already covered the OPs' question but seeing as this was the top search on google for PowerShell format string as date I thought I'd give a different string example.
If like me, you get the time string like this 20190720170000.000000+000
An important thing to note is you need to use ToUniversalTime() when using [System.Management.ManagementDateTimeConverter] otherwise you get offset times against your input.
PS Code
cls
Write-Host "This example is for the 24hr clock with HH"
Write-Host "ToUniversalTime() must be used when using [System.Management.ManagementDateTimeConverter]"
$my_date_24hr_time = "20190720170000.000000+000"
$date_format = "yyyy-MM-dd HH:mm"
[System.Management.ManagementDateTimeConverter]::ToDateTime($my_date_24hr_time).ToUniversalTime();
[System.Management.ManagementDateTimeConverter]::ToDateTime($my_date_24hr_time).ToUniversalTime().ToSTring($date_format)
[datetime]::ParseExact($my_date_24hr_time,"yyyyMMddHHmmss.000000+000",$null).ToSTring($date_format)
Write-Host
Write-Host "-----------------------------"
Write-Host
Write-Host "This example is for the am pm clock with hh"
Write-Host "Again, ToUniversalTime() must be used when using [System.Management.ManagementDateTimeConverter]"
Write-Host
$my_date_ampm_time = "20190720110000.000000+000"
[System.Management.ManagementDateTimeConverter]::ToDateTime($my_date_ampm_time).ToUniversalTime();
[System.Management.ManagementDateTimeConverter]::ToDateTime($my_date_ampm_time).ToUniversalTime().ToSTring($date_format)
[datetime]::ParseExact($my_date_ampm_time,"yyyyMMddhhmmss.000000+000",$null).ToSTring($date_format)
Output
This example is for the 24hr clock with HH
ToUniversalTime() must be used when using [System.Management.ManagementDateTimeConverter]
20 July 2019 17:00:00
2019-07-20 17:00
2019-07-20 17:00
-----------------------------
This example is for the am pm clock with hh
Again, ToUniversalTime() must be used when using [System.Management.ManagementDateTimeConverter]
20 July 2019 11:00:00
2019-07-20 11:00
2019-07-20 11:00
MS doc on [Management.ManagementDateTimeConverter]:
https://learn.microsoft.com/en-us/dotnet/api/system.management.managementdatetimeconverter?view=dotnet-plat-ext-3.1
$invoice = "Jul-16"
[datetime]$newInvoice = "01-" + $invoice
$newInvoice.ToString("yyyy-MM-dd")
There you go, use a type accelerator, but also into a new var, if you want to use it elsewhere, use it like so: $newInvoice.ToString("yyyy-MM-dd")as $newInvoice will always be in the datetime format, unless you cast it as a string afterwards, but will lose the ability to perform datetime functions - adding days etc...
Hope below helps!
PS C:\Users\aameer>$invoice = $object.'Invoice Month'
$invoice = "01-" + $invoice
[datetime]$Format_date =$invoice
Now type is converted. You can use method or can access any property.
Example :$Format_date.AddDays(5)
It's very easy; in my case it works with;
Input:
$Date = '29-07-2022'
DateFormat Convertion:
[datetime]::parseexact($date, 'dd-MM-yyyy', $null).ToString('dd-MMMM-yyyy')
Output:
I had a different but related need to convert a number (seconds) into days/hours/seconds etc.
$seconds = 41414141
New-Timespan -seconds $seconds
Related
I have written a PowerShell script to extract the date from filenames and delete based on that.
Sample file name: TBTT_UAT_01012021_000019.csv
Code to extract date :
$fileDateText = ($filename -split '_')[4]
$fileDate = [System.DateTime]::ParseExact($fileDateText, "dd/MM/yyyy", [System.Globalization.CultureInfo]::InvariantCulture)
But I am getting the following error when I run the script, as it recognizes the date before CSV:
String '000019.csv' was not recognized as a valid DateTime.: FormatException
Can someone advise, please?
Thanks,
I think you may be looking at the wrong array element returning from your split. Also the string you are giving in the overloads for .ParseExact() may be off. This seemed to work in my tests:
$fileDate = ("TBTT_UAT_01012021_000019.csv" -split '_')[2]
[DateTime]::ParseExact($fileDate, "ddMMyyyy", [System.Globalization.CultureInfo]::InvariantCulture)
Returned: Friday, January 1, 2021 12:00:00 AM
If you want to get more granular about the time we'll have to cut up the string file name differently.
Issue has been fixed by changing from:
[System.DateTime]::ParseExact($fileDateText, "dd/MM/yyyy", [System.Globalization.CultureInfo]::InvariantCulture)
to
$fileDate = [DateTime]::ParseExact("$fileDateText", 'ddMMyyyy',[CultureInfo]::InvariantCulture)
if ($filename -match '(?<Timestamp>\d{8})') {
[DateTime]::ParseExact($Matches.Timestamp, 'ddMMyyyy', [CultureInfo]::InvariantCulture)
}
I gravitate toward regexes with named extraction groups rather than doing string manipulation. The syntax is a bit more fiddly, but the resulting script ends up being more resilient.
I have a date string in what I think is ISO8601 format (although I'm not 100% sure), e.g.
20200210T165905+0000
I want to parse this using powershell and have tried the following
$Date = "20200210T165905+0000"
$DatePattern = "yyyyMMdd\THHmmss\+zzzz"
$DateTime = [DateTime]::ParseExact($Date, $DatePattern, $null)
But I get the following error
Exception calling "ParseExact" with "3" argument(s): "String was not recognized as a valid DateTime."
What am I doing wrong?
The Dateformat you have requires a different pattern where the Time zone information is handled by K.
+0000 means that the date is in UTC time (offset 0). If you remove that, the date string is parsed as if it is a LOCAL DateTime, giving you false information (unless you live in a part of the world where UTC is the same as the local time)
$Date = "20200210T165905+0000"
$DatePattern = "yyyyMMddTHHmmssK"
$DateTime = [DateTime]::ParseExact($Date, $DatePattern, $null)
$DateTime
Returns (in my NL Locale => UTC + 1)
10-2-2020 17:59:05
Removing the \+ escaped character from the pattern seems to fix it for me, i.e.,
$DatePattern = "yyyyMMdd\THHmmsszzzz"
The locale of my machine is UK (en-gb). When I do the following (to check expiration date of an SSL cert) the DateTime object stores the value in UK format
$expiration = Get-Date $req.ServicePoint.Certificate.GetExpirationDateString()
See here what happens firstly if you just have the value printed to the command prompt, and secondly what happens if you try to embed that DateTime object value within a string.
PS>$expiration
19 December 2016 23:59:59
PS>write-host "this is the expiration: $expiration"
this is the expiration: 12/19/2016 23:59:59
So we see that it has switched to non UK format (should be 19/12/2016). Why is this, and is there a simple workaround?
It's a string expansion problem and a bit of a pain I'm afraid. You know this one to display incorrectly:
"$(Get-Date 01/02/2016)"
These however, display as you'd expect:
(Get-Date 01/02/2016).ToString()
"$((Get-Date 01/02/2016).ToString())"
Both of these approaches work to work around the problem:
$expiration = Get-Date 01/02/2016
write-host "this is the expiration: $($expiration.ToString())"
write-host ("this is the expiration: {0}" -f $expiration)
You see similar ignorance of the time zone when casting to DateTime:
[DateTime]$var = "01/02/2016"
$var
Chris
You could use a simple string format option
MSDN article:
https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx
$expirationString = "{0:F}" -f $expiration
and then
Write-Host "this is the expiration: $expirationString"
If this also provides the wrong output, you could make a custom format string, like this:
"{0:dd MMMM yyyy hh:mm:ss}"
I've tried a lot of different ways and I can't seem to get it right.
Here is the code of what I have tried so far...
[String]$dateValue = '20161212'
[String]$dateStamp = $dateValue -f (Get-Date)
[String]$dateStamp2 = ([datetime]::parseexact($dateValue, "yyyyMMdd", [System.Globalization.CultureInfo]::InvariantCulture)).Date
[String]$dateStamp3 = ([datetime]::FromFileTime($dateValue)).ToString('g')
Write-Host '$dateStamp = ' $dateStamp
Write-Host '$dateStamp2 = ' $dateStamp2
Write-Host '$dateStamp3 = ' $dateStamp3
Current Code Output
$dateStamp = 20161212
$dateStamp2 = 12/12/2016 00:00:00
$dateStamp3 = 12/31/1600 5:00 PM
Desired Code Output
$dateStamp = 12/12/2016
Any Ideas?
Once you have a datetime object it's easy to convert it to whatever string format you need. You are so close with your second attempt. Adding ToString allows you to specify a string format.
([datetime]::parseexact($dateValue, "yyyyMMdd", [System.Globalization.CultureInfo]::InvariantCulture)).ToString("dd/MM/yyyy")
Given that you have a culture-invariant string as your input and that you want a fixed output format, you may as well perform string parsing, without the need to convert to an intermediate [datetime] instance:
> '20161213' -replace '\d{2}(\d{2})(\d{2})(\d{2})', '$2/$3/$1'
12/13/16
Note that I've changed the day to be different from the month to better highlight the reformatting that takes place.
Generally, though, the [datetime]-based method demonstrated in Nick's helpful answer gives you the most flexibility.
In PowerShell V2, I want to calculate the total seconds and milliseconds of a given string.
My string is 00:03:56,908 and the desired output would be 236.908
My working, but awkward code is
$a = "00:03:56,908"
$a = [datetime]::ParseExact($a,"HH:mm:ss,fff",$null)
[string]($a.Hour*3600 + $a.Minute*60 + $a.Second) +"."+ [string]$a.Millisecond
Is there a smarter / shorter way to achieve this?
All I found was .totalseconds from a TimeSpan object. But this code was even longer in my attempt
The problem with the TimeSpan class in .NET versions earlier than 4.0 is that it's not handling different cultures or formatting strings very well. Given that your string has a comma instead of a period, we'll have to change that if we want to parse it to a timespan, but I think that's still the best way to go at it.
$timeString = "00:03:56,908"
$timeStringWithPeriod = $timeString.Replace(",",".")
$timespan = [TimeSpan]::Parse($timestringWithPeriod)
$totalSeconds = $timespan.TotalSeconds
I wouldn't shy away from TotalSeconds, it can be useful in this circumstance... and reasonably short, if you just extract that property:
PS C:\> $a = "00:03:56,908"
PS C:\> $a = [datetime]::ParseExact($a,"HH:mm:ss,fff",$null)
PS C:\> (New-TimeSpan -Start (Get-Date).Date -End $a).TotalSeconds
236.908
Putting New-TimeSpan in parenthesis allows us to evaluate that statement first, and then to extract TotalSeconds afterwards. Using (Get-Date).Date is important because it defines midnight, and since you converted $a to a DateTime where the date is today, we need to use midnight today as our Start time.