返回指定日期在一段时间间隔时间后的日期

@param string $interval 时间间隔类型，（Y：年、Q：季度、M：月、W：星期、D：日期、H：时、N：分、S：秒）
@param int $value 时间间隔数值，数值为正数获取未来的时间，数值为负数获取过去的时间
@param string $dateTime 日期
@param string $format 返回的日期转换格式
@return string 返回追加后的日期
770632
public static function dateAdd($interval, $value, $dateTime = null, $format = null): string
    {
        $dateTime = $dateTime ? $dateTime : date('Y-m-d H:i:s');
        $date = getdate(self::getTimestamp($dateTime));
        switch ($interval) {
            case 'Y' : // 年
                $date ['year'] += $value;
                break;
            case 'Q' : // 季度
                $date ['mon'] += ($value * 3);
                break;
            case 'M' : // 月
                $date ['mon'] += $value;
                break;
            case 'W' : // 星期
                $date ['mday'] += ($value * 7);
                break;
            case 'D' : // 日
                $date ['mday'] += $value;
                break;
            case 'H' : // 时
                $date ['hours'] += $value;
                break;
            case 'N' : // 分
                $date ['minutes'] += $value;
                break;
            case 'S' : // 秒
            default :
                $date ['seconds'] += $value;
                break;
        }
        return date($format, mktime($date ['hours'], $date ['minutes'], $date ['seconds'], $date ['mon'], $date ['mday'], $date ['year']));
    }
1246472
private function dateIntervalToIntervalSpec(DateInterval $interval)
    {
        $date = sprintf('%uY%uM%uD', $interval->y, $interval->m, $interval->d);
        $time = sprintf('%uH%uM%uS', $interval->h, $interval->i, $interval->s);

        // build extra spec
        $extra = '';
        if ($interval->invert) {
            $extra .= 'I';
        }

        if ($interval->days) {
            $extra .= $interval->days . 'D';
        }

        if (strlen($extra) > 0) {
            $extra = '-' . $extra;
        }

        return sprintf('P%sT%s%s', $date, $time, $extra);
    }
528857
public function formatDateTime(\DateTime $datetime, $format, $calendar = \IntlDateFormatter::GREGORIAN)
    {
        $types = array(
            \IntlDateFormatter::NONE,
            \IntlDateFormatter::NONE,
        );
        if (is_array($format)) {
            if (isset($format[0])) {
                $types[0] = $format[0];
            }
            if (isset($format[1])) {
                $types[1] = $format[1];
            }
            $pattern = null;
        } else {
            $pattern = $format;
        }
        $formatter = new \IntlDateFormatter(
            $this->currentLocale,
            $types[0],
            $types[1],
            $datetime->getTimezone()->getName(),
            $calendar,
            $pattern
        );
        return $formatter->format($datetime);
    }
526020
public static function format($format, $value)
    {
        switch ($format) {
            case 'date-time':
                return self::formatDateTime($value);
            case 'date-time-http':
                return self::formatDateTimeHttp($value);
            case 'date':
                return self::formatDate($value);
            case 'time':
                return self::formatTime($value);
            case 'timestamp':
                return self::formatTimestamp($value);
            case 'boolean-string':
                return self::formatBooleanAsString($value);
            default:
                return $value;
        }
    }
554283
private function formatByMonthGrouping($value)
    {
        $value = $this->getTimestamp($value);
        if ('' === $value) {
            return '-';
        }
        $event = new ParseDateEvent($value, 'F Y');
        $this->dispatcher->dispatch(ContaoEvents::DATE_PARSE, $event);

        return $event->getResult();
    }
901516
public function formatTimeago($value)
    {
        if ($value instanceof DateTime) {
            $value = date_timestamp_get($value);

        } else if (!is_numeric($value) && is_string($value)) {
            $value = strtotime($value);
        }

        return $this->inWords((time() - $value));
    }
1290073
public function dateAdd($number = 0, $interval = "d") {
        $hours =  $this->hour;
        $minutes =  $this->minute;
        $seconds =  $this->second;
        $month =  $this->month;
        $day =  $this->day;
        $year =  $this->year;

        switch ($interval) {
            case "yyyy":
                //---Add $number to year
                $year += $number;
                break;

            case "q":
                //---Add $number to quarter
                $month += ($number*3);
                break;

            case "m":
                //---Add $number to month
                $month += $number;
                break;

            case "y":
            case "d":
            case "w":
                //---Add $number to day of year, day, day of week
                $day += $number;
                break;

            case "ww":
                //---Add $number to week
                $day += ($number*7);
                break;

            case "h":
                //---Add $number to hours
                $hours += $number;
                break;

            case "n":
                //---Add $number to minutes
                $minutes += $number;
                break;

            case "s":
                //---Add $number to seconds
                $seconds += $number;
                break;
        }

        return (new Date(mktime($hours,
                                $minutes,
                                $seconds,
                                $month,
                                $day,
                                $year)));

    }
