Using Windows PowerShell to Work with Dates


Hey, Scripting Guy! Question

Hey, Scripting Guy! I need to be able to use Windows PowerShell to work with dates. Dates have always been a difficult thing to work with, and I just dread scripting anything that has to do with dates. It seemed that VBScript had a dozen functions that were used to work with dates and times. Is there something similar for Windows PowerShell?

— GS


Hey, Scripting Guy! Answer

Hello GS,

Microsoft Scripting Guy Ed Wilson here. I have never had too much problems with dates. Basically, I just pop them in my mouth whole like candy. The best dates I ever had were in Egypt. Oh, wait a minute, you don’t mean those kinds of dates. Sorry. In the old days, databases used to have three fields for the date. One for day, one for month and one for year. You may have heard about the Y2K bug? That was because the field for year was only big enough for the last two numbers of the year … and therefore the year 2000 would be represented as 00. This is a serious problem if you are dealing with medical records and the person is born in 5/4/00. You do not know whether to send the person to geriatrics or to pediatrics.

When working on one of those old systems, you had to build up the date by reading three different fields. If I were going to do a similar thing in Windows PowerShell, it might look like this:

PS C:> $dd = “05”
PS C:> $mm = “09”
PS C:> $yy = “10”
PS C:> “$dd/$mm/$yy”
PS C:>

One of the great things about Windows PowerShell is that it is object oriented. Everything in Windows PowerShell is an object, even the string I just built up…whoops, I spoiled the surprise. Let’s pretend I did not spoil the surprise (I like spoiling my supper too by eating desert first, but that is a different story—although it could have something to do with dates). The following code is really ugly, but it works because of the “object-ness” of Windows PowerShell. To find out what kind of object you are working with, you can use the GetType method as shown here:

PS C:> “$dd/$mm/$yy”.GetType()

IsPublic IsSerial Name                                     BaseType
——– ——– —-                                     ——–
True     True     String                                   System.Object

PS C:>

I said the previous code was ugly, but that is only because it looks strange. In general, I would use a set of parentheses before calling a method like GetType:

PS C:> (“$dd/$mm/$yy”).GetType()

IsPublic IsSerial Name                                     BaseType
——– ——– —-                                     ——–
True     True     String                                   System.Object

PS C:>

Actually using the parentheses is a good idea, because at times you can get yourself into trouble. This is shown here, where I attempt to get the type of the number 1:

PS C:> 1.GetType()
Bad numeric constant: 1..
At line:1 char:3
+ 1. <<<< GetType()
+ CategoryInfo : ParserError: (1.:String) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : BadNumericConstant
PS C:>

The problem is not because the number is not an object and does not have a type. The problem is that Windows PowerShell is not sure what to do. The parentheses help in that regard. Just as in high school algebra, the parentheses tells Windows PowerShell to perform the operation inside before looking outside the parentheses. As shown here, the number 1 is in fact an object:

PS C:> (1).GetType()

IsPublic IsSerial Name                                     BaseType
——– ——– —-                                     ——–
True     True     Int32                                    System.ValueType

PS C:>

Windows PowerShell treats the number 1 as an int32. It is actually smaller than that, and you can specifically cast it to an int16. This is shown here:

PS C:> [int16]1 | gm

   TypeName: System.Int16

