public static function getDateDifference($dateStart, $dateEnd, $differenceUnit = null)
    {
        $validDateStart = self::isValidDate($dateStart, true);
        $validDateEnd = self::isValidDate($dateEnd, true);

        /*
         * The start or end date is unknown?
         * or
         * The start or end date is not valid date?
         *
         * Nothing to do
         */
        if (empty($dateStart) || empty($dateEnd) || !$validDateStart || !$validDateEnd) {
            return null;
        }

        $start = self::getDateTime($dateStart, true);
        $end = self::getDateTime($dateEnd, true);

        $difference = [];
        $dateDiff = $end->getTimestamp() - $start->getTimestamp();

        $daysInSeconds = 0;
        $hoursInSeconds = 0;

        $hourSeconds = 60 * 60;
        $daySeconds = $hourSeconds * 24;

        /*
         * These units are related, because while calculating difference in the lowest unit, difference in the
         * highest unit is required, e.g. while calculating hours I have to know difference in days
         */
        $relatedUnits = [
            self::DATE_DIFFERENCE_UNIT_DAYS,
            self::DATE_DIFFERENCE_UNIT_HOURS,
            self::DATE_DIFFERENCE_UNIT_MINUTES,
        ];

        if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_YEARS === $differenceUnit) {
            $diff = $end->diff($start);

            // Difference between dates in years should be returned only?
            if (self::DATE_DIFFERENCE_UNIT_YEARS === $differenceUnit) {
                return $diff->y;
            }

            $difference[self::DATE_DIFFERENCE_UNIT_YEARS] = $diff->y;
        }

        if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_MONTHS === $differenceUnit) {
            $diff = $end->diff($start);

            // Difference between dates in months should be returned only?
            if (self::DATE_DIFFERENCE_UNIT_MONTHS === $differenceUnit) {
                return $diff->m;
            }

            $difference[self::DATE_DIFFERENCE_UNIT_MONTHS] = $diff->m;
        }

        if (null === $differenceUnit || in_array($differenceUnit, $relatedUnits, true)) {
            $days = (int)floor($dateDiff / $daySeconds);

            // Difference between dates in days should be returned only?
            if (self::DATE_DIFFERENCE_UNIT_DAYS === $differenceUnit) {
                return $days;
            }

            // All units should be returned?
            if (null === $differenceUnit) {
                $difference[self::DATE_DIFFERENCE_UNIT_DAYS] = $days;
            }

            // Calculation for later usage
            $daysInSeconds = $days * $daySeconds;
        }

        if (null === $differenceUnit || in_array($differenceUnit, $relatedUnits, true)) {
            $hours = (int)floor(($dateDiff - $daysInSeconds) / $hourSeconds);

            // Difference between dates in hours should be returned only?
            if (self::DATE_DIFFERENCE_UNIT_HOURS === $differenceUnit) {
                return $hours;
            }

            // All units should be returned?
            if (null === $differenceUnit) {
                $difference[self::DATE_DIFFERENCE_UNIT_HOURS] = $hours;
            }

            // Calculation for later usage
            $hoursInSeconds = $hours * $hourSeconds;
        }

        if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_MINUTES === $differenceUnit) {
            $minutes = (int)floor(($dateDiff - $daysInSeconds - $hoursInSeconds) / 60);

            // Difference between dates in minutes should be returned only?
            if (self::DATE_DIFFERENCE_UNIT_MINUTES === $differenceUnit) {
                return $minutes;
            }

            $difference[self::DATE_DIFFERENCE_UNIT_MINUTES] = $minutes;
        }

        return $difference;
    }