Manipulating Date Ranges with Windows PowerShell

Manipulating Date Ranges with Windows PowerShell

  • Comments 1
  • Likes

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! I need to be able to add and subtract dates so that I can use the results in custom queries for various Windows event logs using Windows PowerShell. Is doing this type of date manipulation easy or hard to do with Windows PowerShell? If it is not too difficult to do, could you whip up some examples of searching date ranges?

-- SH

Hey, Scripting Guy! Answer

Hello SH,

Microsoft Scripting Guy Ed Wilson here. One of the things I used to hate about writing VBScript code was working with dates. It is not that it was difficult, but it did seem a bit arcane. There must have been almost 20 different functions involved in date creation, parsing, and manipulation. Maybe not quite that many, but it seemed so. To make matters worse, I began to develop an aversion to parsing dates, and as a result I would do strange things to avoid parsing dates, which in turn made it more difficult (due to lack of familiarity) when I had to parse a date. So the vicious circle continued to wobble out of control until one day I forced myself to spend a day writing nothing but date manipulation code.

Luckily, date parsing and manipulation in Windows PowerShell is much easier. However, you won’t know it is easier until you sit down and spend some time working with the system.datetime .NET Framework object. Why, you may ask, do I refer to the system.datetime .NET Framework object when just a minute ago I was talking about dates? Because a date in Windows PowerShell is an instance of a datetime (you can leave the word “system” off if you wish) object. You can use the Get-Member cmdlet to see what type of object you are working with. The Get-Date cmdlet returns the current date and time. When the current date and time are piped to the Get-Member cmdlet, the members of a System.DateTime .NET Framework class are displayed. This is shown here:

PS C:\> Get-Date

Monday, August 02, 2010 10:38:36 AM


PS C:\> Get-Date | 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 Compa...
Equals               Method         bool Equals(System.Object value), bool Equals...
GetDateTimeFormats   Method         string[] GetDateTimeFormats(), string[] GetDa...
GetHashCode          Method         int GetHashCode()
GetType              Method         type GetType()
GetTypeCode          Method         System.TypeCode GetTypeCode()
IsDaylightSavingTime Method         bool IsDaylightSavingTime()
Subtract             Method         System.TimeSpan Subtract(System.DateTime valu...
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 for...
ToUniversalTime      Method         System.DateTime ToUniversalTime()
DisplayHint          NoteProperty   Microsoft.PowerShell.Commands.DisplayHintType...
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-Stri...


PS C:\>

The members, methods, and properties of the System.DateTime .NET Framework class that are displayed are instance methods and properties. This means that they work on an instance of the class. Normally, an instance of a class is created when one uses a constructor. Constructors are detailed on MSDN. For example, the constructor for the System.DateTime class indicates that you can use a number of different ways to create an instance of the class. One constructor will accept three integers for input. However, when I supply the month, day, and year, an error arises. A closer look at the constructor indicates that the constructor wants year, month, and day. When this is supplied, a new instance of a system.datetime object is created. Because no time value was supplied to the constructor, the time is set to midnight. Here the New-Object cmdlet is used to create an instance of a system.datetime object:

PS C:\> $dte = New-Object system.datetime(8,1,2010)
New-Object : Exception calling ".ctor" with "3" argument(s): "Year, Month, and Day p
arameters describe an unrepresentable DateTime."
At line:1 char:18
+ $dte = New-Object <<<< system.datetime(8,1,2010)
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationE
xception
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell
.Commands.NewObjectCommand
PS C:\> $dte = New-Object system.datetime(2010,8,1)
PS C:\> $dte
Sunday, August 01, 2010 12:00:00 AM
PS C:\>

Now and today are both static properties from the system.datetime .NET Framework class that return instances of the class. To call a static property, place the class name inside square brackets, use two colons, and then add the property name. To prove that it is a datetime object that is returned, use the gettype method that is always available from any system.object. This is shown here:

PS C:\> [datetime]::now

Monday, August 02, 2010 10:48:39 AM


PS C:\> ([datetime]::now).gettype()

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


PS C:\> [datetime]::today

Monday, August 02, 2010 12:00:00 AM


PS C:\> ([datetime]::today).gettype()

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


PS C:\>

Interestingly enough, the datetime object that is returned via the Get-Date cmdlet is the same object that is returned by the static now property from the datetime class. Use of one or the other is a matter of preference. I generally use the Get-Date cmdlet because it is easier to type. Each methodology is illustrated here:

PS C:\> [datetime]::now
Monday, August 02, 2010 10:51:32 AM
PS C:\> Get-Date
Monday, August 02, 2010 10:51:35 AM
PS C:\>

After you have a datetime object, you can use the methods that are exposed by that object. For example, you can easily use one of the various methods to add minutes, hours, days, months, years, etc., to the current date to create a new date in the future or in the past (if you pass a negative number):

PS C:\> $dte = Get-Date
PS C:\> $dte | Get-Member -MemberType method add*


   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)


