将时间戳划分为几周

时间:2014-04-16 01:50:07

标签: php timestamp strtotime

我希望在PHP中将两个时间戳之间的范围划分为几周。

基本上,我想做的是:

function divide_into_weeks($start_time, $end_time) {
  // Iterate back from the end time,
  // creating an array of timestamps broken into calendar weeks.
  $done = FALSE;
  $divider = $end_time;
  for ($i = 0; !$done; $i++) {
    $timeslots[$i]->end = $divider;
    // Set the start time to the start of the current week.
    $timeslots[$i]->start = strtotime("monday this week", $divider);
    if ($timeslots[$i]->start <= $start_time) {$done = TRUE;}
    // If we loop again, end the previous week one second before the start of this week.
    $divider = $timeslots[$i]->start - 1;
  }
}

然而,该函数遇到无限循环。

为什么呢?因为...

strtotime("monday this week", $monday_of_next_week -1) == $monday_of_last week;

......是的,奇怪的是。这与我测试的其他strtotime操作不同。在其他情况下,你敲了一下,重复一遍,然后用你要求的任何单位之一迭代。但不是本周一(或周日)。

例如:

$today = strtotime("midnight");
$yesterday = strtotime("midnight", $today -1);

...产生明智的结果。

但是到目前为止,我尝试使用“本周一周日”或“本周日”的相同技术已证明毫无结果。

那么,有人可以展示如何将时间戳重复几周吗?

2 个答案:

答案 0 :(得分:1)

我认为这会对你有所帮助:

function divide_into_weeks($start_time, $end_time, $tz) {
    $tz    = new DateTimezone($tz);
    $start = new DateTime("@$start_time");
    $end   = new DateTime("@$end_time");
    $start ->setTimezone($tz)->modify($start->format('o-\WW-1 00:00:00'));
    $end   ->setTimezone($tz)->modify($end  ->format('o-\WW-7'));
    $weeks = [];

    do {
        $weeks[] = [
            'start' => clone $start,
            'end' => new DateTime($start->format('o-\WW-7 23:59:59'), $tz),
        ];
        $start->modify('+7 day');
    } while ($start < $end);

    return $weeks;
}

demo

答案 1 :(得分:0)

这最终成为了解决方法: (修剪了一些不相关的位。)

function divide_timespan_into_units($start_second, $end_second, $time_unit) {
  $timeslots = array();
  // The time_formatter guides strtotime in what parts of a timestamp to trim off to leave timestamps split on calendar divisions.
  switch ($time_unit) {
    case "hour":
      $time_formatter = 'Y-m-d H:00:00';
      break;
    case "day":
      $time_formatter = 'Y-m-d 00:00:00'; 
      break;
    case "week":
      $time_formatter = "monday this week"; 
      break;
  }

  $done = FALSE;
  $divider = $end_second;

  for ($i = 0; !$done; $i++) {
    $timeslots[$i] = (object) array('end' => $divider);
    if ($time_unit == "week") {
      // Dividing timestamps up into calendar weeks requires special handling. 
      //
      // Note on the strange constants "86399" & "86400" in the two lines following:
      // This is a workaround for a fluke in how strtotime treats weeks:
      // 
      // strtotime can't decide if Sunday or Monday is the start of the week.
      // You have to force it by rolling back a full day plus one second from the start of Monday, to get into the previous week.
      //
      // Simply rolling back a second from Sunday by 1 second doesn't get you into the previous week,
      // because if you ask for "this Sunday" on any day other than Sunday, it will return the coming Sunday, not the past Sunday.
      // However, if you back up 1 second from the stroke of midnight Monday, and ask what week you're in, 
      // you'll be told that you're still in the same week.
      //
      // This nudge of an extra 86400 seconds (a full extra day) back and forth forces the week to click over.
      //
      // This will likely be settled in a later version of PHP, but as of 5.3.5 (when this is being coded) it's an issue.
      $timeslots[$i]->start = strtotime("monday this week", $divider-86400);
      $divider = $timeslots[$i]->start+86399;
    } else {
      $timeslots[$i]->start = strtotime(date($time_formatter, $divider));
    }
    if ($timeslots[$i]->start <= $start_second) {$done = TRUE;}
    $divider = $timeslots[$i]->start - 1;
  }
}