为何截断Perl DateTime至‘天’后减一天会得到错误结果?
Perl DateTime截断日期后计算昨日日期出错的原因及修复
你的问题出在时区转换和截断操作的顺序上,具体原因如下:
- 初始
$today = DateTime->now(time_zone => 'local')获取的是本地时区的当前时间,比如假设你的本地时区是UTC-5(美国东部时间),当本地时间是12/02/2024 00:30时,对应的UTC时间是12/02/2024 05:30。 - 你将
$today转成UTC后,调用truncate(to => 'day')会把时间截断到UTC时区的当天0点(也就是12/02/2024 00:00 UTC),这时候这个UTC时间对应的本地时间其实是12/01/2024 19:00(UTC-5)。 - 接着你给截断后的UTC时间减1天,得到
12/01/2024 00:00 UTC,再转成本地时区就是11/30/2024 19:00,所以最终输出的昨日日期是11/30/2024,而原本的$today转回到本地还是12/02/2024,看起来就像是少了一天。
而当你不使用truncate时,直接对UTC时间减1天,是基于原始的UTC时间(比如12/02/2024 05:30 UTC)减一天得到12/01/2024 05:30 UTC,转成本地时区就是12/01/2024 00:30,日期正确。
修复方案
你需要在本地时区下完成截断操作,再处理时区转换和日期减法,或者调整操作顺序确保截断的是对应本地日期的时间:
方案一:直接在本地时区处理(最简洁)
use DateTime; use strict; use warnings; my $today = DateTime->now(time_zone => 'local')->truncate(to => 'day'); my $yesterday = $today->clone->subtract(days => 1); print "YESTERDAY: ".$yesterday->strftime("%m/%d/%Y")."\n"; print " TODAY: ".$today->strftime("%m/%d/%Y")."\n";
这个方案完全不需要切换UTC,截断和减法都在本地时区完成,逻辑直观且不易出错。
方案二:需切换UTC时的正确顺序
use DateTime; use strict; use warnings; # 先在本地时区截断到当天0点 my $today_local = DateTime->now(time_zone => 'local')->truncate(to => 'day'); # 转换为UTC后再做日期减法 my $today_utc = $today_local->clone->set_time_zone('UTC'); my $yesterday_utc = $today_utc->clone->subtract(days => 1); # 转换回本地时区 my $yesterday_local = $yesterday_utc->set_time_zone('local'); print "YESTERDAY: ".$yesterday_local->strftime("%m/%d/%Y")."\n"; print " TODAY: ".$today_local->strftime("%m/%d/%Y")."\n";
这样保证截断的是本地时区的当天0点,后续UTC转换和减法操作不会导致日期偏移。
内容的提问来源于stack exchange,提问作者tjwrona
相关产品推荐
相关产品推荐

