【问题标题】:Dividing timestamps into weeks将时间戳划分为周
【发布时间】:2014-04-16 01:50:07
【问题描述】:

我希望在 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);

...产生合理的结果。

但到目前为止,我对“本周的星期一”或“本周的星期日”使用相同技术的尝试已被证明是徒劳的。

那么,有人可以展示如何将时间戳按周迭代吗?

【问题讨论】:

  • 如果有效,结果应该是什么样的?
  • 你最终会得到一个时间戳数组,其中每个 timestamp[$n]->start 是一周开始的星期一的午夜,timestamp[$n]->end 是下周午夜前的第二个。 (特殊情况:初始时间戳的结束时间,正如所写,将是传递给函数的 $end_time。)
  • 这可能是因为星期几从太阳开始? :)
  • 不。当然,我也尝试过。 “本周日”通常返回下一个星期日。 (当然,除非今天是星期天。)从那个星期天后退并不比从星期一后退更成功。
  • 不,也不是这样。如果你输入一个“现在”时间作为“strtotime”的第二个参数,它将是相对的。然而,仅仅从当前的周一或周日取 -1 以将其跨入下周是不够的。如果您将其后退一天以上,您会看到它点击进入前一周。当然,您可以使用该技术构建一个非常笨拙的解决方法。

标签: php timestamp strtotime


【解决方案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

【讨论】:

    【解决方案2】:

    这最终成为了成功的解决方法: (剪掉了一些不相关的部分。)

    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;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-07-28
      • 2017-05-28
      • 2022-10-06
      • 1970-01-01
      • 1970-01-01
      • 2013-06-30
      • 2021-06-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多