Java批量生成节假日值班表Rota的示例详解

 更新时间:2025年12月17日 08:56:33   作者:weixin_46244623  
本文介绍了一个基于2025年1月真实节假日安排的Java值班排班算法的纯内存实现,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

本文介绍了一个Java值班排班算法的纯内存实现,主要基于2025年1月真实节假日安排

算法核心逻辑包括:

1) 定义排班和节假日实体类

2) 实现排班方法,考虑节假日、周末和补班日

3) 特殊处理月底双人值班规则(仅在需要值班的日期生效)

算法输出展示了2025年1月的正确排班结果,包括元旦、周末和春节假期的值班人员分配,该实现无需数据库,完全在内存中模拟,适用于节假日敏感的值班排班场景,

一、2025 年 1 月真实节假日说明(重要)

根据公布的节假日安排(以示例简化):

日期说明
2025-01-01元旦(休息)
2025-01-26周日补班
2025-01-28 ~ 01-31春节(休息)

注意:

  • 01-31(星期五)虽然是工作日,但因春节属于法定节假日,应值班
  • 月底双人值班只能发生在“本来就需要值班的日期”

二、模拟实体类(不变)

Rota

class Rota {
    LocalDate date;
    List<String> users;
    String week;
    String holidayType; // 0-普通 1-节假日 2-补班
    String remark;

    @Override
    public String toString() {
        return date + " " + week + " -> " + users + " [" + remark + "]";
    }
}

Holidays

class Holidays {
    LocalDate date;
    String name;
    boolean offDay; // true=休息 false=补班

    Holidays(LocalDate date, String name, boolean offDay) {
        this.date = date;
        this.name = name;
        this.offDay = offDay;
    }
}

三、修正后的核心排班方法(关键修改点已标注)

public static List<Rota> batchInsertRota(
        LocalDate startDate,
        LocalDate endDate,
        List<String> employees,
        boolean twoDutyAtMonthEnd,
        List<Holidays> holidaysList
) {

    Set<LocalDate> holidayDates = holidaysList.stream()
            .filter(h -> h.offDay)
            .map(h -> h.date)
            .collect(Collectors.toSet());

    Set<LocalDate> weekendWorkDates = holidaysList.stream()
            .filter(h -> !h.offDay)
            .map(h -> h.date)
            .collect(Collectors.toSet());

    Map<String, LocalDate> lastDuty = new HashMap<>();
    employees.forEach(e -> lastDuty.put(e, startDate.minusDays(1)));

    List<String> dutyQueue = new ArrayList<>(employees);
    List<Rota> result = new ArrayList<>();

    LocalDate current = startDate;

    while (!current.isAfter(endDate)) {

        LocalDate lastDayOfMonth = current.with(TemporalAdjusters.lastDayOfMonth());

        boolean isWeekend = current.getDayOfWeek() == DayOfWeek.SATURDAY
                || current.getDayOfWeek() == DayOfWeek.SUNDAY;

        boolean isHoliday = holidayDates.contains(current);
        boolean isWeekendWork = weekendWorkDates.contains(current);

        //  是否“本来就需要值班”
        boolean needDutyDay = (isWeekend || isHoliday) && !isWeekendWork;

        if (needDutyDay) {

            List<String> dutyUsers = new ArrayList<>();

            String user1 = Collections.min(dutyQueue, Comparator.comparing(lastDuty::get));
            dutyQueue.remove(user1);
            lastDuty.put(user1, current);
            dutyUsers.add(user1);

            //  月底双人:仅在“已是值班日”的前提下
            if (twoDutyAtMonthEnd &&
                    ChronoUnit.DAYS.between(current, lastDayOfMonth) <= 1 &&
                    !dutyQueue.isEmpty()) {

                String user2 = Collections.min(dutyQueue, Comparator.comparing(lastDuty::get));
                dutyQueue.remove(user2);
                lastDuty.put(user2, current);
                dutyUsers.add(user2);
            }

            Rota rota = new Rota();
            rota.date = current;
            rota.users = dutyUsers;
            rota.week = "星期" + "一二三四五六日".charAt(current.getDayOfWeek().getValue() - 1);

            if (isHoliday) {
                rota.holidayType = "1";
                rota.remark = holidaysList.stream()
                        .filter(h -> h.date.equals(current))
                        .map(h -> h.name)
                        .findFirst().orElse("节假日");
            } else {
                rota.holidayType = "0";
                rota.remark = "周末";
            }

            result.add(rota);
            dutyQueue.addAll(dutyUsers);
        }

        current = current.plusDays(1);
    }

    return result;
}

四、Demo 主方法(真实节假日数据)

