日期时间列表工具类详解:高效处理日期范围的利器

在日常开发中,我们经常需要处理各种日期时间相关的业务逻辑,比如生成日期范围、计算时间差、处理闰年等。今天给大家分享一个功能强大的日期时间工具类 DateListUtil,它封装了常见的日期操作,让日期处理变得简单高效。

工具类概述

DateListUtil 是一个专门用于处理日期时间列表的工具类,主要功能包括:

  • 生成日期范围内的每一天
  • 生成时间范围内的小时列表
  • 计算日期时间差
  • 处理日期时间的加减操作
  • 闰年判断和日期格式化

核心功能详解

1. 生成日期范围列表

/**
 * 获取两个日期之间的每一天
 * @param beginDate 开始日期 (格式: yyyy-MM-dd)
 * @param endDate 结束日期 (格式: yyyy-MM-dd)
 * @return 日期字符串列表
 */
public static List<String> getEveryday(String beginDate, String endDate) {
    long days = countDay(beginDate, endDate);
    int[] ymd = splitYMD(beginDate);
    List<String> everyDays = new ArrayList();
    everyDays.add(beginDate);

    for(int i = 0; (long)i < days; ++i) {
        ymd = addOneDay(ymd[0], ymd[1], ymd[2]);
        everyDays.add(formatYear(ymd[0]) + "-" + formatMonthDay(ymd[1]) + "-" + formatMonthDay(ymd[2]));
    }
    return everyDays;
}

使用示例:

List<String> dateList = DateListUtil.getEveryday("2024-01-01", "2024-01-05");
// 返回: ["2024-01-01", "2024-01-02", "2024-01-03", "2024-01-04", "2024-01-05"]

2. 生成小时列表

/**
 * 获取两个日期时间之间的小时列表
 * @param beginDate 开始时间 (格式: yyyy-MM-dd HH:mm)
 * @param endDate 结束时间 (格式: yyyy-MM-dd HH:mm)
 * @return 小时字符串列表
 */
public static List<String> getEveryHour(String beginDate, String endDate) {
    long hours = countHour(beginDate, endDate);
    List<String> everyHours = new ArrayList();

    for(int i = 0; (long)i < hours + 1L; ++i) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
        LocalDateTime now = LocalDateTime.parse(beginDate, formatter);
        LocalDateTime oneHourLater = now.plusHours((long)i);
        String date = oneHourLater.format(formatter);
        int[] ymd = splitYMDH(date);
        everyHours.add(formatMonthDay(ymd[3]));
    }
    return everyHours;
}

使用示例:

List<String> hourList = DateListUtil.getEveryHour("2024-01-01 08:00", "2024-01-01 12:00");
// 返回: ["08", "09", "10", "11", "12"]

3. 时间偏移计算

/**
 * 获取指定时间前后的小时时间
 * @param beginDate 基准时间
 * @param hour 小时数
 * @param fal true:加小时, false:减小时
 * @return 计算后的时间字符串
 */
public static String getSpecialdHour(String beginDate, Integer hour, boolean fal) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    LocalDateTime now = LocalDateTime.parse(beginDate, formatter);
    String date;
    if (fal) {
        LocalDateTime oneHourLater = now.plusHours((long)hour);
        date = oneHourLater.format(formatter);
    } else {
        LocalDateTime oneHourLater = now.minus(Duration.ofHours((long)hour));
        date = oneHourLater.format(formatter);
    }
    return date;
}

使用示例:

// 加3小时
String laterTime = DateListUtil.getSpecialdHour("2024-01-01 10:00", 3, true);
// 返回: "2024-01-01 13:00"

// 减2小时  
String earlierTime = DateListUtil.getSpecialdHour("2024-01-01 10:00", 2, false);
// 返回: "2024-01-01 08:00"

4. 时间差计算

// 计算天数差
public static long countDay(String begin, String end) {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    long day = 0L;
    try {
        Date beginDate = format.parse(begin);
        Date endDate = format.parse(end);
        day = (endDate.getTime() - beginDate.getTime()) / 86400000L;
    } catch (ParseException var8) {
        var8.printStackTrace();
    }
    return day;
}

