从10月1日至3月31日,费用为1美元(第一季)。从4月1日至9月30日,费用为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年开始和结束,或者从2012年开始,仅在2013年就给我提供了10种不同的可能性:日期范围可以在哪一季开始,在哪里结束。
必须有更好的解决方案,而不是迭代if/ the,并为下列条件一次又一次地比较日期:
..。“从第二季开始”等
这不是离X-Y-Z日期还有几天?的复制,因为它只处理计算天数。它没有解决比较一个日期范围和另一个日期范围的问题。
发布于 2012-11-05 10:57:41
这个问题的关键是尽可能地简化它。我认为使用数组作为一年中每一天成本的查找表是可行的。接下来要做的第一件事是生成数组。数组只代表一年中的每一天,而不代表任何特定的年份。我选择使用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。
发布于 2012-11-05 07:50:44
起初,我建议使用PHP提供的DateTime类,天真地假设它有某种可以使用的深思熟虑的API。事实证明,事实并非如此。虽然它具有非常基本的DateTime功能,但它大部分是不可用的,因为对于大多数操作来说,它依赖于DateInterval类。结合起来,这些类代表了另一个糟糕的API设计杰作。
间隔的定义如下:
以Joda为单位的时间间隔表示从一个毫秒到另一个瞬间的时间间隔.这两个瞬间都是日期时间连续体中的完全指定的时间点,都是带有时区的。
然而,在PHP中,间隔只是一个持续时间:
日期间隔存储固定的时间(以年份、月、日、小时等为单位)或相对时间字符串(如"2天“)。
不幸的是,PHP的DateInterval定义不允许交叉/重叠计算( OP需要这样做),因为PHP的间隔在日期时间连续体中没有特定的位置。因此,我实现了一个(非常基本的)类,它遵循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;
}
}它可以这样使用:
$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());https://stackoverflow.com/questions/13227912
复制相似问题