Получить все недели указанного месяца, недели с вс-сб - PullRequest
1 голос
/ 05 августа 2020

РЕДАКТИРОВАТЬ

Я пробовал этот код прямо ниже. Это близко, но все еще не найдены недели с 1-го числа месяца до 1-й субботы, затем каждую неделю после вс-сб до последнего воскресенья до конца месяца.

function get_weeks($month, $year) {
    $weeks = array();

    $date = DateTime::createFromFormat('mY', $month.$year);
    $date->modify('first day of this month');

    $end = clone $date;
    $end->modify('last day of this month');
    $interval = DateInterval::createFromDateString('1 week');
    $period = new DatePeriod($date, $interval, $end);

    $counter = 1;
    foreach ($period as $dt) {
        $end_of_week = clone $dt;
        $end_of_week->modify('this Saturday');
        $weeks[] = sprintf("Week %u: %s - %s", 
            $counter,
            $dt->format('Y-m-d'),
            $end_of_week->format('Y-m-d')
        );      
        $counter++;
    }

    return $weeks;
}
$weeks = get_weeks('08', '2020');
print_r($weeks); 

Он печатает:

Array
(
[0] => Week 1: 2020-08-01 - 2020-08-01
[1] => Week 2: 2020-08-08 - 2020-08-08
[2] => Week 3: 2020-08-15 - 2020-08-15
[3] => Week 4: 2020-08-22 - 2020-08-22
[4] => Week 5: 2020-08-29 - 2020-08-29
)

Но вместо этого он должен напечатать:

Array
(
[0] => Week 1: 2020-08-01 - 2020-08-01 //correct for this month since 1st day of month and 1st Saturday of this month just happen to be on the same day
[1] => Week 2: 2020-08-02 - 2020-08-08 
[2] => Week 3: 2020-08-09 - 2020-08-15 
[3] => Week 4: 2020-08-16 - 2020-08-22 
[4] => Week 5: 2020-08-23 - 2020-08-29 
[5] => Week 6: 2020-08-30 - 2020-08-31 //last Sunday until end of month
)

ОРИГИНАЛЬНАЯ ЗАПИСЬ

Моя цель - получить данные временной метки для указанного номера недели указанного месяца. Я начинаю свою неделю в вс, заканчиваю в сб. Итак, я пытаюсь получить все временные метки для каждой недели в конкретном c месяце, чтобы я мог построить график, показывая общее количество часов каждой недели. Но сначала мне нужно указать начало и конец каждой недели для этого месяца. Мне удалось сделать это для каждого дня недели определенной c недели, но настройка недели / месяца для меня слишком сложна.

Вот что у меня есть:

