<?php

namespace common\helpers;

use yii\db\Expression;

/**
 * 日期
 *
 * @package    Helper
 * @author     Aries <forphp@qq.com>
 */
class Date {
    const OCI_TIME_FORMAT_FULL = 'YYYY-MM-DD HH24:MI:SS';
    const OCI_TIME_FORMAT_DATE = 'YYYY-MM-DD';
    const OCI_TIME_FORMAT_MONTH = 'YYYY-MM';
    const OCI_TIME_FORMAT_YEAR = 'YYYY';
    const OCI_TIME_FORMAT_SHORT_DATE = 'YYYYMMDD';
    const OCI_TIME_FORMAT_SHORT_MONTH = 'YYYYMM';
    const OCI_DATE_FORMAT_PHP = 'Y-m-d';

    /**
     * 检测日期的格式
     * @param $value
     * @return bool
     */
    public static function validator($value) {
        if (!preg_match("#^\d{4}([/-])([0][0-9]|[1][0-2])\\1([0-2][0-9]|[3][0-1])$#", $value)) {
            return false;
        }
        return true;
    }

    /**
     * 获取当前时间，主要用于console里面获取当前时间，方便日后系统日期在这里面修改
     * @param int $days
     * @return int|mixed
     */
    public static function nowTime($days = 0) {
        $days = \Yii::$app->params['daysDiff'];
        if (\Yii::$app->id == 'app-console') {
            return time() + $days * 24 * 60 * 60;
        } else {
            return __SYSTEM_TIME__ + $days * 24 * 60 * 60;
        }
    }

    /**
     * 时间转换
     *
     * @param null $value
     * @param string $format
     * @return false|null|string
     */
    public static function convert($value = null, $format = 'Y-m-d') {
        if (is_null($value)) $value = date($format, self::nowTime()); //相对于某一时间的昨天
        //if (!self::validator($value)) $value = date($format, self::nowTime());
        if (Validator::validateQuickLy('chMonth', $value)) {
            return $value . '-01';
        }
        if (!Validator::validateQuickLy('chDate', $value)) {
            $value = date($format, $value);
        }
        return $value;
    }

    /**
     * 今天
     *
     * @param string $format
     * @return false|string
     */
    public static function today($format = 'Y-m-d') {
        return date($format, self::nowTime());
    }

    /**
     * 今天的开始时间
     *
     * @return false|int
     */
    public static function todayStart() {
        $relative = self::convert();
        return strtotime($relative);
    }

    /**
     * 今天的结束时间
     *
     * @return false|int
     */
    public static function todayEnd() {
        $relative = self::convert();
        return strtotime($relative . ' +1 day') - 1;
    }

    /**
     * 昨天
     *
     * @param null $relative
     * @param string $format
     * @return false|int|string
     */
    public static function yesterday($relative = null, $format = null) {
        $relative = self::convert($relative);
        $yestoday = strtotime($relative . '-1 day');
        if (!is_null($format)) {
            return date($format, $yestoday);
        }
        return $yestoday;
    }

    /**
     * 昨天的开始时间[0点]
     *
     * @param null $relative
     * @return false|int
     */
    public static function yesterdayStart($relative = null) {
        $date = self::yesterday($relative, 'Y-m-d');
        return strtotime($date);
    }

    /**
     * 昨天的结束时间[23:59:59]
     *
     * @param null $relative
     * @return false|int
     */
    public static function yesterdayEnd($relative = null) {
        $date = self::yesterday($relative, 'Y-m-d');
        return strtotime($date . ' +1 day') - 1;
    }

    /**
     * 上个月
     *
     * @param null $relative
     * @param string $format
     * @return false|int|string
     */
    public static function lastMonth($relative = null, $format = null) {
        $relative = self::convert($relative);
        $lastMonth = strtotime($relative . 'first day of previous month');
        if(!is_null($format)){
            return date($format ,$lastMonth);
        }
        return $lastMonth;
    }

    /**
     * 上几个月的时间
     * @param int $num
     * @param null $relative
     * @param null $format
     * @return false|int|string
     */
    public static function lastNumMonth($num = 1, $relative = null, $format = null) {
        $relative = self::convert($relative,'Y-m');
        $lastMonth = strtotime($relative . '-' . $num . ' month');
        if (!is_null($format)) {
            return date($format, $lastMonth);
        }
        return $lastMonth;
    }

    /**
     * 上几天的时间
     * @param int $num
     * @param null $relative
     * @param null $format
     * @return false|int|string
     */
    public static function lastNumDay($num = 1, $relative = null, $format = null) {
        $relative = self::convert($relative,'Y-m-d');
        $lastDay = strtotime($relative . '-' . $num . ' day');
        if (!is_null($format)) {
            return date($format, $lastDay);
        }
        return $lastDay;
    }

