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
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”
05/09/10
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”
05/09/10
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. 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 &
nbsp; 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
Sunday
PS C:>
What was the day of the year?
129
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)
Wednesday,
0 comments