Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 计算一个日期范围内的天数与另一个日期范围内的天数_Php - Fatal编程技术网

Php 计算一个日期范围内的天数与另一个日期范围内的天数

Php 计算一个日期范围内的天数与另一个日期范围内的天数,php,Php,从10月1日到3月31日,费用为1美元(第一季)。从4月1日到9月30日,费用为2美元(第二季) 我如何计算给定日期范围(用户输入)的总费用,取决于该日期范围中第1季和第2季的天数 下面给出了用户日期范围的天数,但我不知道如何对照第1季或第2季进行测试: $user_input_start_date = getdate( $a ); $user_input_end_date = getdate( $b ); $start_date_new = mktime( 12, 0, 0, $user_i

从10月1日到3月31日,费用为1美元(第一季)。从4月1日到9月30日,费用为2美元(第二季)

我如何计算给定日期范围(用户输入)的总费用,取决于该日期范围中第1季和第2季的天数

下面给出了用户日期范围的天数,但我不知道如何对照第1季或第2季进行测试:

$user_input_start_date = getdate( $a );
$user_input_end_date = getdate( $b );

$start_date_new = mktime( 12, 0, 0, $user_input_start_date['mon'], $user_input_start_date['mday'], $user_input_start_date['year'] );
$end_date_new = mktime( 12, 0, 0, $user_input_end_date['mon'], $user_input_end_date['mday'], $user_input_end_date['year'] );

return round( abs( $start_date_new - $end_date_new ) / 86400 );
考虑到日期范围从2012年开始到2013年结束,或者从2012年开始到2013年结束,这给了我10种不同的可能性,即日期范围可以从哪个季节开始,在哪里结束

对于以下情况,必须有一个比迭代if/else和反复比较日期更好的解决方案:

  • 日期范围完全在第1季之内
  • 日期范围从第1季开始,到第2季结束
  • 日期范围从第1季开始,跨越第2季,在第1季的第二部分结束
  • 。。。“第二季开始”等等


    这不是as的副本,因为它只涉及计算天数。它没有解决将一个日期范围与另一个日期范围进行比较的问题。

    起初,我建议使用PHP提供的,天真地假设它有某种经过深思熟虑的API可以使用。事实证明并非如此。虽然它具有非常基本的DateTime功能,但它基本上不可用,因为对于大多数操作,它依赖于
    DateInterval
    类。总之,这些类代表了糟糕API设计的另一个杰作

    间隔的定义如下:

    $seasonStart = DateTime::createFromFormat('j-M-Y', '01-Apr-2012');
    $seasonEnd = DateTime::createFromFormat('j-M-Y', '30-Sep-2012');
    
    $userStart = DateTime::createFromFormat('j-M-Y', '01-Jan-2012');
    $userEnd = DateTime::createFromFormat('j-M-Y', '02-Apr-2012');
    
    $i1 = new ProperDateInterval($seasonStart, $seasonEnd);
    $i2 = new ProperDateInterval($userStart, $userEnd);
    
    $overlap = $i1->overlap($i2);
    var_dump($overlap->getDuration());
    
    Joda Time中的间隔表示从一毫秒到另一毫秒的时间间隔。这两个实例都是datetime连续体中完全指定的实例,包含时区

    然而,在PHP中,间隔只是一个持续时间:

    日期间隔存储固定的时间量(以年、月、日、小时等为单位)或相对时间字符串[如“2天”]

    不幸的是,PHP的DateInterval定义不允许交叉/重叠计算(OP需要),因为PHP的时间间隔在datetime连续体中没有特定的位置。因此,我实现了一个(非常基本的)类,它遵循JodaTime对区间的定义。它没有经过广泛的测试,但应该完成以下工作:

    class ProperDateInterval {
        private $start = null;
        private $end = null;
    
        public function __construct(DateTime $start, DateTime $end) {
            $this->start = $start;
            $this->end = $end;
        }
    
        /**
        * Does this time interval overlap the specified time interval.
        */
        public function overlaps(ProperDateInterval $other) {
            $start = $this->getStart()->getTimestamp();
            $end = $this->getEnd()->getTimestamp();
    
            $oStart = $other->getStart()->getTimestamp();
            $oEnd = $other->getEnd()->getTimestamp();
    
            return $start < $oEnd && $oStart < $end;
        }
    
        /**
         * Gets the overlap between this interval and another interval.
         */
        public function overlap(ProperDateInterval $other) {
            if(!$this->overlaps($other)) {
                // I haven't decided what should happen here yet.
                // Returning "null" doesn't seem like a good solution.
                // Maybe ProperDateInterval::EMPTY?
                throw new Exception("No intersection."); 
            }
    
            $start = $this->getStart()->getTimestamp();
            $end = $this->getEnd()->getTimestamp();
    
            $oStart = $other->getStart()->getTimestamp();
            $oEnd = $other->getEnd()->getTimestamp();
    
            $overlapStart = NULL;
            $overlapEnd = NULL;
            if($start === $oStart || $start > $oStart) {
                $overlapStart = $this->getStart();
            } else {
                $overlapStart = $other->getStart();
            }
    
            if($end === $oEnd || $end < $oEnd) {
                $overlapEnd = $this->getEnd();
            } else {
                $overlapEnd = $other->getEnd();
            }
    
            return new ProperDateInterval($overlapStart, $overlapEnd);
        }
    
        /**
         * @return long The duration of this interval in seconds.
         */
        public function getDuration() {
            return $this->getEnd()->getTimestamp() - $this->getStart()->getTimestamp();
        }
    
    
        public function getStart() {
            return $this->start;
        }
    
    
        public function getEnd() {
            return $this->end;
        }
    }
    

    这个问题的关键是尽可能地简化它。我认为使用数组作为一年中每天成本的查找表是可行的。然后要做的第一件事是生成数组。数组只表示一年中的每一天,而不表示任何特定的年份。我选择使用2012来生成查找数组,因为它是闰年,所以有可能的每一天

    function getSeasonArray()
    {
        /**
         * I have chosen 2012 as it was a leap year. All we want to do is
         * generate an array which has avery day of the year in it.
         */
        $startDate = new DateTime('1st January 2012');
        //DatePeriod always drops the last day.
        $endDate = new DateTime('1st January 2013');
        $season2Start = new DateTime('1st April 2012');
        $season2End = new DateTime('1st October 2012');
    
        $allDays = new DatePeriod($startDate, new DateInterval('P1D'), $endDate);
        $season2Days = new DatePeriod($season2Start, new DateInterval('P1D'), $season2End);
    
        $seasonArray = array();
    
        foreach($allDays as $day){
            $seasonArray[] = $day->format('d-M');
            $seasonArray[$day->format('d-M')]['season'] = 1;
        }
    
        foreach($season2Days as $day){
            $seasonArray[$day->format('d-M')]['season'] = 2;
        }
    
        return $seasonArray;
    }
    
    完成后,您只需要计算以下时间:-

    $bookingStartDate = new DateTime();//Or wherever you get this from
    $bookingEndDate = new DateTime();
    $bookingEndDate->setTimestamp(strtotime('+ 7 month'));//Or wherever you get this from
    $bookingPeriod = new DatePeriod($bookingStartDate, new DateInterval('P1D'),   $bookingEndDate);
    
    然后我们可以进行计算:-

    $seasons = getSeasonArray();
    $totalCost = 0;
    foreach($bookingPeriod as $day){
        $totalCost += $seasons[$day->format('d-M')]['season'];
        var_dump($day->format('d-M') . ' = $' . $seasons[$day->format('d-M')]['season']);
    }
    var_dump($totalCost);
    
    我选择了一个较长的预订期,这样您就可以扫描var_dump()输出,并验证一年中每一天的正确价格

    这是在工作中分心之间进行的一次快速尝试,我相信经过一点思考,你可以将其塑造成一个更优雅的解决方案。我想摆脱双重迭代,例如,不幸的是,工作压力阻止我在这方面花费更多的时间


    有关这些有用类的更多信息,请参阅PHP。

    此类的可能副本不是副本。他需要比较几个日期范围的重叠,而不仅仅是计算天数。@vascowhite:是的,我最初误解了这个问题。不幸的是,PHP DateTime API并没有经过深思熟虑(这是出乎意料的)。我目前正在检查是否有一个简单的解决方案可以使用API来实现这一点。我认为DatePeriod类可能是这里解决方案的关键。