How to know how many Sundays have php mysql months

Asked

Viewed 2,879 times

8

Let’s say the year is: 2016 I need to know how many Sundays have the months of the year and save and result in php variable. Reason: I need to pass a condition,:

if ($dom_mes == 4 )
{     
    //CONDIÇÃO A     
} 
elseif ($dom_mes == 5 )
{
    //CONDIÇÃO B    
}
else
{
    //NADA A FAZER    
}
  • 1

    can start here http://answall.com/q/136778/4793

  • I reversed your edition, because it invalidates the existing answers. If you have new doubt, do it separately.

  • Okay, @Bacco, thank you.

  • @otaciojb remember to put all the details in the new question, to avoid having to modify later. When it is still unanswered, it still does (at the risk of harming someone who is developing something to post). When it comes to small details, that’s fine, but in this case, I was going to change the gist of the question. Complements are always welcome, as long as they do not change the main.

  • @Bacco Blza, Aobrigado. See new question, I think it was very clear: http://answall.com/questions/160477/passar-results-de-um-array-em-condi%C3%A7%C3%B5es-Else-if

  • @otaciojb I think you can explain a little better the result you want to get. Remember that it may be that people go in there, and have not seen this post here. If you want, you can put a link in that indicating the code of this one here that you are using as reference.

  • I answered your other question @otaciojb . Check out if it looks good.

Show 2 more comments

3 answers

7


You can get it month by month. I modified the example to make a loop:

<?php
$array = [];
$ano = 2016;


for($i = 1; $i <= 12; $i++){
    $data = $ano . '-' . $i. '-01';

    $inicio = new DateTime($data);
    $fim = new DateTime($inicio->format('Y-m-t'));
    $dias = $inicio->diff($fim, true)->days;

    $array[$i] = intval($dias / 7) + ($inicio->format('N') + $dias % 7 >= 7);
}
?>
<pre>
<?=print_r($array) ?>
</pre>
  • I went around and turned 55, I’m trying to see what might be wrong:

  • I edited the code. See if it fits

  • Array ( [1] => 5 [2] => 4 [3] => 4 [4] => 4 [5] => 5 [6] => 4 [7] => 5 [8] => 4 [9] => 4 [10] => 5 [11] => 4 [12] => 4 ) 1 , Perfect, Thank you !

  • Returns in 0.1 milliseconds

6

Follows an alternative solution:

function domingosNoMes( $mes, $ano ) {
    $t = gmmktime( 0, 0, 0, $mes, 1, $ano );
    $ult = date( 't', $t );
    $sem  = date( 'w', $t );
    return floor( ( $ult - 1 ) / 7 ) + ( $sem == 0 || $sem > ( 35 - $ult ) );
}

See working on IDEONE.

It is similar to the mathematical technique of Hugo Leonardo, who dispenses with the use of loops, only changes the part of using native functions directly, without objects.

If you want, you can simplify even more using N in place of w in the date, if you do not need compatibility with older versions of PHP, making it easy to remove || expression, with a small adjustment.

Remember that if you are using a 32-bit PHP, use timestamps only works until 2038. Now, if someone is still using things in 32 bits in the 2038, surely they have much more serious problems than timestamp :D

  • Returns in 0.054 milliseconds

2

One more

<?php

$week_day = 1; // The desired week day (sunday: 1, monday:2 .... saturday: 0)
$year = '2016'; // Year, 4 digits

$rs = array();
$month = 1;
while ($month <= 12) {
    $day = 1;
    $date = new DateTime($year.'-'.$month.'-'.$day);
    $day_last = $date->format('t');
    $i = 1;
    while ($day <= $day_last) {
        $date->add(new DateInterval('P'.$i.'D'));
        //$date->add(date_interval_create_from_date_string($i.' days'));
        $day_week = $date->format('w');
        if ($day_week == $week_day) {
            $rs[$month][] = $day;
            $i = 7;
        }
        $day += $i;
    }
    $month++;
}

echo '<pre>';
print_r($rs);
echo '</pre>';

Maintains a single instance of DateTime() for each month instead of creating an instance for each day of each month.

Don’t go every day of every month.
By identifying the first "Sunday", the counter jumps from 7 to 7, bringing a considerable performance gain than checking day by day. That is, instead of making 365/366 iterations, it only makes something around 52.

The routine is reusable. Just change the day code of the week and the year to get results for other days or years.