// 计算小时差
public static long countHour(String begin, String end) {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    long hour = 0L;
    try {
        Date beginDate = format.parse(begin);
        Date endDate = format.parse(end);
        hour = (endDate.getTime() - beginDate.getTime()) / 3600000L;
    } catch (ParseException var8) {
        var8.printStackTrace();
    }
    return hour;
}

使用示例:

long days = DateListUtil.countDay("2024-01-01", "2024-01-10"); // 返回: 9
long hours = DateListUtil.countHour("2024-01-01 08:00", "2024-01-01 18:00"); // 返回: 10

技术亮点

1. 混合使用新旧日期API

工具类巧妙地将传统的 SimpleDateFormat 与现代的 LocalDateTime 结合使用:

// 传统API - 用于简单的时间差计算
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date beginDate = format.parse(begin);

// 现代API - 用于复杂的时间操作
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime now = LocalDateTime.parse(beginDate, formatter);

2. 精确的闰年处理

public static boolean isLeapYear(int year) {
    return year >= gregorianCutoverYear ? 
        (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) : 
        (year % 4 == 0);
}

// 闰年和平年的每月天数数组
private static final int[] DAYS_P_MONTH_LY = new int[]{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
private static final int[] DAYS_P_MONTH_CY = new int[]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

3. 日期分量智能处理

// 拆分年月日
public static int[] splitYMD(String date) {
    date = date.replace("-", "").replace(" ", "");
    return new int[]{
        Integer.parseInt(date.substring(0, 4)),   // 年
        Integer.parseInt(date.substring(4, 6)),   // 月  
        Integer.parseInt(date.substring(6, 8))    // 日
    };
}

// 格式化保证两位数
public static String formatMonthDay(int decimal) {
    DecimalFormat df = new DecimalFormat("00");
    return df.format((long)decimal);
}

实际应用场景

1. 报表系统

// 生成月度报表的日期范围
public List<Report> generateMonthlyReport(String month) {
    String startDate = month + "-01";
    String endDate = month + "-31"; // 实际应该计算当月最后一天
    
    List<String> dates = DateListUtil.getEveryday(startDate, endDate);
    List<Report> reports = new ArrayList<>();
    
    for (String date : dates) {
        Report report = generateDailyReport(date);
        reports.add(report);
    }
    return reports;
}

2. 数据统计

// 统计每小时的访问量
public Map<String, Integer> getHourlyVisitStats(String startTime, String endTime) {
    List<String> hours = DateListUtil.getEveryHour(startTime, endTime);
    Map<String, Integer> stats = new LinkedHashMap<>();
    
    for (String hour : hours) {
        int count = getVisitCountByHour(hour);
        stats.put(hour + ":00", count);
    }
    return stats;
}

3. 任务调度

// 计算任务执行时间
public void scheduleTask(String baseTime, int delayHours) {
    String executeTime = DateListUtil.getSpecialdHour(baseTime, delayHours, true);
    
    // 计算任务预计完成时间(假设任务需要2小时)
    String estimatedEndTime = DateListUtil.getSpecialdHour(executeTime, 2, true);
    
    scheduleTaskAt(executeTime, estimatedEndTime);
}

使用注意事项

  1. 日期格式要求

    • 日期格式必须为 yyyy-MM-dd
    • 日期时间格式必须为 yyyy-MM-dd HH:mm
  2. 异常处理

    • 方法内部捕获了 ParseException,但生产环境建议改进异常处理
    • 调用方应确保传入的日期格式正确
  3. 性能考虑

    • 对于大数据量的日期范围,建议分批处理
    • 频繁调用时注意字符串操作的性能开销
  4. 线程安全

    • SimpleDateFormat 不是线程安全的,需要注意使用场景

总结

DateListUtil 工具类为我们提供了一套完整的日期时间处理解决方案,具有以下优点:

  • 功能全面:覆盖了日常开发中大部分的日期时间处理需求
  • 使用简单:方法封装良好,调用方便
  • 算法准确:正确处理了闰年、月末等边界情况
  • 灵活性强:支持多种日期时间操作场景

无论是报表生成、数据分析还是任务调度,这个工具类都能大大提升开发效率。希望这个工具类能够对大家的项目开发有所帮助!

完整代码

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mnsn.framework.boot.utils;

import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class DateListUtil {
    private static transient int gregorianCutoverYear = 1582;
    private static final int[] DAYS_P_MONTH_LY = new int[]{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    private static final int[] DAYS_P_MONTH_CY = new int[]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    public static final String SHORT_DATE_FORMAT = "yyyy-MM-dd";
    private static final int Y = 0;
    private static final int M = 1;
    private static final int D = 2;
    private static final int H = 3;

    public DateListUtil() {
    }

    public static List<String> getEveryday(String beginDate, String endDate) {
        long days = countDay(beginDate, endDate);
        int[] ymd = splitYMD(beginDate);
        List<String> everyDays = new ArrayList();
        everyDays.add(beginDate);

        for(int i = 0; (long)i < days; ++i) {
            ymd = addOneDay(ymd[0], ymd[1], ymd[2]);
            String var10001 = formatYear(ymd[0]);
            everyDays.add(var10001 + "-" + formatMonthDay(ymd[1]) + "-" + formatMonthDay(ymd[2]));
        }

        return everyDays;
    }

    public static List<String> getEveryHour(String beginDate, String endDate) {
        long hours = countHour(beginDate, endDate);
        List<String> everyHours = new ArrayList();

        for(int i = 0; (long)i < hours + 1L; ++i) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
            LocalDateTime now = LocalDateTime.parse(beginDate, formatter);
            LocalDateTime oneHourLater = now.plusHours((long)i);
            String date = oneHourLater.format(formatter);
            int[] ymd = splitYMDH(date);
            everyHours.add(formatMonthDay(ymd[3]));
        }

        return everyHours;
    }

    public static String getSpecialdHour(String beginDate, Integer hour, boolean fal) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
        LocalDateTime now = LocalDateTime.parse(beginDate, formatter);
        String date;
        LocalDateTime oneHourLater;
        if (fal) {
            oneHourLater = now.plusHours((long)hour);
            date = oneHourLater.format(formatter);
        } else {
            oneHourLater = now.minus(Duration.ofHours((long)hour));
            date = oneHourLater.format(formatter);
        }

        return date;
    }

    public static long countDay(String begin, String end) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        long day = 0L;

        try {
            Date beginDate = format.parse(begin);
            Date endDate = format.parse(end);
            day = (endDate.getTime() - beginDate.getTime()) / 86400000L;
        } catch (ParseException var8) {
            var8.printStackTrace();
        }

        return day;
    }

    public static long countHour(String begin, String end) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        long hour = 0L;

        try {
            Date beginDate = format.parse(begin);
            Date endDate = format.parse(end);
            hour = (endDate.getTime() - beginDate.getTime()) / 3600000L;
        } catch (ParseException var8) {
            var8.printStackTrace();
        }

        return hour;
    }

    public static int[] splitYMD(String date) {
        date = date.replace("-", "").replace(" ", "");
        int[] ymd = new int[]{Integer.parseInt(date.substring(0, 4)), Integer.parseInt(date.substring(4, 6)), Integer.parseInt(date.substring(6, 8))};
        return ymd;
    }

    public static int[] splitYMDH(String date) {
        date = date.replace("-", "").replace(" ", "");
        int[] ymd = new int[]{Integer.parseInt(date.substring(0, 4)), Integer.parseInt(date.substring(4, 6)), Integer.parseInt(date.substring(6, 8)), Integer.parseInt(date.substring(8, 10))};
        return ymd;
    }

    private static int[] addOneDay(int year, int month, int day) {
        if (isLeapYear(year)) {
            ++day;
            if (day > DAYS_P_MONTH_LY[month - 1]) {
                ++month;
                if (month > 12) {
                    ++year;
                    month = 1;
                }

                day = 1;
            }
        } else {
            ++day;
            if (day > DAYS_P_MONTH_CY[month - 1]) {
                ++month;
                if (month > 12) {
                    ++year;
                    month = 1;
                }

                day = 1;
            }
        }

        int[] ymd = new int[]{year, month, day};
        return ymd;
    }

    public static boolean isLeapYear(int year) {
        return year >= gregorianCutoverYear ? year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) : year % 4 == 0;
    }

    public static String formatYear(int decimal) {
        DecimalFormat df = new DecimalFormat("0000");
        return df.format((long)decimal);
    }

    public static String formatMonthDay(int decimal) {
        DecimalFormat df = new DecimalFormat("00");
        return df.format((long)decimal);
    }

    public static int convert0to24(int hour) {
        return hour == 0 ? 24 : hour;
    }
}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