java获取n个工作日后的日期, 排除周末和节假日(顺延)
一.写在前面
需求描述
工作需要获取n个工作日后的日期, 需要排除weekend和holiday, holiday存在数据库中, 存入的形式是一个节日有起始日期和截止日期(以下文中有关于节假日的表截图).
思路解析
大致为: 根据指定日期获取它tomorrow的日期, 判断tomorrow是否是周末和节假日, 如果不是则将tomorrow赋给today继续循环, 循环n次, 返回的today即是目标结果.
1.查询数据库中的holiday, 存入list(需要注意的是, holiday记录里startTime和endTime颠倒的脏数据要剔除, startTime在endTime之后的记录显然是脏数据)
2.判断today是否是周末
3.判断today是否是节假日
4.获取tomorrow的日期, 判断是否是weekend和holiday, 如果不是则将tomorrow赋给today继续循环, 循环n次, 返回today
(这里的today是指指定日期. 如:获取今天以后第10个工作日的日期 今天的日期就是指定日期).
工具类如何使用?
使用方法见博文末尾说明.
二.以下为测试代码(测试时日期为2018-08-28)
package dong.test; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List; /**
* Created by liangyadong on 2018/8/28 0028.
*/
public class HolidayTest { private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); public static void main(String[] args) throws ParseException {
//查询数据库中holiday,遍历存入list(表中每条记录存放的是假期的起止日期,遍历每条结果,并将其中的每一天都存入holiday的list中),以下为模拟假期
List holidayList = new ArrayList();
holidayList.add("2018-08-29");
holidayList.add("2018-08-30");
holidayList.add("2018-10-01");
holidayList.add("2018-10-02");
holidayList.add("2018-10-03");
holidayList.add("2018-10-04");
holidayList.add("2018-10-05");
holidayList.add("2018-10-06");
holidayList.add("2018-10-07"); //获取计划激活日期
Date scheduleActiveDate = getScheduleActiveDate(holidayList);
System.out.println("10个工作日后,即计划激活日期为::" + sdf.format(scheduleActiveDate));
} //获取计划激活日期
public static Date getScheduleActiveDate(List<String> list) throws ParseException {
// java.sql.Date currentDate = new java.sql.Date(System.currentTimeMillis());//获取当前日期2018-08-26
Date today = new Date();//Mon Aug 27 00:09:29 CST 2018
Date tomorrow = null;
int delay = 1;
int num = 10;//根据需要设置,这个值就是业务需要的n个工作日
while(delay <= num){
tomorrow = getTomorrow(today);
//当前日期+1即tomorrow,判断是否是节假日,同时要判断是否是周末,都不是则将scheduleActiveDate日期+1,直到循环num次即可
if(!isWeekend(sdf.format(tomorrow)) && !isHoliday(sdf.format(tomorrow),list)){
delay++;
today = tomorrow;
} else if (isWeekend(sdf.format(tomorrow))){
// tomorrow = getTomorrow(tomorrow);
today = tomorrow;
System.out.println(sdf.format(tomorrow) + "::是周末");
} else if (isHoliday(sdf.format(tomorrow),list)){
// tomorrow = getTomorrow(tomorrow);
today = tomorrow;
System.out.println(sdf.format(tomorrow) + "::是节假日");
}
}
System.out.println("10个工作日后,即计划激活日期为::" + sdf.format(today));
return today;
} /**
* 获取明天的日期
*
* @param date
* @return
*/
public static Date getTomorrow(Date date){
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, +1);
date = calendar.getTime();
return date;
} /**
* 判断是否是weekend
*
* @param sdate
* @return
* @throws ParseException
*/
public static boolean isWeekend(String sdate) throws ParseException {
Date date = sdf.parse(sdate);
Calendar cal = Calendar.getInstance();
cal.setTime(date);
if(cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY){
return true;
} else{
return false;
} } /**
* 判断是否是holiday
*
* @param sdate
* @param list
* @return
* @throws ParseException
*/
public static boolean isHoliday(String sdate, List<String> list) throws ParseException {
if(list.size() > 0){
for(int i = 0; i < list.size(); i++){
if(sdate.equals(list.get(i))){
return true;
}
}
}
return false;
} }
输出main方法的执行结果:
2018-08-29::是节假日
2018-08-30::是节假日
2018-09-01::是周末
2018-09-02::是周末
2018-09-08::是周末
2018-09-09::是周末
10个工作日后,即计划激活日期为::2018-09-13
10个工作日后,即计划激活日期为::2018-09-13
查看上面打印结果符合预期, 下面则是应用的说明.
三.应用
1.首先看一下我数据库中存放的holiday, 每一个节日都是一个范围(有开始日期和结束日期)