function task_range_month_week($monthweek, $cap_start_raw, $cap_end_raw) {
    $start    = new DateTime(date('Y-m-d',$cap_start_raw));
    $end      = new DateTime(date('Y-m-d',$cap_end_raw+86399));        
    $interval = DateInterval::createFromDateString('1 week');
    $period   = new DatePeriod($start, $interval, $end);
    foreach ($period as $dt) {
        //just make it return the values for only a single (specified) week of the month
        //if ($dt->format("N") == $monthweek) {
            $cap_start = strtotime($dt->format("Y-m-d 00:00:00"));
            $cap_end = strtotime($dt->format("Y-m-d 23:59:59"));
        //}
}

Тогда Я бы назвал функцию так, где $cap_start_raw и $cap_end_raw - даты начала и окончания месяца, а $monthweek - это указанный номер недели (1-6). Поэтому я пытаюсь получить время с воскресенья по субботу (или любых других неполных дней недели месяца) для этой конкретной c недели.

Тогда $cap_start и $cap_end будут выходными для диапазона указанной недели.

Я хочу вызвать эту функцию следующим образом:

//get the 1st week of August 2020, Sun 00:00:00 - Sat 11:59:59 (or whatever days of the month are still in this week)
task_range_month_week(1, 1596240000, 1598918399) 
//this would output the 2 new timestamps for that week(1)
//$cap_start = 1XXXXXXXXX;
//$cap_end = 1XXXXXXXXX;

//get the 2nd week of August 2020, Sun 00:00:00 - Sat 11:59:59 (or whatever days of the month are still in this week)
task_range_month_week(2, 1596240000, 1598918399)
//this would output the 2 new timestamps for that week(2)
//$cap_start = 1XXXXXXXXX;
//$cap_end = 1XXXXXXXXX;
etc...

Я считаю, что это имеет отношение к части $dt->format(), но не знаю, как ее получить

Предполагаемый результат должен вернуть значения отметок времени $ cap_start и $ cap_end.

Другой способ сказать, что это ...

... он возвращает новые метки времени начала и конца для предполагаемого диапазона вывода. Я вызываю функцию task_range_month_week () для каждой недели, которую я ищу, чтобы найти начало и конец отдельной недели (вывод $ cap_start, $ cap_end). Итак, поскольку в августе 2020 года есть дни, охватывающие 6 различных календарных недель, я вызываю эту функцию 6 раз, каждый с указанием в месяц в месяц для 1-6 в случае этого месяца. Тогда в случае 1-й недели месяца новый выходной диапазон будет иметь $ cap_start 1-го числа месяца в 00:00:00, а поскольку $ cap_end выпадает на субботу, когда я хотите закончить мои недели (начинаются по воскресеньям), он должен вывести $ cap_end в тот же день в 23:59:59. Затем следующая неделя будет с воскресенья по субботу и так далее, пока не будут найдены все время начала и окончания недели для этого месяца, причем первая и последняя недели будут иметь диапазоны только до максимального отсечения, которое является началом месяца и время окончания.

Если я установлю «1 день» вместо «1 неделя» и раскомментирую if ($dt->format("N") == $monthweek), тогда он будет работать, когда я использую дни указанной недели, которые у меня уже есть для этого график. Но как заставить его работать на недельную настройку?

Есть идеи?

Ответы [ 2 ]

1 голос
/ 13 августа 2020

Я решил подойти к этой задаче с точки зрения арифметики c, а не с точки зрения даты и времени.

Может быть, есть элегантная техника изменения объекта datetime, которую я не рассматривал, но я не считаю, что мой подход с подсветкой вызова функций отвратителен. переменная / рассчитанная сумма и уничтожение l oop, когда представлены все дни полного месяца.

Код: ( Demo )

function get_weeks($month, $year) {
    $weeks = [];
    $ym = $year . '-' . $month;
    $final = date('t', strtotime($ym));
    $firstSat = date('d', strtotime("first Saturday of $ym"));
    $d = 1;
    $weekNo = 0;

    do {
        $weekEnd = $d === 1 ? $firstSat : min($final, $d + 6);
        $weeks[] = sprintf(
            "Week %d: %s-%02d - %s-%02d",
            ++$weekNo,
            $ym,
            $d,
            $ym,
            $weekEnd
        );
        $d = $weekEnd + 1;
    } while ($weekEnd < $final);

    return $weeks;
}
foreach (['01','02','03','04','05','06', '07', '08', '09', '10', '11', '12'] as $month) {
    echo var_export(get_weeks($month, '2020'), true) . "\n";
}

Вывод :

array (
  0 => 'Week 1: 2020-01-01 - 2020-01-04',
  1 => 'Week 2: 2020-01-05 - 2020-01-11',
  2 => 'Week 3: 2020-01-12 - 2020-01-18',
  3 => 'Week 4: 2020-01-19 - 2020-01-25',
  4 => 'Week 5: 2020-01-26 - 2020-01-31',
)
array (
  0 => 'Week 1: 2020-02-01 - 2020-02-01',
  1 => 'Week 2: 2020-02-02 - 2020-02-08',
  2 => 'Week 3: 2020-02-09 - 2020-02-15',
  3 => 'Week 4: 2020-02-16 - 2020-02-22',
  4 => 'Week 5: 2020-02-23 - 2020-02-29',
)
array (
  0 => 'Week 1: 2020-03-01 - 2020-03-07',
  1 => 'Week 2: 2020-03-08 - 2020-03-14',
  2 => 'Week 3: 2020-03-15 - 2020-03-21',
  3 => 'Week 4: 2020-03-22 - 2020-03-28',
  4 => 'Week 5: 2020-03-29 - 2020-03-31',
)
array (
  0 => 'Week 1: 2020-04-01 - 2020-04-04',
  1 => 'Week 2: 2020-04-05 - 2020-04-11',
  2 => 'Week 3: 2020-04-12 - 2020-04-18',
  3 => 'Week 4: 2020-04-19 - 2020-04-25',
  4 => 'Week 5: 2020-04-26 - 2020-04-30',
)
array (
  0 => 'Week 1: 2020-05-01 - 2020-05-02',
  1 => 'Week 2: 2020-05-03 - 2020-05-09',
  2 => 'Week 3: 2020-05-10 - 2020-05-16',
  3 => 'Week 4: 2020-05-17 - 2020-05-23',
  4 => 'Week 5: 2020-05-24 - 2020-05-30',
  5 => 'Week 6: 2020-05-31 - 2020-05-31',
)
array (
  0 => 'Week 1: 2020-06-01 - 2020-06-06',
  1 => 'Week 2: 2020-06-07 - 2020-06-13',
  2 => 'Week 3: 2020-06-14 - 2020-06-20',
  3 => 'Week 4: 2020-06-21 - 2020-06-27',
  4 => 'Week 5: 2020-06-28 - 2020-06-30',
)
array (
  0 => 'Week 1: 2020-07-01 - 2020-07-04',
  1 => 'Week 2: 2020-07-05 - 2020-07-11',
  2 => 'Week 3: 2020-07-12 - 2020-07-18',
  3 => 'Week 4: 2020-07-19 - 2020-07-25',
  4 => 'Week 5: 2020-07-26 - 2020-07-31',
)
array (
  0 => 'Week 1: 2020-08-01 - 2020-08-01',
  1 => 'Week 2: 2020-08-02 - 2020-08-08',
  2 => 'Week 3: 2020-08-09 - 2020-08-15',
  3 => 'Week 4: 2020-08-16 - 2020-08-22',
  4 => 'Week 5: 2020-08-23 - 2020-08-29',
  5 => 'Week 6: 2020-08-30 - 2020-08-31',
)
array (
  0 => 'Week 1: 2020-09-01 - 2020-09-05',
  1 => 'Week 2: 2020-09-06 - 2020-09-12',
  2 => 'Week 3: 2020-09-13 - 2020-09-19',
  3 => 'Week 4: 2020-09-20 - 2020-09-26',
  4 => 'Week 5: 2020-09-27 - 2020-09-30',
)
array (
  0 => 'Week 1: 2020-10-01 - 2020-10-03',
  1 => 'Week 2: 2020-10-04 - 2020-10-10',
  2 => 'Week 3: 2020-10-11 - 2020-10-17',
  3 => 'Week 4: 2020-10-18 - 2020-10-24',
  4 => 'Week 5: 2020-10-25 - 2020-10-31',
)
array (
  0 => 'Week 1: 2020-11-01 - 2020-11-07',
  1 => 'Week 2: 2020-11-08 - 2020-11-14',
  2 => 'Week 3: 2020-11-15 - 2020-11-21',
  3 => 'Week 4: 2020-11-22 - 2020-11-28',
  4 => 'Week 5: 2020-11-29 - 2020-11-30',
)
array (
  0 => 'Week 1: 2020-12-01 - 2020-12-05',
  1 => 'Week 2: 2020-12-06 - 2020-12-12',
  2 => 'Week 3: 2020-12-13 - 2020-12-19',
  3 => 'Week 4: 2020-12-20 - 2020-12-26',
  4 => 'Week 5: 2020-12-27 - 2020-12-31',
)
0 голосов
/ 05 августа 2020

У меня есть функция, которая предоставляет даты начала и окончания недели в виде массива объектов DateTime на основе указанного c номера недели (1-6) в указанном c месяце и году. В случае ошибки функция возвращает NULL.

function datesWeekInMonth(int $monthWeekNumber, int $month, int $year):?array {
  //week from Sun to Sat ! 
  $sat = date_create('first Sat of '.$year.'-'.$month);
  if($monthWeekNumber < 1 OR $sat === false) return NULL;
  if($monthWeekNumber == 1) return [date_create($year.'-'.$month.'-01'),$sat];
  $lastDayOfMonth = date_create('last Day of '.$year.'-'.$month);
  for($i=1;$i<$monthWeekNumber;$i++) {
    $sun = (clone $sat)->modify('+1 Day');
    $sat->modify('next Sat');
  }
  if($sun > $lastDayOfMonth) return NULL;
  return [$sun,min($sat,$lastDayOfMonth)];
}

Пример использования:

$result = datesWeekInMonth(3,8,2020); //third week of August 2020

var_dump($result);
/*
array(2) {
  [0]=>
  object(DateTime)#4 (3) {
    ["date"]=>
    string(26) "2020-08-09 00:00:00.000000"
    ["timezone_type"]=>
    int(3)
    ["timezone"]=>
    string(13) "Europe/Berlin"
  }
  [1]=>
  object(DateTime)#1 (3) {
    ["date"]=>
    string(26) "2020-08-15 00:00:00.000000"
    ["timezone_type"]=>
    int(3)
    ["timezone"]=>
    string(13) "Europe/Berlin"
  }
}
*/
...