简体中文 繁體中文 English 日本語 Deutsch 한국 사람 بالعربية TÜRKÇE português คนไทย Français

站内搜索

搜索

活动公告

11-02 12:46
10-23 09:32
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,将及时处理!
10-23 09:31
10-23 09:28
通知:签到时间调整为每日4:00(东八区)
10-23 09:26

使用Eclipse开发天数计算系统从基础日期操作到高级时间处理从简单天数差到复杂工作日计算的完整项目实战

3万

主题

349

科技点

3万

积分

大区版主

木柜子打湿

积分
31898

三倍冰淇淋无人之境【一阶】财Doro小樱(小丑装)立华奏以外的星空【二阶】⑨的冰沙

发表于 2025-9-18 14:10:17 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
1. 项目概述和目标

天数计算系统是一个常见的实用工具,广泛应用于项目管理、财务计算、日程安排等领域。本项目的目标是开发一个功能全面的天数计算系统,能够处理从简单的日期差计算到复杂的工作日计算等各种需求。

项目主要功能包括:

• 基本日期操作(创建、格式化、解析)
• 简单天数差计算
• 高级时间处理(时间段计算、日期加减)
• 工作日计算(排除周末和节假日)
• 自定义工作日规则

通过本项目的开发,读者将全面掌握Java中日期时间处理的各个方面,并学会如何在Eclipse环境中构建一个完整的应用程序。

2. 环境搭建(Eclipse配置)

2.1 安装Eclipse IDE