2.从数据库中查询holiday结果集, 遍历结果集将每一天holiday存到holidayList中
2.1 serviceImpl:
//查询holiday列表
public List getHolidayList(){
//存放holiday的每一天
List holidayList = new ArrayList(); List<HolidayInfoEntity> list = customerManageDao.getHolidayList();
//遍历holidayList
if(list!=null&&list.size()>0){
for(HolidayInfoEntity holidayInfoEntity : list){
Date startTime = holidayInfoEntity.getStartTime();
Date endTime = holidayInfoEntity.getEndTime(); SimpleDateFormat sdf = PersDateUtils.getSdf(PersDateUtils.FORMAT_DATE_SPLIT);
String sstartTime = sdf.format(startTime);
String sendTime = sdf.format(endTime); Date tomorrow = HolidayUtils.getTomorrow(startTime);
if(!sstartTime.equals(sendTime)){
holidayList.add(sstartTime);
while(!sdf.format(tomorrow).equals(sendTime)){
tomorrow = HolidayUtils.getTomorrow(startTime);
holidayList.add(sdf.format(tomorrow));
startTime = tomorrow;
}
}else{
holidayList.add(sstartTime);
}
}
} return holidayList;
}
2.2 daoImpl:(在这一步筛选符合逻辑的holiday, 即startTime小于endTime的)
//获取holiday列表
@Override
public List getHolidayList() {
StringBuilder hql = new StringBuilder(" from HolidayInfoEntity h where h.startTime <= h.endTime ");
String hqlQuery = hql.toString();
Query query = getSession().createQuery(hqlQuery);
List<HolidayInfoEntity> list = query.list();
return list;
}
2.3 debug查看查询到的节假日:

