PHP Calendar days left only of current month - php

I'm using an calendar rendering library (simplecalender/donatj) for one of my projects but I can't figure out how to display only the days left of current month and not the full month.
As far as I understand, this is the part that builds the calender:
public function show( $echo = true ) {
if( $this->wday_names ) {
$wdays = $this->wday_names;
} else {
$today = (86400 * (date("N")));
$wdays = array();
for( $i = 0; $i < 7; $i++ ) {
$wdays[] = strftime('%a', time() - $today + ($i * 86400));
}
}
$this->arrayRotate($wdays, $this->offset);
$wday = date('N', mktime(0, 0, 1, $this->now['mon'], 1, $this->now['year'])) - $this->offset;
$no_days = cal_days_in_month(CAL_GREGORIAN, $this->now['mon'], $this->now['year']);
If I change no_days to 25 only days 1-25 are displayed within the calendar. So almost what I want.
Any idea how I can display 25 to 31 only (days left for July)?
Thanks.
Here's the rest of the code:
$out = '<table cellpadding="0" cellspacing="0" class="SimpleCalendar"><thead><tr>';
for( $i = 0; $i < 7; $i++ ) {
$out .= '<th>' . $wdays[$i] . '</th>';
}
$out .= "</tr></thead>\n<tbody>\n<tr>";
$wday = ($wday + 7) % 7;
if( $wday == 7 ) {
$wday = 0;
} else {
$out .= str_repeat('<td class="SCprefix"> </td>', $wday);
}
$count = $wday + 1;
for( $i = 1; $i <= $no_days; $i++ ) {
$out .= '<td' . ($i == $this->now['mday'] && $this->now['mon'] == date('n') && $this->now['year'] == date('Y') ? ' class="today"' : '') . '>';
$datetime = mktime(0, 0, 1, $this->now['mon'], $i, $this->now['year']);
$out .= '<time datetime="' . date('Y-m-d', $datetime) . '">' . $i . '</time>';
$dHtml_arr = false;
if( isset($this->dailyHtml[$this->now['year']][$this->now['mon']][$i]) ) {
$dHtml_arr = $this->dailyHtml[$this->now['year']][$this->now['mon']][$i];
}
if( is_array($dHtml_arr) ) {
foreach( $dHtml_arr as $dHtml ) {
$out .= '<div class="event">' . $dHtml . '</div>';
}
}
$out .= "</td>";
if( $count > 6 ) {
$out .= "</tr>\n" . ($i != $count ? '<tr>' : '');
$count = 0;
}
$count++;
}
$out .= ($count != 1 ? str_repeat('<td class="SCsuffix"> </td>', 8 - $count) : '') . "</tr>\n</tbody></table>\n";
if( $echo ) {
echo $out;
}
return $out;
}
private function arrayRotate( &$data, $steps ) {
$count = count($data);
if( $steps < 0 ) {
$steps = $count + $steps;
}
$steps = $steps % $count;
for( $i = 0; $i < $steps; $i++ ) {
array_push($data, array_shift($data));
}
}

Related

Create Associative Array inside a for loop

