我们正在创建一个非常通用的订购系统,该系统会在付费周期的当周为用户提供付款。
我们的薪资周期为两周一次,因此我们认为第1周将是ODD周,第2周将是即将到来的一周。
等等。
我们可以使用以下内容来确定它是奇数还是偶数周:
self::$now = new DateTime();
if (self::$now->format('W') % 2 === 0) {
// Week is even -
} else {
// Week is odd
}
如果是奇数周,我们希望将该周的星期日用作当前薪资周期的“开始日期”。另一方面,如果是偶数周,我们希望采用当周的周六并将其作为当前工资周期的“结束日期”。
以前,我们计算这些开始和结束日期的方法相当粗糙。我们只选择了一个任意日期作为两周工资周期的第一个日期,并使用一些凌乱的DateTime()
代码来计算差异等等。我们不想这样做,而是依赖于周是偶数还是奇数。
以下是我们用来计算之前开始和结束日期的代码:
public function getPreviousPeriodStart() {
$daysIntoCurrentPeriod = ((int)self::$now->diff(self::$refStart)->format('%a') % self::PERIOD_LENGTH);
self::$prevPeriodStart = new DateTime('2 weeks ago');
self::$prevPeriodStart->sub(new DateInterval('P'.$daysIntoCurrentPeriod.'D'));
return self::$prevPeriodStart;
}
public function getPreviousPeriodEnd() {
$daysLeftCurrentPeriod = self::PERIOD_LENGTH - ((int)self::$now->diff(self::$refStart)->format('%a') % self::PERIOD_LENGTH) - 1;
self::$prevPeriodStart = new DateTime('2 weeks ago');
self::$prevPeriodStart->add(new DateInterval('P'.$daysLeftCurrentPeriod.'D'));
return (self::$prevPeriodStart);
}
同样,我知道这很糟糕且很草率,这就是为什么我要改进它!
一旦我们确定了当前薪资周期的开始和结束日期,我们希望能够确定以下值:
我正在努力寻找最清洁,最安全的方法来处理这个问题。如果这种方法或方法不理想,我会欢迎任何其他建议 - 我只是想确保这是准确和可维护的!
答案 0 :(得分:3)
就像我在评论中所说的那样,奇数/偶数方法会在有奇数周的年份失败,就像2015年一样,有53周。因此,2015年的上周将是奇数,然后下周(2016年的第一周)也将是奇数。可能这不是故意的吗?
你的第一种方法更好。 选择一个日期作为参考,该参考是一个奇怪的开始日期日期。基于此,您现在知道当前时段是奇数还是偶数,请参阅方法isOdd()
。 / p>
示例:的
class DateTimeExtended extends DateTime {
# ref start date is odd
const REF_START = '2013-W43-1';
protected function isOdd(DateTime $dt)
{
$ref = new DateTime(self::REF_START);
return floor($dt->diff($ref)->days / 7) % 2 == 0;
}
public function getCurrentPeriodStart()
{
$dt = new DateTime($this->format('o-\WW-1'));
if (!$this->isOdd($dt)) {
$dt->modify('-1 week');
}
return $dt;
}
public function getCurrentPeriodEnd()
{
$dt = new DateTime($this->format('o-\WW-7'));
if ($this->isOdd($dt)) {
$dt->modify('+1 week');
}
return $dt;
}
public function getPreviousPeriodStart()
{
$dt = $this->getCurrentPeriodStart();
return $dt->modify('-2 week');
}
public function getPreviousPeriodEnd()
{
$dt = $this->getCurrentPeriodEnd();
return $dt->modify('-2 week');
}
}
使用(demo):
$dt = new DateTimeExtended;
print_r( $dt->getCurrentPeriodStart() ); # 2013-10-21
print_r( $dt->getCurrentPeriodEnd() ); # 2013-11-03
print_r( $dt->getPreviousPeriodStart() ); # 2013-10-07
print_r( $dt->getPreviousPeriodEnd() ); # 2013-10-20
就像问题评论中已经说过的Dwayne Towell一样,ISO8601周从星期一开始,而不是星期日,所以你需要调整代码才能让它像那样工作。只需替换ISO格式,例如this。