Use PowerShell to Convert Date Formats Easily

Use PowerShell to Convert Date Formats Easily

  • Comments 8
  • Likes

Summary: Microsoft Scripting Guy Ed Wilson discusses four different techniques for using Windows PowerShell to convert date formats.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I have a problem. Although I am sure you hear this a lot, this problem is causing me a major problem at work. Here is the deal. We are a large company and we have operations both in the United States and in Germany. The problem is that in the United States, as you are well aware, we write the date like this: 8/24/11. Or we write it like this: 8/24/2011. We always list the month, then the day, and then the year. In Germany, however, they seem to write it day, then month, and then year. They also use a period for the separator instead of the forward slash. Therefore, my German colleagues would write today’s date as 24.8.11 or 24.8.2011.

This is causing major confusion in our office, and I do not think it is fair to just tell our German colleagues to write the date the way we do in the United States. I need a Windows PowerShell script that will translate the date from the way we write it in the United States to the way they write the date in Germany. Please help—this is driving me crazy!

—SL

 

Hey, Scripting Guy! AnswerHello SL,

Microsoft Scripting Guy Ed Wilson here. Writing a date as day.month.year is not just a German thing. In fact, many countries write the date in that format. In fact, day.month.year is a very good way to write dates (and is used by the military) because, while it may be possible that I might not remember what day it is, I nearly always remember what month it is.

SL, you specifically asked for a script that could convert a month/day/year formatted string to a day.month.year formatted string. In the first case, the separator is a forward slash, and in the second case, the separator is a period. Here is such a script, ConvertMonthDayYearToDayMonthYear.ps1:

$usdate = "8/24/11"

$dateParts = $usdate -split "/"

$deDate = "$($dateparts[1]).$($dateParts[0]).$($dateParts[2])"

$deDate

In the ConvertMonthDayYearToDayMonthYear.ps1 script, the first thing I do is assign a month/day/year string to a variable named $usdate, as shown here:

$usdate = "8/24/11"

Next, I use the split operator to split the string into three parts (it creates an array with three elements in it). The obvious place to split the string is at the forward slash character. The cool thing about the split operator is that it does not include the character that is split upon in the parts that are created. The syntax of the split operator is really simple, I use it after the string that I want to split, and I specify the character to split upon. After I use the split operator to break the string into three parts, I store the parts (an array) in the $dateParts variable. Here is the line of code that uses the split operator to create the array from the string:

$dateParts = $usdate -split "/"

Now that I have the three parts of the date from the string stored in a variable named $dateParts, I can reassemble them into the format that is required by your German colleagues. To do this, I use square brackets to indicate which portion I want to retrieve. I then build up the string in the order and manner you specified. Because the parts are stored in an array, I can use array notation to retrieve specific elements of the array. To retrieve the month from the array, I would use a zero inside square brackets. All arrays begin with zero in Windows PowerShell, so the first element is zero. Here is the code that would retrieve the month (the first element of the array) from the parts stored in the $dateParts variable:

$dateParts[0]

To build the German date, I use an expanding string. An expanding string in Windows PowerShell is one that will expand to display the value contained inside a variable. Unfortunately, at times rather than just expand and reveal the value contained inside the object, it will unravel the object itself. When that happens, it is necessary to use a subexpression to force evaluation of the object first. After the object has been evaluated, it will return only the value that is referenced. A subexpression begins with a dollar sign, and then opens a pair of parentheses and ends by closing the parentheses. These subexpression characters are shown here:

$( )

A subexpression that will force the return of the value that is stored in element 1 that is contained in the array stored in the variable $dateparts is shown here:

$($dateparts[1])

After I use the subexpression to return the numbers stored in the various elements of the array, I place a period between each of the three elements. I then return the German formatted date to the $deDate variable, as shown here:

$deDate = "$($dateparts[1]).$($dateParts[0]).$($dateParts[2])"

Some people do not like using subexpressions, and therefore tend to avoid expanding strings. One way to avoid using subexpressions and expanding strings is to use literal strings and concatenation. For example, I have already shown that when addressing an element in an array, it returns the value that is contained inside that element, unless that technique occurs inside expanding strings. If I avoid the strings, and simply place the reference to the element number on a line, I get the value in the element. If I then concatenate (glue) the element reference with a period, and glue it to another element reference, another period, and another element reference, I get the date I wanted to create. The concatenation operator is the plus sign (+). Here is the portion of the script that creates the date string; one key point to remember is that concatenation is required on both sides of the period (+ '.' +).

$dateparts[1] + '.' + $dateParts[0] + '.' + $dateParts[2]

The remainder of the ConvertMonthDayYearToDayMonthYearUseLiteralString.ps1 script is the same as the previous code. The complete script is shown here:

