Pull to refresh

О разных тиках замолвите слово или как не получить ошибку в Powershell при работе с Get-Date

Reading time2 min
Views3.2K
Доброго дня, любители Powershell.

Я люблю его, и сегодня заметил одну странность, которая мотивировала к написанию данного поста. Думаю, вам тоже будет интересно. Дело о лишнем тике. Если интересно, добро пожаловать под кат:

В чем суть странности?

В одной обработке для удобства выбора нужно было число дней до конца месяца.

Вычислялось это одной строкой такого вида:

((Get-date -Day 1).AddMonths(1)-(get-date)).days-1

Что характерно ее вычисление может давать разные результаты:

Сначала я подумал, что с кодом что-то не то, или версией Powershell.

Проверил на нескольких машинках и понял, что ситуация воспроизводима.

Поэтому сел дебажить и писать функцию.

У меня получилось такое, в коде сразу идут комментарии:

Function Get-DaysToEndOfMonths([int]$Month=1)
    {If($Month -lt 1){[int]$Month = 1}
    $CurrentDate = get-date       #Получаем текущую дату
    $CurrentDay = $CurrentDate.day #И какой это день
    $FirstDayCurrentMonths = (Get-date -Day 1) #Первый день текущего месяца
   #$FirstDayNextMonths = $FirstDayCurrentMonths.AddMonths($Month) #Первый день искомого месяца
   #Ага, так можно сразу отнять один день, чтобы получить последний день до искомого месяца
    $LastDay = $FirstDayCurrentMonths.AddMonths($Month).AddDays(-1) #Последний день искомого месяца
    $DaysToEndOfMonths = $($LastDay - $CurrentDate).Days #Сколько дней до искомого месяца
    #Или через New-TimeSpan
    #$NewTimeSpan = New-TimeSpan -Start $CurrentDate -End $LastDay
    #$DaysToEndOfMonths = $NewTimeSpan.Days #Сколько дней
    Write-debug "$DaysToEndOfMonths days to the end of the next $Month month"
    }
Get-DaysToEndOfMonths(1)

Ну и после того как написал, сел еще подумать и пришел к такой строке:

[int]((((Get-Date -day 01).AddMonths(1)).AddDays(-1)).Day-(Get-date).Day) 

Она уже не давала ошибку, но может, так как:

Оказывается, что мы не учитываем час\минуты\секунды, а вернее тактовые тики процессора.
Заметим, что, Get-date выдаёт значение в миллисекундах.

Но если при выполнении вычислений первый и второй вызов Get-date пришёлся на один тик, то будут такие значения:

(Get-date -day 1).AddMonth(1) = 1.12.2019 15:33:00:500
Get-date = 1.11.2019 15:33:00:500

Вычтем и получим 30 00:00:00:000
Но если вызов второго Get-date выпадает на следующий тик, то его значение будет
=>
1.11.2019 15:33:00:501

И тогда мы получим значение в
29 23:59:59:999

Теперь, когда проблема найдена, мы можем сделать так:


#Число дней до конца месяца
((((Get-Date -day 01).AddMonths(1)).AddDays(-1))-(Get-date -Hour 0 -Minute 0 -Second 0 -Millisecond 0)).Days

И у нас всегда будет одинаковое значение.

Будьте внимательны и хороших выходных!
Tags:
Hubs:
+7
Comments8

Articles