根据工作日/节假日收货要求计算预计发货时间

1.需求: 根据下单时间orderTime(这里默认是系统时间); 客户收货时间要求:工作日=1,节假日2; 计算预计发货时间(这里需要运输时长);

2.思路:  要计算预计发货时间,(仓库的发货截止时间当天的16:30 ;16:30以后的当做第二天的订单)

    首先计算正常情况到货时间, 例如正常情况下: 某订单是8月16号的单子, 上海-->江苏省南京市  8月16号 16:30 发货, 运输时效为17小时,预计到货时间是8月17号 9:30(周六) ,

    然后,根据预计到货时间开始计算出客户要求的工作日/节假日时间. 如果客户要求节假日送货,说明8月16号16:30 正常发货即可,延迟时间delayDays=0;

    假如客户需要工作日送货(即到货时间是8月19号 9:30 (周一)  ),推迟发货天数delayDays=2,即8月18号 16:30 发货.

3.难点及解决方案:  这里比较困难的地方是如何获取预计的到货时间是工作日/节假日,并且找到符合要求的预计到货时间.

      解决方案基本两种,

  第一,维护一个日历表,专门用来查询日期是工作日还是节假日. 优点是比较容易获取数据,查询方便;   缺点:法定节假日和补班难以维护,手头不一定有现成数据.

  第二,请求第三方网站,查询节假日类型, 优点:查询方便,直接HTTP请求获取; 缺点:第三方网站稳定和安全问题,可能导致不能使用,无法查询;

4 我这里选第二种方案 ,当然,请示领导后得到允许使用第三方网站 http://api.goseek.cn ; 如果第三方不稳定的情况下,直接根据正常日期的周末和工作日来判断就可以;

5.下面提供获取延迟发货天数的代码,(仓库发货截止时间是当天的16:30,这里默认的发货时间就是16:30 ,具体的快递发货时间可以自行调节 )

6.请求第三方网站工具类

package utils.time;

import net.sf.json.JSONObject;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;


public class HolidayUtil {
    /*
    获取指定日期的节假日信息
    1、接口地址:http://api.goseek.cn/Tools/holiday?date=数字日期,支持https协议。
    2、返回数据:正常工作日对应结果为 0, 法定节假日对应结果为 1, 节假日调休补班对应的结果为 2,休息日对应结果为 3
    3、节假日数据说明:本接口包含2017年起的中国法定节假日数据,数据来源国务院发布的公告,每年更新1次,确保数据最新
    4、示例: 请求和返回数据格式
    http://api.goseek.cn/Tools/holiday?date=20191005    {"code":10000,"data":1}     国庆节
    http://api.goseek.cn/Tools/holiday?date=20190805       {"code":10000,"data":0}       星期一
    http://api.goseek.cn/Tools/holiday?date=20190817       {"code":10000,"data":3}       星期六
    http://api.goseek.cn/Tools/holiday?date=20190818      {"code":10000,"data":3}        星期日
    http://api.goseek.cn/Tools/holiday?date=20190815     {"code":10000,"data":0}     星期四
    http://api.goseek.cn/Tools/holiday?date=20190913    {"code":10000,"data":1}       中秋节
    http://api.goseek.cn/Tools/holiday?date=20190929    {"code":10000,"data":2}     调休补班
    * */

