tags:

views:

217

answers:

3

My script's input parameter is a date or a number. Here's a script that works fine, so you can see what I am trying to do:

param($date = (Get-Date))

if ($date -match "^\d+$")
{  
    $date = (Get-Date).AddDays($date)
} 
elseif ($date -as [DateTime]) 
{
    $date = [DateTime]::Parse($date)  
}
else 
{  
    'You entered an invalid date'
    exit 1
}

Here's my previous attempt that does not work:

param($date = (Get-Date))

if ($date -as [DateTime]) 
{
    $date = [DateTime]::Parse($date)  
}
elseif ($date -match "^\d+$")
{  
    $date = (Get-Date).AddDays($date)
} 
else 
{  
    'You entered an invalid date'
    exit 1
}

When I input a number, the script breaks at date parsing line. It looks like my "is is date" check returns true when given a number.

Is it a bug? Is it by design?

+4  A: 

Well, you can cast any integer to a DateTime, simply because DateTime is just a number behind the scenes.

Every DateTime has a Ticks property which are 100 ns intervals since 0001-01-01. You can initialize a DateTime with those ticks, even though I didn't find a use for it so far.

PS> ([datetime]1234).Ticks
1234

But that's why you can cast a number to DateTime and it works. It's probably just a date very far back in time :-)

So basically, what you're doing now, i. e. checking for a number first, is the proper way to go as the cast to DateTime doesn't suffice in helping you determining whether it's a date or a number.

Joey
I prefer this approach to using the [DateTime]::Parse method because this approach has a very nifty side-effect. Since PowerShell will always try to cast whatever it gets for a parameter to the type it needs, you can call this function with simple strings in any localized datetime format:i.e. Foo "1:OO PM", Foo "1/1/2012 20:12"Hope this helps
Start-Automating
I don't follow. The same works for DateTime parse, it uses the culture of the current thread when parsing the string. Ultimately, I would venture that the PowerShell conversion winds up at DateTime.Parse or DateTime.TryParse. I see no reason why they would want to reimplement that code.
Keith Hill
+2  A: 

You can let the .NET Framework help you with this:

function ParseDate([string]$date)
{
    $result = 0
    if (!([DateTime]::TryParse($date, [ref]$result)))
    {
        throw "You entered an invalid date: $date"
     }

    $result
}

ParseDate 'June 51, 2001'
Keith Hill
A: 

Yes, you can check that a string contains date by using ‘(-as [DateTime])’. The problem in my original script is that I assumed that script input parameters are strings. Apparently, numerical parameter is automatically converted to integer, unless it is typed with quotes. So, I should have written

if ([string]$date -as [DateTime])  

forcing converting possible number back to string, as Keith does in his answer.

Same flaw applies to my integer check. The script fails when given “Oct,3” (without quotes). Does PS create an array here?

Why does parsing fail when check succeeds? Johannes explained that. Expression

$date -as [DateTime]

instructs PS to convert input to date. Converting number makes sense (date 1 is January 01, 0001), so it does not fail when given a number. Expression

[DateTime]::Parse($date)

specifically parses a string, so giving it an integer does not make sense and leads to error.

It was wasteful of me to use both, anyway. First, I convert to date in the condition, only to throw away the result. Then, I recreate the result with different syntax. I’m changing that to

$date = $date -as [DateTime];
if (!$date)
{  
    'You entered an invalid date'
    exit 1
}

Thanks all.

buti-oxa