【问题标题】:How does PowerShell handle ((Get-Date).Month)-1 in January?PowerShell 如何在一月份处理 ((Get-Date).Month)-1?
【发布时间】:2020-04-07 04:52:58
【问题描述】:

几个月前我写了一个 Powershell/Robocopy 备份脚本。它为备份创建一个文件夹,其中包含进行备份的年份和月份(例如:2019 11)。这个月总是必须少一个,因为脚本在每个新月的第一天运行。一切都一帆风顺,但我刚刚意识到我不确定脚本在 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”?有没有办法让我轻松测试依赖时间的行为,而无需手动调整我的电脑日历?

【问题讨论】:

  • 只需将日期设置为[datetime]'01-01-2020',然后执行减法?

标签: powershell logic powershell-4.0 powershell-5.0


【解决方案1】:

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

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

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

System.DateTime.ToString() 方法允许您使用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 日,这是它在美英文化 (en-US) 中返回的结果。

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

【讨论】:

  • 感谢您的精彩回答!很多有用的信息,我希望能帮助其他人,因为他们将来遇到这个线程。 @hcm 也有完美的答案!
【解决方案2】:

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

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

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

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

【讨论】:

  • 感谢您的回答!这个答案会起作用,并且肯定会回答我的问题。我的脚本设置为通过任务计划程序在每个月的第一天运行,但其他答案不需要日期为每月的第一天。如果我的同事决定采用我的脚本,这会使他们更加万无一失。再次感谢您的贡献!
【解决方案3】:

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

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

然后,您的代码将生成“2020 0”作为输出。 你最好有这样的东西。您也不必在下个月的第一天跑步:

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

【讨论】:

  • 感谢您的回答!太棒了! mkement0 首先提供了一个非常相似的答案,并且非常详细,所以我必须给他答案,但是你的答案也很棒,我要感谢你帮助我!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-15
  • 1970-01-01
  • 1970-01-01
  • 2022-01-04
相关资源
最近更新 更多