Date::Manip::Recur处理月末重复日期缺失问题求助
解决Date::Manip::Recur生成还款日期时小月缺失的问题
问题分析
当设置的还款日为29/30/31号时,Date::Manip::Recur遇到没有对应日期的月份(如2月)会直接跳过该月份的日期——模块文档明确说明,为了性能不会自动修正无效日期,而是返回undef。要实现自动适配当月最后有效日期的需求,需要手动处理每个月份的日期构造逻辑。
解决方案
放弃直接依赖Recur的自动生成逻辑,改为遍历每个目标月份,手动构造还款日:若指定日期在当月无效,则自动替换为当月最后一天,再筛选出在起止日期范围内的日期。
修改后的代码
#!/usr/bin/perl use strict; use warnings; use Date::Manip::Date; use DateTime::Format::Strptime; use String::Util qw(trim); my $reoccur_date = 30; # 创建起止日期对象 my $start_manip = Date::Manip::Date->new(); my $end_manip = Date::Manip::Date->new(); $start_manip->parse_format('%d/%m/%Y', '29/10/2023'); $end_manip->parse_format('%d/%m/%Y', '28/09/2024'); # 转换为DateTime对象方便日期操作 my $dt_format = DateTime::Format::Strptime->new( pattern => '%Y%m%d%H:%M:%S', on_error => 'croak', ); my $start_dt = $dt_format->parse_datetime(trim($start_manip->value)); my $end_dt = $dt_format->parse_datetime(trim($end_manip->value)); my @dates_reoccur; # 初始化当前日期为起始月的还款日(若起始日晚于还款日则从下月开始) my $current_dt = $start_dt->clone(); if ($current_dt->day > $reoccur_date) { $current_dt->add(months => 1); } # 尝试设置还款日,无效则替换为当月最后一天 eval { $current_dt->set(day => $reoccur_date); }; $current_dt->set(day => $current_dt->month_length) if $@; # 遍历所有符合范围的月份 while ($current_dt <= $end_dt) { push @dates_reoccur, $current_dt->clone() if $current_dt >= $start_dt; # 进入下一个月并调整还款日 $current_dt->add(months => 1); eval { $current_dt->set(day => $reoccur_date); }; $current_dt->set(day => $current_dt->month_length) if $@; } # 输出结果 my $dates_found = @dates_reoccur; print "There are $dates_found list members\n"; foreach my $dt (@dates_reoccur){ print "Found date: " . $dt->strftime('%d %B %Y') . "\n"; }
关键逻辑说明
- 手动遍历每个月份,彻底避免
Date::Manip::Recur跳过无效日期的问题 - 通过
eval捕获设置无效日期的异常,自动调用month_length获取当月最后一天进行替换 - 提前判断起始日与还款日的先后关系,避免生成早于起始时间的无效提醒
内容的提问来源于stack exchange,提问作者bsddude
相关产品推荐
相关产品推荐

