/**
 * 日期工具类</br>
 * 引用方式：<b>this.dateUtil.&lt;object|method&gt;</b></br>
 * 其中&lt;object|method&gt;包括：
 * 
 * @property {} <b>供Element的Picker组件使用</b>
 * @property {object} datePickerOptions 日期选择器的通用快捷选项。快捷选项包括：“今天、前一天、后一天”
 * @property {object} dateRangePickerOptions 起止日期选择器的通用快捷选项。快捷选项包括：“最近三天、最近一周、最近一个月”
 * @property {object} getDateRangePickerOptions 起止日期选择器的通用快捷选项。快捷选项包括：“最近三天、最近一周、最近一个月”，可新增未来日期不可选<br/>
 *    参数： disableFuture = {boolean} 未来时间是否不可选，default=false<br/>
 *           &emsp;&emsp;&emsp;&ensp;includeToday = {boolean} 不可选的时间是否包含今天，default=false<br/>
 * 
 * @property {} <b>格式转换</b>
 * @property {method} timeFormat(time,formatter,seperator) 将时间转换为指定输出格式<br/>
 *    参数： time = {object|string} 待处理的Date对象或字符串(格式为YYYY-MM-DD HH:mm:ss或HH:mm:ss, 支持日期/分隔符)<br/>
 *           &emsp;&emsp;&emsp;&ensp;formatter = {string} 输出的时间格式，支持HH:mm:ss、HH:mm或HH，default="HH:mm:ss"<br/>
 *           &emsp;&emsp;&emsp;&ensp;seperator = {string} 输出的时间分隔符，支持':'或'CN'，default=':'<br/>
 *    返回： string = 格式化的时间字符串<br/>
 * @property {method} dateFormat(date,formatter,seperator) 将日期转换为指定输出格式<br/>
 *    参数： date = {object|string} 待处理的Date对象或字符串(格式为YYYY-MM-DD HH:mm:ss或YYYY-MM-DD, 支持日期/分隔符)<br/>
 *           &emsp;&emsp;&emsp;&ensp;formatter = {string} 输出的日期格式，支持YYYY-MM-DD、YYYY-MM、YYYY或MM-DD，default="YYYY-MM-DD"<br/>
 *           &emsp;&emsp;&emsp;&ensp;seperator = {string} 输出的日期分隔符，支持'-'、'/'、'.'或'CN'，default='-'<br/>
 *    返回： string = 格式化的日期字符串<br/>
 * @property {method} dateTimeFormat(dateTime,formatter,seperator) 将日期时间转换为指定输出格式<br/>
 *    参数： dateTime = {object|string} 待处理的Date对象或字符串(格式为YYYY-MM-DD HH:mm:ss, 支持日期/分隔符)<br/>
 *           &emsp;&emsp;&emsp;&ensp;formatter = {string} 输出的日期时间格式，其中日期和时间两部分必须以空格分隔，default="YYYY-MM-DD HH:mm:ss"<br/>
 *           &emsp;&emsp;&emsp;&ensp;seperator = {string} 输出的日期分隔符，支持'-'、'/'或'CN'(对时间也有效)，default='-'<br/>
 *    返回： string = 格式化的日期时间字符串<br/>
 * 
 * @property {} <b>日期计算</b>
 * @property {method} getTodayStr(formatter,seperator) 获取当前日期字符串，缺省格式为YYYY-MM-DD<br/>
 *    参数： formatter = {string} 输出的日期格式，支持YYYY-MM-DD、YYYY-MM、YYYY或MM-DD，default="YYYY-MM-DD"<br/>
 *           &emsp;&emsp;&emsp;&ensp;seperator = {string} 输出的日期分隔符，支持'-'、'/'或'CN'，default='-'<br/>
 *    返回： string = 当天的日期字符串<br/>
 * @property {method} getRecentDateStr(delta,formatter,seperator) 获取当前或其指定前、后日期的字符串<br/>
 *    参数： delta = -1~昨天的日期，0~今天的日期，1~明天的日期；依次类推<br/>
 *           &emsp;&emsp;&emsp;&ensp;formatter = {string} 输出的日期格式，支持YYYY-MM-DD、YYYY-MM、YYYY或MM-DD，default="YYYY-MM-DD"<br/>
 *           &emsp;&emsp;&emsp;&ensp;seperator = {string} 输出的日期分隔符，支持'-'、'/'或'CN'，default='-'<br/>
 *    返回： string = 期望的日期字符串<br/>
 * @property {method} compareDate(date1,date2) 比较两个日期的大小<br/>
 *    参数： date1 = {object|string} 日期1对象或字符串<br/>
 *           &emsp;&emsp;&emsp;&ensp;date2 = {object|string} 日期2对象或字符串<br/>
 *    返回： number = 0~日期1=日期2，1~日期1>日期2，-1~日期1<日期2<br/>
 * @property {method} calcDifference(date1,date2,unit) 获取两个日期相差的年数/天数/小时/分钟/秒<br/>
 *    参数： date1 = {object|string} 日期1对象或字符串<br/>
 * 			 &emsp;&emsp;&emsp;&ensp;date2 = {object|string} 日期2对象或字符串<br/>
 *           &emsp;&emsp;&emsp;&ensp;unit = {string} 单位(year/day/hour/minute/second),default='year'<br/>
 *    返回： number = 相差的年数（浮点数）<br/>
 * @property {method} yearsAgoText(date1,date2) 获取两个日期相差年数的文字描述（小于一年/1年/2年/...）<br/>
 *    参数： date1 = {object|string} 日期1对象或字符串<br/>
 *           &emsp;&emsp;&emsp;&ensp;date2 = {object|string} 日期2对象或字符串<br/>
 *    返回： number = 年数的文字描述（小于一年/1年/2年/...）<br/>
 * @property {method} getCurrentMonthFirstDate() 获取当前时间所在的本月第一天日期<br/>
 *    返回： date = 当前时间所在的本月第一天日期<br/>
 * @property {method} getCurrentYearFirstDate() 获取当前时间所在的本年第一天日期<br/>
 *    返回： date = 当前时间所在的本年第一天日期<br/>
 * @property {method} parseDate2Millis(date) 获取传入日期与 1970 年 1 月 1 日午夜之间相差的毫秒数<br/>
 *    参数： date = {string|date} 日期或者日期字符串<br/>
 *    返回： number = 与 1970 年 1 月 1 日午夜之间相差的毫秒数<br/>
 * @property {method} numberPrefix0(n) 处理传入数值是否前缀新增0<br/>
 *    参数： n = {number} 待处理的数值<br/>
 *    返回： number = 处理后前缀是否新增0的数值<br/>
 * 
 * @Author: liusheng, wanqian
 * @Date: 2021-11-26 11:43:52
 */
