简体   繁体   English

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

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

I wrote a Powershell/Robocopy backup script a few months back.几个月前我写了一个 Powershell/Robocopy 备份脚本。 It creates a folder for the backups with the year and month that the backups were taken (ex: 2019 11).它会为备份创建一个文件夹,其中包含备份的年份和月份(例如:2019 11)。 The month always has to be one less because the script runs on the first of each new month.这个月总是必须少一个,因为脚本在每个新月的第一天运行。 Everything has been smooth sailing but I just realized that I'm not really sure how the script will behave come January 1st.一切都一帆风顺,但我刚刚意识到我不太确定剧本在 1 月 1 日的表现如何。 Does anyone have any incite as to what the output will be on January 1st, and is there a way for me to test this to confirm?有没有人对 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".

When run on January 1st, what will it name the folder for the December backups?在 1 月 1 日运行时,它将为 12 月备份的文件夹命名什么? Will it be called "2019 12"?会叫《2019 12》吗? "2019 00"? “2019 00”? Is there a way for me to easily test the behavior that relies on time, without manually adjusting my PC's calendar?有没有一种方法可以让我轻松测试依赖于时间的行为,而无需手动调整我的 PC 的日历?

Get-Date optionally accepts a date to operate on (via -Date or positionally), which defaults to the current point in time. Get-Date可选地接受要操作的日期(通过-Date或位置),默认为当前时间点。

Additionally, you can use -Day to modify the day-of-the-month part of the target date (as well as -Month and -Year , analogously);此外,您可以使用-Day来修改目标日期的日期部分(以及-Month-Year ,类似地); passing -Day 1 returns the date of the first of the month that the target date falls into.通过-Day 1返回目标日期所在月份的第一天。

Calling .AddDays(-1) on the resulting date is then guaranteed to fall in the previous month (it returns the previous month's last day).然后保证在结果日期上调用.AddDays(-1)落在上个月(它返回上个月的最后一天)。

The .ToString() method of System.DateTime allows you to perform custom string formatting of a date, using custom date and time format strings . System.DateTime.ToString()方法允许您使用自定义日期和时间格式字符串执行日期的自定义字符串格式设置。

To put it all together:把它们放在一起:

# 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')

The above yields:以上产量:

2019 12

Note: PowerShell's casts such as [datetime] '1/1/2020' generally use the invariant culture for stability of behavior across different cultures;注意: PowerShell 的转换,例如[datetime] '1/1/2020'通常使用不变文化来实现跨不同文化的行为稳定性; this virtual culture is associated with the US-English culture and supports its month-first date format (eg, 12/1/2020 refers to 1 December 2020, not 12 January 2020).这种虚拟文化与美国英语文化相关联,并支持其以月为首的日期格式(例如,12/1/ 12/1/2020指的是 2020 年 12 月 1 日,而不是 2020 年 1 月 12 日)。

Surprisingly, by contrast, when you pass arguments to cmdlets, data conversions are culture-sensitive ;令人惊讶的是,相比之下,当您将参数传递给 cmdlet 时,数据转换区分文化的 that is, in the French culture ( fr-FR ), for instance, calling Get-Date 12/1/2020 would result in 12 January 2020, not 1 December 2020, which is what it returns in the US-English culture ( en-US )).也就是说,例如,在法国文化 ( fr-FR ) 中,调用Get-Date 12/1/2020将导致 2020 年 1 月 12 日,而不是 2020 年 12 月 1 日,这是它在美国英语文化 ( en-US - en-US ))。

This problematic discrepancy in behavior is discussed in this GitHub issue - the behavior is unlikely to change, however, in the interest of preserving backward compatibility.GitHub 问题中讨论了这种有问题的行为差异 - 但是,为了保持向后兼容性,该行为不太可能改变。

You are able to create an arbitrary date like so您可以像这样创建任意日期

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

Your code however will then generate "2020 0" as an output.但是,您的代码将生成“2020 0”作为输出。 You'd be better off with something like this.你最好用这样的东西。 You would not be bound to running on the first day of the next month either:您也不必在下个月的第一天跑步:

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

If you can guarantee that you will always run this on the first of the month, then you can use $folderName = ((Get-Date) - (New-TimeSpan -Days 1)).ToString("yyyy MM") .如果您可以保证始终在每月的第一天运行它,那么您可以使用$folderName = ((Get-Date) - (New-TimeSpan -Days 1)).ToString("yyyy MM") See Microsoft Docs on New-TimeSpan and this StackOverflow question on formatting dates请参阅有关New-TimeSpan Microsoft Docs有关格式化日期的 StackOverflow 问题

EDIT: hcm's answer leads to a better response here;编辑: hcm 的回答在这里得到了更好的回应; instead of using the New-Timespan method above, modify my suggested code above to而不是使用上面的New-Timespan方法,将上面我建议的代码修改为

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

This eliminates the requirement that the supporting code be run on the first of the month.这消除了支持代码在每月的第一天运行的要求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM