PowerShell日期无法正确比较

时间:2018-10-01 12:05:31

标签: powershell

我正在尝试在每月的最后一个工作日重新启动PC。该脚本每天下午7:25运行,目的是检查今天的日期,看看是否是该月的最后一个工作日。如果是,它将重新引导PC。如果不是,则记录为不是。

我当时想PowerShell可能会按滴答作比较,而Get-Weekday函数和Get-Date函数的运行时间之间的滴答滴答稍微有些偏离。

日志摘录:

COMP1 - 09/26/2018 17:24:08 - Not last weekday of month 09/28/2018 17:24:08 > 09/26/2018 17:24:08 
COMP1 - 09/27/2018 17:24:09 - Not last weekday of month 09/28/2018 17:24:09 > 09/27/2018 17:24:09 
COMP1 - 09/28/2018 17:24:01 - Not last weekday of month 09/28/2018 17:24:01 > 09/28/2018 17:24:01 
COMP1 - 09/28/2018 17:24:01 - Not last weekday of month 09/28/2018 17:24:01 > 09/28/2018 17:24:01 

代码:

#Gets last weekday of the month
function Get-Weekday {
    param(
        $Month = $(Get-Date -format 'MM'),
        $Year = $(Get-Date -format 'yyyy'),
        $Days = 1..5
        )
    $MaxDays = [System.DateTime]::DaysInMonth($Year, $Month)
    1..$MaxDays | ForEach-Object {
            Get-Date -day $_ -Month $Month -Year $Year |
              Where-Object { $Days -contains $_.DayOfWeek }  
    }
}

    #Last day of the month
    $lwom = (Get-Weekday -Month (Get-Date).Month) | Select-Object -Last 1
    #Returns:  09/28/2018 17:24:16

    # Get Today's date.
    $ModDate = Get-Date
    #Returns:  09/28/2018 17:24:16

    #If Last day of month = Today's Date    
    if ( $lwom -eq $ModDate ) { 


        #Creates the wscript shell for the popup -- box automatically closes after 10 seconds, script sleeps for 60
        $wshell = New-Object -ComObject Wscript.Shell
        $wshell.Popup("This computer will reboot in 60 seconds.  Click OK and save your work!",10,"Save Your Data",48+0)
        $xCmdString = {sleep 60}
        Invoke-Command $xCmdString

        #Next popup created to reboot in 5 seconds.  
        $wshell.Popup("Rebooting...",4,"Rebooting",48+0)
        $xCmdString = {sleep 5}
        Invoke-Command $xCmdString
        Restart-Computer -Force
          }

    else { 
        Add-Content 'EOM-reboot_log.txt' "$env:computername - $ModDate - Not last weekday of month $lwom > $ModDate " 
         }

最终解决方案:

function LastDayThisMonth {
    return (Get-Date -Day 1).Date.AddMonths(1).AddDays(-1)
}

function WorkingDay {
    param ([datetime]$date=(Get-Date).Date)
    While (!([int]$date.DayOfWeek % 6)){$date=$date.AddDays(-1)}
    Return $date.Date
}

    $lwom = WorkingDay -Date (LastDayThisMonth) #Does not need .Date because it's already in the function.
    $ModDate = (Get-Date).Date  # .Date on the variables will return the date and ignores the time.  Time become 12:00:00 AM of both da


    if ( $lwom -eq $ModDate ) { 

                #Writes to the log file.
                Add-Content 'c:\EOM-reboot_log.txt' "$env:computername - $ModDate -  End of Month Weekday" 

                #Creates the wscript shell for the popup -- box automatically closes after 10 seconds, script sleeps for 60
                $wshell = New-Object -ComObject Wscript.Shell
                $wshell.Popup("This computer will reboot in 60 seconds.  Click OK and save your work!",10,"Save Your Data",48+0)
                $xCmdString = {sleep 60}
                Invoke-Command $xCmdString

                #Next popup created to reboot in 5 seconds.  
                $wshell.Popup("Rebooting...",4,"Rebooting",48+0)
                $xCmdString = {sleep 5}
                Invoke-Command $xCmdString
                Restart-Computer -Force
          }

    else { 
        Add-Content 'c:\EOM-reboot_log.txt' "$env:computername - $ModDate - Not last weekday of month $lwom > $ModDate " 
 }