    /**
     * 下月
     * @param null $relative
     * @param null $format
     * @return false|int|string
     */
    public static function nextMonth($relative = null, $format = null) {
        $relative = self::convert($relative);
        $nextMonth = strtotime($relative . ' first day of next month');
        if(!is_null($format)){
            return date($format ,$nextMonth);
        }
        return $nextMonth;
    }

    /**
     * 下个月的指定日期
     * @param null $relative
     * @param null $format
     * @return false|int
     */
    public static function nextMonthDay($relative = null, $format = null) {
        $day = date('d', $relative);
        $nextMonthFirstDay = self::nextMonth($relative, $format = null);
        return strtotime(date('Y-m-'.$day, $nextMonthFirstDay));
    }

    /**
     * 一年的开始
     * @param null $relative
     * @return false|int
     */
    public static function yearStart($relative = null) {
        $relative = self::convert($relative, 'Y-01-01');
        return strtotime($relative);
    }

    /**
     * 一年的结束
     * @param null $relative
     * @return false|int
     */
    public static function yearEnd($relative = null) {
        $relative = self::convert($relative, 'Y-12-31');
        return strtotime($relative . ' +1 day') - 1;
    }

    /**
     * 月开始时间
     *
     * @param null $relative
     * @return false|int
     */
    public static function monthStart($relative = null) {
        $relative = self::convert($relative, 'Y-m-01');
        return strtotime($relative);
    }

    /**
     * 月结束时间[23:59:59]
     *
     * @param null $relative
     * @return false|int
     */
    public static function monthEnd($relative = null) {
        $firstday = self::convert($relative, 'Y-m-01');
        return strtotime($firstday . " +1 month") - 1;
    }

    /**
     * 某一天开始的时间 00:00:00
     *
     * @param null $relative
     * @return false|int
     */
    public static function dayStart($relative = null) {
        $day = self::convert($relative);
        return strtotime($day);
    }

    /**
     * 某一天开始的时间 23:59:59
     *
     * @param null $relative
     * @return false|int
     */
    public static function dayEnd($relative = null) {
        $day = self::convert($relative);
        return strtotime($day . ' +1 day') - 1;
    }

    /**
     * 一天中某个小时的时间戳
     * @param null $relative
     * @param $hour
     * @return false|int
     */
    public static function dayHour($relative = null, $hour = '00') {
        $day = self::convert($relative);
        $day = $day . " $hour:00:00";
        return strtotime($day);
    }

    /**
     * 一天中某小时某分钟的时间戳
     * @param null $relative
     * @param string $hourMinute
     * @return false|int
     */
    public static function dayMinute($relative = null, $hourMinute = '00:00') {
        $day = self::convert($relative);
        $day = $day . " $hourMinute:00";
        return strtotime($day);
    }

    /**
     * 本周的开始到结束
     *
     * @param null $relative
     * @return array
     */
    public static function thisWeek($relative = null) {
        if (is_null($relative)) {
            $relative = self::nowTime();
        } else if (Validator::validateQuickLy('chDate', $relative)) {
            $relative = strtotime($relative);
        }
        $startTime = strtotime('last Monday', $relative); //周一
        $endTime = strtotime('Sunday', $relative);  //周日
        return [
            'start' => self::dayStart($startTime),
            'end' => self::dayEnd($endTime),
        ];
    }

    /**
     * 七天的数据
     *
     * @param string $format
     * @param null $relative
     * @return array
     */
    public static function sevenDays($format = 'Y-m-d', $relative = null) {
        $data = [];
        if (is_null($relative)) $relative = self::nowTime();
        if (Validator::validateQuickLy('chDate', $relative)) {
            $relative = strtotime($relative);
        }
        for ($i = 7; $i >= 0; $i--) {
            $time = strtotime("-$i day", $relative);
            $data[] = [
                'date' => date($format, $time),
                'time' => $time,
                'shortDate' => date('m-d', $time),
            ];
        }
        $data[] = [
            'date' => date($format, $relative),
            'time' => $relative,
            'shortDate' => date('m-d', $relative),
        ];
        return $data;
    }

    /**
     * 半年
     *
     * @param string $format
     * @param null $relative
     * @return array
     */
    public static function halfYear($format = 'Y-m-d', $relative = null) {
        $data = [];
        if (is_null($relative)) $relative = self::nowTime();
        if (Validator::validateQuickLy('chDate', $relative)) {
            $relative = strtotime($relative);
        }
        for ($i = 5; $i >= 0; $i--) {
            $time = strtotime("-$i month", $relative);
            $month = date('n', $time);
            $data[] = [
                'date' => date($format, $time),
                'time' => $time,
                'month' => $month,
            ];
        }
        return $data;
    }

