1<?php 2/** 3 * Plugin Countdown: Displays countdown from a specific date 4 * Syntax: <COUNTDOWN:date|description> 5 * date has to be formatted as GNU date (see strtotime) 6 * e.g. <COUNTDOWN:yyyy-mm-dd|description> 7 * <COUNTDOWN:mm/dd/yyy|description> 8 * 9 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 10 * @author Ekkart Kleinod <ekkart [at] ekkart.de> (V 2.x) 11 * @author Ron Peters <rbpeters [at] peterro.com> (V 1.0) 12 * @author Luis Machuca <luis [dot] machuca [at] gulix [dot] cl> (V 2.5+) 13 * @version 3.0 14 * 15 */ 16// must be run within Dokuwiki 17if (!defined('DOKU_INC')) { 18 die(); 19} 20if(!defined('DW_LF')) define('DW_LF',"\n"); 21require_once(DOKU_PLUGIN.'syntax.php'); 22 23/** 24 * Plugin-Class for Countdown-Plugin. 25 */ 26class syntax_plugin_countdown extends DokuWiki_Syntax_Plugin { 27 28 function syntax_plugin_countdown () { 29 global $ACT; 30 if ($ACT==='show' && $this->getConf('time_message') > 0) 31 msg ('Server time for Countdown plugin is: '. hsc(date('Y-m-d H:i')), 2); 32 } 33 34 function getType(){ 35 return 'substition'; 36 } 37 38 public function getPType() 39 { 40 return 'normal'; 41 } 42 43 function getSort(){ 44 return 721; 45 } 46 47 function connectTo($mode) { 48 $this->Lexer->addSpecialPattern('\<COUNTDOWN\:.+?\>',$mode,'plugin_countdown'); 49 } 50 51 // fix by Steffan Huehner 52 function handle($match, $state, $pos, Doku_Handler $handler) { 53 $stripped = substr($match,11,-1); 54 // separate date from description 55 $stripped = preg_split('/(?<!\\\\)\|/', $stripped, 3); 56 // $stripped has the form <date>|<description>|<format> 57 // convert all the escaped "\|" into "|" 58 for ($i=0; $i < count($stripped); $i++) { 59 $stripped[$i] = str_replace('\|', '|', $stripped[$i]); 60 } 61 return $stripped; 62 } 63 64 /** 65 * Create output. 66 */ 67 // fix by Steffan Huehner 68 function render($mode, Doku_Renderer $renderer, $data) { 69 list($dest, $descr, $fmt) = $data; 70 $Hoy= new DateTimeImmutable(); 71 $Next= new DateTimeImmutable($dest); 72 $dt_diff= date_diff($Hoy,$Next); 73 $dt_days = $dt_diff->days * ($dt_diff->invert ? -1 : 1); 74 if (!$descr) $descr = $this->getLang('nodesc'); 75/* 76 $thatDate = strtotime ($dest); 77 if ($thatDate <= 0) { 78 $renderer->doc .= $this->getLang('wrongformat'). ': '. $dest. '.'; 79 return true; 80 } 81*/ 82 // compose msg 83 84 if ($dt_days == 0 && $this->getConf('use_today') ) { 85 $Text1= 'Today '. $dt_diff->format("%H:%I"); 86 $WithHorus= false; 87 } else { 88 $ldays= $this->getLang('days'); 89 $Text1= $dt_diff->format(); 90 if ($this->getConf('with_hours')) { 91 $Text1.= $dt_diff->format("%a ${ldays} %H:%I"); 92 } else { 93 $Text1.= $dt_diff->format("%a ${ldays}"); 94 } 95 96 } 97 $TextArray[]= $Text1; 98 $TextArray[]= ($dt_diff->invert ? $this->getLang('since') : $this->getLang('until')); 99 $pdesc= p_render('xhtml', p_get_instructions($descr), $info); 100 $pdesc= str_replace('<p>', '', $pdesc); 101 $pdesc= str_replace('</p>', '', $pdesc); 102 $TextArray[] = $pdesc; 103 //$renderer->doc.= print_r($dt_diff, true); 104 //$difdata= $this->compute($thatDate); 105 $msg= implode(' ', $TextArray); 106 if ('xhtml' === $mode) { 107 $renderer->doc .= '<!-- countdown begin '. $data[0]. '-->'; 108 $renderer->doc .= '<span class="countdown">'; 109 $renderer->doc .= $msg; // sprintf("%d", $dt_days) . ' '; 110 111 //if ($this->getConf('business_days') > 0) $renderer->doc .= sprintf("(%u)", $difdata['bdays']). ' '; 112 //$renderer->doc .= ($difdata['days'] == 1) ? $this->getLang('oneday') : $this->getLang('days'); 113 //$renderer->doc .= ' '; 114 // if with_hours, ... hh:mm left ... 115 //if ($this->getConf('with_hours') ) $renderer->doc .= sprintf('%02d',$difdata['hours']). ':'. sprintf('%02d',$difdata['minutes']) . ' '; 116 // "since" or "until" 117 //$renderer->doc .= ($difdata['distance'] < 0) ? $this->getLang('since') : $this->getLang('until'); 118 //$renderer->doc .= ; 119 120 121 //$renderer->doc .= $pdesc; 122 // output date? 123 if ($this->getConf('include_date') ) { 124 $renderer->doc .= " (" . strftime($this->getLang('outputformat'), $Next->getTimestamp()) . ")"; 125 } 126 // end tag 127 $renderer->doc .= '</span><!-- countdown end -->'. DW_LF; 128 return true; 129 } 130 else if ('text' === $mode) { 131 $renderer->doc .= sprintf("%u %s %02u:%02u %s" 132 , abs($difdata['days']), ($difdata['days'] == 1 ? $this->getLang('oneday') : $this->getLang('days') ) 133 , $difdata['hours'], $difdata['minutes'] 134 , ($difdata['distance'] < 0 ? $this->getLang('since') : $this->getLang('until') ) 135 ); 136 $renderer->doc .= ' '. p_render('text', p_get_instructions($description), $info); 137 if ($this->getConf('include_date') ) { 138 $renderer->doc .= " (" . strftime($this->getLang('outputformat'), $thatDate) . ")"; 139 } 140 return true; 141 } 142 else 143 { 144 // no adequate renderer found 145 } 146 return false; 147 } 148 149 /** 150 @brief Returns an array with the time difference to the specified timestamp. 151 **/ 152 private function compute ($targetdate) { 153 // compute date difference in days: 86400 = 24*60*60 = seconds of one day 154 $t= time(); 155 $diffseconds = $targetdate - $t; 156 $difference = $diffseconds / 86400; 157 158 return array( 159 'distance' => $difference, 160 'days' => abs(($difference)), 161 'bdays' => $this->bdaysbetween( $t, $targetdate, array() ), 162 'hours' => abs($diffseconds / 3600) % 24, 163 'minutes' => abs($diffseconds / 60) % 60, 164 'seconds' => abs($diffseconds ) % 60 165 ); 166 } 167 168 /** @fn bdaysbetween 169 @ brief Business days between date1 and date2 170 Lifted from php.net 171 **/ 172 private function bdaysbetween($startDate,$endDate,$holidays) { 173 //The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24 174 //We add one to inlude both dates in the interval. 175 $days = ($endDate - $startDate) / 86400 + 1; 176 177 $no_full_weeks = floor($days / 7); 178 $no_remaining_days = fmod($days, 7); 179 180 //It will return 1 if it's Monday,.. ,7 for Sunday 181 $the_first_day_of_week = date("N",$startDate); 182 $the_last_day_of_week = date("N",$endDate); 183 184 //-->The two can be equal in leap years when february has 29 days, 185 //the equal sign is added here 186 //In the first case the whole interval is within a week, 187 //in the second case the interval falls in two weeks. 188 if ($the_first_day_of_week <= $the_last_day_of_week){ 189 if ($the_first_day_of_week <= 6 && 6 <= $the_last_day_of_week) $no_remaining_days--; 190 if ($the_first_day_of_week <= 7 && 7 <= $the_last_day_of_week) $no_remaining_days--; 191 } 192 else{ 193 if ($the_first_day_of_week <= 6) { 194 //In the case when the interval falls in two weeks, there will be a weekend for sure 195 $no_remaining_days = $no_remaining_days - 2; 196 } 197 } 198 199 //The no. of business days is: (number of weeks between the two dates) * (5 working days) + the remainder 200//---->february in none leap years gave a remainder of 0 but still calculated weekends between first and last day, this is one way to fix it 201 $workingDays = $no_full_weeks * 5; 202 if ($no_remaining_days > 0 ) 203 { 204 $workingDays += $no_remaining_days; 205 } 206 207 //We subtract the holidays 208 foreach($holidays as $holiday){ 209 $time_stamp=strtotime($holiday); 210 //If the holiday doesn't fall in weekend 211 if ($startDate <= $time_stamp && $time_stamp <= $endDate && date("N",$time_stamp) != 6 && date("N",$time_stamp) != 7) 212 $workingDays--; 213 } 214 215 return $workingDays; 216 } 217 218 219} 220