Hi I've created an array with a for loop inside. The array doesn't have any data inside it until it reaches the for loop. I wanted to add an associative array to what I've done so far. For example my array currently ouputs
[0] => Array
(
[0] => Version 5
[1] => Feb-16
[2] => gary
[3] => 80
[4] => P
)
I would like it to have headings instead of numbers
[0] => Array
(
Version => Version 5
Date => Feb-16
Name => gary
RandNum => 80
Letter => P
}
I'm not sure how i'd fit into my loop and how I could if my different columns these headings. Below is my current code. Which outputs the array at the top.
for($i = 0; $i <= 3; $i++){
for($j = 0; $j <= 4; $j++){
if ($j == 0){
$times_table[$i][$j]= "Version 5" ;
}
else if ($j == 1){
$cur_date = date("M-y", $currentdate);
$currentdate = strtotime('+1 month', $currentdate);
$times_table[$i][$j]= "<strong>" . $cur_date . "</strong>" ;
}
else{
$times_table[$i][$j]= "gary" ;
}
if ($j == 3) {
$numbers = mt_rand(1, 100);
$times_table[$i][$j]= $numbers ;
}
if ($j == 4){
if($i == 0 || $i == 3)
{
$pay = "P";
$times_table[$i][$j]= $pay ;
}
else{
$int = "I";
$times_table[$i][$j]= $int ;
}
}
}
}
Try this..
for($i = 0; $i <= 3; $i++){
for($j = 0; $j <= 4; $j++){
if ($j == 0){
$times_table[$i]['Version']= "Version 5" ;
}
else if ($j == 1){
$cur_date = date("M-y", $currentdate);
$currentdate = strtotime('+1 month', $currentdate);
$times_table[$i]['Date']= "<strong>" . $cur_date . "</strong>" ;
}
else{
$times_table[$i]['Name']= "gary" ;
}
if ($j == 3) {
$numbers = mt_rand(1, 100);
$times_table[$i]['RandNum']= $numbers ;
}
if ($j == 4){
if($i == 0 || $i == 3)
{
$pay = "P";
$times_table[$i]['Letter']= $pay ;
}
else{
$int = "I";
$times_table[$i]['Letter']= $int ;
}
}
}
}
Hope this will solve your problem.
In my opinion, your second for loop is not needed. You should know that you can create associative arrays like this :
<?php
$times_table = [];
$times_tables[] = [
'Version' => 'Version 5',
'Date' => 'Feb-16',
'Name' => 'gary',
'RandNum' => '80',
'Letter' => 'P',
];
To match with your code :
<?php
$times_table = [];
for($i = 0; $i <= 3; $i++){
$times_table[$i]['Version']= "Version 5" ;
$cur_date = date("M-y", $currentdate);
$currentdate = strtotime('+1 month', $currentdate);
$times_table[$i]['Date']= "<strong>" . $cur_date . "</strong>" ;
$times_table[$i]['Name']= "gary" ;
$numbers = mt_rand(1, 100);
$times_table[$i]['RandNum']= $numbers ;
switch ($i) {
case 0:
case 3:
$letter = 'P';
break;
default:
$letter = 'I';
}
$times_table[$i]['Letter']= $letter;
}
I think this should do what you want in a cleaner way !
for($i = 0; $i <= 3; $i++){
for($j = 0; $j <= 4; $j++){
if ($j == 0){
$times_table["Version"][$j]= "Version 5" ;
}
else if ($j == 1){
$cur_date = date("M-y", $currentdate);
$currentdate = strtotime('+1 month', $currentdate);
$times_table["Date"][$j]= "<strong>" . $cur_date . "</strong>" ;
}
else{
$times_table["Name"][$j]= "gary" ;
}
if ($j == 3) {
$numbers = mt_rand(1, 100);
$times_table["RandNum"][$j]= $numbers ;
}
if ($j == 4){
if($i == 0 || $i == 3)
{
$pay = "P";
$times_table["Letter"][$j]= $pay ;
}
else{
$int = "I";
$times_table["Letter"][$j]= $int ;
}
}
}
}
You can create associative array like this:
$a=array("Version"=> "Version 5",
"Date"=> "Feb-16",
"Name" => "gary",
"RandNum" => 80,
"Letter" => "P"
)
To access this array in for loop use $a['key']. For eg. to access version5, use $a['version'], to access Feb-16 use $a['Date'].

Find a very first Fibonacci number which has 1000 digits