817359
protected static function intervalHasTime(DateInterval $interval)
    {
        // The array_key_exists and get_object_vars are used as a workaround to check microsecond support.
        // Both isset and property_exists will fail on PHP 7.0.14 - 7.0.21 due to the following bug:
        // https://bugs.php.net/bug.php?id=74852
        return $interval->h || $interval->i || $interval->s || array_key_exists('f', get_object_vars($interval)) && $interval->f;
    }
467422
public function rule_date_format( $key, $value, $format = 'd/m/Y' ) 
	{
		return date( $format, strtotime( trim( $value ) ) ) == trim( $value );
	}
743180
public function format($format, $value)
    {
        switch ($format) {
            case 'date-time':
                return $this->formatDateTime($value);
            case 'date-time-http':
                return $this->formatDateTimeHttp($value);
            case 'date':
                return $this->formatDate($value);
            case 'time':
                return $this->formatTime($value);
            case 'timestamp':
                return $this->formatTimestamp($value);
            case 'boolean-string':
                return $this->formatBooleanAsString($value);
            default:
                return $value;
        }
    }
13258
public function getOffsetDates($format, $interval = 30)
    {
        Argument::i()
            //argument 1 must be a string
            ->test(1, 'string')
            //argument 2 must be an integer
            ->test(2, 'int');

        $dates = array();
        $interval *= 60;

        for ($i=-12*3600; $i <= (12*3600); $i+=$interval) {
            $time = $this->time + $i;
            $dates[$i] = date($format, $time);
        }

        return $dates;
    }
597918
private function formatByDayGrouping($value)
    {
        $value = $this->getTimestamp($value);
        if ('' === $value) {
            return '-';
        }
        $event = new ParseDateEvent($value, Config::get('dateFormat'));
        $this->dispatcher->dispatch(ContaoEvents::DATE_PARSE, $event);

        return $event->getResult();
    }
25562
public static function getSecondsFromInterval(DateInterval $interval)
    {
        $map   = [31536000, 2592000, 86400, 3600, 60, 1];
        $parts = explode('.', $interval->format('%y.%m.%d.%h.%i.%s'));
        $value = 0;

        foreach ($parts as $key => $val) {
            $value+= $val * $map[$key];
        }

        return $value;
    }
163268
public static function getDateTimeFromPeriodOrString($value, \DateTime $def = null) {
			$value = trim($value);

			if (!$value)
				return $def ?: new \DateTime();

			$initialChar = strtoupper(substr($value, 0, 1));

			if ($initialChar === 'P' || $initialChar === '+' || $initialChar === '-') {
				if ($initialChar !== 'P')
					$period = substr($value, 1);
				else
					$period = $value;

				$date = new \DateTime();

				if ($initialChar === '+')
					$date->add(new \DateInterval($period));
				else
					$date->sub(new \DateInterval($period));

				return $date;
			}

			return new \DateTime($value);
		}
156208
public static function dateFormat($val, $format = 'Y-m-d'): bool
    {
        if (!$val || !($unixTime = \strtotime($val))) {
            return false;
        }

        // 校验日期的格式有效性
        return \date($format, $unixTime) === $val;
    }
721591
public static function addInterval($interval, $format = self::DEFAULT_TIME_FORMAT)
    {
        $date = Clock::now()->toDateTime();
        $date->add(new DateInterval($interval));
        return $date->format($format);
    }
946808
protected function castValue($value)
    {
        if ($value instanceof \DateTime) {
            $value = [
                'unix' => (int) $value->format('U'),
                'time' => (string) $value->format('Y-m-d\TH:i:s'),
                'tz' => $value->getTimezone()->getName(),
            ];
        } elseif ($value instanceof \DateInterval) {
            $value = [
                'interval' => $value->format('P%yY%mM%dDT%HH%IM%SS'),
                'days' => $value->days,
                'y' => $value->y,
                'm' => $value->m,
                'd' => $value->d,
                'h' => $value->h,
                'i' => $value->i,
                's' => $value->s,
            ];
        } elseif ($value instanceof \DateTimeZone) {
            $value = [
                'tz' => $value->getName(),
            ];
        }
        
        return $value;
    }