3.调用HolidayUtils中的getScheduleActiveDate传入正确的参数, 返回值即是排除节假日和周末后的指定n个工作日后的日期.(HolidayUtils如下)
代码备份
=====================分割线: 封装到工具类内方便直接调用=====================
HolidayUtils.java
package com.ppms.utils; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List; /**
* Created by liangyadong on 2018/8/28 0028.
*/
public class HolidayUtils {
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
/**
* 获取计划激活日期
* @param today opening date
* @param list holidayList
* @param num num个工作日后
* @return
* @throws ParseException
*/
public static Date getScheduleActiveDate(Date today, List<String> list, int num) throws ParseException {
Date tomorrow = null;
int delay = 1;
while(delay <= num){
tomorrow = getTomorrow(today);
//当前日期+1,判断是否是节假日,不是的同时要判断是否是周末,都不是则scheduleActiveDate日期+1
if(!isWeekend(sdf.format(tomorrow)) && !isHoliday(sdf.format(tomorrow),list)){
delay++;
today = tomorrow;
} else if (isWeekend(sdf.format(tomorrow))){
today = tomorrow;
} else if (isHoliday(sdf.format(tomorrow),list)){
today = tomorrow;
}
} return today;
} /**
* 获取tomorrow的日期
*
* @param date
* @return
*/
public static Date getTomorrow(Date date){
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, +1);
date = calendar.getTime();
return date;
} /**
* 判断是否是weekend
*
* @param sdate
* @return
* @throws ParseException
*/
public static boolean isWeekend(String sdate) throws ParseException {
Date date = sdf.parse(sdate);
Calendar cal = Calendar.getInstance();
cal.setTime(date);
if(cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY){
return true;
} else{
return false;
} } /**
* 判断是否是holiday
*
* @param sdate
* @param list
* @return
* @throws ParseException
*/
public static boolean isHoliday(String sdate, List<String> list) throws ParseException {
if(list.size() > 0){
for(int i = 0; i < list.size(); i++){
if(sdate.equals(list.get(i))){
return true;
}
}
}
return false;
}
}
PersDateUtils.java
package com.ppms.utils; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date; /**
* Created by yadongliang on 2018/7/2 0002.
*/
public class PersDateUtils { public static final String FORMAT_DATE_SPLIT = "yyyy-MM-dd";
public static final String FORMAT_DATE_NONE = "yyyyMMdd";
public static final String FORMAT_DATE_TIME = "yyyy-MM-dd HH:mm:ss:SSS";
public static final String FORMAT_FULL_DATE_TIME = "yyyyMMddHHmmssSSS";
public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; //获取指定格式
public static SimpleDateFormat getSdf(String pattern) {
return new SimpleDateFormat(pattern);
} //获取系统当前时间
public static Date getDate() {
return new Date();
} //获取当前日历
public static Calendar getCalendar() {
return Calendar.getInstance();
} //获取指定格式的日期sDate
public static String getPatternDate(String pattern, Date date){
return getSdf(pattern).format(date);
} //字符串转日期
public static Date str2Date(String str, SimpleDateFormat sdf) {
if (null == str || "".equals(str)) {
return null;
}
Date date = null;
try {
date = sdf.parse(str);
return date;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
} }
使用说明
将HolidayUtils.java和PersDateUtils.java拷贝到自己项目中, 调用HolidayUtils中的getScheduleActiveDate()传入正确的参数, 返回值即是目标日期.
Date getScheduleActiveDate(Date today, List<String> list, int num)
参数说明:
Date today: 指定日期 格式 yyyy-MM-dd
List<String> list: 业务内定义的节假日的list 格式 yyyy-MM-dd
int num: 指定天数
举个栗子:
获取今天(2018-08-28)起 天后的日期, 节假日从数据库中查询并存入到holidayList中, 标红的参数传入方法中即可.
思路基本上这样, 逻辑不是很严谨, 如果有bug, 欢迎留言讨论~
java获取n个工作日后的日期, 排除周末和节假日(顺延)的更多相关文章
- java获取当前年份、月份和日期字符串等
Java获取当前年份.月份和日期是通过Calendar类的实例对象来获取的. 首先创建一个Calendar类的实例对象,Calendar类属于java.util包. Calendar calendar ...
- N个工作日后的日期
这里对特殊日期采用了模拟的方式,在实际开发中当然这些数据是从数据库中读取,调用方法时 只需传入开始时间(一般当前) 和N(代表N个工作日) /// <summary> /// 获取时间 / ...
- java获取上周任意一天的日期
/** * 获取上周周几的日期,默认一周从周一开始 * @param dayOfWeek * @param weekOffset * @return */ public static Date get ...
- JAVA获取当前年份,月份、日期、小时、分钟、秒等
import java.util.Calendar; public class Main { public static void main(String[] args) { Calendar cal ...
- JAVA获取当前日期指定天数之后的日期
/** * 获取day天之后的日期 * @param day 天数 * @return */ public static String getDate(int day){ Calendar calen ...
- java获取一段字符串里符合日期的正则表达式的字符串
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Test3 { public static v ...
- python 递归计算若干工作日后的日期
import datetime # 根据第一次计算出来的休息日数,计算还需要的工作日数.(递归调用) def get_next_date(self, start_date, weekend_days) ...
- 【原创】java 获取十个工作日之前或之后的日期(算当天)-完美解决-费元星
[原创]java 获取十个工作日之后的日期(算当天)-完美解决-费元星(仅考虑星期六星期天) /** * * 根据开始日期 ,需要的工作日天数 ,计算工作截止日期,并返回截止日期 * @param s ...
- java获取当天,前天,明天,本周,本月,本年的开始日期时间和结束日期时间
package demoone; import java.sql.Timestamp; import java.text.ParseException; import java.text.Simple ...
随机推荐
- 超酷实用的jQuery焦点图赏析及源码
焦点图应用在现代网页中使用十分广泛,有注重简单小巧的,也有注重华丽美观的,大部分jQuery焦点图都可以滑动和切换图片,并且在切换图片时产生不同的动画特效.今天我们要分享一些超酷而且实用的jQuery ...
- Annotation Type EnableTransactionManagement
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/Ena ...
- JAVA-MyBatis ORM
MyBatis 的前身就是 iBatis .是一个数据持久层(ORM)框架. iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架.iBATIS提供的持久 ...
- Linux动态链接库的使用
1.前言 在实际开发过程中,各个模块之间会涉及到一些通用的功能,比如读写文件,查找.排序.为了减少代码的冗余,提高代码的质量,可以将这些通用的部分提取出来,做出公共的模块库.通过动态链接库可以实现多个 ...
- Linux反编译
转自:http://bbs.pediy.com/showthread.php?threadid=11315 一个简单的linux crackme的逆向前言 最不喜欢的就是写破解教程,酒后一时冲动 ...
- IIS 7.5: HOW TO ENABLE TLS 1.1 AND TLS 1.2
In IIS 7.5, which is installed on Windows 2008 R2 servers, only SSL 3.0 and TLS 1.0 are enabled for ...
- pycharm下设置自己的模板
在File---settings---File and Code Templates---Python script 脚本里添加: #!usr/bin/env python #-*- coding:u ...
- ThinkPHP3.0启动过程
以Blog举例载入项目入口文件 D:\wamp\www\Examples\Blog\index.php 定义常量 APP_NAME,Blog APP_P ...
- @TargetAPI + 版本判断实现高低API版本兼容
安卓开发中,在低版本SDK使用高版本的API会报错.一般处理方法是换一种实现方法,或者在高版本SDK中使用高版本API,低版本SDK中使用效果可能会差点的折衷方案:后者可以用如下技巧来实现. 步骤 S ...
- ArcMap工具箱参数名称的Bug
已经忍了很久了,今天一定要说一说,强大的 ArcGIS居然还存在这种Bug问题.如下图所示:使用了追加工具,有三个要素图层,且三个数据与目标数据不是同一数据,但它们的名称一致,这样执行,将会出现&qu ...