    public static Integer request(String httpArg) {
        String httpUrl =  "http://api.goseek.cn/Tools/holiday?date=";
        BufferedReader reader = null;
        String result = null;
        StringBuffer sbf = new StringBuffer();
        httpUrl += httpArg;

        // int d = 0;
        Integer d = null;  // 节假日类型,这里默认为null

        try {
            URL url = new URL(httpUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();
            InputStream is = connection.getInputStream();
            reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            String strRead = null;
            while ((strRead = reader.readLine()) != null) {
                sbf.append(strRead);
                sbf.append("
");
            }
            reader.close();
            result = sbf.toString();
            JSONObject ob = JSONObject.fromObject(result);
            if (ob != null) {
                d = Integer.parseInt(ob.getString("data"));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return d;
    }


    /*请求例子*/
    public static void main(String[] args) {
        //判断今天是否是工作日 周末 还是节假日
        SimpleDateFormat f = new SimpleDateFormat("yyyyMMdd");
        String httpArg = "20190216";//f.format(new Date());
        System.out.println(httpArg);
        int n = request(httpArg);
        System.out.println(httpArg + " 请求判断工作日节假日例子结果:" + n);
        //工作日对应结果为 0, 休息日对应结果为 1, 节假日对应的结果为 2

    }

}

7. 计算延迟发货天数

package utils.time;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class DelayDaysDemo {

    public static Integer SCHEDULLE_TYPE_WEEK = 1;  //传投递时延要求,:1=工作日,2=节假日,
    public static Integer SCHEDULLE_TYPE_WEEKEND = 2;  //传投递时延要求,:1=工作日,2=节假日,

    public static String TIME_FORM_HOLIDAY = "yyyyMMdd";  //判断日期是否是工作日节假日周末的时间格式

    /**
     * @Param: startDate  ,预计到达日期(*必填)
     * @Param: scheduleType   传投递时延要求,:1=工作日,2=节假日,(*必填)
     * @Description: 获取日期开始的第一个工作日或者休息日, 返回startDate往后推迟的天数
     * @Author: zyf    2019/8/14
     */
    public static Integer getDelayDay(Date startDate, Integer scheduleType) throws Exception {
        //优先发送http请求第三方查询日期的网站,其次比较正常工作日和周六周末
        SimpleDateFormat f = new SimpleDateFormat(TIME_FORM_HOLIDAY);  //被判断日期的格式
        /*从当天日期开始,往后面推30天内的时间,找出符合要求的日期*/
        for (int i = 0; i < 30; i++) {

            String formatDay = f.format(startDate);

            Integer holidayType = null; //默认null,工作日/节假日类型:1=工作日,2=节假日,对应延时要求的类型1,2
            try {
                //调用第三方工具判断今天是否是工作日 周末 还是节假日,返回的数据类型,工作日=0,法定节假日=1,调休补班=2,休息日=3
                Integer responseType = HolidayUtil.request(formatDay);
                //int c=1/0;  //测试第三方异常

                //返回的类型匹配工作日/节假日类型
                if (responseType != null) {
                    switch (responseType) {
                        case 0:
                            holidayType = SCHEDULLE_TYPE_WEEK; //1,  1=工作日,2=节假日
                            break;
                        case 1:
                            holidayType = SCHEDULLE_TYPE_WEEKEND;//2,  1=工作日,2=节假日
                            break;
                        case 2:
                            holidayType = SCHEDULLE_TYPE_WEEK;//1,  1=工作日,2=节假日
                            break;
                        case 3:
                            holidayType = SCHEDULLE_TYPE_WEEKEND;//2,  1=工作日,2=节假日
                            break;
                        default:
                            break;
                    }
                }
            } catch (Exception e) {
                //logger.error(formatDay + " 调用第三方工具判断是否是工作日出现异常!!", e);
                e.printStackTrace();
                System.out.println(formatDay + " 调用第三方工具判断是否是工作日出现异常!!");
                //有异常继续向下进行
            }

            System.out.println(formatDay + " 工作日/节假日类型是:" + holidayType);

            //try 第三方请求的异常,如果异常,走正常的周末周中类型判断
            if (holidayType == null) {
                holidayType = dayTypeForWeek(startDate);
            }

            if (scheduleType == holidayType) {
                return i;       //如果延时要求的类型跟当前遍历到的日期类型符合直接返回否则继续
            } else {
                startDate = getNextMoreDay(startDate, 1);   //类型不符合,天数+1
                continue;
            }

        }

        return null;  //没有找到直接返回null

    }


    /**
     * @param pDate 修要判断的时间
     * @return dayForWeek 判断结果
     * @Exception 判断是否是周末,//1=工作日,2=节假日
     */
    public static Integer dayTypeForWeek(Date pDate) throws Exception {
        Calendar cal = Calendar.getInstance();
        cal.setTime(pDate);
        int week = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (week == 6 || week == 0) { //0代表周日,6代表周六
            return 2;
        }
        return 1;
    }


    /**
     * @Param: sourceDate  原日期
     * @Param: n  后n天
     * @Description: 获取下N天的时间
     * @Author: zyf    2019/8/14
     */
    public static Date getNextMoreDay(Date sourceDate, int n) {
        int oneDayTime = 24 * 60 * 60 * 1000;       //一天代表的毫秒数
        long initMilliSeconds = sourceDate.getTime() + oneDayTime * n;
        return new Date(initMilliSeconds);  //毫秒时间格式化成Date类型
    }


}

8. 原预计发货时间+延迟发货天数n=真正的预计发货时间 .

9.总结

 ①选择合适的解决问题方法.道路千万条~

   ② 具体问题需要具体分析,这里计算的预计发货时间只是一个大概的时间范围,具体的时间还跟快递的运输时效,快递的到达(送货)时间有关.

比如,由程序计算出的预计到达时间是周五20:00点,这个时间算工作日呢还是节假日? 这里就要根据实际业务继续优化计算方法了~

  ③如果不怕麻烦,可以将国家节假日的数据存到自己的数据库或者配置文件中,然后写个逻辑去判断下!当然,节假日的数据每年都要维护~~

原文地址:https://www.cnblogs.com/coloz/p/11349662.html