You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Perl中基于业务日历计算添加指定小时后的工作日

Perl 实现基于自定义业务日历的小时累加功能

核心实现思路

  1. 借助DateTime系列模块处理日期时间的解析与运算,避免手动处理日期边界、时区等复杂问题
  2. 逐天消耗需累加的小时数:
    • 先判断当前日期是否为有效工作日(非周末、不在节假日列表内)
    • 若为工作日,计算当天剩余可工作时长,优先消耗剩余小时数;若剩余小时数超过当天剩余时长,扣除当天时长后跳转到下一个工作日的开始时间继续处理
    • 若为非工作日,直接跳转到下一个工作日的开始时间,不消耗小时数

依赖模块

先安装必要的CPAN模块:

cpanm DateTime DateTime::Format::Strptime

代码实现

假设你的业务日历哈希结构如下(可根据实际定义调整):

# 与你已有的%sansSLA、%sla8_18、%slaMax对应示例结构
my %sla8_18 = (
    work_period => {
        start => '08:00',
        end   => '18:00'
    },
    holidays => [
        '2022-01-01',
        '2022-10-01'
        # 其他节假日...
    ]
);

核心功能函数:

use strict;
use warnings;
use DateTime;
use DateTime::Format::Strptime;

# 解析日期字符串为DateTime对象
sub parse_datetime {
    my ($dt_str) = @_;
    my $parser = DateTime::Format::Strptime->new(
        pattern   => '%Y-%m-%d %H:%M',
        time_zone => 'local', # 可按需改为UTC或其他时区
        on_error  => 'croak',
    );
    return $parser->parse_datetime($dt_str);
}

# 判断日期是否为有效工作日
sub is_business_day {
    my ($dt, $calendar) = @_;
    # 排除周末(周六=6,周日=7)
    return 0 if $dt->day_of_week >= 6;
    # 排除节假日
    my $date_str = $dt->ymd;
    foreach my $holiday (@{$calendar->{holidays}}) {
        return 0 if $holiday eq $date_str;
    }
    return 1;
}

# 按业务日历累加小时数
sub add_business_hours {
    my ($start_dt_str, $hours_to_add, $calendar) = @_;
    my $current_dt = parse_datetime($start_dt_str);
    my $remaining_hours = $hours_to_add;

    # 解析业务时段为分钟数,方便计算
    my ($work_start_h, $work_start_m) = split /:/, $calendar->{work_period}->{start};
    my ($work_end_h, $work_end_m) = split /:/, $calendar->{work_period}->{end};
    my $work_start_min = $work_start_h * 60 + $work_start_m;
    my $work_end_min = $work_end_h * 60 + $work_end_m;
    my $daily_work_min = $work_end_min - $work_start_min;

    while ($remaining_hours > 0) {
        # 跳转到下一个有效工作日(如果当前不是)
        until (is_business_day($current_dt, $calendar)) {
            $current_dt->add(days => 1);
            $current_dt->set(hour => $work_start_h, minute => $work_start_m);
        }

        # 计算当前时间在当天工作时段中的剩余时长
        my $current_min = $current_dt->hour * 60 + $current_dt->minute;
        my $remaining_today_min;

        if ($current_min < $work_start_min) {
            $remaining_today_min = $daily_work_min;
            $current_dt->set(hour => $work_start_h, minute => $work_start_m);
        } elsif ($current_min > $work_end_min) {
            $current_dt->add(days => 1);
            $current_dt->set(hour => $work_start_h, minute => $work_start_m);
            next;
        } else {
            $remaining_today_min = $work_end_min - $current_min;
        }

        my $remaining_min = $remaining_hours * 60;
        if ($remaining_min <= $remaining_today_min) {
            # 当天剩余时长足够,直接累加
            $current_dt->add(minutes => $remaining_min);
            $remaining_hours = 0;
        } else {
            # 当天时长不足,扣除后跳到下一个工作日
            $remaining_min -= $remaining_today_min;
            $remaining_hours = $remaining_min / 60;
            $current_dt->add(days => 1);
            $current_dt->set(hour => $work_start_h, minute => $work_start_m);
        }
    }

    return $current_dt->strftime('%Y-%m-%d %H:%M');
}

测试示例

# 示例1:2022-07-18 16:30 添加5小时
my $result1 = add_business_hours('2022-07-18 16:30', 5, \%sla8_18);
print "示例1结果:$result1\n"; # 输出:2022-07-19 12:30

# 示例2:2022-07-15 16:30(周五)添加5小时
my $result2 = add_business_hours('2022-07-15 16:30', 5, \%sla8_18);
print "示例2结果:$result2\n"; # 输出:2022-07-18 12:30

适配已有哈希结构

如果你的%sansSLA、%sla8_18、%slaMax哈希键名或结构与示例不同,只需调整is_business_day和add_business_hours中读取业务时段、节假日的逻辑即可,比如修改$calendar->{xxx}的键名匹配实际定义。

内容的提问来源于stack exchange,提问作者Jimmy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 01:15:39