#PSTip Comparing DateTime with a given precision

Note: This tip requires PowerShell 2.0 or above.

Comparing two System.DateTime objects in PowerShell is really easy. All you need to do is:

PS> $date1 = $date2 = Get-Date
PS> $date1 -eq $date2

When the two objects are compared their Ticks properties are in fact compared:

PS> $date1.Ticks -eq $date2.Ticks

Ticks are the most precise way to represent a DateTime; there are 10,000 ticks in one millisecond. That is 10 million ticks in one second. In my current project I needed the comparisons to be a little less precise and consider DateTime objects equal even if they were a few milliseconds apart. To do that I decided to trim the DateTime objects by removing any excess milliseconds and ticks.

Doing that in PowerShell 3.0 is pretty easy:

PS> $date = Get-Date
PS> $date.Ticks

PS> Get-Date -Date ($date) -Millisecond 0  | Select -ExpandProperty Ticks

This will take the current date and set its Millisecond and any extra Ticks to 0.

In PowerShell 2.0 the conversion is a little bit more challenging because there is no Millisecond parameter there. And you can’t simply use the AddMilliseconds method to remove the extra milliseconds, because that won’t affect the extra ticks:

PS> $date.AddMilliseconds(- $date.Millisecond) | Select -ExpandProperty Ticks

Another workaround has to be used:

PS> [datetime]($Date.Ticks - $date.Ticks % 10000000) | Select -ExpandProperty Ticks

I needed to make the script compatible with PowerShell 2.0 and I also wanted it to be readable. So I ended up writing function to do it, and more:

function Trim-Date {

    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]

        [String]$Precision = 'Second'

    process {

        if ($Precision -eq 'Tick')
            return $Date

        $TickCount = Switch ($Precision)
            'Millisecond' { 10000; break }
            'Second' { ( New-TimeSpan -Seconds 1 ).ticks; break }
            'Minute' { ( New-TimeSpan -Minutes 1 ).ticks; break }
            'Hour' { ( New-TimeSpan -Hours 1 ).ticks; break }
            'Day' { ( New-TimeSpan -Days 1 ).ticks; break }

        $Result = $Date.Ticks - ( $Date.Ticks % $TickCount )

This function takes two parameters: Date and Precision. The Date is the DateTime object to be trimmed and the Precision specifies what is the biggest unit to be kept. If, for example, Hour precision is specified, minutes, seconds, millisecond and extra ticks are set to 0. In the following example the default Second precision is used so just milliseconds and any extra ticks are set to zero.

PS> $date | Trim-Date -Precision Second  | Select -ExpandProperty Ticks

The function also turned out to be great for checking if two timestamps were created during the same day:

PS> ([datetime]"2013/12/10 12:14:36" | Trim-Date -Precision Day) -eq ([datetime]"2013/12/10 18:10:21" | Trim-Date -Precision Day)

or creating precise plans for the next day:

PS> (Get-Date -Hour 11).AddDays(1) | Trim-Date -Precision Hour
Tuesday, February 11, 2014 11:00:00 AM
Filed in: Columns, Tips and Tricks Tags: , ,
© 5727 PowerShell Magazine. All rights reserved. XHTML / CSS Valid.
Proudly designed by Theme Junkie.
%d bloggers like this: