3

Could somebody please help me to resolve this PHP timestamp riddle

I'm trying to find number of weekdays based on two given dates.

I'm getting a string date eg starting date: 01/10/2019 (1st of October 2019) and explode it to a array => $s

Array $s set like this:

Array ( [0] => 01 [1] => 10 [2] => 2019 )

then I made a Unix timestamp from it :

date('U', mktime(0, 0, 0, $s[1], $s[0], $s[2]));

I get 1569884400 as the result of above date conversion.

then I use a loop to run this and so I can find number of week days based on the 2 given dates..

this is a result of that loop and as you can see for some reason 27th October repeating.

Just to clarify the top of this PHP page i have timezone set

date_default_timezone_set('Europe/London');

this is the code behind the below result

total $total_days based on last date (in this case 31st October 2019 and ie: 31 days)

October 2019 should have 23 working days, Since I get 2x 27th Octobers I will get only 22 weekdays.

What am I doing wrong here?

 $wk_days = array(1, 2, 3, 4, 5);
  $days = 0;
  for ($i = 0; $i < $total_days; $i++) {
    $tmp = $first + ($i * 86400);
    echo  $i." x86400 add to ". $first . " ==> " . $tmp. " and the new date is "  .date('Y-m-d',$tmp) ."<br/>";

    $chk = date('w', $tmp);

    if (in_array($chk, $wk_days)) {
      $days++;
    }
  }

0 x86400 add to 1569884400 ==> 1569884400 and the new date is 2019-10-01

1 x86400 add to 1569884400 ==> 1569970800 and the new date is 2019-10-02

2 x86400 add to 1569884400 ==> 1570057200 and the new date is 2019-10-03

3 x86400 add to 1569884400 ==> 1570143600 and the new date is 2019-10-04

4 x86400 add to 1569884400 ==> 1570230000 and the new date is 2019-10-05

...

23 x86400 add to 1569884400 ==> 1571871600 and the new date is 2019-10-24

24 x86400 add to 1569884400 ==> 1571958000 and the new date is 2019-10-25

25 x86400 add to 1569884400 ==> 1572044400 and the new date is 2019-10-26

26 x86400 add to 1569884400 ==> 1572130800 and the new date is 2019-10-27 //***

27 x86400 add to 1569884400 ==> 1572217200 and the new date is 2019-10-27 //***

28 x86400 add to 1569884400 ==> 1572303600 and the new date is 2019-10-28

29 x86400 add to 1569884400 ==> 1572390000 and the new date is 2019-10-29

30 x86400 add to 1569884400 ==> 1572476400 and the new date is 2019-10-30

2
  • 1
    1569884400 is September 30th, not October 1st. Could that be the problem? (Note that I haven't really gone through the rest of the logic in detail.) I think first and foremost you should double-check your conversion at the beginning. Commented Jan 15, 2020 at 13:59
  • 1
    You compute the date at midnight. You shoud compute it at 12 pm in order to avoid having a problem when the time changes from summer to winter on the last Sunday of October. So use date('U', mktime(12, 0, 0, $s[1], $s[0], $s[2])); Commented Jan 15, 2020 at 14:00

4 Answers 4

2

You don't need anything that complicated. You can have a simple while loop and count the weekdays. It might not be the most efficient way to do it, but it should work.

function getNoOfWeekdays(string $startdate, string $enddate, string $format = 'd/m/Y'): int
{
    $start = date_create_from_format($format, $startdate);
    $end = date_create_from_format($format, $enddate);

    $count = 0;
    while ($start <= $end) {
        if ($start->format('N') < 6) $count++;
        $start->modify('+1 days');
    }

    return $count;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Instead of a simple while loop, this can also be done with DatePeriod and a DateInterval "+1 weekday". The start date must be modified for this.
1

Maybe you could try with this code:

  $initial = "2019-10-01";
  $last = "2019-10-31";
  $wk_days = array(1, 2, 3, 4, 5);
  $days = 0;
  $date = $initial;
  do{

    $chk = date("w",strtotime($date));
    if(in_array($chk,$wk_days))
      $days++;
    $date = date("Y-m-d",strtotime("$date +1 day"));

  }while($date!=date("Y-m-d",strtotime("$last +1 day")));
    echo $days;
?>

Comments

1

I created a PHP extension for DateTime API called dt. You can find it here. Using it is very easy:

$start = '2019-10-01';
$end = '2019-11-01'; 

$start = dt::create($start);

//exclude end with true as 3.parameter
$countWeekdaysOct2019 = $start->countDaysTo('1,2,3,4,5',$end, true); //23

$countSundaysOct2019 = $start->countDaysTo('0',$end, true); //4

$countSaturdaysOct2019 = $start->countDaysTo('6',$end, true); //4

Comments

1

Try this (see my comment above) in order to avoid to problem of changing from summer to winter time:

$first = date('U', mktime(12 /* 12 pm!! */, 0, 0, $s[1], $s[0], $s[2]));
//
// some code here that the author didn't show and we hardly can extrapolate
// ...
//
$wk_days = array(1, 2, 3, 4, 5);
  $days = 0;
  for ($i = 0; $i < $total_days; $i++) {
    $tmp = $first + ($i * 86400);
    echo  $i." x86400 add to ". $first . " ==> " . $tmp. " and the new date is "  .date('Y-m-d',$tmp) ."<br/>";

    $chk = date('w', $tmp);

    if (in_array($chk, $wk_days)) {
      $days++;
    }
  }

4 Comments

Does this mean we have to manually handle summer time although we introduce the time zone?
No, no, what I mean is that if you compute the date from the timestamp at the border of your day (at midnight), and the border moves twice in a year, with a day of 25 hours in autumn and a day of 23 hours in the spring, you will create unwanted side effects. That is the reason why I suggest you to compute the timestamp of the day at 12 pm, instead of midnight.
After a while, I realize that what may work in the time zone of London may not work at the antipods. It should me more prudent to perform date arithmetics in a way that doesn't interact with timezones and daylight saving times.
I updated the code as you suggest and it work well. Thanks for the prompt help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.