PowerShell 如何处理一月份的 ((Get-Date).Month)-1?

How does PowerShell handle ((Get-Date).Month)-1 in January?

几个月前我写了一个 Powershell/Robocopy 备份脚本。它会为备份创建一个文件夹,其中包含备份的年份和月份(例如:2019 11)。这个月总是必须少一个,因为脚本 运行s 在每个新月的第一天。一切都一帆风顺,但我刚刚意识到我不太确定剧本在 1 月 1 日的表现如何。有没有人知道 1 月 1 日的输出是什么,我有没有办法对此进行测试以确认?

$month = (Get-Date -UFormat "%Y") + ' ' + ((((Get-Date).Month) - 1)).ToString()
# When run on November 1st, it creates a folder for the October backups called "2019 10".
# When run on December 1st, it creates a folder for the November backups called "2019 11".

在 1 月 1 日 运行 时,它将为 12 月备份的文件夹命名什么?会叫《2019 12》吗? “2019 00”?有没有一种方法可以让我轻松测试依赖于时间的行为,而无需手动调整我的 PC 的日历?

如果你能保证你总是运行这个月的第一天,那么你可以使用$folderName = ((Get-Date) - (New-TimeSpan -Days 1)).ToString("yyyy MM")。参见 Microsoft Docs on New-TimeSpan and this Whosebug question on formatting dates

编辑: 在这里得到更好的回应;不要使用上面的 New-Timespan 方法,而是将上面我建议的代码修改为

$foldername = (Get-Date).AddMonths(-1).ToString("yyyy MM")

这消除了支持代码在每月的第一天为 运行 的要求。

Get-Date 可选地接受要操作的日期(通过 -Date 或位置),默认为当前时间点。

此外,您可以使用-Day修改目标日期的日期部分(以及-Month-Year,类似);传递 -Day 1 returns 目标日期所在月份的第一天。

在结果日期上调用 .AddDays(-1) 然后保证在上个月(它 returns 上个月的最后一天)。

.ToString() method of System.DateTime allows you to perform custom string formatting of a date, using custom date and time format strings.

总而言之:

# PRODUCTION USE:
# The reference date - now.
$now = Get-Date

# OVERRIDE FOR TESTING:
# Set $now to an arbitrary date, 1 January 2020 in this case.
# Note: With this syntax, *month comes first*, irrespective or the current culture.
$now = [datetime] '1/1/2020'

# Get the first day of the month of the date in $now,
# subtract 1 day to get the last day of the previous month,
# then use .ToString() to produce the desired format.
(Get-Date $now -Day 1).AddDays(-1).ToString('yyyy MM')

以上结果:

2019 12

注意:PowerShell 的转换 例如 [datetime] '1/1/2020' 通常使用 invariant culture 来保证跨不同行为的稳定性文化;这种虚拟文化与美国英语文化相关联,并支持其以月为首的日期格式(例如,12/1/2020 指的是 2020 年 12 月 1 日,而不是 2020 年 1 月 12 日)。

令人惊讶的是,相比之下,当您将 参数 传递给 cmdlet 时,数据转换 文化敏感;也就是说,例如,在法国文化 (fr-FR) 中,调用 Get-Date 12/1/2020 将导致 2020 年 1 月 12 日,而不是 2020 年 12 月 1 日,这就是它在美国英语中的 returns文化 (en-US)).

this GitHub issue 中讨论了这种有问题的行为差异 - 但是,为了保持向后兼容性,该行为不太可能改变。

您可以像这样创建任意日期

$testdate = get-date -year 2020 -month 1 -day 1

然而,您的代码将生成“2020 0”作为输出。 你最好用这样的东西。您也不会在下个月的第一天绑定到 运行:

$month = $(get-date (get-date $testdate).AddMonths(-1) -format "yyyy MM")