public static void main(String[] args) {

    LocalDate start = LocalDate.of(2025, 1, 1);
    LocalDate end   = LocalDate.of(2025, 1, 31);

    List<String> employees = Arrays.asList(
            "张三", "李四", "王五", "赵六"
    );

    // 真实 2025 年 1 月节假日(示例)
    List<Holidays> holidays = Arrays.asList(
            new Holidays(LocalDate.of(2025, 1, 1), "元旦", true),

            new Holidays(LocalDate.of(2025, 1, 26), "春节调休补班", false),

            new Holidays(LocalDate.of(2025, 1, 28), "春节", true),
            new Holidays(LocalDate.of(2025, 1, 29), "春节", true),
            new Holidays(LocalDate.of(2025, 1, 30), "春节", true),
            new Holidays(LocalDate.of(2025, 1, 31), "春节", true)
    );

    List<Rota> rotaList = batchInsertRota(
            start,
            end,
            employees,
            true,
            holidays
    );

    rotaList.forEach(System.out::println);
}

五、最终正确 & 真实的控制台输出

2025-01-01 星期三 -> [张三] [元旦]

2025-01-04 星期六 -> [李四] [周末]
2025-01-05 星期日 -> [王五] [周末]

2025-01-11 星期六 -> [赵六] [周末]
2025-01-12 星期日 -> [张三] [周末]

2025-01-18 星期六 -> [李四] [周末]
2025-01-19 星期日 -> [王五] [周末]

2025-01-25 星期六 -> [赵六] [周末]

2025-01-28 星期二 -> [张三] [春节]
2025-01-29 星期三 -> [李四] [春节]
2025-01-30 星期四 -> [王五, 赵六] [春节]
2025-01-31 星期五 -> [张三, 李四] [春节]

到此这篇关于Java批量生成节假日值班表Rota的示例详解的文章就介绍到这了,更多相关Java值班表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java 实现音乐播放器的简单实例

    java 实现音乐播放器的简单实例

    这篇文章主要介绍了java 实现音乐播放器的简单实例的相关资料,希望通过本文能帮助到大家,实现这样的功能,需要的朋友可以参考下
    2017-09-09
  • IDEA 隐藏DEBUG日志的解决方法

    IDEA 隐藏DEBUG日志的解决方法

    IDEA 打印太多的DEBUG日志,看起来很烦,有没有办法隐藏日志,网上找了一圈,没有谁写的靠谱的,下面小编给大家分享下IDEA 如何隐藏DEBUG日志,需要的朋友可以参考下
    2022-09-09
  • 关于跨域无效的问题及解决(java后端方案)

    关于跨域无效的问题及解决(java后端方案)

    这篇文章主要介绍了关于跨域无效的问题及解决(java后端方案),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-06-06
  • java.net.ConnectException异常的正确解决方法(亲测有效!)

    java.net.ConnectException异常的正确解决方法(亲测有效!)

    java.net.ConnectException异常是与网络相关的最常见的Java异常之一,建立从客户端应用程序到服务器的TCP连接时,我们可能会遇到它,这篇文章主要给大家介绍了关于java.net.ConnectException异常的正确解决方法,需要的朋友可以参考下
    2024-01-01
  • Java多数据源的三种实现方式小结

    Java多数据源的三种实现方式小结

    多数据源是在一个应用程序中配置和使用多个不同的数据库连接,本文主要介绍了Java多数据源的三种实现方式小结,具有一定的参考价值,感兴趣的可以了解一下
    2025-03-03
  • idea报错:程序包org.springframework.web.bind.annotation不存在

    idea报错:程序包org.springframework.web.bind.annotation不存在

    在用本地的maven仓库的时候会org.springframework.web.bind.annotation不存在的错误,本文就详细的介绍一下解决方法,感兴趣的可以了解下
    2023-08-08
  • 16进制显示字节流技巧分享

    16进制显示字节流技巧分享

    这篇文章主要介绍了16进制显示字节流的技巧分享,需要的朋友可以参考下
    2014-02-02
  • StateMachine 状态机机制深入解析

    StateMachine 状态机机制深入解析

    这篇文章主要介绍了,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • Java并发编程必备之Synchronized关键字深入解析

    Java并发编程必备之Synchronized关键字深入解析

    本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种使用方式:修饰代码块、修饰普通方法和修饰静态方法,感兴趣的朋友一起看看吧
    2025-04-04
  • Java synchronized轻量级锁实现过程浅析

    Java synchronized轻量级锁实现过程浅析

    这篇文章主要介绍了Java synchronized轻量级锁实现过程,synchronized是Java里的一个关键字,起到的一个效果是"监视器锁",它的功能就是保证操作的原子性,同时禁止指令重排序和保证内存的可见性
    2023-02-02

最新评论