1: Domingo
2: Segunda
3: Terça
4: Quarta
5: Quinta
6: Sexta
0: Sábado

The return is a multidimensional array. For the year 2016, this is the result:

Array
(
    [1] => Array
        (
            [0] => 3
            [1] => 10
            [2] => 17
            [3] => 24
            [4] => 31
        )

    [2] => Array
        (
            [0] => 7
            [1] => 14
            [2] => 21
            [3] => 28
        )

    [3] => Array
        (
            [0] => 6
            [1] => 13
            [2] => 20
            [3] => 27
        )

    [4] => Array
        (
            [0] => 3
            [1] => 10
            [2] => 17
            [3] => 24
        )

    [5] => Array
        (
            [0] => 1
            [1] => 8
            [2] => 15
            [3] => 22
            [4] => 29
        )

    [6] => Array
        (
            [0] => 5
            [1] => 12
            [2] => 19
            [3] => 26
        )

    [7] => Array
        (
            [0] => 3
            [1] => 10
            [2] => 17
            [3] => 24
            [4] => 31
        )

    [8] => Array
        (
            [0] => 7
            [1] => 14
            [2] => 21
            [3] => 28
        )

    [9] => Array
        (
            [0] => 4
            [1] => 11
            [2] => 18
            [3] => 25
        )

    [10] => Array
        (
            [0] => 2
            [1] => 9
            [2] => 16
            [3] => 23
            [4] => 30
        )

    [11] => Array
        (
            [0] => 6
            [1] => 13
            [2] => 20
            [3] => 27
        )

    [12] => Array
        (
            [0] => 4
            [1] => 11
            [2] => 18
            [3] => 25
        )

)

Simply iterate the result to extract what you need.
I preferred to omit this part because iterate array() is something very basic.

Another important point is that the routine will still work even after the year 2038.
Of course in 2038 it will be rare or null someone using 32-bit systems. The concern is with the current epoch. Still many use 32-bit systems currently and may want to do operations with dates after 2038 under these environments, which may return erroneous results.

One more detail, regardless of the solution you choose, save the result in a static file or even in a database because if you need to run again you don’t need to run it all over again. If you executed once, the second time onwards is redundant because it will always bring the same result. This is a matter of performance and optimization. Do as you see fit.

Optimized version

This new optimized version runs 0.21 milliseconds. The previous one runs at 0.245 milliseconds. It also consumes less memory, saving about 458 bytes compared to the original

It follows the same logic as the original with the difference that now only one instance of Datetime().

What kills the performance a little is having to summon $date->format('m') and $date->format('d') to get the month and day. Which are optional because the question does not ask that. But I preferred to show a more detailed result stating which days were found the day of the week, in the case of Sunday.

The repeat limit is the total number of days of the year. The total is 366 for leap year and 365 for non-leap year.

When finding the first "Sunday", the increments are every 7 days, thus avoiding the eternal loop 365 or 366 times. In this scheme, we have only 54 iterations.

$week_day = 0; // The desired week day (sunday: 1, monday:2 .... saturday: 0)
$year = '2016'; // Year, 4 digits

$rs = array();
$days = (((($year % 4) == 0) && ((($year % 100) != 0) || (($year %400) == 0))))? 366: 365;
$date = new DateTime(($year - 1).'-12-31');
$day = 1;
$i = 1;
while ($day <= $days) {
    $date->add(new DateInterval('P'.$i.'D'));
    //$date->add(date_interval_create_from_date_string($i.' days'));
    $day_week = (int)$date->format('w');
    if ($day_week == $week_day) {
        $rs[(int)$date->format('m')][] = (int)$date->format('d');
        $i = 7;
    }
    $day += $i;
}

echo '<pre>';
print_r($rs);
echo '</pre>';

I also made a change in both versions in the following excerpt

    $date->add(new DateInterval('P'.$i.'D'));
    //$date->add(date_interval_create_from_date_string($i.' days'));

The original version was built with PHP running under Android. In this PHP has no class DateInterval() even if it’s version 7. That’s why I used date_interval_create_from_date_string().

Now I did using a Windows PC and could optimize more by switching back to new DateInterval() for date_interval_create_from_date_string() is an alias of the same. Alias functions (shortcut), are always slower "".

Browser other questions tagged

You are not signed in. Login or sign up in order to post.