Wednesday, May 28, 2008

Generating Random Dates


One of the new cmdlets in PowerShell CTP2 is Get-Random. Get-Random gets a random number or selects objects randomly from a collection. 

I wanted to generate random DateTime objects with it but there is no built-in capability for that, yet it doesn't mean you can't use Get-Random it to generate random dates :)

At its base, a DateTime object is measured in 100-nanosecond units called Ticks. So I tried to use Get-Date to initialize a DateTime using Ticks. Again, Get-Date doesn't have any parameter for that so I checked the underlying object, System.DateTime.

One of the System.DateTime constructors allows you to initialize a new instance of the DateTime structure to a specified number of ticks. The maximum value for ticks is determined by:

PS > [datetime]::maxValue.ticks


Now, Can I use Get-Random to generate a number in the range of 0-3155378975999999999 (exclusive)? 
The help for Get-Random says: Without parameters or input, "Get-Random" returns a randomly selected 32-bit unsigned integer between 0 and Int32.MaxValue (0x7FFFFFFF, 2,147,483,647), so it shouldn't be a problem with the ticks input to generate a higher value then the max value of Int32.MaxValue:

PS > Get-Random ([datetime]::maxValue.ticks)

PS > Get-Random ([datetime]::maxValue.ticks)

Yes I can! So I tried to generate a new DateTime using that method:


PS > new-object dateTime (Get-Random ([datetime]::maxValue.ticks))
Friday, March 09, 3951 11:00:06 PM

PS > new-object dateTime (Get-Random ([datetime]::maxValue.ticks))
Wednesday, October 07, 2476 1:36:05 AM


Cool. But this can give a date between the Year 0 and 9999:

PS > new-object datetime ([datetime]::maxValue.ticks)

Friday, December 31, 9999 11:59:59 PM


If you want to have random DateTime between a specific period of time then you can use the Get-Random -min and -max parameters:

PS > $dateMin = get-date -year 1980 -month 1 -day 1
PS > $dateMax = get-date -year 2007 -month 1 -day 1

PS > new-object datetime (Get-Random -min $dateMin.ticks -max $dateMax.ticks) Thursday, November 14, 2002 9:45:23 AM

PS > new-object datetime (Get-Random -min $dateMin.ticks -max $dateMax.ticks)
Friday, December 07, 2001 6:17:54 PM

PS > new-object datetime (Get-Random -min $dateMin.ticks -max $dateMax.ticks)
Monday, April 01, 2002 4:50:52 PM


I didn't find any use for random dates yet, but it is good to know you can create them.


Anonymous said...

This is actually very useful! I have a huge amount of files that for testing purposes would like to change the LastWriteTime to some random date between min/max.

You mention this is on ctp2, but I have some rendition of it installed with PowerShell v1. (trying to find it this is native or part of the Community Extensions). Anyway, I'm unable to get things to work as the min/max params to Get-Random cannot bind to my DateTime.Ticks because the number is too big (i.e. Int64 to Int32 conversion is not too happy).

I'm still trying to get this to work, but if you have any tips that would be cool!

Shay Levy said...

Hi Scott

I found a piece of C# on the internet, I twicked it:

[int64]$min = [int64]::maxValue
[int64]$max = [int64]::maxValue

$random = new-object random
$rnd64 = ($max*1.0 - $min*1.0)*$random.NextDouble() + $min*1.0

Can you check if it works for you?


Anonymous said...

Hi Shay,

Thanks for the reply! Applying what you found, here is what we end up with:

[DateTime]$theMin = "1/1/2008" [DateTime]$theMax = [DateTime]::Now

$theRandomGen = new-object random
$theRandomTicks = [Convert]::ToInt64( ($theMax.ticks * 1.0 - $theMin.Ticks * 1.0 ) * $theRandomGen.NextDouble() + $theMin.Ticks * 1.0 )
new-object DateTime($theRandomTicks)

Thanks so much for the post. It was just what the Dr. ordered. :)


-Matt said...

You rock. Thank you! Staggered task triggers just got a whole lot easier.