PS C:\> $dte

Monday, August 02, 2010 10:58:58 AM


PS C:\> $dte.AddDays(1)

Tuesday, August 03, 2010 10:58:58 AM


PS C:\> $dte.AddDays(-1)

Sunday, August 01, 2010 10:58:58 AM


PS C:\> $dte.AddHours(8)

Monday, August 02, 2010 6:58:58 PM


PS C:\> $dte.AddHours(-8)

Monday, August 02, 2010 2:58:58 AM


PS C:\>

This can easily be incorporated with a cmdlet such as Get-EventLog. If I want to see event log entries from the application log that occurred in the last hour, I can use code that looks like this:

PS C:\> Get-EventLog -LogName application -After $dte.AddMinutes(-60)

   Index Time          EntryType   Source                 InstanceID Message
   ----- ----          ---------   ------                 ---------- -------
   19016 Aug 02 10:24  Information Office Software P...   1073742827 The Software...
   19015 Aug 02 10:24  Information Office Software P...   1073742827 The Software...
   19014 Aug 02 10:24  Information Office Software P...   1073742827 The Software...
   19013 Aug 02 10:24  0           Office Software P...   1073742726 The Software...
   19012 Aug 02 10:24  Information Office Software P...   1073742890 Initializati...
   19011 Aug 02 10:24  Information Office Software P...   1073742724 The Software...


PS C:\>

When working with two datetime objects, you can subtract them and a timespan object is returned. This is shown here:

PS C:\> $dte = Get-Date
PS C:\> $sDate = Get-Date
PS C:\> $sDate - $dte


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 8
Milliseconds      : 533
Ticks             : 85332000
TotalDays         : 9.87638888888889E-05
TotalHours        : 0.00237033333333333
TotalMinutes      : 0.14222
TotalSeconds      : 8.5332
TotalMilliseconds : 8533.2



PS C:\> ($sDate - $dte).gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     TimeSpan                                 System.ValueType


PS C:\>

A system.TimeSpan .NET Framework class has a number of interesting properties and methods. These are shown here:

PS C:\> $ts = $sDate - $dte
PS C:\> $ts | gm


   TypeName: System.TimeSpan

Name              MemberType Definition
----              ---------- ----------
Add               Method     System.TimeSpan Add(System.TimeSpan ts)
CompareTo         Method     int CompareTo(System.Object value), int CompareTo(Sy...
Duration          Method     System.TimeSpan Duration()
Equals            Method     bool Equals(System.Object value), bool Equals(System...
GetHashCode       Method     int GetHashCode()
GetType           Method     type GetType()
Negate            Method     System.TimeSpan Negate()
Subtract          Method     System.TimeSpan Subtract(System.TimeSpan ts)
ToString          Method     string ToString()
Days              Property   System.Int32 Days {get;}
Hours             Property   System.Int32 Hours {get;}
Milliseconds      Property   System.Int32 Milliseconds {get;}
Minutes           Property   System.Int32 Minutes {get;}
Seconds           Property   System.Int32 Seconds {get;}
Ticks             Property   System.Int64 Ticks {get;}
TotalDays         Property   System.Double TotalDays {get;}
TotalHours        Property   System.Double TotalHours {get;}
TotalMilliseconds Property   System.Double TotalMilliseconds {get;}
TotalMinutes      Property   System.Double TotalMinutes {get;}
TotalSeconds      Property   System.Double TotalSeconds {get;}


PS C:\>

In general, I allow Windows PowerShell to display all of the properties of the timespan object. For example, if I am interested in seeing how long it takes my Windows 7 desktop to start and to present the Explorer desktop, I can use the Get-Process cmdlet to return the starttime of both the smss process and the explorer process. I can then subtract the two times, which will return a timespan object. The results are shown in the following image. Keep in mind that to return the starttime property of the smss process, the Windows PowerShell console must be running with administrator rights.

Image of results of subtracting one date from another

SH, that is all there is to using methods from the DateTime object to perform date manipulation. Date Week will continue tomorrow when we will talk about working with Windows Management Instrumentation and dates.

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

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Ed, it seems like every time I Google for PowerShell help, I end up on your site. You have saved me so much headache and frustration. Posts like this, which are probably very basic to you, are incredibly helpful for someone like me who is new to PowerShell. So THANK YOU for this post and all of your others. :)