this is what i have coded to solve my problem it can produce a 10th digit number quickly, i have changed php.ini max-execution-time to 10000 still its not getting an answer in an hour . how can i run this code quickly/sppedly .
function fabNumber($n){
if($n==1 || $n==2) {
return 1;
}
return fabNumber($n-2) + fabNumber($n-1);
}
function count_digit($number){
return strlen($number);
}
$i = 1;
$count = 1;
while( $count != 1000){
$fab_number = fabNumber($i);
$count = count_digit($fab_number);
//var_dump($fab_number ,$count)."<br>";
++$i;
echo $fab_number . " index of ". $i ."<br>" ;
}
should i use GMP library
Edit 1:
function fabNumber($n){
if($n==1 || $n==2) {
return 1;
}
return gmp_strval( fabNumber($n-2) )+ gmp_strval(fabNumber($n-1) );
}
function count_digit($number){
return strlen($number);
}
$i = 1;
$count = 1;
while( $count != 100){
$fab_number =gmp_strval( fabNumber($i));
$count = count_digit($fab_number);
//var_dump($fab_number ,$count)."<br>";
++$i;
echo gmp_strval($fab_number) . " index of ". $i ."<br>" ;
}
#same slow progress
Something like:
function getFibonacci() {
$i = '0';
$k = '1'; //first fibonacci value
yield $k;
while(true) {
$k = gmp_add($i, $k);
$i = gmp_sub($k, $i);
yield $k;
}
}
foreach(getFibonacci() as $value) {
if (strlen($value) == 1000) {
break;
}
}
echo $value, PHP_EOL;
(PHP >= 5.5.0)
you can caching numbers to save time because in your version you recalculate all numbers at each iteration
$GLOBALS["fabTab"] = array();
function fabNumber($n){
if($n==1 || $n==2) {
return "1";
}
if (!isset($GLOBALS["fabTab"][$n])) {
$GLOBALS["fabTab"][$n] = bcadd(fabNumber($n-2), fabNumber($n-1));
}
return $GLOBALS["fabTab"][$n];
}
function count_digit($number){
return strlen($number);
}
$start = time();
$i = 1;
$count = 1;
while( $count != 1000) {
$fab_number = fabNumber($i);
$count = count_digit($fab_number);
//var_dump($fab_number ,$count)."<br>";
++$i;
}
echo "$fab_number<br/>index of ". $i ."<br>" ;
echo $count . " digits<br>" ;
echo (time() - $start) . " seconds<br>" ;

PHP Skip something a certain amout of times in loop

I have a ton of for loops for generating a table, with results from my MySQL DB. Some of the more important information are the start and end date. I calculate how many days this absence has besides the start date(For example 02.03.2015 - 04.03.2015, 2 days). I save this result in $difference, however I get this result during a for loop, so I cant simply go to the for loop and say $xyz - difference.
So I thought about skiping the <td>'s in the loop, as many times as the difference.
Here in the picture you see that the <td>'s are off the amount of days the absence lasts.
How can I skip them as many times as the difference, so the tables looks right again?
My code is still a mess so no comments about that:
echo '<table class="table table table-bordered table-striped table-hover">';
echo '<thead>';
for ($l = 0; $l < $days; $l++) {
if ($l == 0) {
echo '<th>', '<b>Day</b>', '</th>';
} else {
$date = "$current-$month-$l";
$date = date('D', strtotime($date));
$date = substr($date, 0, -1);
echo '<th class="center">', $date,'</th>';
}
echo "\n";
}
echo '</thead>';
echo '<tbody>';
for ($l = 0; $l < $days; $l++) {
if ($l == 0) {
echo '<td>', '<b>Onshore</b>', '</td>';
} else {
echo '<th class="center">', $l, '</th>';
}
echo "\n";
}
for ($i = 0; $i < $count_user; $i++) {
echo '<tr>';
$result = mysql_query("select start, end, type_FK, employee_FK FROM absences where employee_FK = {$array_user[$i]['employee_ID']} and MONTH(start) = $month and YEAR(start) = $current");
while ($row = mysql_fetch_assoc($result)) {
$array_absences[] = $row;
}
$count = 0;
if (!empty($array_absences)) {
$count = count($array_absences);
}
for ($j = 0; $j < $days; $j++) {
$true = 0;
if ($j == 0 && $i == $count_on) {
echo '<td>';
echo '<b>Offshore</b>';
echo '</td>';
for($k = 0; $k < $days -1; $k++){
echo '<td>';
echo '</td>';
}
echo '</tr>';
}
if ($j == 0) {
echo '<td>';
echo $array_user[$i]['name'], ' ', $array_user[$i]['surname'];
echo '</td>';
}
for ($k = 0; $k < $count; $k++) {
$array_absences[$k]['start'] = substr($array_absences[$k]['start'], -2);
$array_absences[$k]['end'] = substr($array_absences[$k]['end'], -2);
$array_absences[$k]['start'] = ereg_replace("^0", "", $array_absences[$k]['start']);
$array_absences[$k]['end'] = ereg_replace("^0", "", $array_absences[$k]['end']);
$difference = $array_absences[$k]['end'] - $array_absences[$k]['start'];
if ($j == $array_absences[$k]['start'] && $array_absences[$k]['employee_FK'] == $array_user[$i]['employee_ID']) {
$true = 1;
$result = mysql_query("select approved from absences where DAY(start) = $j and MONTH(start) = $month");
while ($row = mysql_fetch_assoc($result)) {
$approved[] = $row;
$n++;
}
$now = date('Y-m-d');
$absence = strtotime("$current/$month/$j");
$absence = date('Y-m-d',$absence);
for ($q = 0; $q < $difference+1; $q++) {
if ($approved[$n]['approved'] == 1) {
echo '<td class="center green">';
} elseif ($approved[$n]['approved'] == 0 && $now <= $absence) {
echo '<td class="center orange">';
} elseif ($approved[$n]['approved'] == 0 && $now > $absence) {
echo '<td class="center red">';
}
for ($l = 0; $l < $count_types; $l++) {
if ($array_absences[$k]['type_FK'] == $types[$l]['type_ID']) {
echo $types[$l]['short'];
}
}
echo '</td>';
}
}
}
//Days that are not absences
//Skip this the amounts of $difference
echo '<td ';
//If weekend special coloring
$date = "$current-$month-$j+1";
$date = new DateTime($date);
$day = $date->format("w");
if ($day == 6 || $day == 0) {
echo 'class = "weekend"';
}
echo '>';
echo '</td>';
echo "\n";
}
echo '</tr>';
}
I'm afraid I did not really get the sense of your explanations, however, to skip something in a loop, you can use the continue keyword for this.
For example :
for($i = 0; $i++; i<1000){
if($i < 200 && $i > 100)
continue;
// Computations are here....
}

