use DateTime;
use DateTime::TimeZone;
my $dt = DateTime->new( {
year => 2014, month => 10, day => 19,
hour => 2, minute=> 2, second=> 0
});
$dt->set_time_zone(DateTime::TimeZone->new( name => 'America/Sao_Paulo' ));
$dt->truncate(to => 'day');
失败,消息Invalid local time for date in time zone: America/Sao_Paulo
。
因为2014-10-19 00:00:00
不是America/Sao_Paulo
时区中的有效时间。最终结果应该是2014-10-19 01:00:00
.
我的伪代码理论
Try to truncate directly to the datetime object inside an eval
IF fails
IF the truncation level is "day"
-1 day
truncate
+ seconds of a day
IF the truncation level is "month"
-1 month
truncate
seconds of a month. <--- Now here I need to take care of seconds of every month and even leapyear
ELSE im happy
有什么帮助来改进我的理论或提供更简单的方法吗?
由于错误仅在小时设置为零时发生,因此更正必须始终是将小时设置为 1。除午夜外,时间变化的区域不会有问题。
这意味着您可以编写这样的简单异常处理程序。
我很想说,没有区域在一个月的第一天开始夏令时,所以截断到月份时不应该出现问题。但我不能保证这一点,所以我也为此编写了一个块。
use strict;
use warnings;
use 5.010;
use DateTime;
use DateTime::TimeZone;
use Try::Tiny;
my $dt = DateTime->new( {
year => 2014, month => 10, day => 19,
hour => 2, minute=> 2, second=> 0
});
my $sao_paolo = DateTime::TimeZone->new( name => 'America/Sao_Paulo' );
$dt->set_time_zone($sao_paolo);
try {
$dt->truncate(to => 'day');
}
catch {
die $_ unless /Invalid local time for date/;
$dt->truncate(to => 'hour');
$dt->set({hour => 1});
};
say $dt;
try {
$dt->truncate(to => 'month');
}
catch {
die $_ unless /Invalid local time for date/;
$dt->truncate(to => 'hour');
$dt->set({day => 1, hour => 1});
};
say $dt;
输出
2014-10-19T01:00:00
2014-10-01T00:00:00