    /**
     * 日期间的差
     * @param $start
     * @param $end
     * @return \DateInterval|false
     */
    public static function diff($start, $end) {
        $start = Validator::validateQuickLy('chDate', $start) ? $start : date('Y-m-d', $start);
        $end = Validator::validateQuickLy('chDate', $end) ? $end : date('Y-m-d', $end);
        $sdate = date_create($start);
        $edate = date_create($end);
        $diff = date_diff($sdate, $edate);
        $result = [];
        $result['y'] = $diff->y + $diff->m / 12 + $diff->d / 365.25;
        $result['m'] = $diff->y * 12 + $diff->m + $diff->d / 30 + $diff->h / 24;
        $result['d'] = $diff->y * 365.25 + $diff->m * 30 + $diff->d + $diff->h / 24 + $diff->i / 60;
        $result['h'] = ($diff->y * 365.25 + $diff->m * 30 + $diff->d) * 24 + $diff->h + $diff->i / 60;
        $result['i'] = (($diff->y * 365.25 + $diff->m * 30 + $diff->d) * 24 + $diff->h) * 60 + $diff->i + $diff->s / 60;
        $result['s'] = ((($diff->y * 365.25 + $diff->m * 30 + $diff->d) * 24 + $diff->h) * 60 + $diff->i) * 60 + $diff->s;
        return $result;
    }

    /**
     * 所传日期是周几
     * @param $relative
     * @return false|string
     */
    public static function dateWeek($relative = null) {
        $day = self::convert($relative);
        return date('w', strtotime($day));
    }

    /**
     * 是不是UNIXTIME
     * @param $time
     * @return bool
     */
    public static function isUnixtime($time) {
        $len = strlen($time);
        if ($len < 10) {
            return false;
        }
        if ($len > 10) {
            $time = substr($time, 0, 10);
        }
        return ctype_digit($time) && $time <= 2147483647;
    }

    /**
     * 获取Oracle支持的to_date的时间格式
     * @param null $dateTime
     * @param string $format
     * @return Expression
     */
    public static function ociToDate($dateTime = null, $format = self::OCI_TIME_FORMAT_FULL) {
        if ($dateTime === null) {
            $dateTime = self::nowTime();
        }

//        if (self::isUnixtime($dateTime)) {
//            $dateTime = date('Y-m-d H:i:s', $dateTime);
//        }
//
//        return new Expression("TO_DATE('$dateTime', '$format')");

        if (!self::isUnixtime($dateTime)) {
            $dateTime = strtotime($dateTime);
        }

        return date('Y-m-d', $dateTime);
    }

    /**
     * UTC时间转时间戳
     * @param $dateTime
     * @return false|int
     */
    public static function utcToTime($dateTime) {
        return strtotime($dateTime);
    }

    /**
     * 是否是正确的年月格式
     * @param $yearMonth
     * @return false|int
     */
    public static function isYearMonth($yearMonth) {
        return preg_match('/^\d{4}[0-1]\d$/', $yearMonth);
    }

    /**
     * 当前年份
     * @return false|string
     */
    public static function nowYear() {
        return date('Y', self::nowTime());
    }

    /**
     * 当月
     * @return false|string
     */
    public static function nowYearMonth() {
        return date('Ym', self::nowTime());
    }

    /**
     * 获取日期区间的值
     * @param array $params
     * @return array|bool
     */
    public static function getDateRange($params = []){
        $default = [
            'startKey'=>'startDate',
            'endKey'=>'endDate',
            'value'=>null,
        ];
        $params = Tool::deepParse($params ,$default);
        if(!is_null($params['value'])){
            list($startDate, $endDate) = $params['value'];
        }else{
            $startDate = \Yii::$app->request->all($params['startKey']);
            $endDate = \Yii::$app->request->all($params['endKey']);
            $startDate = urldecode($startDate);
            $endDate = urldecode($endDate);
        }
        $startTime = strtotime($startDate);
        $endTime = strtotime($endDate);
        if(!$startTime || !$endTime){
            return false;
        }
        $monthStart = self::monthStart($startTime);
        return [
            'startDate'=>$startDate,
            'endDate'=>$endDate,
            'startTime'=>$startTime,
            'monthStart'=>$monthStart,
            'monthStartDate'=>date(self::OCI_DATE_FORMAT_PHP, $monthStart),
            'endTime'=>strtotime($endDate.'+1 day') - 1, //获取$endDate的23:59:59
        ];
    }
}