More simplified way of creating page links dynamically?

well I have a working script (see below) but it seems quite clunky and redundant; in my defense I wrote this code many moons ago, but that's not the point. I was curious if anyone has an idea on a more efficient way of writing this code, with less loops and conditionals and, well, noise in the code.
Code in question:
private function pageLinks($num, $page = 1, $search = false, $ne = false) {
$query = ($search) ? '&query='.$search : null;
$by = (is_numeric($ne)) ? '&by='.$ne : null;
$links = 'Page(s):1';
$count = 1;
$npp = $this->numPerPage;
$buttons = 9;
$half = 4;
for($i = 1; $i <= $num; $i++) {
if(($i%$npp) === 0) {
$count++;
}
}
if($count < $buttons) {
for($i = 2; $i <= $count; $i++) {
$links .= '' . $i . '';
}
} elseif($page <= ($half + 2)) {
for($i = 2; $i <= $buttons; $i++) {
$links .= '' . $i . '';
}
$links .= '...' . $count . '';
} elseif($page <= ($count - ($half + 2))) {
$links .= '...';
for($i = $half; $i > 0; $i--) {
$links .= '' . ($page - $i) . '';
}
$links .= '' . ($page - $i) . '';
for($i = 1; $i <= $half; $i++) {
$links .= '' . ($page + $i) . '';
}
$links .= '...' . $count . '';
} else {
$links .= '...';
for($i = $buttons - 1; $i >= 0; $i--) {
$links .= '' . ($count - $i) . '';
}
}
return($links);
}
The method is called like so:
$links = $this->pageLinks($count, $page, $url, $ne);
And the variables are as such:
$count = total number of clients in database (int)
$page = current page to build from (int)
$url = the name or email for the search (String)
$ne = is for the search string either by name (1) or email (2) (int)
And the output is something like (as links):
Page(s):1 2 3 4 5 6 7 8 9...33
Or if you're in the middle (page 20):
Page(s):1...16 17 18 19 20 21 22 23 24...33
Now this isn't always called through a search function, hence the default values for $url and $ne, but that's not very important. My question is there a cleaner way to handle building of these links? Or am I stuck with this cluster of loops?
With the help of the people at codereview.stackexchange.com I found exactly what I needed. You can find the answer here for a more in-depth approach, but here is the updated code if anyone comes across this and is curious:
private function pageLinks($num, $page = 1, $search = false, $ne = false) {
$query = ($search && is_numeric($ne)) ? "&query=" . $search . "&by=" . $ne : null;
$links = "Page(s):" . $this->page_link(1, $query);
$npp = $this->numPerPage;
$half = 4;
$count = floor($num / $npp) + 1;
$from = $page - $half;
if($from <= 2) {
$from = 2;
}
$to = $page + $half;
if($to >= $count - 1) {
$to = $count - 1;
}
if($from > 2) {
$links .= "...";
}
for($i = $from; $i <= $to; $i++) {
$links .= $this->page_link($i, $query);
}
if($i < $count) {
$links .= "...";
}
$links .= $this->page_link($count, $query);
return($links);
}
private function page_link($num, $query) {
return("" . $num . "");
}

