I am currently generating an html table which contains dates in it's header
Those dates are the supposedly first days of each week through the whole year (the displayed year may change according to a filter), and they are generated by the following code
<?php $firstDay = strtotime($year . 'W' . str_pad($week, 2, '0', STR_PAD_LEFT)); ?>
<td><?= date('d/m/Y', $firstDay) ?></td>
This is inside a for loop that makes the $week go from 1 to the number of weeks in the whole year.
What I have noticed is that for some years, the last monday of December from the previous year is included in there too, such as 29/12/2014 when I select 2015 in the filter.
So far, to determine the number of weeks that are in a month, I used to count the number of mondays in said month programmatically and used it as the colspan for the row above the dates row, and so, there are uncounted weeks for january for some years, which makes the table shift.
The rendered html for the year 2015 would look like this
<table>
<thead>
<tr>
<th colspan="4">January</th>
<th colspan="4">February</th>
[...]
</tr>
<tr>
<!-- Under January cell -->
<th>29/12/2014</th>
<th>05/01/2015</th>
<th>12/01/2015</th>
<th>19/01/2015</th>
<!-- Under February cell -->
<th>26/01/2015</th>
<th>02/02/2015</th>
[...]
</tr>
</thead>
[...]
And after searching and testing a lot of week per month counters, none of those that I found seem to include that last monday from the previous year.
Could anyone find out how to count the weeks including that extra week from the previous year when it occurs?
The number of weeks falling in a given month is basically the number of days in a month, plus an offset that depends on which day of a week the month started in, divided by 7. Here is a solution using DateInterval and DatePeriod:
/**
* Get number of weeks starting *Monday*, occuring in a given month.
* A week occurs in a month if any day from that week falls in the month.
* #param $month_date is expected to be DateTime.
* #param $count_last count partial week at the end of month as part of month.
*/
function weeks_in_month($month_date, $count_last=true) {
$fn = $count_last ? 'ceil' : 'floor';
$start = new DateTime($month_date->format('Y-m'));
$days = (clone $start)->add(new DateInterval('P1M'))->diff($start)->days;
$offset = $month_date->format('N') - 1;
return $fn(($days + $offset)/7);
}
/**
* Wrapper over weeks_in_month() to get weeks in month for each month of a given year.
* #param $year_date is expected to be a DateTime.
*/
function year_month_weeks($year_date, $count_last=true) {
$start = new DateTime($year_date->format('Y') . '-01');
$year_month_weeks = [];
foreach(new DatePeriod($start, new DateInterval('P1M'), 11) as $month) {
$year_month_weeks[] += weeks_in_month($month, $count_last);
}
return $year_month_weeks;
}
print_r(year_month_weeks(new DateTime('2008-01'), true));
Gives:
Array
(
[0] => 5
[1] => 5
[2] => 6
[3] => 5
[4] => 5
[5] => 6
[6] => 5
[7] => 5
[8] => 5
[9] => 5
[10] => 5
[11] => 5
)
This can be validated against output of cal. For the first 6 months of 2008 should have 6 weeks in March, Jun, 5 for the rest:
>ncal -Mb -m 1 -A 5 2008
2008
January February March
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 1 2 3 1 2
7 8 9 10 11 12 13 4 5 6 7 8 9 10 3 4 5 6 7 8 9
14 15 16 17 18 19 20 11 12 13 14 15 16 17 10 11 12 13 14 15 16
21 22 23 24 25 26 27 18 19 20 21 22 23 24 17 18 19 20 21 22 23
28 29 30 31 25 26 27 28 29 24 25 26 27 28 29 30
31
April May June
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 1 2 3 4 1
7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8
14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15
21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22
28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29
30
Recently did a listing quite simliar with Carbon.
Here a Snipped with some example output:
<?php
use Carbon\Carbon;
$counter = Carbon::createFromDate(2018, 1, 1);
$end = $counter->copy()->endOfYear();
$months = [];
for (; $counter <= $end; $counter->addWeek()) {
// just to avoid E_NOTICE
if (!isset($months[$counter->month])) {
$months[$counter->month] = [
'count' => 0,
'weekstarts' => [],
];
}
++$months[$counter->month]['count'];
$months[$counter->month]['weekstarts'][] = $counter->copy();
}
foreach ($months as $month) {
printf('Month has %d weeks', $month['count']);
echo PHP_EOL;
foreach ($month['weekstarts'] as $num => $weekStartDate) {
printf('Week %d starts at %s', $num + 1, $weekStartDate);
echo PHP_EOL;
}
echo PHP_EOL;
}
So, this was my turnaround, using the function used to generate the first days of each week
function getIsoWeeksInYear($year) {
$date = new DateTime;
$date->setISODate($year, 53);
return ($date->format("W") === "53" ? 53 : 52);
}
function getWeeksPerMonth($year) {
$allWeeks = $this->getIsoWeeksInYear($year);
$allFirstDays = [];
for ($i = 0; $i < $allWeeks; $i++) {
$allFirstDays[] = date('m/Y', strtotime($year . "W" . str_pad($i, 2, "0", STR_PAD_LEFT)));
}
$countWeek = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
foreach ($allFirstDays as $firstDay) {
$theMonth = explode('/', $firstDay);
for ($i = 1; $i < 13; $i++) {
if ($theMonth[0] == $i) {
$countWeek[$i - 1]++;
}
}
}
return $countWeek;
}
So, the idea was to get a whole array of week numbers and use it in a loop for the colspans
<?php $span = getWeeksPerMonth($year) ?>
<?php for ($i = 1; $i < 13; $i++): ?>
<th colspan="<?= $span[$i - 1] ?>"><?= strftime('%B', mktime(0, 0, 0, $i)) ?></th>
<?php endfor ?>
And for the row below, I just use what I already used earlier in my question
<?php for ($i = 0; $i < getIsoWeeksInYear($year); $i++): ?>
<?php $firstDay = strtotime($year . 'W' . str_pad($week, 2, '0', STR_PAD_LEFT)); ?>
<th><?= date('d/m/Y', $firstDay) ?></th>
<?php endfor ?>
So, there may be some previous year included week in january and some next year excluded week for december.
Maybe, there are still some stuff to tweak somewhere. Anyway, I'll test out the other anwers and I guess I'll mark the easiest one to use as the answer.
Edit
It looks like I didn't have to explode the obtained date, as I initally thought I would have to use the year in some condition for the week starting the previous year
Related
I am using simple pagination with following code.
But I want to show 1 2 3 ..... 10 11 12 type pagination.
When more number of pages are there, pagination should be adjusted accordingly.
My current simple pagination php code is :
<?php
if (isset($_GET["start"])){
$start = $db->filter($_GET["start"]);
}
if(empty($start)){
$start= 0;
}
$maxrecords = 10;
$pagination_query = "select * from table order by id desc";
$pagination_count = $db->num_rows($pagination_query);
$query = "select * from table order by id desc limit $start,$maxrecords"; // For record to display...
$result = $db->get_results($query);
?>
<div class="pagination">
<?php
for($i=0;$i<ceil($pagination_count/$maxrecords);$i++){
if($start==$i*$maxrecords){
?>
<a class='active'> <?php print $i+1;?></a>
<?php }else{ ?>
<?php print $i+1;?>
<?php
}
}
?>
</div>
<!-- Rest code to display records goes here -->
Now this code is working rightly...
Only thing is it is showing paginatin - 1 2 3 4 5 6 7 like unlimited depending upon total records in database...
I want to convert it to 1 2 3 .... 22 23 24 etc...
Your valuable help appreciated...
My answer begins by some notes about what I'm seeing about pagers.
Then, this answer doesn't provide the "expected result" you want, but I think it could be more "flexible".
I think your query to get the number of record seems to be expensive. You could just use a count(*) :
$pagination_query = "select count(*) as num from table order by id desc" ;
$pagination_count = $db->get_field_result() ; // I don't know your DB API.
I think your query to get the current results seems to doesn't take care about the $start and $maxrecords (but I don't known your database API) :
$query = "select * from table order by id desc limit ".($start*$maxrecords).",$maxrecords"; // range 0+10, 10+10, 20+10, ...
You could use several loops to display begining pages, "around current", and ending pages.
Here is a "sample" code, not perfect, but it could helps you to imaging your own pager.
$start = 7 ; // try with 1, 7, 24, 75...
$pagination_count = 40 ; // Number of results
$maxrecords = 10 ;
$num_pages = ceil($pagination_count / $maxrecords) ;
// echo "num_pages=$num_pages\n" ; // Just for dev
if ($start > $num_pages) { $start = $num_pages; }
if ($num_pages < 6) {
for ($i = 0; $i < $num_pages ; $i++) {
echo render_page_link($i, $start);
}
}
else {
// Begining
for ($i = 0 ; $i < min(3, $num_pages); $i++) {
echo render_page_link($i,$start) ;
}
echo ' (...) ' ;
$have_middle = ($start > 3 && $start <= $num_pages - 3) ;
if ($have_middle) {
// Around current
for ($i = max(3, $start - 3); $i < min($start + 3 - 1, $num_pages - 3) ; $i++) {
echo render_page_link($i,$start) ;
}
}
// Ending
if ($have_middle) echo ' (...) ' ;
for ($i = $num_pages - 3; $i < $num_pages ; $i++) {
echo render_page_link($i,$start);
}
}
echo "\n"; // just because I test on CLI.
// Here is a little function to display the link:
// Currently just "plain text", but could be <a> or <span> with CSS...
function render_page_link($index, $current = -1)
{
if ($index != $current - 1) return ($index+1) . " " ;
return "[".($index+1)."] " ;
}
Example result for 1 to 24 pages
[1] 2 3 (...) 22 23 24
1 [2] 3 (...) 22 23 24
1 2 [3] (...) 22 23 24
1 2 3 (...) [4] 5 6 (...) 22 23 24
1 2 3 (...) 4 [5] 6 7 (...) 22 23 24
1 2 3 (...) 4 5 [6] 7 8 (...) 22 23 24
1 2 3 (...) 5 6 [7] 8 9 (...) 22 23 24
1 2 3 (...) 6 7 [8] 9 10 (...) 22 23 24
1 2 3 (...) 7 8 [9] 10 11 (...) 22 23 24
1 2 3 (...) 8 9 [10] 11 12 (...) 22 23 24
1 2 3 (...) 9 10 [11] 12 13 (...) 22 23 24
1 2 3 (...) 10 11 [12] 13 14 (...) 22 23 24
1 2 3 (...) 11 12 [13] 14 15 (...) 22 23 24
1 2 3 (...) 12 13 [14] 15 16 (...) 22 23 24
1 2 3 (...) 13 14 [15] 16 17 (...) 22 23 24
1 2 3 (...) 14 15 [16] 17 18 (...) 22 23 24
1 2 3 (...) 15 16 [17] 18 19 (...) 22 23 24
1 2 3 (...) 16 17 [18] 19 20 (...) 22 23 24
1 2 3 (...) 17 18 [19] 20 21 (...) 22 23 24
1 2 3 (...) 18 19 [20] 21 (...) 22 23 24
1 2 3 (...) 19 20 [21] (...) 22 23 24
1 2 3 (...) [22] 23 24
1 2 3 (...) 22 [23] 24
1 2 3 (...) 22 23 [24]
How to do that?
For example look at this October 2015 calendar
- - - 1 2 3 4 <---- 1st Week - TOTAL : 4 Days
5 6 7 8 9 10 11 <---- 2nd Week - TOTAL : 7 Days
12 13 14 15 16 17 18 <---- 3rd Week - TOTAL : 7 Days
19 20 21 22 23 24 25 <---- 4th Week - TOTAL : 7 Days
26 27 28 29 30 31 - <---- 5th Week - TOTAL : 6 Days
Now i want to get those total 4 Days, 7 Days, 7 Days,etc in an array so its just like this.
Array (
[0] => Array
([TOTAL] => 4)
[1] => Array
([TOTAL] => 7)
[2] => Array
([TOTAL] => 7)
[3] => Array
([TOTAL] => 7)
[4] => Array
([TOTAL] => 6)
)
Thanks in advance.
<?php
$date = '1-Oct-2015';
$date_timstamp = strtotime($date);
$day_in_month = date('t', $date_timstamp);
$arr_day_in_week = array();
$j=0;
for($i=0; $i<$day_in_month; $i++){
$day = date('D', $date_timstamp);
if($day == 'Sun'){
$j++;
$arr_day_in_week[] = $j;
$j=0;
}else{
$j++;
}
$date_timstamp += 24*60*60;
}
if($j>0){
$arr_day_in_week[] = $j;
}
print_r($arr_day_in_week);
?>
This post might be good use :
https://codereview.stackexchange.com/questions/5451/is-this-a-good-algorithm-to-find-each-week-in-a-given-month
Not sure it has the full solution to your problem but it's a good starting point imo
Got it..by modifying harry answer
$_TOTAL_DAY = cal_days_in_month(CAL_GREGORIAN,'10','2015');
$_COLLECT = array();
$SUM_WEEK = 0;
for($I=1; $I <= $_TOTAL_DAY; $I++){
$LOOP_DATE = date($year.'-'.$month.'-'.$I);
$LOOP_DAY = strtoupper(date('D',strtotime($LOOP_DATE)));
if($LOOP_DAY == 'SUN'){
$SUM_WEEK++;
$_COLLECT[] = $SUM_WEEK;
$SUM_WEEK = 0;
} else{
$SUM_WEEK++;
}
}
if($SUM_WEEK>0){
$_COLLECT[] = $SUM_WEEK;
}
print_r($_COLLECT);
die();
thank you :)
Im trying to make a table consist some sort of cinema seat from A[1-20] to J[1-20]. I have a txt file which contain seats that are reserved, like this:
A2;
A1;
A3;
A7;
if a seat is reserved, the bgcolor of table must be red. This is the full code:
<?php
$file = fopen($path,"r") or exit("cant open file");
$seat="";
while(!feof($file))
{
$seat.= fgets($file);
}
$seat_splitted = explode(";",$seat);
fclose($file);
$arrTable[]="";
$letter="";
$tableContent="";
for($i = 0,$counter=0;$i<10;$i++,$counter++)
{
if($i==0)
$letter="A";
else if($i==1)
$letter="B";
else if($i==2)
$letter="C";
else if($i==3)
$letter="D";
else if($i==4)
$letter="E";
else if($i==5)
$letter="F";
else if($i==6)
$letter="G";
else if($i==7)
$letter="H";
else if($i==8)
$letter="I";
else if($i==9)
$letter="J";
?>
<tr>
<?php
for($j = 1;$j<21;$j++)
{
$arrTable[$counter]= $letter.$j;
foreach($seat_splitted as $value)
{
if(strcmp($value,$arrTable[$counter])==0)
//if($value == $letter.$j)
{
$GLOBALS['color']="red";
break;
}
else
$GLOBALS['color']="white";
}
?>
<td bgcolor="<?php echo $GLOBALS['color']; ?>"> <?php echo $arrTable[$counter]?> </td>
<?php
$counter++;
}
?>
</tr>
<?php
}
?>
I dont know why when if(strcmp($value,$arrTable[$counter])==0) or //if($value == $letter.$j), its only catch the first seat which is "A2". But when i change the txt file to this:
A2;A1;A3;A7;
the IF can catch them all. Is it wrong to concatenate string like this? $seat.= fgets($file);. What can i do to make it work with the first txt file? Sorry for my bad english.
I think something like this should work for you. I simplified everything a bit.
1. First I create an array ($seats) with all seats in it. Which has a structure like this:
Array
(
[A] => Array
(
[1] => free
[2] => free
[3] => free
//...
//...
2. After this I get all reserved seats from the file into an array. (A better solution would be if you have all this data in a database!)
3. Then I loop through each reserved seat and also set it to that in the $seats array, so that it gets something like this:
Array
(
[A] => Array
(
[1] => reserved
[2] => free
[3] => reserved
//...
//...
4. At the end I simply print the table
Code:
<?php
//create seats
$rows = range(strtoupper("A"), strtoupper("J"));
$columns = range(1, 20);
$seats = array_combine($rows, array_map(function($v)use($columns){
return array_combine($columns, array_fill(0, count($columns), "free"));
}, $rows));
//get reserved seats
$reservedSeats = array_map(function($v){
return trim($v, ";");
}, file("test.txt", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES));
//set reserved seats
foreach($reservedSeats as $reserved) {
$checkOne = preg_replace("/[^A-Z]*/", "", $reserved);
$checkTwo = preg_replace("/[^0-9]*/", "", $reserved);
if(isset($seats[$checkOne]) && isset($seats[$checkOne][$checkTwo]))
$seats[$checkOne][$checkTwo] = "reserved";
}
//print seats
$reservedColor = "red";
$defaultColor = "white";
$rowColor = "green";
echo "<table border='1'>";
foreach($seats as $row) {
echo "<tr><td bgcolor='" . $rowColor . "'>" . $rowKey . "</td>";
foreach($row as $key => $seat)
echo "<td bgcolor='" . ($seat == "reserved"?$reservedColor:$defaultColor) . "'>" . $key . "</td>";
echo "</tr>";
}
echo "</table>";
?>
output (without colors):
A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
C 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
D 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
E 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
F 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
G 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
H 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
I 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
J 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
IF you use the explode as you do, you will get an array of:
["A2","\nB1","\nC3"...]
So you have to deal with the \n
Maybe you could have a try as explode(";\n",$seat)
Update: in some system u need to use \r\n. So here is the correct final solution: explode(";\r\n",$seat)
How do i create a nested loop that will output the following numbers?
each round the inner loop increase from 1 to 5, 5 to 10 and so on.
from i = 0 to 5
inner loop:
result: 1 2 3 4 5
result: 6 7 8 9 1 0
result: 11 12 13 14 15
result: 16 17 18 19 20
next
for($i=0;$i<50;$i++)
{
$s = $i +5;
echo $s;
}
unless you have to use an inner do...while loop, this will work:
<?php
$max = 5;
for($i=0;$i<$max;$i++){
for($j=1;$j<=$max;$j++){
echo str_pad(($i*$max)+$j,4);
}
echo "\r\n";
}
output:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
I used str_pad() just to make the columns more uniform
Using PHP I want to show the day of the month in ordinal way like ::
1 first
2 second
3 third
4 fourth
5 fifth
6 sixth
7 seventh
8 eighth
9 ninth
10 tenth
11 eleventh
12 twelfth
13 thirteenth
14 fourteenth
15 fifteenth
16 sixteenth
17 seventeenth
18 eighteenth
19 nineteenth
20 twentieth
21 twenty-first
22 twenty-second
23 twenty-third
24 twenty-fourth
25 twenty-fifth
26 twenty-sixth
27 twenty-seventh
28 twenty-eighth
29 twenty-ninth
30 thirtieth
31 thirty-first
e.g.
if date is 22-Feb it should show : twenty-second Feb
Thanks in advance....
Well, you already have your "array" there, just put it in code:
$ordinals = array(
1=>"first",
2=>"second",
// ...
);
Then you can access the array:
echo $ordinals[date("d")];