Name        MemberType Definition
—-        ———- ———-
CompareTo   Method     int CompareTo(System.Object value), int CompareTo(System.Int16 value)
Equals      Method     bool Equals(System.Int16 obj), bool Equals(System.Object obj)
GetHashCode Method     int GetHashCode()
GetType     Method     type GetType()
GetTypeCode Method     System.TypeCode GetTypeCode()
ToString    Method     string ToString(System.IFormatProvider provider), string ToString(string …

Casting? What is that? Windows PowerShell has a dynamic type system, and I can convert one data type to another data type on the fly. By default, Windows PowerShell treats all numbers as int32. As seen earlier, I can constrain the type, force the type, or cast the type (whatever jargon you wish to use) to make my int32 into an int16. Cool? Ok, perhaps it depends on your geek factor. Let’s get back to the problem at hand: dates. We have just seen that we had a string when we put the numbers together. Remember this?

PS C:> “$dd/$mm/$yy”
PS C:> “$dd/$mm/$yy”.GetType()

IsPublic IsSerial Name                                     BaseType
——– ——– —-                                     ——–
True     True     String                                   System.Object

PS C:>

One of the really cool things about objects is they have methods and properties. The problem is that our date is a string. Dates are awesome in cakes and in cookies, but not if they are strings. The members of a system.string class are suboptimal for dealing with dates. This is shown in the following image.

Image of members of system.string class

While it is true that I could do string manipulation to parse the date, it would be better if we had a datetime object to work with. To do this, we can cast the string to a system.datetime .NET Framework object. We can then use the GetType method to ensure the conversion has taken place; although this last step is basically redundant because the results of the cast are immediately observable. Remember me saying that using the “ugly code” could get you into trouble? This is shown here, where an error is thrown. The fix is to use the parentheses:

PS C:> [datetime]”$dd/$mm/$yy”

Sunday, May 09, 2010 12:00:00 AM

PS C:> [datetime]”$dd/$mm/$yy”.GetType()
Cannot convert the “System.String” value of type “System.RuntimeType” to type “System.DateTime”.
At line:1 char:32
+ [datetime]”$dd/$mm/$yy”.GetType <<<< ()
    + CategoryInfo          : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

PS C:> ([datetime]”$dd/$mm/$yy”).GetType()

IsPublic IsSerial Name                                     BaseType
——– ——– —-                                     ——–
True     True     DateTime                                 System.ValueType

PS C:>

In addition to gaining a nicer display of the date, the conversion from string to date has provided a number of useful members. Using the Get-Member cmdlet displays the methods and properties that are supplied by the system.datetime .NET Framework class:

PS C:> [datetime]”$dd/$mm/$yy” | Get-Member

   TypeName: System.DateTime

Name                 MemberType     Definition
—-                 ———-     ———-
Add                  Method         System.DateTime Add(System.TimeSpan value)
AddDays              Method         System.DateTime AddDays(double value)
AddHours             Method         System.DateTime AddHours(double value)
AddMilliseconds      Method         System.DateTime AddMilliseconds(double value)
AddMinutes           Method         System.DateTime AddMinutes(double value)
AddMonths            Method         System.DateTime AddMonths(int months)
AddSeconds           Method         System.DateTime AddSeconds(double value)
AddTicks             Method         System.DateTime AddTicks(long value)
AddYears             Method         System.DateTime AddYears(int value)
CompareTo            Method         int CompareTo(System.Object value), int CompareTo(System.Dat…
Equals               Method         bool Equals(System.Object value), bool Equals(System.DateTim…
GetDateTimeFormats   Method         string[] GetDateTimeFormats(), string[] GetDateTimeFormats(S…
GetHashCode          Method         int GetHashCode()
GetType              Method         type GetType()
GetTypeCode          Method         System.TypeCode GetTypeCode()
IsDaylightSavingTime Method         bool IsDaylightSavingTime()
Subtract             Method         System.TimeSpan Subtract(System.DateTime value), System.Date…
ToBinary             Method         long ToBinary()
ToFileTime           Method         long ToFileTime()
ToFileTimeUtc        Method         long ToFileTimeUtc()
ToLocalTime          Method         System.DateTime ToLocalTime()
ToLongDateString     Method         string ToLongDateString()
ToLongTimeString     Method         string ToLongTimeString()
ToOADate             Method         double ToOADate()
ToShortDateString    Method         string ToShortDateString()
ToShortTimeString    Method         string ToShortTimeString()
ToString             Method         string ToString(), string ToString(string format), string To…
ToUniversalTime      Method         System.DateTime ToUniversalTime()
Date                 Property       System.DateTime Date {get;}
Day                  Property       System.Int32 Day {get;}
DayOfWeek            Property       System.DayOfWeek DayOfWeek {get;}
DayOfYear            Property       System.Int32 DayOfYear {get;}
Hour                 Property       System.Int32 Hour {get;}
Kind                 Property       System.DateTimeKind Kind {get;}
Millisecond          Property       System.Int32 Millisecond {get;}
Minute               Property       System.Int32 Minute {get;}
Month                Property       System.Int32 Month {get;}
Second               Property       System.Int32 Second {get;}
Ticks                Property       System.Int64 Ticks {get;}
TimeOfDay            Property       System.TimeSpan TimeOfDay {get;}
Year                 Property       System.Int32 Year {get;}
DateTime             ScriptProperty System.Object DateTime {get=if ((& { Set-StrictMode -Version…

PS C:>


GS, it is obvious that you are not the only one who thought working with dates was annoying. The large collection of methods and properties exposed by the datetime class can help to smooth out the difficulty of working with dates. The benefits are immediately available, and most are extremely easy to use. For example, what was the day of the week for our date that we created?

PS C:> ([datetime]“$dd/$mm/$yy”).dayOfWeek
PS C:>

What was the day of the year? 

PS C:> ([datetime]“$dd/$mm/$yy”).dayOfyear
PS C:>

What about if I need to add 45 days to my original date? It is no problem using the addDays method:

PS C:> ([datetime]“$dd/$mm/$yy”).addDays(45)

Comments (10)

  1. Anonymous says:

    This is the command I used when converting an ADUser LastLogonTimeStamp into normal date format.

    [datetime]::FromFileTime((Get-ADUser $UserID -Properties *).LastLogonTimeStamp)

  2. SJL says:

    Hey guys, that's cool. But a quick question, what if my string was in "mm/dd/yy" format? How can I let PowerShell know that the string is in that format so it can cast it correctly?

  3. Ed Wilson says:

    @sjl you can use the -uformat parameter to control the way PowerShell displays the date. Here is an example:

    PS C:> Get-Date -UFormat %m/%d/%y


  4. Dan_IT says:

    The date is 5th September format is day/month/year, yet when you use datetime it says date is 9th May. How do you keep the non USA date format?

  5. JV says:




  6. JV says:


  7. BPK says:

    Warning everyone!!! [DateTime] casting in Powershell ALWAYS assumes MDY format irrespective of your culture. If you observe well in Ed’s example above, his $dd variable with value of 05 is not interpreted as he intended as the day but rather as the month
    (May) while his $mm variable value for month was interpreted as the day. If the value for the $dd variable had been 13 or greater the cast would have thrown an error of invalid date. I had a tough time with this for a long time before I found out that it is
    deliberate design feature by the Powershell Team. The pain however is that the behaviour is not explicitly documented officially anywhere.

    So persons like me who write dates in DMY format and have my culture date format set that way erroneously assume that Powershell will interpret the date string cast according to my culture. You never get to find out that your dates are bugged as long as Powershell
    never throws an error for as long as the day value never exceeds 12. So your operations on dates succeed but they are returning wrong results without your knowing. For instance, I had written a script that was comparing dates to get the difference in the number
    of days if they are up to a particular number of 5 and then execute some commands. for example, 12/05/2015 – 09/05/2015, according to my culture should just be 3 days but alas Powershell gets 91 days and my commands execute when they are not intended to

    Please take note.

  8. BPK says:

    As an advice to persons using DMY date format, to ensure Powershell always interprets your date literals correctly, always pass your month value as name word rather than numbers. The full month name – January, February, March, etc., or their 3-letter abbreviations
    – Jan, Feb, Mar, etc will never fail.

    [DateTime]"12 Feb, 2015"
    [DateTime]"12 February 2015"
    All the above will all always be interpreted correctly even though MDY format is always assumed by Powershell.

    And where [DateTime]"22/05/2015" will throw an error of invalid datetime, [DateTime]"22/May/2015" will succeed

  9. MercyBrew says:

    Someone just unintentionally brought an internationalization issue to my attention with my adviced workaround above. My workaround only works if the month name is specified in English. This is because the [DateTime] type accelerator uses the Invariant
    Culture to interpret date literals. The Invariant culture unfortunately only recognizes month names in English.

    While I have not personally confirmed it, I am 100% certain that the following will fail in Powershell

    [DateTime]"12/Mrz/2015" (German)
    [DateTime]"12/Mars/2015" (French)

    Even if the culture of the system is German or French as applicable, simply because the month names will not be recognized by the Invariant Culture which is the culture the [DateTime] type accelerator is bound to for casting date strings


  10. Trdr says:

    Just use YMD format like "2015-12-31" where possible no matter what your local settings are.
    Seems this works fine in all MS products.

Skip to main content