2 个答案:

答案 0 :(得分:4)

  

我当时想PowerShell可能会按滴答作比较,而Get-Weekday函数和Get-Date函数的运行时间之间的滴答略有偏离。

是的,这很容易测试...

$date1 = Get-Date
$date2 = Get-Date

$date1.ToString("dd-MM-yyyy hh:mm:ss:fff")
$date2.ToString("dd-MM-yyyy hh:mm:ss:fff")

$date1 -eq $date2

重复运行此命令将显示成功和失败的混合,并且表明datetime唯一的相等方法是每个日期/时间值分别相同。

01-10-2018 09:11:02:729
01-10-2018 09:11:02:730
False

01-10-2018 09:11:04:378
01-10-2018 09:11:04:378
True

话虽这么说

$lwom -eq $ModDate正在比较日期和时间$lwom.Date -eq $ModDate.Date只会查看日期本身。因此,除非您在午夜之前运行此程序,否则将获得一致且可预测的结果。

答案 1 :(得分:3)

通过这种方式,更容易获得IMO的当前月份的最后一天:

function LastDayThisMonth {
    return (Get-Date -Day 1).Date.AddMonths(1).AddDays(-1)
}

获取给定日期/今天的最后一个工作日的功能:

function WorkingDay {
    param ([datetime]$date=(Get-Date).Date)
    While (!([int]$date.DayOfWeek % 6)){$date=$date.AddDays(-1)}
    Return $date.Date
}
  • 这里(!([int]$date.DayOfWeek % 6))在星期六/日的计算结果为true,因此减去了一天。

所以在9/30/2018这是

$lwom = WorkingDay -Date (LastDayThisMonth)

返回

09/28/2018 00:00:00

避免毫秒/间隔问题。

编辑出于完整性考虑,增强功能WorkingDay具有-After开关,可在下一个工作日(启用)或在给定日期/日期之后获得。

function WorkingDay {
    param ([Parameter(Mandatory=$False,Position=0)] [datetime]$Date=(Get-Date).Date,
           [Parameter(Mandatory=$False,Position=1)] [switch]$After)
    If($PSBoundParameters.ContainsKey("After")){[int]$Offset=1}else{[int]$Offset=-1}
    While (!([int]$Date.DayOfWeek % 6)){$Date=$Date.AddDays($Offset)}
    Return $Date.Date
}

"Date       WDayBefore WDayAfter"
"----       ---------- ---------"
-7..7|%{
    $Date=(get-Date).Date.AddDays($_)
    "{0,-10:ddd dd} {1,-10:ddd dd} {2,-10:ddd dd} " -f `
        $Date,
        (WorkingDay -Date $Date),
        (WorkingDay -Date $Date -After )
}

测试例程的输出(德语语言环境):

> Q:\Test\2018\10\01\SO_17-56.ps1
Date       WDayBefore WDayAfter
----       ---------- ---------
Mo 24      Mo 24      Mo 24
Di 25      Di 25      Di 25
Mi 26      Mi 26      Mi 26
Do 27      Do 27      Do 27
Fr 28      Fr 28      Fr 28
Sa 29      Fr 28      Mo 01
So 30      Fr 28      Mo 01
Mo 01      Mo 01      Mo 01
Di 02      Di 02      Di 02
Mi 03      Mi 03      Mi 03
Do 04      Do 04      Do 04
Fr 05      Fr 05      Fr 05
Sa 06      Fr 05      Mo 08
So 07      Fr 05      Mo 08
Mo 08      Mo 08      Mo 08