New-TimeSpan of two midnight dates is skipped every other day
I am trying to simply calculate the number of days until a user's password expires. I am using TimeSpan for this. My code in practice looks like this:
(New-TimeSpan -Start (get-date -hour 0 -minute 0 -second 0) -End (Get-Date $_.PasswordLastSet -hour 0 -minute 0 -second 0).AddDays(90)).Days
So, if the current date is 90 days after the date the password was last set, the days before the password expires will be 0.
Unfortunately, this code will return the same result for many consecutive days. For some reason I can't get quite consistent results here, I suppose it depends on the time of day, but I'm not sure why. We skip most of the time every other day. So if we run this every day of the week, we will return 4,4,2,2,0,0.
To replicate easily, you can use the following:
$x = (get-date).AddDays(-90)
(New-TimeSpan -Start (get-date $x -hour 0 -minute 0 -second 0).AddDays(90) -End (get-date -hour 0 -minute 0 -second 0)).Days
(New-TimeSpan -Start (get-date $x -hour 0 -minute 0 -second 0).AddDays(89) -End (get-date -hour 0 -minute 0 -second 0)).Days
source to share
Ok I found it. It depends on milliseconds. Sometimes the difference would be 1 day and a few milliseconds. Sometimes these few milliseconds go to the other side, so the difference will be 23 hours 59 minutes 59 seconds. 78 milliseconds (for example). This displays as 0 days!
To see this, just remove .Hours
from your example and try to replicate it.
New-TimeSpan -Start (get-date $x -hour 0 -minute 0 -second 0).AddDays(89) -End (get-date -hour 0 -minute 0 -second 0)
Days : 0
Hours : 23
Minutes : 59
Seconds : 59
Milliseconds : 78
Ticks : 863990781260
TotalDays : 0.999989330162037
TotalHours : 23.9997439238889
TotalMinutes : 1439.98463543333
TotalSeconds : 86399.078126
TotalMilliseconds : 86399078.126
To fix this problem, just add one second to the calculation and you will get the correct number of days.
source to share
Why is it so difficult? You can subtract the current date from the date 90 days before and get TotalDays
:
(Get-Date) - (Get-Date).AddDays(-90) | Select-Object -ExpandProperty TotalDays
Now you only need to check if there is a result -le 90
.
Note. Since Igor figured out that TotalMilliseconds might be the root of your problem, I would suggest extracting the date only once :
$date= Get-Date
$date - $date.AddDays(-90) | Select-Object -ExpandProperty TotalDays
Then you don't need to deal with Hours, Minutes, Sedna, Milliseconds and Slander.
source to share