1. 访问Eclipse官方网站(https://www.eclipse.org/)
2. 下载适合你操作系统的Eclipse IDE for Enterprise Java Developers版本
3. 安装Eclipse(解压下载的文件即可)

2.2 配置Java开发环境

1. 确保已安装JDK(推荐JDK 8或更高版本)
2. 在Eclipse中配置JDK:打开Eclipse,选择”Window” > “Preferences”在左侧树形菜单中,展开”Java” > “Installed JREs”点击”Add”按钮,选择已安装的JDK目录
3. 打开Eclipse,选择”Window” > “Preferences”
4. 在左侧树形菜单中,展开”Java” > “Installed JREs”
5. 点击”Add”按钮,选择已安装的JDK目录

• 打开Eclipse,选择”Window” > “Preferences”
• 在左侧树形菜单中,展开”Java” > “Installed JREs”
• 点击”Add”按钮,选择已安装的JDK目录

2.3 创建新项目

1. 在Eclipse中,选择”File” > “New” > “Java Project”
2. 输入项目名称,例如”DayCalculator”
3. 选择合适的JRE版本
4. 点击”Finish”完成项目创建

2.4 项目结构设计

在项目中创建以下包结构:

• com.daycalculator.core:核心计算逻辑
• com.daycalculator.ui:用户界面
• com.daycalculator.util:工具类
• com.daycalculator.exception:自定义异常
• com.daycalculator.test:测试类

3. 基础日期操作

3.1 Java日期API介绍

Java提供了多种日期时间API,主要包括:

• java.util.Date:早期的日期类
• java.util.Calendar:提供更丰富的日期操作
• java.text.SimpleDateFormat:日期格式化和解析
• Java 8引入的java.time包:现代日期时间API

3.2 日期创建和格式化

让我们创建一个基础日期操作类,演示日期的创建和格式化:
  1. package com.daycalculator.core;
  2. import java.text.SimpleDateFormat;
  3. import java.util.Date;
  4. import java.util.Calendar;
  5. public class BasicDateOperations {
  6.    
  7.     // 获取当前日期
  8.     public static Date getCurrentDate() {
  9.         return new Date();
  10.     }
  11.    
  12.     // 使用Calendar创建特定日期
  13.     public static Date createSpecificDate(int year, int month, int day) {
  14.         Calendar calendar = Calendar.getInstance();
  15.         calendar.set(year, month - 1, day); // 月份从0开始
  16.         return calendar.getTime();
  17.     }
  18.    
  19.     // 格式化日期
  20.     public static String formatDate(Date date, String pattern) {
  21.         SimpleDateFormat sdf = new SimpleDateFormat(pattern);
  22.         return sdf.format(date);
  23.     }
  24.    
  25.     // 默认格式化日期 (yyyy-MM-dd)
  26.     public static String formatDefaultDate(Date date) {
  27.         return formatDate(date, "yyyy-MM-dd");
  28.     }
  29. }
复制代码

3.3 日期解析和验证

接下来,我们添加日期解析和验证的方法:
  1. package com.daycalculator.core;
  2. import java.text.ParseException;
  3. import java.text.SimpleDateFormat;
  4. import java.util.Date;
  5. public class DateParser {
  6.    
  7.     // 解析日期字符串
  8.     public static Date parseDate(String dateStr, String pattern) throws ParseException {
  9.         SimpleDateFormat sdf = new SimpleDateFormat(pattern);
  10.         sdf.setLenient(false); // 严格解析,不允许非法日期
  11.         return sdf.parse(dateStr);
  12.     }
  13.    
  14.     // 使用默认格式解析日期 (yyyy-MM-dd)
  15.     public static Date parseDefaultDate(String dateStr) throws ParseException {
  16.         return parseDate(dateStr, "yyyy-MM-dd");
  17.     }
  18.    
  19.     // 验证日期字符串是否有效
  20.     public static boolean isValidDate(String dateStr, String pattern) {
  21.         try {
  22.             parseDate(dateStr, pattern);
  23.             return true;
  24.         } catch (ParseException e) {
  25.             return false;
  26.         }
  27.     }
  28.    
  29.     // 使用默认格式验证日期字符串
  30.     public static boolean isValidDefaultDate(String dateStr) {
  31.         return isValidDate(dateStr, "yyyy-MM-dd");
  32.     }
  33. }
复制代码

4. 简单天数差计算

4.1 基本天数差计算方法

计算两个日期之间的天数差是一个常见需求。我们可以使用以下几种方法:

1. 使用Date类和毫秒差计算
2. 使用Calendar类
3. 使用Java 8的java.time包

4.2 考虑时区因素

在计算日期差时,时区是一个重要因素。我们需要确保两个日期在相同的时区下进行比较。

4.3 代码实现

让我们创建一个天数差计算类:
  1. package com.daycalculator.core;
  2. import java.util.Calendar;
  3. import java.util.Date;
  4. import java.util.TimeZone;
  5. public class DateDifferenceCalculator {
  6.    
  7.     // 使用Date类计算天数差(不考虑时间部分)
  8.     public static int calculateDaysBetween(Date startDate, Date endDate) {
  9.         // 重置时间部分为00:00:00
  10.         Date start = resetTime(startDate);
  11.         Date end = resetTime(endDate);
  12.         
  13.         // 计算毫秒差
  14.         long diff = end.getTime() - start.getTime();
  15.         
  16.         // 转换为天数
  17.         return (int) (diff / (24 * 60 * 60 * 1000));
  18.     }
  19.    
  20.     // 重置日期的时间部分为00:00:00
  21.     private static Date resetTime(Date date) {
  22.         Calendar calendar = Calendar.getInstance();
  23.         calendar.setTime(date);
  24.         calendar.set(Calendar.HOUR_OF_DAY, 0);
  25.         calendar.set(Calendar.MINUTE, 0);
  26.         calendar.set(Calendar.SECOND, 0);
  27.         calendar.set(Calendar.MILLISECOND, 0);
  28.         return calendar.getTime();
  29.     }
  30.    
  31.     // 使用Calendar类计算天数差
  32.     public static int calculateDaysBetweenWithCalendar(Date startDate, Date endDate) {
  33.         Calendar startCalendar = Calendar.getInstance();
  34.         startCalendar.setTime(startDate);
  35.         
  36.         Calendar endCalendar = Calendar.getInstance();
  37.         endCalendar.setTime(endDate);
  38.         
  39.         // 重置时间部分
  40.         resetTimeCalendar(startCalendar);
  41.         resetTimeCalendar(endCalendar);
  42.         
  43.         // 计算完整的天数差
  44.         int days = 0;
  45.         while (startCalendar.before(endCalendar)) {
  46.             startCalendar.add(Calendar.DAY_OF_MONTH, 1);
  47.             days++;
  48.         }
  49.         
  50.         return days;
  51.     }
  52.    
  53.     // 重置Calendar的时间部分
  54.     private static void resetTimeCalendar(Calendar calendar) {
  55.         calendar.set(Calendar.HOUR_OF_DAY, 0);
  56.         calendar.set(Calendar.MINUTE, 0);
  57.         calendar.set(Calendar.SECOND, 0);
  58.         calendar.set(Calendar.MILLISECOND, 0);
  59.     }
  60.    
  61.     // 考虑时区的天数差计算
  62.     public static int calculateDaysBetweenWithTimeZone(Date startDate, Date endDate, TimeZone timeZone) {
  63.         Calendar startCalendar = Calendar.getInstance(timeZone);
  64.         startCalendar.setTime(startDate);
  65.         
  66.         Calendar endCalendar = Calendar.getInstance(timeZone);
  67.         endCalendar.setTime(endDate);
  68.         
  69.         // 重置时间部分
  70.         resetTimeCalendar(startCalendar);
  71.         resetTimeCalendar(endCalendar);
  72.         
  73.         // 计算完整的天数差
  74.         int days = 0;
  75.         while (startCalendar.before(endCalendar)) {
  76.             startCalendar.add(Calendar.DAY_OF_MONTH, 1);
  77.             days++;
  78.         }
  79.         
  80.         return days;
  81.     }
  82. }
复制代码

5. 高级时间处理

5.1 Java 8日期时间API

Java 8引入了全新的日期时间API,位于java.time包中,提供了更直观、更强大的日期时间处理能力。主要类包括:

• LocalDate:表示日期(年月日)
• LocalTime:表示时间(时分秒)
• LocalDateTime:表示日期时间
• ZonedDateTime:带时区的日期时间
• Period:表示日期间隔
• Duration:表示时间间隔

5.2 时间段计算

使用Java 8的API,我们可以更方便地计算时间段:
  1. package com.daycalculator.core;
  2. import java.time.LocalDate;
  3. import java.time.Period;
  4. import java.time.temporal.ChronoUnit;
  5. public class AdvancedDateOperations {
  6.    
  7.     // 使用Java 8 API计算两个日期之间的天数差
  8.     public static long calculateDaysBetweenJava8(LocalDate startDate, LocalDate endDate) {
  9.         return ChronoUnit.DAYS.between(startDate, endDate);
  10.     }
  11.    
  12.     // 计算两个日期之间的月数差
  13.     public static long calculateMonthsBetweenJava8(LocalDate startDate, LocalDate endDate) {
  14.         return ChronoUnit.MONTHS.between(startDate, endDate);
  15.     }
  16.    
  17.     // 计算两个日期之间的年数差
  18.     public static long calculateYearsBetweenJava8(LocalDate startDate, LocalDate endDate) {
  19.         return ChronoUnit.YEARS.between(startDate, endDate);
  20.     }
  21.    
  22.     // 使用Period计算日期间隔
  23.     public static Period calculatePeriodBetween(LocalDate startDate, LocalDate endDate) {
  24.         return Period.between(startDate, endDate);
  25.     }
  26.    
  27.     // 获取Period中的年、月、日
  28.     public static String getPeriodDetails(Period period) {
  29.         return String.format("%d 年, %d 月, %d 日",
  30.             period.getYears(), period.getMonths(), period.getDays());
  31.     }
  32. }
复制代码

5.3 日期加减操作
  1. package com.daycalculator.core;
  2. import java.time.LocalDate;
  3. import java.time.temporal.ChronoUnit;
  4. public class DateArithmeticOperations {
  5.    
  6.     // 日期加天数
  7.     public static LocalDate addDays(LocalDate date, long days) {
  8.         return date.plusDays(days);
  9.     }
  10.    
  11.     // 日期减天数
  12.     public static LocalDate subtractDays(LocalDate date, long days) {
  13.         return date.minusDays(days);
  14.     }
  15.    
  16.     // 日期加月数
  17.     public static LocalDate addMonths(LocalDate date, long months) {
  18.         return date.plusMonths(months);
  19.     }
  20.    
  21.     // 日期减月数
  22.     public static LocalDate subtractMonths(LocalDate date, long months) {
  23.         return date.minusMonths(months);
  24.     }
  25.    
  26.     // 日期加年数
  27.     public static LocalDate addYears(LocalDate date, long years) {
  28.         return date.plusYears(years);
  29.     }
  30.    
  31.     // 日期减年数
  32.     public static LocalDate subtractYears(LocalDate date, long years) {
  33.         return date.minusYears(years);
  34.     }
  35.    
  36.     // 使用ChronoUnit进行日期加减
  37.     public static LocalDate addUnits(LocalDate date, long amount, ChronoUnit unit) {
  38.         return date.plus(amount, unit);
  39.     }
  40.    
  41.     public static LocalDate subtractUnits(LocalDate date, long amount, ChronoUnit unit) {
  42.         return date.minus(amount, unit);
  43.     }
  44. }
复制代码

6. 工作日计算

6.1 工作日概念和规则

工作日通常指周一到周五,不包括周末(周六和周日)。在某些情况下,还需要排除法定节假日。

6.2 排除周末的计算
  1. package com.daycalculator.core;
  2. import java.time.DayOfWeek;
  3. import java.time.LocalDate;
  4. import java.time.temporal.ChronoUnit;
  5. import java.util.List;
  6. import java.util.stream.Collectors;
  7. import java.util.stream.Stream;
  8. public class WorkdayCalculator {
  9.    
  10.     // 计算两个日期之间的工作日数(排除周末)
  11.     public static long calculateWorkdaysBetween(LocalDate startDate, LocalDate endDate) {
  12.         long daysBetween = ChronoUnit.DAYS.between(startDate, endDate) + 1; // 包含开始日期
  13.         
  14.         // 计算完整的周数和剩余天数
  15.         long fullWeeks = daysBetween / 7;
  16.         long remainingDays = daysBetween % 7;
  17.         
  18.         // 计算周末天数
  19.         long weekendDays = fullWeeks * 2;
  20.         
  21.         // 计算剩余天数中的周末天数
  22.         LocalDate currentDate = startDate.plusDays(fullWeeks * 7);
  23.         for (int i = 0; i < remainingDays; i++) {
  24.             if (isWeekend(currentDate)) {
  25.                 weekendDays++;
  26.             }
  27.             currentDate = currentDate.plusDays(1);
  28.         }
  29.         
  30.         return daysBetween - weekendDays;
  31.     }
  32.    
  33.     // 判断是否是周末
  34.     private static boolean isWeekend(LocalDate date) {
  35.         DayOfWeek day = date.getDayOfWeek();
  36.         return day == DayOfWeek.SATURDAY || day == DayOfWeek.SUNDAY;
  37.     }
  38.    
  39.     // 获取两个日期之间的所有工作日
  40.     public static List<LocalDate> getWorkdaysBetween(LocalDate startDate, LocalDate endDate) {
  41.         return Stream.iterate(startDate, date -> date.isBefore(endDate) || date.isEqual(endDate), date -> date.plusDays(1))
  42.                 .filter(date -> !isWeekend(date))
  43.                 .collect(Collectors.toList());
  44.     }
  45. }
复制代码

6.3 排除节假日的计算
  1. package com.daycalculator.core;
  2. import java.time.LocalDate;
  3. import java.util.HashSet;
  4. import java.util.List;
  5. import java.util.Set;
  6. import java.util.stream.Collectors;
  7. import java.util.stream.Stream;
  8. public class HolidayWorkdayCalculator extends WorkdayCalculator {
  9.    
  10.     private Set<LocalDate> holidays = new HashSet<>();
  11.    
  12.     // 添加节假日
  13.     public void addHoliday(LocalDate date) {
  14.         holidays.add(date);
  15.     }
  16.    
  17.     // 批量添加节假日
  18.     public void addHolidays(List<LocalDate> holidayList) {
  19.         holidays.addAll(holidayList);
  20.     }
  21.    
  22.     // 移除节假日
  23.     public void removeHoliday(LocalDate date) {
  24.         holidays.remove(date);
  25.     }
  26.    
  27.     // 判断是否是节假日
  28.     public boolean isHoliday(LocalDate date) {
  29.         return holidays.contains(date);
  30.     }
  31.    
  32.     // 判断是否是工作日(不是周末也不是节假日)
  33.     public boolean isWorkday(LocalDate date) {
  34.         return !isWeekend(date) && !isHoliday(date);
  35.     }
  36.    
  37.     // 计算两个日期之间的工作日数(排除周末和节假日)
  38.     public long calculateWorkdaysBetweenWithHolidays(LocalDate startDate, LocalDate endDate) {
  39.         return Stream.iterate(startDate, date -> date.isBefore(endDate) || date.isEqual(endDate), date -> date.plusDays(1))
  40.                 .filter(date -> isWorkday(date))
  41.                 .count();
  42.     }
  43.    
  44.     // 获取两个日期之间的所有工作日(排除周末和节假日)
  45.     public List<LocalDate> getWorkdaysBetweenWithHolidays(LocalDate startDate, LocalDate endDate) {
  46.         return Stream.iterate(startDate, date -> date.isBefore(endDate) || date.isEqual(endDate), date -> date.plusDays(1))
  47.                 .filter(date -> isWorkday(date))
  48.                 .collect(Collectors.toList());
  49.     }
  50.    
  51.     // 计算从开始日期开始的第n个工作日
  52.     public LocalDate getNthWorkday(LocalDate startDate, int n) {
  53.         LocalDate currentDate = startDate;
  54.         int workdayCount = 0;
  55.         
  56.         while (workdayCount < n) {
  57.             currentDate = currentDate.plusDays(1);
  58.             if (isWorkday(currentDate)) {
  59.                 workdayCount++;
  60.             }
  61.         }
  62.         
  63.         return currentDate;
  64.     }
  65. }
复制代码

6.4 自定义工作日规则
  1. package com.daycalculator.core;
  2. import java.time.DayOfWeek;
  3. import java.time.LocalDate;
  4. import java.util.HashSet;
  5. import java.util.List;
  6. import java.util.Set;
  7. import java.util.stream.Collectors;
  8. import java.util.stream.Stream;
  9. public class CustomWorkdayCalculator {
  10.    
  11.     private Set<DayOfWeek> weekendDays = new HashSet<>();
  12.     private Set<LocalDate> holidays = new HashSet<>();
  13.     private Set<LocalDate> workdaysOnWeekend = new HashSet<>(); // 周末中的特殊工作日
  14.    
  15.     public CustomWorkdayCalculator() {
  16.         // 默认周末是周六和周日
  17.         weekendDays.add(DayOfWeek.SATURDAY);
  18.         weekendDays.add(DayOfWeek.SUNDAY);
  19.     }
  20.    
  21.     // 设置周末日
  22.     public void setWeekendDays(Set<DayOfWeek> days) {
  23.         weekendDays.clear();
  24.         weekendDays.addAll(days);
  25.     }
  26.    
  27.     // 添加周末日
  28.     public void addWeekendDay(DayOfWeek day) {
  29.         weekendDays.add(day);
  30.     }
  31.    
  32.     // 移除周末日
  33.     public void removeWeekendDay(DayOfWeek day) {
  34.         weekendDays.remove(day);
  35.     }
  36.    
  37.     // 添加节假日
  38.     public void addHoliday(LocalDate date) {
  39.         holidays.add(date);
  40.     }
  41.    
  42.     // 批量添加节假日
  43.     public void addHolidays(List<LocalDate> holidayList) {
  44.         holidays.addAll(holidayList);
  45.     }
  46.    
  47.     // 移除节假日
  48.     public void removeHoliday(LocalDate date) {
  49.         holidays.remove(date);
  50.     }
  51.    
  52.     // 添加周末中的特殊工作日
  53.     public void addWorkdayOnWeekend(LocalDate date) {
  54.         workdaysOnWeekend.add(date);
  55.     }
  56.    
  57.     // 移除周末中的特殊工作日
  58.     public void removeWorkdayOnWeekend(LocalDate date) {
  59.         workdaysOnWeekend.remove(date);
  60.     }
  61.    
  62.     // 判断是否是周末
  63.     public boolean isWeekend(LocalDate date) {
  64.         return weekendDays.contains(date.getDayOfWeek());
  65.     }
  66.    
  67.     // 判断是否是节假日
  68.     public boolean isHoliday(LocalDate date) {
  69.         return holidays.contains(date);
  70.     }
  71.    
  72.     // 判断是否是周末中的特殊工作日
  73.     public boolean isWorkdayOnWeekend(LocalDate date) {
  74.         return workdaysOnWeekend.contains(date);
  75.     }
  76.    
  77.     // 判断是否是工作日
  78.     public boolean isWorkday(LocalDate date) {
  79.         if (isWeekend(date)) {
  80.             return isWorkdayOnWeekend(date);
  81.         } else {
  82.             return !isHoliday(date);
  83.         }
  84.     }
  85.    
  86.     // 计算两个日期之间的工作日数
  87.     public long calculateWorkdaysBetween(LocalDate startDate, LocalDate endDate) {
  88.         return Stream.iterate(startDate, date -> date.isBefore(endDate) || date.isEqual(endDate), date -> date.plusDays(1))
  89.                 .filter(date -> isWorkday(date))
  90.                 .count();
  91.     }
  92.    
  93.     // 获取两个日期之间的所有工作日
  94.     public List<LocalDate> getWorkdaysBetween(LocalDate startDate, LocalDate endDate) {
  95.         return Stream.iterate(startDate, date -> date.isBefore(endDate) || date.isEqual(endDate), date -> date.plusDays(1))
  96.                 .filter(date -> isWorkday(date))
  97.                 .collect(Collectors.toList());
  98.     }
  99.    
  100.     // 计算从开始日期开始的第n个工作日
  101.     public LocalDate getNthWorkday(LocalDate startDate, int n) {
  102.         LocalDate currentDate = startDate;
  103.         int workdayCount = 0;
  104.         
  105.         while (workdayCount < n) {
  106.             currentDate = currentDate.plusDays(1);
  107.             if (isWorkday(currentDate)) {
  108.                 workdayCount++;
  109.             }
  110.         }
  111.         
  112.         return currentDate;
  113.     }
  114. }
复制代码

7. 完整项目实现

7.1 项目结构设计

现在,让我们整合所有组件,构建一个完整的天数计算系统。

项目结构如下:
  1. DayCalculator/
  2. ├── src/
  3. │   ├── com/
  4. │   │   └── daycalculator/
  5. │   │       ├── core/
  6. │   │       │   ├── BasicDateOperations.java
  7. │   │       │   ├── DateParser.java
  8. │   │       │   ├── DateDifferenceCalculator.java
  9. │   │       │   ├── AdvancedDateOperations.java
  10. │   │       │   ├── DateArithmeticOperations.java
  11. │   │       │   ├── WorkdayCalculator.java
  12. │   │       │   ├── HolidayWorkdayCalculator.java
  13. │   │       │   └── CustomWorkdayCalculator.java
  14. │   │       ├── ui/
  15. │   │       │   ├── MainFrame.java
  16. │   │       │   ├── DateDifferencePanel.java
  17. │   │       │   ├── WorkdayCalculatorPanel.java
  18. │   │       │   └── HolidayManagerPanel.java
  19. │   │       ├── util/
  20. │   │       │   ├── DateUtils.java
  21. │   │       │   └── HolidayLoader.java
  22. │   │       ├── exception/
  23. │   │       │   └── DateParseException.java
  24. │   │       └── test/
  25. │   │           └── DateCalculatorTest.java
  26. │   └── resources/
  27. │       └── holidays.properties
  28. └── lib/
复制代码

7.2 核心类设计

让我们创建一个核心服务类,整合所有功能:
  1. package com.daycalculator.core;
  2. import java.time.LocalDate;
  3. import java.time.ZoneId;
  4. import java.util.Date;
  5. import java.util.List;
  6. import java.util.TimeZone;
  7. import java.util.HashSet;
  8. import java.util.Set;
  9. public class DayCalculatorService {
  10.    
  11.     private CustomWorkdayCalculator workdayCalculator;
  12.    
  13.     public DayCalculatorService() {
  14.         this.workdayCalculator = new CustomWorkdayCalculator();
  15.     }
  16.    
  17.     // 基本日期操作
  18.    
  19.     public Date getCurrentDate() {
  20.         return BasicDateOperations.getCurrentDate();
  21.     }
  22.    
  23.     public Date createSpecificDate(int year, int month, int day) {
  24.         return BasicDateOperations.createSpecificDate(year, month, day);
  25.     }
  26.    
  27.     public String formatDate(Date date, String pattern) {
  28.         return BasicDateOperations.formatDate(date, pattern);
  29.     }
  30.    
  31.     public String formatDefaultDate(Date date) {
  32.         return BasicDateOperations.formatDefaultDate(date);
  33.     }
  34.    
  35.     public Date parseDate(String dateStr, String pattern) throws Exception {
  36.         try {
  37.             return DateParser.parseDate(dateStr, pattern);
  38.         } catch (Exception e) {
  39.             throw new Exception("日期解析错误: " + e.getMessage(), e);
  40.         }
  41.     }
  42.    
  43.     public Date parseDefaultDate(String dateStr) throws Exception {
  44.         try {
  45.             return DateParser.parseDefaultDate(dateStr);
  46.         } catch (Exception e) {
  47.             throw new Exception("日期解析错误: " + e.getMessage(), e);
  48.         }
  49.     }
  50.    
  51.     public boolean isValidDate(String dateStr, String pattern) {
  52.         return DateParser.isValidDate(dateStr, pattern);
  53.     }
  54.    
  55.     public boolean isValidDefaultDate(String dateStr) {
  56.         return DateParser.isValidDefaultDate(dateStr);
  57.     }
  58.    
  59.     // 日期差计算
  60.    
  61.     public int calculateDaysBetween(Date startDate, Date endDate) {
  62.         return DateDifferenceCalculator.calculateDaysBetween(startDate, endDate);
  63.     }
  64.    
  65.     public int calculateDaysBetweenWithCalendar(Date startDate, Date endDate) {
  66.         return DateDifferenceCalculator.calculateDaysBetweenWithCalendar(startDate, endDate);
  67.     }
  68.    
  69.     public int calculateDaysBetweenWithTimeZone(Date startDate, Date endDate, String timeZoneId) {
  70.         return DateDifferenceCalculator.calculateDaysBetweenWithTimeZone(
  71.             startDate, endDate, TimeZone.getTimeZone(timeZoneId));
  72.     }
  73.    
  74.     // Java 8 日期操作
  75.    
  76.     public LocalDate convertToLocalDate(Date date) {
  77.         return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
  78.     }
  79.    
  80.     public Date convertToDate(LocalDate localDate) {
  81.         return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
  82.     }
  83.    
  84.     public long calculateDaysBetweenJava8(LocalDate startDate, LocalDate endDate) {
  85.         return AdvancedDateOperations.calculateDaysBetweenJava8(startDate, endDate);
  86.     }
  87.    
  88.     public long calculateMonthsBetweenJava8(LocalDate startDate, LocalDate endDate) {
  89.         return AdvancedDateOperations.calculateMonthsBetweenJava8(startDate, endDate);
  90.     }
  91.    
  92.     public long calculateYearsBetweenJava8(LocalDate startDate, LocalDate endDate) {
  93.         return AdvancedDateOperations.calculateYearsBetweenJava8(startDate, endDate);
  94.     }
  95.    
  96.     public String calculatePeriodBetween(LocalDate startDate, LocalDate endDate) {
  97.         return AdvancedDateOperations.getPeriodDetails(
  98.             AdvancedDateOperations.calculatePeriodBetween(startDate, endDate));
  99.     }
  100.    
  101.     // 日期算术运算
  102.    
  103.     public LocalDate addDays(LocalDate date, long days) {
  104.         return DateArithmeticOperations.addDays(date, days);
  105.     }
  106.    
  107.     public LocalDate subtractDays(LocalDate date, long days) {
  108.         return DateArithmeticOperations.subtractDays(date, days);
  109.     }
  110.    
  111.     public LocalDate addMonths(LocalDate date, long months) {
  112.         return DateArithmeticOperations.addMonths(date, months);
  113.     }
  114.    
  115.     public LocalDate subtractMonths(LocalDate date, long months) {
  116.         return DateArithmeticOperations.subtractMonths(date, months);
  117.     }
  118.    
  119.     public LocalDate addYears(LocalDate date, long years) {
  120.         return DateArithmeticOperations.addYears(date, years);
  121.     }
  122.    
  123.     public LocalDate subtractYears(LocalDate date, long years) {
  124.         return DateArithmeticOperations.subtractYears(date, years);
  125.     }
  126.    
  127.     // 工作日计算
  128.    
  129.     public void setWeekendDays(List<java.time.DayOfWeek> days) {
  130.         workdayCalculator.setWeekendDays(new HashSet<>(days));
  131.     }
  132.    
  133.     public void addHoliday(LocalDate date) {
  134.         workdayCalculator.addHoliday(date);
  135.     }
  136.    
  137.     public void addHolidays(List<LocalDate> holidayList) {
  138.         workdayCalculator.addHolidays(holidayList);
  139.     }
  140.    
  141.     public void removeHoliday(LocalDate date) {
  142.         workdayCalculator.removeHoliday(date);
  143.     }
  144.    
  145.     public void addWorkdayOnWeekend(LocalDate date) {
  146.         workdayCalculator.addWorkdayOnWeekend(date);
  147.     }
  148.    
  149.     public void removeWorkdayOnWeekend(LocalDate date) {
  150.         workdayCalculator.removeWorkdayOnWeekend(date);
  151.     }
  152.    
  153.     public long calculateWorkdaysBetween(LocalDate startDate, LocalDate endDate) {
  154.         return workdayCalculator.calculateWorkdaysBetween(startDate, endDate);
  155.     }
  156.    
  157.     public List<LocalDate> getWorkdaysBetween(LocalDate startDate, LocalDate endDate) {
  158.         return workdayCalculator.getWorkdaysBetween(startDate, endDate);
  159.     }
  160.    
  161.     public LocalDate getNthWorkday(LocalDate startDate, int n) {
  162.         return workdayCalculator.getNthWorkday(startDate, n);
  163.     }
  164. }
复制代码

7.3 用户界面设计

让我们创建一个简单的Swing用户界面:
  1. package com.daycalculator.ui;
  2. import javax.swing.*;
  3. import java.awt.*;
  4. import java.awt.event.ActionEvent;
  5. import java.awt.event.ActionListener;
  6. import java.time.LocalDate;
  7. import java.time.format.DateTimeFormatter;
  8. import java.time.format.DateTimeParseException;
  9. import java.util.Arrays;
  10. import java.util.HashSet;
  11. import java.util.Set;
  12. import java.util.TimeZone;
  13. public class MainFrame extends JFrame {
  14.    
  15.     private DayCalculatorService service;
  16.     private JTabbedPane tabbedPane;
  17.    
  18.     public MainFrame() {
  19.         service = new DayCalculatorService();
  20.         initUI();
  21.     }
  22.    
  23.     private void initUI() {
  24.         setTitle("天数计算系统");
  25.         setSize(800, 600);
  26.         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  27.         setLocationRelativeTo(null);
  28.         
  29.         tabbedPane = new JTabbedPane();
  30.         
  31.         // 添加各个功能面板
  32.         tabbedPane.addTab("日期差计算", new DateDifferencePanel(service));
  33.         tabbedPane.addTab("工作日计算", new WorkdayCalculatorPanel(service));
  34.         tabbedPane.addTab("节假日管理", new HolidayManagerPanel(service));
  35.         
  36.         add(tabbedPane, BorderLayout.CENTER);
  37.     }
  38.    
  39.     public static void main(String[] args) {
  40.         SwingUtilities.invokeLater(() -> {
  41.             MainFrame frame = new MainFrame();
  42.             frame.setVisible(true);
  43.         });
  44.     }
  45. }
  46. class DateDifferencePanel extends JPanel {
  47.    
  48.     private DayCalculatorService service;
  49.     private JTextField startDateField;
  50.     private JTextField endDateField;
  51.     private JButton calculateButton;
  52.     private JTextArea resultArea;
  53.    
  54.     public DateDifferencePanel(DayCalculatorService service) {
  55.         this.service = service;
  56.         initUI();
  57.     }
  58.    
  59.     private void initUI() {
  60.         setLayout(new BorderLayout(10, 10));
  61.         setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
  62.         
  63.         // 输入面板
  64.         JPanel inputPanel = new JPanel(new GridLayout(2, 2, 5, 5));
  65.         
  66.         inputPanel.add(new JLabel("开始日期 (yyyy-MM-dd):"));
  67.         startDateField = new JTextField();
  68.         inputPanel.add(startDateField);
  69.         
  70.         inputPanel.add(new JLabel("结束日期 (yyyy-MM-dd):"));
  71.         endDateField = new JTextField();
  72.         inputPanel.add(endDateField);
  73.         
  74.         // 按钮面板
  75.         JPanel buttonPanel = new JPanel();
  76.         calculateButton = new JButton("计算");
  77.         calculateButton.addActionListener(new CalculateButtonListener());
  78.         buttonPanel.add(calculateButton);
  79.         
  80.         // 结果面板
  81.         resultArea = new JTextArea(10, 30);
  82.         resultArea.setEditable(false);
  83.         JScrollPane scrollPane = new JScrollPane(resultArea);
  84.         
  85.         // 添加组件
  86.         add(inputPanel, BorderLayout.NORTH);
  87.         add(buttonPanel, BorderLayout.CENTER);
  88.         add(scrollPane, BorderLayout.SOUTH);
  89.     }
  90.    
  91.     private class CalculateButtonListener implements ActionListener {
  92.         @Override
  93.         public void actionPerformed(ActionEvent e) {
  94.             try {
  95.                 String startDateStr = startDateField.getText();
  96.                 String endDateStr = endDateField.getText();
  97.                
  98.                 if (startDateStr.isEmpty() || endDateStr.isEmpty()) {
  99.                     JOptionPane.showMessageDialog(DateDifferencePanel.this,
  100.                         "请输入开始日期和结束日期", "错误", JOptionPane.ERROR_MESSAGE);
  101.                     return;
  102.                 }
  103.                
  104.                 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
  105.                 LocalDate startDate = LocalDate.parse(startDateStr, formatter);
  106.                 LocalDate endDate = LocalDate.parse(endDateStr, formatter);
  107.                
  108.                 // 计算各种日期差
  109.                 long daysBetween = service.calculateDaysBetweenJava8(startDate, endDate);
  110.                 long monthsBetween = service.calculateMonthsBetweenJava8(startDate, endDate);
  111.                 long yearsBetween = service.calculateYearsBetweenJava8(startDate, endDate);
  112.                 String periodBetween = service.calculatePeriodBetween(startDate, endDate);
  113.                
  114.                 // 显示结果
  115.                 StringBuilder result = new StringBuilder();
  116.                 result.append("日期差计算结果:\n\n");
  117.                 result.append("天数差: ").append(daysBetween).append(" 天\n");
  118.                 result.append("月数差: ").append(monthsBetween).append(" 个月\n");
  119.                 result.append("年数差: ").append(yearsBetween).append(" 年\n");
  120.                 result.append("详细间隔: ").append(periodBetween).append("\n");
  121.                
  122.                 resultArea.setText(result.toString());
  123.                
  124.             } catch (DateTimeParseException ex) {
  125.                 JOptionPane.showMessageDialog(DateDifferencePanel.this,
  126.                     "日期格式错误,请使用 yyyy-MM-dd 格式", "错误", JOptionPane.ERROR_MESSAGE);
  127.             } catch (Exception ex) {
  128.                 JOptionPane.showMessageDialog(DateDifferencePanel.this,
  129.                     "计算错误: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
  130.             }
  131.         }
  132.     }
  133. }
  134. class WorkdayCalculatorPanel extends JPanel {
  135.    
  136.     private DayCalculatorService service;
  137.     private JTextField startDateField;
  138.     private JTextField endDateField;
  139.     private JButton calculateButton;
  140.     private JTextArea resultArea;
  141.     private JComboBox<String> weekendRuleCombo;
  142.     private JCheckBox excludeHolidaysCheck;
  143.    
  144.     public WorkdayCalculatorPanel(DayCalculatorService service) {
  145.         this.service = service;
  146.         initUI();
  147.     }
  148.    
  149.     private void initUI() {
  150.         setLayout(new BorderLayout(10, 10));
  151.         setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
  152.         
  153.         // 输入面板
  154.         JPanel inputPanel = new JPanel(new GridLayout(4, 2, 5, 5));
  155.         
  156.         inputPanel.add(new JLabel("开始日期 (yyyy-MM-dd):"));
  157.         startDateField = new JTextField();
  158.         inputPanel.add(startDateField);
  159.         
  160.         inputPanel.add(new JLabel("结束日期 (yyyy-MM-dd):"));
  161.         endDateField = new JTextField();
  162.         inputPanel.add(endDateField);
  163.         
  164.         inputPanel.add(new JLabel("周末规则:"));
  165.         weekendRuleCombo = new JComboBox<>(new String[]{
  166.             "周六周日为周末", "仅周日为周末", "周五周六为周末", "自定义周末"
  167.         });
  168.         inputPanel.add(weekendRuleCombo);
  169.         
  170.         excludeHolidaysCheck = new JCheckBox("排除节假日");
  171.         inputPanel.add(excludeHolidaysCheck);
  172.         inputPanel.add(new JLabel()); // 占位
  173.         
  174.         // 按钮面板
  175.         JPanel buttonPanel = new JPanel();
  176.         calculateButton = new JButton("计算工作日");
  177.         calculateButton.addActionListener(new CalculateButtonListener());
  178.         buttonPanel.add(calculateButton);
  179.         
  180.         // 结果面板
  181.         resultArea = new JTextArea(10, 30);
  182.         resultArea.setEditable(false);
  183.         JScrollPane scrollPane = new JScrollPane(resultArea);
  184.         
  185.         // 添加组件
  186.         add(inputPanel, BorderLayout.NORTH);
  187.         add(buttonPanel, BorderLayout.CENTER);
  188.         add(scrollPane, BorderLayout.SOUTH);
  189.     }
  190.    
  191.     private class CalculateButtonListener implements ActionListener {
  192.         @Override
  193.         public void actionPerformed(ActionEvent e) {
  194.             try {
  195.                 String startDateStr = startDateField.getText();
  196.                 String endDateStr = endDateField.getText();
  197.                
  198.                 if (startDateStr.isEmpty() || endDateStr.isEmpty()) {
  199.                     JOptionPane.showMessageDialog(WorkdayCalculatorPanel.this,
  200.                         "请输入开始日期和结束日期", "错误", JOptionPane.ERROR_MESSAGE);
  201.                     return;
  202.                 }
  203.                
  204.                 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
  205.                 LocalDate startDate = LocalDate.parse(startDateStr, formatter);
  206.                 LocalDate endDate = LocalDate.parse(endDateStr, formatter);
  207.                
  208.                 // 设置周末规则
  209.                 int weekendRuleIndex = weekendRuleCombo.getSelectedIndex();
  210.                 switch (weekendRuleIndex) {
  211.                     case 0: // 周六周日为周末
  212.                         service.setWeekendDays(Arrays.asList(
  213.                             java.time.DayOfWeek.SATURDAY,
  214.                             java.time.DayOfWeek.SUNDAY));
  215.                         break;
  216.                     case 1: // 仅周日为周末
  217.                         service.setWeekendDays(Arrays.asList(
  218.                             java.time.DayOfWeek.SUNDAY));
  219.                         break;
  220.                     case 2: // 周五周六为周末
  221.                         service.setWeekendDays(Arrays.asList(
  222.                             java.time.DayOfWeek.FRIDAY,
  223.                             java.time.DayOfWeek.SATURDAY));
  224.                         break;
  225.                     case 3: // 自定义周末
  226.                         // 这里可以添加更复杂的自定义周末设置界面
  227.                         JOptionPane.showMessageDialog(WorkdayCalculatorPanel.this,
  228.                             "自定义周末功能待实现", "提示", JOptionPane.INFORMATION_MESSAGE);
  229.                         return;
  230.                 }
  231.                
  232.                 // 如果需要排除节假日,添加一些示例节假日
  233.                 if (excludeHolidaysCheck.isSelected()) {
  234.                     // 这里应该从数据库或配置文件加载节假日
  235.                     // 这里仅添加几个示例节假日
  236.                     service.addHoliday(LocalDate.of(2023, 1, 1)); // 元旦
  237.                     service.addHoliday(LocalDate.of(2023, 1, 21)); // 春节
  238.                     service.addHoliday(LocalDate.of(2023, 1, 22)); // 春节
  239.                     service.addHoliday(LocalDate.of(2023, 10, 1)); // 国庆节
  240.                 }
  241.                
  242.                 // 计算工作日
  243.                 long workdays = service.calculateWorkdaysBetween(startDate, endDate);
  244.                
  245.                 // 显示结果
  246.                 StringBuilder result = new StringBuilder();
  247.                 result.append("工作日计算结果:\n\n");
  248.                 result.append("工作日数量: ").append(workdays).append(" 天\n");
  249.                
  250.                 // 获取所有工作日列表
  251.                 java.util.List<LocalDate> workdayList = service.getWorkdaysBetween(startDate, endDate);
  252.                 result.append("\n工作日列表 (前10个):\n");
  253.                 for (int i = 0; i < Math.min(10, workdayList.size()); i++) {
  254.                     result.append(workdayList.get(i).toString()).append("\n");
  255.                 }
  256.                 if (workdayList.size() > 10) {
  257.                     result.append("... 共 ").append(workdayList.size()).append(" 个工作日\n");
  258.                 }
  259.                
  260.                 resultArea.setText(result.toString());
  261.                
  262.             } catch (DateTimeParseException ex) {
  263.                 JOptionPane.showMessageDialog(WorkdayCalculatorPanel.this,
  264.                     "日期格式错误,请使用 yyyy-MM-dd 格式", "错误", JOptionPane.ERROR_MESSAGE);
  265.             } catch (Exception ex) {
  266.                 JOptionPane.showMessageDialog(WorkdayCalculatorPanel.this,
  267.                     "计算错误: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
  268.             }
  269.         }
  270.     }
  271. }
  272. class HolidayManagerPanel extends JPanel {
  273.    
  274.     private DayCalculatorService service;
  275.     private JTextField holidayField;
  276.     private JButton addButton;
  277.     private JButton removeButton;
  278.     private JTextArea holidayListArea;
  279.     private JButton loadSampleHolidaysButton;
  280.    
  281.     public HolidayManagerPanel(DayCalculatorService service) {
  282.         this.service = service;
  283.         initUI();
  284.     }
  285.    
  286.     private void initUI() {
  287.         setLayout(new BorderLayout(10, 10));
  288.         setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
  289.         
  290.         // 输入面板
  291.         JPanel inputPanel = new JPanel(new GridLayout(1, 2, 5, 5));
  292.         
  293.         inputPanel.add(new JLabel("节假日日期 (yyyy-MM-dd):"));
  294.         holidayField = new JTextField();
  295.         inputPanel.add(holidayField);
  296.         
  297.         // 按钮面板
  298.         JPanel buttonPanel = new JPanel(new GridLayout(1, 3, 5, 5));
  299.         addButton = new JButton("添加节假日");
  300.         addButton.addActionListener(new AddButtonListener());
  301.         removeButton = new JButton("移除节假日");
  302.         removeButton.addActionListener(new RemoveButtonListener());
  303.         loadSampleHolidaysButton = new JButton("加载示例节假日");
  304.         loadSampleHolidaysButton.addActionListener(new LoadSampleHolidaysListener());
  305.         buttonPanel.add(addButton);
  306.         buttonPanel.add(removeButton);
  307.         buttonPanel.add(loadSampleHolidaysButton);
  308.         
  309.         // 节假日列表面板
  310.         holidayListArea = new JTextArea(10, 30);
  311.         holidayListArea.setEditable(false);
  312.         JScrollPane scrollPane = new JScrollPane(holidayListArea);
  313.         
  314.         // 添加组件
  315.         add(inputPanel, BorderLayout.NORTH);
  316.         add(buttonPanel, BorderLayout.CENTER);
  317.         add(scrollPane, BorderLayout.SOUTH);
  318.     }
  319.    
  320.     private void updateHolidayList() {
  321.         // 由于我们的服务类没有提供获取节假日列表的方法,这里暂时显示示例文本
  322.         holidayListArea.setText("节假日列表功能待实现\n\n" +
  323.             "已添加的节假日将影响工作日计算结果。\n" +
  324.             "使用'加载示例节假日'按钮添加一些示例节假日。");
  325.     }
  326.    
  327.     private class AddButtonListener implements ActionListener {
  328.         @Override
  329.         public void actionPerformed(ActionEvent e) {
  330.             try {
  331.                 String holidayStr = holidayField.getText();
  332.                
  333.                 if (holidayStr.isEmpty()) {
  334.                     JOptionPane.showMessageDialog(HolidayManagerPanel.this,
  335.                         "请输入节假日日期", "错误", JOptionPane.ERROR_MESSAGE);
  336.                     return;
  337.                 }
  338.                
  339.                 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
  340.                 LocalDate holidayDate = LocalDate.parse(holidayStr, formatter);
  341.                
  342.                 // 添加节假日
  343.                 service.addHoliday(holidayDate);
  344.                
  345.                 // 清空输入框
  346.                 holidayField.setText("");
  347.                
  348.                 // 更新节假日列表
  349.                 updateHolidayList();
  350.                
  351.                 JOptionPane.showMessageDialog(HolidayManagerPanel.this,
  352.                     "节假日添加成功", "成功", JOptionPane.INFORMATION_MESSAGE);
  353.                
  354.             } catch (DateTimeParseException ex) {
  355.                 JOptionPane.showMessageDialog(HolidayManagerPanel.this,
  356.                     "日期格式错误,请使用 yyyy-MM-dd 格式", "错误", JOptionPane.ERROR_MESSAGE);
  357.             } catch (Exception ex) {
  358.                 JOptionPane.showMessageDialog(HolidayManagerPanel.this,
  359.                     "添加失败: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
  360.             }
  361.         }
  362.     }
  363.    
  364.     private class RemoveButtonListener implements ActionListener {
  365.         @Override
  366.         public void actionPerformed(ActionEvent e) {
  367.             try {
  368.                 String holidayStr = holidayField.getText();
  369.                
  370.                 if (holidayStr.isEmpty()) {
  371.                     JOptionPane.showMessageDialog(HolidayManagerPanel.this,
  372.                         "请输入要移除的节假日日期", "错误", JOptionPane.ERROR_MESSAGE);
  373.                     return;
  374.                 }
  375.                
  376.                 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
  377.                 LocalDate holidayDate = LocalDate.parse(holidayStr, formatter);
  378.                
  379.                 // 移除节假日
  380.                 service.removeHoliday(holidayDate);
  381.                
  382.                 // 清空输入框
  383.                 holidayField.setText("");
  384.                
  385.                 // 更新节假日列表
  386.                 updateHolidayList();
  387.                
  388.                 JOptionPane.showMessageDialog(HolidayManagerPanel.this,
  389.                     "节假日移除成功", "成功", JOptionPane.INFORMATION_MESSAGE);
  390.                
  391.             } catch (DateTimeParseException ex) {
  392.                 JOptionPane.showMessageDialog(HolidayManagerPanel.this,
  393.                     "日期格式错误,请使用 yyyy-MM-dd 格式", "错误", JOptionPane.ERROR_MESSAGE);
  394.             } catch (Exception ex) {
  395.                 JOptionPane.showMessageDialog(HolidayManagerPanel.this,
  396.                     "移除失败: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
  397.             }
  398.         }
  399.     }
  400.    
  401.     private class LoadSampleHolidaysListener implements ActionListener {
  402.         @Override
  403.         public void actionPerformed(ActionEvent e) {
  404.             try {
  405.                 // 添加一些示例节假日
  406.                 service.addHoliday(LocalDate.of(2023, 1, 1));   // 元旦
  407.                 service.addHoliday(LocalDate.of(2023, 1, 21));  // 春节
  408.                 service.addHoliday(LocalDate.of(2023, 1, 22));  // 春节
  409.                 service.addHoliday(LocalDate.of(2023, 1, 23));  // 春节
  410.                 service.addHoliday(LocalDate.of(2023, 1, 24));  // 春节
  411.                 service.addHoliday(LocalDate.of(2023, 1, 25));  // 春节
  412.                 service.addHoliday(LocalDate.of(2023, 1, 26));  // 春节
  413.                 service.addHoliday(LocalDate.of(2023, 1, 27));  // 春节
  414.                 service.addHoliday(LocalDate.of(2023, 4, 5));   // 清明节
  415.                 service.addHoliday(LocalDate.of(2023, 5, 1));   // 劳动节
  416.                 service.addHoliday(LocalDate.of(2023, 6, 22));  // 端午节
  417.                 service.addHoliday(LocalDate.of(2023, 6, 23));  // 端午节
  418.                 service.addHoliday(LocalDate.of(2023, 6, 24));  // 端午节
  419.                 service.addHoliday(LocalDate.of(2023, 9, 29));  // 中秋节
  420.                 service.addHoliday(LocalDate.of(2023, 9, 30));  // 中秋节
  421.                 service.addHoliday(LocalDate.of(2023, 10, 1));  // 国庆节
  422.                 service.addHoliday(LocalDate.of(2023, 10, 2));  // 国庆节
  423.                 service.addHoliday(LocalDate.of(2023, 10, 3));  // 国庆节
  424.                 service.addHoliday(LocalDate.of(2023, 10, 4));  // 国庆节
  425.                 service.addHoliday(LocalDate.of(2023, 10, 5));  // 国庆节
  426.                 service.addHoliday(LocalDate.of(2023, 10, 6));  // 国庆节
  427.                
  428.                 // 更新节假日列表
  429.                 updateHolidayList();
  430.                
  431.                 JOptionPane.showMessageDialog(HolidayManagerPanel.this,
  432.                     "示例节假日加载成功", "成功", JOptionPane.INFORMATION_MESSAGE);
  433.                
  434.             } catch (Exception ex) {
  435.                 JOptionPane.showMessageDialog(HolidayManagerPanel.this,
  436.                     "加载失败: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
  437.             }
  438.         }
  439.     }
  440. }
复制代码

7.4 测试用例

让我们创建一些测试用例来验证我们的系统:
  1. package com.daycalculator.test;
  2. import com.daycalculator.core.DayCalculatorService;
  3. import org.junit.jupiter.api.Test;
  4. import static org.junit.jupiter.api.Assertions.*;
  5. import java.time.LocalDate;
  6. import java.time.Month;
  7. import java.util.Arrays;
  8. import java.util.List;
  9. public class DateCalculatorTest {
  10.    
  11.     private DayCalculatorService service = new DayCalculatorService();
  12.    
  13.     @Test
  14.     public void testCalculateDaysBetween() {
  15.         LocalDate startDate = LocalDate.of(2023, Month.JANUARY, 1);
  16.         LocalDate endDate = LocalDate.of(2023, Month.JANUARY, 10);
  17.         
  18.         long days = service.calculateDaysBetweenJava8(startDate, endDate);
  19.         assertEquals(9, days); // 不包括开始日期
  20.     }
  21.    
  22.     @Test
  23.     public void testCalculateWorkdaysBetween() {
  24.         LocalDate startDate = LocalDate.of(2023, Month.JANUARY, 2); // 周一
  25.         LocalDate endDate = LocalDate.of(2023, Month.JANUARY, 8); // 周日
  26.         
  27.         long workdays = service.calculateWorkdaysBetween(startDate, endDate);
  28.         assertEquals(5, workdays); // 周一到周五
  29.     }
  30.    
  31.     @Test
  32.     public void testCalculateWorkdaysWithHolidays() {
  33.         LocalDate startDate = LocalDate.of(2023, Month.JANUARY, 2); // 周一
  34.         LocalDate endDate = LocalDate.of(2023, Month.JANUARY, 8); // 周日
  35.         
  36.         // 添加一个节假日(周三)
  37.         service.addHoliday(LocalDate.of(2023, Month.JANUARY, 4));
  38.         
  39.         long workdays = service.calculateWorkdaysBetween(startDate, endDate);
  40.         assertEquals(4, workdays); // 周一、周二、周四、周五
  41.     }
  42.    
  43.     @Test
  44.     public void testDateArithmetic() {
  45.         LocalDate date = LocalDate.of(2023, Month.JANUARY, 1);
  46.         
  47.         LocalDate plus10Days = service.addDays(date, 10);
  48.         assertEquals(LocalDate.of(2023, Month.JANUARY, 11), plus10Days);
  49.         
  50.         LocalDate minus2Months = service.subtractMonths(date, 2);
  51.         assertEquals(LocalDate.of(2022, Month.NOVEMBER, 1), minus2Months);
  52.         
  53.         LocalDate plus1Year = service.addYears(date, 1);
  54.         assertEquals(LocalDate.of(2024, Month.JANUARY, 1), plus1Year);
  55.     }
  56.    
  57.     @Test
  58.     public void testGetNthWorkday() {
  59.         LocalDate startDate = LocalDate.of(2023, Month.JANUARY, 1); // 周日
  60.         
  61.         // 第5个工作日应该是周五
  62.         LocalDate nthWorkday = service.getNthWorkday(startDate, 5);
  63.         assertEquals(LocalDate.of(2023, Month.JANUARY, 6), nthWorkday);
  64.     }
  65.    
  66.     @Test
  67.     public void testCustomWeekend() {
  68.         // 设置周末只有周日
  69.         service.setWeekendDays(Arrays.asList(java.time.DayOfWeek.SUNDAY));
  70.         
  71.         LocalDate startDate = LocalDate.of(2023, Month.JANUARY, 2); // 周一
  72.         LocalDate endDate = LocalDate.of(2023, Month.JANUARY, 8); // 周日
  73.         
  74.         long workdays = service.calculateWorkdaysBetween(startDate, endDate);
  75.         assertEquals(6, workdays); // 周一到周六
  76.     }
  77. }
复制代码

8. 扩展功能和优化

8.1 性能优化

对于大量日期计算,我们可以进行一些性能优化:
  1. package com.daycalculator.core;
  2. import java.time.LocalDate;
  3. import java.util.List;
  4. import java.util.concurrent.ConcurrentHashMap;
  5. import java.util.concurrent.ConcurrentMap;
  6. public class OptimizedWorkdayCalculator extends CustomWorkdayCalculator {
  7.    
  8.     // 缓存计算结果
  9.     private ConcurrentMap<String, Long> workdayCache = new ConcurrentHashMap<>();
  10.     private ConcurrentMap<String, List<LocalDate>> workdayListCache = new ConcurrentHashMap<>();
  11.    
  12.     @Override
  13.     public long calculateWorkdaysBetween(LocalDate startDate, LocalDate endDate) {
  14.         String cacheKey = startDate.toString() + "_" + endDate.toString();
  15.         
  16.         // 检查缓存
  17.         Long cachedResult = workdayCache.get(cacheKey);
  18.         if (cachedResult != null) {
  19.             return cachedResult;
  20.         }
  21.         
  22.         // 计算结果
  23.         long result = super.calculateWorkdaysBetween(startDate, endDate);
  24.         
  25.         // 存入缓存
  26.         workdayCache.put(cacheKey, result);
  27.         
  28.         return result;
  29.     }
  30.    
  31.     @Override
  32.     public List<LocalDate> getWorkdaysBetween(LocalDate startDate, LocalDate endDate) {
  33.         String cacheKey = startDate.toString() + "_" + endDate.toString();
  34.         
  35.         // 检查缓存
  36.         List<LocalDate> cachedResult = workdayListCache.get(cacheKey);
  37.         if (cachedResult != null) {
  38.             return cachedResult;
  39.         }
  40.         
  41.         // 计算结果
  42.         List<LocalDate> result = super.getWorkdaysBetween(startDate, endDate);
  43.         
  44.         // 存入缓存
  45.         workdayListCache.put(cacheKey, result);
  46.         
  47.         return result;
  48.     }
  49.    
  50.     // 清除缓存
  51.     public void clearCache() {
  52.         workdayCache.clear();
  53.         workdayListCache.clear();
  54.     }
  55.    
  56.     // 清除特定日期范围的缓存
  57.     public void clearCacheForRange(LocalDate startDate, LocalDate endDate) {
  58.         String cacheKey = startDate.toString() + "_" + endDate.toString();
  59.         workdayCache.remove(cacheKey);
  60.         workdayListCache.remove(cacheKey);
  61.     }
  62. }
复制代码

8.2 国际化支持

为了支持多语言,我们可以添加国际化功能:
  1. package com.daycalculator.util;
  2. import java.text.MessageFormat;
  3. import java.util.Locale;
  4. import java.util.ResourceBundle;
  5. public class I18nSupport {
  6.    
  7.     private static final String BUNDLE_NAME = "messages";
  8.     private static ResourceBundle messages;
  9.     private static Locale currentLocale = Locale.getDefault();
  10.    
  11.     static {
  12.         loadMessages();
  13.     }
  14.    
  15.     public static void setLocale(Locale locale) {
  16.         currentLocale = locale;
  17.         loadMessages();
  18.     }
  19.    
  20.     private static void loadMessages() {
  21.         try {
  22.             messages = ResourceBundle.getBundle(BUNDLE_NAME, currentLocale);
  23.         } catch (Exception e) {
  24.             // 如果找不到指定语言的资源文件,使用默认语言
  25.             messages = ResourceBundle.getBundle(BUNDLE_NAME, Locale.ENGLISH);
  26.         }
  27.     }
  28.    
  29.     public static String getMessage(String key) {
  30.         try {
  31.             return messages.getString(key);
  32.         } catch (Exception e) {
  33.             return key; // 如果找不到消息,返回键名
  34.         }
  35.     }
  36.    
  37.     public static String getMessage(String key, Object... params) {
  38.         try {
  39.             String pattern = messages.getString(key);
  40.             return MessageFormat.format(pattern, params);
  41.         } catch (Exception e) {
  42.             return key; // 如果找不到消息,返回键名
  43.         }
  44.     }
  45. }
复制代码

创建资源文件:

• messages_en.properties(英文)
• messages_zh.properties(中文)

8.3 异常处理

创建自定义异常类:
  1. package com.daycalculator.exception;
  2. public class DateParseException extends Exception {
  3.    
  4.     public DateParseException() {
  5.         super();
  6.     }
  7.    
  8.     public DateParseException(String message) {
  9.         super(message);
  10.     }
  11.    
  12.     public DateParseException(String message, Throwable cause) {
  13.         super(message, cause);
  14.     }
  15.    
  16.     public DateParseException(Throwable cause) {
  17.         super(cause);
  18.     }
  19. }
复制代码

9. 总结和展望

9.1 项目总结

本项目实现了一个功能全面的天数计算系统,包括:

• 基础日期操作(创建、格式化、解析)
• 简单天数差计算
• 高级时间处理(时间段计算、日期加减)
• 工作日计算(排除周末和节假日)
• 自定义工作日规则
• 用户界面
• 性能优化
• 国际化支持

通过这个项目,我们学习了:

• Java日期时间API的使用
• 从传统的Date和Calendar到现代的java.time包
• 如何设计灵活的工作日计算系统
• 如何构建一个完整的Java应用程序
• 性能优化技巧
• 国际化支持

9.2 未来展望

未来可以考虑的扩展方向:

1. Web界面:将系统转换为Web应用,使用Spring Boot等框架
2. 移动应用:开发Android或iOS版本
3. 云服务:将计算功能部署为云服务,提供API接口
4. 更多日期计算功能:如农历支持、工作班次计算等
5. 数据库集成:持久化节假日和工作日规则
6. 更多性能优化:如并行计算、更高效的缓存策略等

通过这个项目,我们不仅学习了Java日期时间处理的各种技术,还了解了如何构建一个完整的应用程序。希望这个项目能够帮助读者在实际工作中处理各种日期计算需求。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

频道订阅

频道订阅

加入社群

加入社群

联系我们|TG频道|RSS

Powered by Pixtech

© 2025 Pixtech Team.