$usdate = "8/24/11"

$dateParts = $usdate -split "/"

$deDate = $dateparts[1] + '.' + $dateParts[0] + '.' + $dateParts[2]

$deDate 

Personally, I hate concatenation (was abused with VBScript), so I will do anything to avoid concatenation—even use the format operator. In fact, in my second list of top ten Windows PowerShell tricks, it will probably figure rather high in the ranking. (For the first list of my favorite top ten Windows PowerShell tricks, see this collection of Hey, Scripting Guy! Blog posts). Anyway, I can build a string by using a string with symbols for substitution. The first position is 0, next is 1, and then 2. The curly brackets surround the element for which substitution will take place. I place the period between the curly brackets and then supply an array of elements that are used when creating the string. The f is the format operator. This sounds more complicated than it really is. Here is the code I use:

"{0}.{1}.{2}" -f $dateparts[1],$dateParts[0],$dateParts[2]

The remainder of the script is the same as the other ones in today’s article. The complete ConvertMonthDayYearToDayMonthYearUseFormatSpecifier.ps1 script is shown here:

# ConvertMonthDayYearToDayMonthYearUseFormatSpecifier.ps1

# hsg-8-24-11

$usdate = "8/24/11"

$dateParts = $usdate -split "/"

$deDate = "{0}.{1}.{2}" -f $dateparts[1],$dateParts[0],$dateParts[2]

$deDate

The script and associated output are shown in the following figure.

Image of script and associated output

SL, that is all there is to using string techniques to work with dates. Join me tomorrow when I will talk about using culture settings to convert dates.

 

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Somewhat more complicated, but I think I would have went for using the .Net DateTime and CultureInfo classes. Makes it easier to convert between any two cultures. So if SL's company opens an office in Japan, just passing in 'ja-JP' instead of 'de-DE' could easily get 2011/08/24. Plus you get some nice errors if the value passed in is not a date.

    $usDate = "8/24/11"

    $parsedDate = [System.DateTime]::Parse($usDate, [System.Globalization.CultureInfo]::GetCultureInfo("en-US"))

    $deDate = $parsedDate.ToString("d", [System.Globalization.CultureInfo]::GetCultureInfo("de-DE"))

    $deDate

  • What's wrong with good old legacy Get-Date?

    get-date 02/21/11 -f dd.M.yyy

    It is a great converter as long as you don't need to specify culture.  If you need culture then, as has been noted in another comment, use the NET class.

    Don't forget the accelerator - [datetime].  It is very handy.

    [datetime]::Parse('01/01/0001')

    [datetime]::Parse('01/01/0001',[System.Globalization.CultureInfo]::GetCultureInfo("en-US"))

  • Just another variation, if you don't care that the eventual output is a String.

    $Date.ToString("dd.M.yyy")

  • @JRV nothing wrong with Get-Date. BUT the scenario was that the date already existed as a string in a text file, and the formatting of that date had to be converted to another format. In this exact scenario, Get-Date would not work.

    @Harry Steinhilber - you "spoiled my suprise" tommorow I am talking about using the culture classes to more precisely convert date time values -- with the added advantage that it does not require lots of complicated changes from one culture to another.

    @Sgrinker - that is one of my favorite "tricks" when I do not care if the output is a string. It really is cool!

  • Since when can't Get-Date not convert strings in files into dates?

    $usdate = "8/24/11

    Get-Date $usdate -f dd.MM.yyy

    It works just like yours.

    It works this way too. See the dots..

    $usdate = "8.24.11"

    Get-Date $usdate -f dd.MM.yyy

    see the dashes.

    $usdate = "8-24-11"

    Get-Date $usdate -f dd.MM.yyy

    Get-Date is very smart. You can grep anything that even smells like a date in a file and it will convert it.

  • Life would be much easier if all countries standardized.  Metric system, dates, basically any unit of measurement. 2011-08-24 is easier to read and it also has the added benefit of being able to sort by date, especially if prepended to filenames.  It also follows the order of magnitude when including the time (e.g. 2011-08-24-1632) where the units get smaller as you move to the right.

    I guess that in the meantime it is Powershell to the rescue again.

  • Hi Ed,

    there are many ways to Rome ( where I want to go for a holiday sometime soon or later :-)

    I would have used the type cast and maybe add a call tho the ToShortDatetime() method:

    PS C:\Users\Schulte> ([DateTime]"08/24/2011").ToShortDateString()

    24.08.2011

    It works culture independently and results in a new datetime object that can be used directly or even converted to a string if necessary.

    Klaus

  • I made to mistakes in my earlier comment:

    1. "ToShortDatetime()" should be replaced by "ToShortDateString()"

    2. I should have read your next blog entry before commenting on this one :-(

    Klaus.