phpdatetimeweek-numberdateinterval

Get all weeks of specified month, weeks from Sun-Sat


EDIT

I tried this code directly below. It's close, but still not finding the weeks from 1st of month to 1st saturday, then every week after from Sun-Sat, until last Sun to end of month.

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

It prints:

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
)

But it should instead print:

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
)

ORIGINAL POST

My goal is to pull timestamp data for the specified week number of specified month. I start my week on Sun, end on Sat. So I'm trying to get all timestamps collectively for each week in a specific month so I can graph it out, showing each week's total hours. But first I need the start and end of each week specified for that month. I was able to do this for each weekday of a specific week, but the week/month setup is too complex for me.

Here's what I have:

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"));
        //}
}

Then I would call the function like so, where the $cap_start_raw and $cap_end_raw are the month start and end dates, and $monthweek is the specified week number (1-6). Therefore, I'm trying to get the time from Sunday - Saturday (or whatever partial week days of the month) for that specific week.

The $cap_start and $cap_end would then be outputs for the specified week's range.

I want to call that function with this:

//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...

I believe it has to do with $dt->format() part, but not sure how to get it to work.

The intended output would return the $cap_start and $cap_end timestamp values.

Another way to say this is...

...it returns the new start and end timestamps for the intended output range. I call the task_range_month_week() function for each week that I'm looking to find a the individual week's start and end ( the $cap_start, $cap_end output). So since August 2020 has days that span over 6 different calendar weeks, I'll call that function 6 times, each with a $monthweek specified for 1-6 in this month's case. Then in the case of the 1st week for the month, the new output range would have the $cap_start on the 1st of the month at 00:00:00, and since the $cap_end happens to fall on a Saturday, which are when I want to end my weeks (starts on Sundays), it should output the $cap_end on that same day at 23:59:59. Then the next week would be from Sun-Sat, and so on, until all of the week's start and end times for that month are found, with the first and last weeks only having ranges to the maximum cut off which is the month start and end times.

If I set it to "1 day" instead of "1 week", and uncomment if ($dt->format("N") == $monthweek) then it works for when I do days of the specified week, which I already have setup for that graph. But how to make it work for the weeks setup?

Any ideas?


Solution

  • I decided to come at this task from an arithmetic perspective rather than a datetime perspective.

    Maybe there is an elegant datetime object mutating technique that I didn't consider, but I don't find my function-call-light approach to be hideous.

    I am confident that my variable naming will offer sufficient logical guidance through my script, but effectively I am increasing the start and end days of a given week by a variable/calulated amount and killing the loop when all of the days of the full month are represented.

    Code: (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";
    }
    

    Output:

    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',
    )