let DateUtil = {
    /**
     * @Description: 定义日期选择器的通用快捷选项，用法参见SysIndex.vue
     * @Author: liusheng
     * @Date: 2021-02-10 11:36:23
     */
    datePickerOptions: {
        shortcuts: [{
            text: '今天',
            onClick(picker) {
                picker.$emit('pick', new Date());
            }
        }, {
            text: '前一天',
            onClick(picker) {
                const date = picker.date;
                date.setTime(date.getTime() - 3600 * 1000 * 24);
                picker.$emit('pick', date);
            }
        }, {
            text: '后一天',
            onClick(picker) {
                const date = picker.date;
                let delta = 3600 * 1000 * 24;
                if (date.getTime() + delta > new Date().getTime()) return;

                date.setTime(date.getTime() + delta);
                picker.$emit('pick', date);
            }
        }]
    },

    /**
     * @Description: 起止日期选择器的通用快捷选项，用法参见LogQuery.vue
     * @Author: liusheng，wanqian
     * @Date: 2021-02-10 11:36:23
     */
    dateRangePickerOptions: {
        shortcuts: [{
            text: '最近三天',
            onClick(picker) {
                const end = new Date();
                const start = new Date();
                start.setTime(start.getTime() - 3600 * 1000 * 24 * 2);
                // 将开始时间时分秒转换为00:00:00，结束的转换为23:59:59，否则8-24 16:00到8-26 16:00这种会少一天
                start.setHours(0);
                start.setMinutes(0);
                start.setSeconds(0);
                end.setHours(23);
                end.setMinutes(59);
                end.setSeconds(59);
                picker.$emit('pick', [start, end]);
            }
        }, {
            text: '最近一周',
            onClick(picker) {
                const end = new Date();
                const start = new Date();
                start.setTime(start.getTime() - 3600 * 1000 * 24 * 6);
                // 将开始时间时分秒转换为00:00:00，结束的转换为23:59:59，否则8-24 16:00到8-26 16:00这种会少一天
                start.setHours(0);
                start.setMinutes(0);
                start.setSeconds(0);
                end.setHours(23);
                end.setMinutes(59);
                end.setSeconds(59);
                picker.$emit('pick', [start, end]);
            }
        }, {
            text: '最近一个月',
            onClick(picker) {
                const end = new Date();
                const start = new Date();
                start.setTime(start.getTime() - 3600 * 1000 * 24 * 29);
                // 将开始时间时分秒转换为00:00:00，结束的转换为23:59:59，否则8-24 16:00到8-26 16:00这种会少一天
                start.setHours(0);
                start.setMinutes(0);
                start.setSeconds(0);
                end.setHours(23);
                end.setMinutes(59);
                end.setSeconds(59);
                picker.$emit('pick', [start, end]);
            }
        }]
    },

    /**
     * @Description: 起止日期选择器的通用快捷选项，基于dateRangePickerOptions，新增了不可选日期
     * @Author: liusheng，wanqian
     * @Date: 2022-09-26 17:06:23
     * @param {boolean} disableFuture 未来时间是否不可选
     * @param {boolean} includeToday 不可选的时间是否包含今天
     */
    getDateRangePickerOptions(disableFuture = false, includeToday = false) {
        let options = {...this.dateRangePickerOptions };
        if (!disableFuture) return options;
        // 根据需求这里对比的现在时间需要把时分秒设置为23:59:59
        let dateNow = new Date();
        dateNow.setHours(23);
        dateNow.setMinutes(59);
        dateNow.setSeconds(59);
        options.disabledDate = includeToday ?
            function(date) { return date.getTime() / (1000 * 3600 * 24) >= dateNow.getTime() / (1000 * 3600 * 24) - 1; } :
            function(date) { return date.getTime() > dateNow.getTime(); }
        return options;
    },

    /**
     * @Description: 将时间转换为指定输出格式
     * @Author: liusheng
     * @Date: 2021-11-26 11:43:23
     * @param {object|string} time 待处理的Date对象或字符串(格式为YYYY-MM-DD HH:mm:ss或HH:mm:ss, 支持日期/分隔符)
     * @param {string} formatter 输出的时间格式，支持HH:mm:ss、HH:mm或HH，缺省为HH:mm:ss
     * @param {string} seperator 输出的时间分隔符，支持':'或'CN'，缺省为':'
     * @return {string} 格式化的时间字符串
     */
    timeFormat(time, formatter = "HH:mm:ss", seperator = ':') {
        if (typeof(time) == 'string' && /^\d{2}:\d{2}:\d{2}$/.test(time)) {
            time = this.getTodayStr() + ' ' + time;
        }

        time = new Date(this.parseDate2Millis(time));
        switch (formatter) {
            case "HH:mm:ss":
                return this.numberPrefix0(time.getHours()) + (seperator === 'CN' ? '时' : ':') +
                    this.numberPrefix0(time.getMinutes()) + (seperator === 'CN' ? '分' : ':') +
                    this.numberPrefix0(time.getSeconds()) + (seperator === 'CN' ? '秒' : '');
            case "HH:mm":
                return this.numberPrefix0(time.getHours()) + (seperator === 'CN' ? '时' : ':') +
                    this.numberPrefix0(time.getMinutes()) + (seperator === 'CN' ? '分' : '');
            case "HH":
                return this.numberPrefix0(time.getHours()) + (seperator === 'CN' ? '时' : '');
            default:
                return 'error';
        }
    },

    /**
     * @Description: 将日期转换为指定输出格式
     * @Author: liusheng
     * @Date: 2021-11-26 11:43:23
     * @param {object|string} date 待处理的Date对象或字符串(格式为YYYY-MM-DD HH:mm:ss或YYYY-MM-DD, 支持日期/分隔符)
     * @param {string} formatter 输出的日期格式，支持YYYY-MM-DD、YYYY-MM、YYYY或MM-DD，缺省为YYYY-MM-DD
     * @param {string} seperator 输出的日期分隔符，支持'-'、'/'、'.'或'CN'，缺省为'-'
     * @return {string} 格式化的日期字符串
     */
    dateFormat(date, formatter = "YYYY-MM-DD", seperator = '-') {
        if (seperator !== '-' && seperator !== '/' && seperator !== 'CN' 
          && seperator !== '.') return 'error';
        date = new Date(this.parseDate2Millis(date));
        let year = date.getFullYear();
        let month = date.getMonth() + 1;
        let day = date.getDate();
        if (seperator !== 'CN') {
            month = this.numberPrefix0(month);
            day = this.numberPrefix0(day);
        }
        let yearSeperator1 = seperator === 'CN' ? '年' : seperator;
        let yearSeperator2 = seperator === 'CN' ? '年' : '';
        let monthSeperator1 = seperator === 'CN' ? '月' : seperator;
        let monthSeperator2 = seperator === 'CN' ? '月' : '';
        let daySeperator = seperator === 'CN' ? '日' : '';
        switch (formatter) {
            case "YYYY-MM-DD":
                return year.toString() + yearSeperator1 + month + monthSeperator1 + day + daySeperator;
            case "YYYY-MM":
                return year.toString() + yearSeperator1 + month + monthSeperator2;
            case "YYYY":
                return year.toString() + yearSeperator2;
            case "MM-DD":
                return month + monthSeperator1 + day + daySeperator;
            default:
                return 'error';
        }
    },

    /**
     * @Description: 将日期时间转换为指定输出格式
     * @Author: liusheng
     * @Date: 2021-11-26 11:43:23
     * @param {object|string} dateTime 待处理的Date对象或字符串(格式为YYYY-MM-DD HH:mm:ss, 支持日期/分隔符)
     * @param {string} formatter 输出的日期时间格式，缺省为YYYY-MM-DD HH:mm:ss。其中日期和时间两部分必须以空格分隔
     * @param {string} seperator 输出的日期时间分隔符，日期支持'-'、'/'或'CN'，缺省为'-'；时间支持':'或'CN'，缺省为':'
     * @return {string} 格式化的日期时间字符串
     */
    dateTimeFormat(dateTime, formatter = "YYYY-MM-DD HH:mm:ss", seperator = '-') {
        dateTime = new Date(this.parseDate2Millis(dateTime));
        let formatters = formatter.split(' ');
        let str = this.dateFormat(dateTime, formatters[0], seperator) + ' ';
        str += this.timeFormat(dateTime, formatters[1], seperator);
        return str;
    },

    /**
     * @Description: 获取当前日期字符串，格式：YYYY-MM-DD
     * @Author: sunhuihong, liusheng
     * @Date: 2022-02-21
     * 
     * @param {string} formatter 输出的日期格式，支持YYYY-MM-DD或MM-DD，缺省为YYYY-MM-DD
     * @param {string} seperator 输出的日期分隔符，支持'-'、'/'或'CN'，缺省为'-'
     * @return {string} 当前日期字符串
     */
    getTodayStr(formatter = "YYYY-MM-DD", seperator = '-') {
        return this.dateFormat(new Date(), formatter, seperator);
    },

    /**
     * @Description: 获取当前或其前、后日期的月份-日期字符串
     * @Author: sunhuihong, liusheng
     * @Date: 2022-02-21
     * 
     * @param {number} delta -1~昨天的日期，0~今天的日期，1~明天的日期；依次类推
     * @param {string} formatter 输出的日期格式，支持YYYY-MM-DD或MM-DD，缺省为YYYY-MM-DD
     * @param {string} seperator 输出的日期分隔符，支持'-'、'/'或'CN'，缺省为'-''
     * @return {string} 期望的日期字符串
     */
    getRecentDateStr(delta, formatter = "YYYY-MM-DD", seperator = '-') {
        let date = new Date();
        let targetMillis = date.getTime() + 1000 * 60 * 60 * 24 * delta;
        date.setTime(targetMillis);
        return this.dateFormat(date, formatter, seperator);
    },

    /**
     * @Description: 比较两个日期的大小
     * @Author: wanqian, liusheng
     * @Date: 2022-02-21
     * @param {object|string} date1 日期1对象或字符串
     * @param {object|string} date2 日期2对象或字符串
     * @return {number} 0~日期1=日期2，1~日期1>日期2，-1~日期1<日期2
     */
    compareDate(date1, date2) {
        let millis1 = this.parseDate2Millis(date1);
        let millis2 = this.parseDate2Millis(date2);
        if (millis1 > millis2) return 1;
        return (millis1 < millis2) ? -1 : 0;
    },

    /**
     * @Description: 获取两个日期相差的年数/天数/小时/分钟/秒
     * @Author: wanqian
     * @Date: 2022-02-21
     * @param {object|string} date1 日期1对象或字符串
     * @param {object|string} date2 日期2对象或字符串
     * @param {string} unit 单位(year/day/hour/minute/second),缺省为year
     * @return {number} 相差的年数/天数/小时/分钟/秒（浮点数）
     */
    calcDifference(date1, date2, unit = 'year') {
        let millis = this.parseDate2Millis(date2) - this.parseDate2Millis(date1);
        let standard;
        switch (unit) {
            case "year":
                standard = 365 * 24 * 60 * 60 * 1000;
                break;
            case "day":
                standard = 24 * 60 * 60 * 1000;
                break;
            case "hour":
                standard = 60 * 60 * 1000;
                break;
            case "minute":
                standard = 60 * 1000;
                break;
            case "second":
                standard = 1000;
                break;
            default:
                standard = 1000;
                break;
        }
        return millis / parseFloat(standard);
    },

    /**
     * @Description: 返回两个日期相差年数的文字描述（小于一年/1年/2年。。。。）
     * @Author: wanqian
     * @Date: 2021-02-10 11:36:23
     * @param {object|string} date1 日期1对象或字符串
     * @param {object|string} date2 日期2对象或字符串
     * @return {string} 小于一年/1年/2年/...
     */
    yearsAgoText(date1, date2) {
        let delta = this.calcDifference(date1, date2);
        return delta < 1 ? '小于一年' : (Math.floor(delta) + '年');
    },

    /**
     * @Description: 获取当前时间所在的本月第一天日期
     * @Author: wanqian
     * @Date: 2022-10-11 13:36:23
     * @return {date} 当前时间所在的本月第一天日期
     */
    getCurrentMonthFirstDate() {
        let date = new Date();
        date.setDate(1);
        return date;
    },

    /**
     * @Description: 获取当前时间所在的本年第一天日期
     * @Author: wanqian
     * @Date: 2022-10-11 13:36:23
     * @return {date} 当前时间所在的本年第一天日期
     */
    getCurrentYearFirstDate() {
        let date = this.getCurrentMonthFirstDate();
        date.setMonth(0);
        return date;
    },

    /**
     * @Description: 获取传入日期与 1970 年 1 月 1 日午夜之间相差的毫秒数
     * @Author: wanqian
     * @Date: 2022-11-29 15:51:23
     * @param {string/date} date 日期或者日期字符串
     * @return {number} 与 1970 年 1 月 1 日午夜之间相差的毫秒数
     */
    parseDate2Millis(date) {
        let target = (typeof date == 'string') ? date.replace(/-/g, "/") : date;
        return Date.parse(target);
    },

    /**
     * @Description: 处理传入数值是否前缀新增0
     * @Author: wanqian
     * @Date: 2022-11-29 15:51:23
     * @param {number} n 待处理的数值
     * @return {number} 处理后前缀是否新增0的数值
     */
    numberPrefix0(n) {
        return (n < 10) ? ('0' + n) : ('' + n);
    }
}

export default DateUtil