Seven flags to concise list of days of the week?

I have an array/string/integer of 7 flags, one for each day of the week (of a recurring event). How can I convert this to a brief list of the days?
So, for example
Given 1011001, return 'Su, T-W, Sa'.
Given 0111011, return 'M-W, F-Sa'.
What's the shortest way to accomplish this?
EDIT
For comparison, here's my own inelegant code:
<?php
function dowstring($dow) {
if ($dow == 0) return "Error";
$ddow = ["Su", "M", "T", "W", "Th", "F", "Sa"];
$t = strrev( sprintf('%07b', $dow) );
$u = str_split($t);
$out = '';
$cu = count($u);
$nn = 0; // number of days thus far counted
$v = 0; // number in the run
for($i = 0; $i < $cu; $i++) {
if ($u[$i]) {
if ($v == 0) {
$out .= ($nn) ? ", " : '';
$out .= $ddow[$i];
}
$nn++;
$v++;
}
else {
if ($v > 1) {
$out .= ($nn) ? "-" . $ddow[$i-1] : '';
}
$v = 0;
}
}
// in case Saturday is part of a run
if ($v > 1) {
$out .= ($nn) ? "-" . $ddow[$i-1] : '';
}
return $out;
}
echo "<pre>";
// testing script
for ($i = 1; $i < pow(2, 7); $i++) {
$ds = dowstring($i);
$j = strrev( sprintf("%07b", $i) );
printf("%s %s\n", $j, $ds);
}
echo "</pre>";
?>
EDIT
Another attempt, inspired by Prasanth:
function dowstring($dow) {
if ($dow == 0) return "Error";
$ddow = ["Su", "M", "T", "W", "Th", "F", "Sa"];
$t = strrev( sprintf('%07b', $dow) );
$v = array_keys( array_filter( str_split($t) ) );
$cv = count($v); $w = array();
$out = $ddow[$v[0]];
for ($i = 1; $i < $cv; $i++) $w[] = $v[$i] - $v[$i - 1] - 1;
$w = ( $cv == 1 ) ? array($w) : $w;
for ($i = 1; $i < $cv; $i++) {
if (!$w[$i - 1]) $last = $ddow[$v[$i]];
else {
if ( isset($last) ) $out .= '-' . $last;
$out .= ', ' . $ddow[$v[$i]];
unset($last);
}
}
if ($i > 1 && !$w[$i-2] ) $out .= '-' . $ddow[ $v[$i-1] ];
return $out;
}
I'd like to see something better. Anyone?
Try this:
$days=array('1'=>'Monday','2'=>'Tuesay','3'=>'Wednesday','4'=>'Thursday','5'=>'Friday','6'=>'Saturday','7'=>'Sunday');
$pattern = '1000110';
$arr1 = str_split($pattern);
$i=0;
foreach($days as $key => $tes) {
if($key - $arr1[$i] != $key) {
echo $tes;
}
$i++;
}
Adjust days array according to the sequence of days you want
Try this :
<?php
$days = array('Su','M','T','W','Th','F','Sa');
function checkConsec($d) {
for($i=0;$i<count($d);$i++) {
if(isset($d[$i+1]) && $d[$i]+1 != $d[$i+1]) {
return false;
}
}
return true;
}
$str = '0111011';
$array = array_keys(array_filter(str_split($str)));
$temp = array();
$res = array();
for($i=0;$i<count($array);$i++){
$temp[] = $array[$i];
if(checkConsec($temp) && count($temp) > 1){
$res[$temp[0]] = $days[$temp[0]]."-".$days[$temp[count($temp)-1]];
}else{
$res[$array[$i]] = $days[$array[$i]];
$temp = array();
$temp[] = $array[$i];
}
}
echo implode(",",$res);
?>

Categories