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 ...
随机推荐
- map练习
/* 编写程序统计并输出所读入的单词出现的次数 */ /* //代码一:---用map索引实现惊人的简练 #include <iostream> #include <map> ...
- Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别
为什么要用jsonp? 相信大家对跨域一定不陌生,对同源策略也同样熟悉.什么,你没听过?没关系,既然是深入浅出,那就从头说起. 假如我写了个index页面,页面里有个请求,请求的是一个json数据(不 ...
- JAVA-安装apache tomcat服务器
下载地址:http://tomcat.apache.org/ 选择需要下载的版本 下载windows service installer,找到文件双击进行安装 next i agree next ne ...
- 人生规划和GTD——"知"、"得"与"合"
作为<小强升职记>的读书感悟,给我自己.作为分享,也送给或许需要的给你. 我不知道你是否真的需要.但我受Amy师姐等一众人的影响,已经爱上了分享.呵呵,话也可以倒过来说,其实分享也就是爱. ...
- android中Snackbar(Design Support)的使用
Snackbar是Android Design Support Library中的一个组件,想使用Snackbar,必须先引入Design Support,我这里引入的是当前的最新版本: implem ...
- C# “贝格尔”编排法
采用“贝格尔”编排法,编排时如果参赛队为双数时,把参赛队数分一半(参赛队为单数时,最后以“0”表示形成双数),前一半由1号开始,自上而下写在左边:后一半的数自下而上写在右边,然后用横线把相对的号数连接 ...
- Word2007视频教程
超级好教程 http://v.youku.com/v_show/id_XMTAwOTgwNTIw.html 视频: oeasy教你玩转office系列之Word视频教程01 http://v.youk ...
- h5可伸缩布局方案
https://github.com/amfe/lib-flexible ib.flexible 移动端自适应方案,相关文章请参考此处 Update[2016年01月13日] 首先,由衷的感谢@完颜( ...
- 规避javascript多人开发函数重名问题
命名空间 封闭空间 js模块化mvc(数据层.表现层.控制层) seajs 变量转换成对象的属性 对象化
- JNI 引用问题梳理(转)
局部引用: JNI 函数内部创建的 jobject 对象及其子类( jclass . jstring . jarray 等) 对象都是局部引用,它们在 JNI 函数返回后无效: 一般情况下,我们应该依 ...