Initial Kohana install
[speedfreak] / Server / system / helpers / date.php
1 <?php defined('SYSPATH') OR die('No direct access allowed.');
2 /**
3  * Date helper class.
4  *
5  * $Id: date.php 4316 2009-05-04 01:03:54Z kiall $
6  *
7  * @package    Core
8  * @author     Kohana Team
9  * @copyright  (c) 2007-2008 Kohana Team
10  * @license    http://kohanaphp.com/license.html
11  */
12 class date_Core {
13
14         /**
15          * Converts a UNIX timestamp to DOS format.
16          *
17          * @param   integer  UNIX timestamp
18          * @return  integer
19          */
20         public static function unix2dos($timestamp = FALSE)
21         {
22                 $timestamp = ($timestamp === FALSE) ? getdate() : getdate($timestamp);
23
24                 if ($timestamp['year'] < 1980)
25                 {
26                         return (1 << 21 | 1 << 16);
27                 }
28
29                 $timestamp['year'] -= 1980;
30
31                 // What voodoo is this? I have no idea... Geert can explain it though,
32                 // and that's good enough for me.
33                 return ($timestamp['year']    << 25 | $timestamp['mon']     << 21 |
34                         $timestamp['mday']    << 16 | $timestamp['hours']   << 11 |
35                         $timestamp['minutes'] << 5  | $timestamp['seconds'] >> 1);
36         }
37
38         /**
39          * Converts a DOS timestamp to UNIX format.
40          *
41          * @param   integer  DOS timestamp
42          * @return  integer
43          */
44         public static function dos2unix($timestamp = FALSE)
45         {
46                 $sec  = 2 * ($timestamp & 0x1f);
47                 $min  = ($timestamp >>  5) & 0x3f;
48                 $hrs  = ($timestamp >> 11) & 0x1f;
49                 $day  = ($timestamp >> 16) & 0x1f;
50                 $mon  = ($timestamp >> 21) & 0x0f;
51                 $year = ($timestamp >> 25) & 0x7f;
52
53                 return mktime($hrs, $min, $sec, $mon, $day, $year + 1980);
54         }
55
56         /**
57          * Returns the offset (in seconds) between two time zones.
58          * @see     http://php.net/timezones
59          *
60          * @param   string          timezone that to find the offset of
61          * @param   string|boolean  timezone used as the baseline
62          * @return  integer
63          */
64         public static function offset($remote, $local = TRUE)
65         {
66                 static $offsets;
67
68                 // Default values
69                 $remote = (string) $remote;
70                 $local  = ($local === TRUE) ? date_default_timezone_get() : (string) $local;
71
72                 // Cache key name
73                 $cache = $remote.$local;
74
75                 if (empty($offsets[$cache]))
76                 {
77                         // Create timezone objects
78                         $remote = new DateTimeZone($remote);
79                         $local  = new DateTimeZone($local);
80
81                         // Create date objects from timezones
82                         $time_there = new DateTime('now', $remote);
83                         $time_here  = new DateTime('now', $local);
84
85                         // Find the offset
86                         $offsets[$cache] = $remote->getOffset($time_there) - $local->getOffset($time_here);
87                 }
88
89                 return $offsets[$cache];
90         }
91
92         /**
93          * Number of seconds in a minute, incrementing by a step.
94          *
95          * @param   integer  amount to increment each step by, 1 to 30
96          * @param   integer  start value
97          * @param   integer  end value
98          * @return  array    A mirrored (foo => foo) array from 1-60.
99          */
100         public static function seconds($step = 1, $start = 0, $end = 60)
101         {
102                 // Always integer
103                 $step = (int) $step;
104
105                 $seconds = array();
106
107                 for ($i = $start; $i < $end; $i += $step)
108                 {
109                         $seconds[$i] = ($i < 10) ? '0'.$i : $i;
110                 }
111
112                 return $seconds;
113         }
114
115         /**
116          * Number of minutes in an hour, incrementing by a step.
117          *
118          * @param   integer  amount to increment each step by, 1 to 30
119          * @return  array    A mirrored (foo => foo) array from 1-60.
120          */
121         public static function minutes($step = 5)
122         {
123                 // Because there are the same number of minutes as seconds in this set,
124                 // we choose to re-use seconds(), rather than creating an entirely new
125                 // function. Shhhh, it's cheating! ;) There are several more of these
126                 // in the following methods.
127                 return date::seconds($step);
128         }
129
130         /**
131          * Number of hours in a day.
132          *
133          * @param   integer  amount to increment each step by
134          * @param   boolean  use 24-hour time
135          * @param   integer  the hour to start at
136          * @return  array    A mirrored (foo => foo) array from start-12 or start-23.
137          */
138         public static function hours($step = 1, $long = FALSE, $start = NULL)
139         {
140                 // Default values
141                 $step = (int) $step;
142                 $long = (bool) $long;
143                 $hours = array();
144
145                 // Set the default start if none was specified.
146                 if ($start === NULL)
147                 {
148                         $start = ($long === FALSE) ? 1 : 0;
149                 }
150
151                 $hours = array();
152
153                 // 24-hour time has 24 hours, instead of 12
154                 $size = ($long === TRUE) ? 23 : 12;
155
156                 for ($i = $start; $i <= $size; $i += $step)
157                 {
158                         $hours[$i] = $i;
159                 }
160
161                 return $hours;
162         }
163
164         /**
165          * Returns AM or PM, based on a given hour.
166          *
167          * @param   integer  number of the hour
168          * @return  string
169          */
170         public static function ampm($hour)
171         {
172                 // Always integer
173                 $hour = (int) $hour;
174
175                 return ($hour > 11) ? 'PM' : 'AM';
176         }
177
178         /**
179          * Adjusts a non-24-hour number into a 24-hour number.
180          *
181          * @param   integer  hour to adjust
182          * @param   string   AM or PM
183          * @return  string
184          */
185         public static function adjust($hour, $ampm)
186         {
187                 $hour = (int) $hour;
188                 $ampm = strtolower($ampm);
189
190                 switch ($ampm)
191                 {
192                         case 'am':
193                                 if ($hour == 12)
194                                         $hour = 0;
195                         break;
196                         case 'pm':
197                                 if ($hour < 12)
198                                         $hour += 12;
199                         break;
200                 }
201
202                 return sprintf('%02s', $hour);
203         }
204
205         /**
206          * Number of days in month.
207          *
208          * @param   integer  number of month
209          * @param   integer  number of year to check month, defaults to the current year
210          * @return  array    A mirrored (foo => foo) array of the days.
211          */
212         public static function days($month, $year = FALSE)
213         {
214                 static $months;
215
216                 // Always integers
217                 $month = (int) $month;
218                 $year  = (int) $year;
219
220                 // Use the current year by default
221                 $year  = ($year == FALSE) ? date('Y') : $year;
222
223                 // We use caching for months, because time functions are used
224                 if (empty($months[$year][$month]))
225                 {
226                         $months[$year][$month] = array();
227
228                         // Use date to find the number of days in the given month
229                         $total = date('t', mktime(1, 0, 0, $month, 1, $year)) + 1;
230
231                         for ($i = 1; $i < $total; $i++)
232                         {
233                                 $months[$year][$month][$i] = $i;
234                         }
235                 }
236
237                 return $months[$year][$month];
238         }
239
240         /**
241          * Number of months in a year
242          *
243          * @return  array  A mirrored (foo => foo) array from 1-12.
244          */
245         public static function months()
246         {
247                 return date::hours();
248         }
249
250         /**
251          * Returns an array of years between a starting and ending year.
252          * Uses the current year +/- 5 as the max/min.
253          *
254          * @param   integer  starting year
255          * @param   integer  ending year
256          * @return  array
257          */
258         public static function years($start = FALSE, $end = FALSE)
259         {
260                 // Default values
261                 $start = ($start === FALSE) ? date('Y') - 5 : (int) $start;
262                 $end   = ($end   === FALSE) ? date('Y') + 5 : (int) $end;
263
264                 $years = array();
265
266                 // Add one, so that "less than" works
267                 $end += 1;
268
269                 for ($i = $start; $i < $end; $i++)
270                 {
271                         $years[$i] = $i;
272                 }
273
274                 return $years;
275         }
276
277         /**
278          * Returns time difference between two timestamps, in human readable format.
279          *
280          * @param   integer       timestamp
281          * @param   integer       timestamp, defaults to the current time
282          * @param   string        formatting string
283          * @return  string|array
284          */
285         public static function timespan($time1, $time2 = NULL, $output = 'years,months,weeks,days,hours,minutes,seconds')
286         {
287                 // Array with the output formats
288                 $output = preg_split('/[^a-z]+/', strtolower((string) $output));
289
290                 // Invalid output
291                 if (empty($output))
292                         return FALSE;
293
294                 // Make the output values into keys
295                 extract(array_flip($output), EXTR_SKIP);
296
297                 // Default values
298                 $time1  = max(0, (int) $time1);
299                 $time2  = empty($time2) ? time() : max(0, (int) $time2);
300
301                 // Calculate timespan (seconds)
302                 $timespan = abs($time1 - $time2);
303
304                 // All values found using Google Calculator.
305                 // Years and months do not match the formula exactly, due to leap years.
306
307                 // Years ago, 60 * 60 * 24 * 365
308                 isset($years) and $timespan -= 31556926 * ($years = (int) floor($timespan / 31556926));
309
310                 // Months ago, 60 * 60 * 24 * 30
311                 isset($months) and $timespan -= 2629744 * ($months = (int) floor($timespan / 2629743.83));
312
313                 // Weeks ago, 60 * 60 * 24 * 7
314                 isset($weeks) and $timespan -= 604800 * ($weeks = (int) floor($timespan / 604800));
315
316                 // Days ago, 60 * 60 * 24
317                 isset($days) and $timespan -= 86400 * ($days = (int) floor($timespan / 86400));
318
319                 // Hours ago, 60 * 60
320                 isset($hours) and $timespan -= 3600 * ($hours = (int) floor($timespan / 3600));
321
322                 // Minutes ago, 60
323                 isset($minutes) and $timespan -= 60 * ($minutes = (int) floor($timespan / 60));
324
325                 // Seconds ago, 1
326                 isset($seconds) and $seconds = $timespan;
327
328                 // Remove the variables that cannot be accessed
329                 unset($timespan, $time1, $time2);
330
331                 // Deny access to these variables
332                 $deny = array_flip(array('deny', 'key', 'difference', 'output'));
333
334                 // Return the difference
335                 $difference = array();
336                 foreach ($output as $key)
337                 {
338                         if (isset($$key) AND ! isset($deny[$key]))
339                         {
340                                 // Add requested key to the output
341                                 $difference[$key] = $$key;
342                         }
343                 }
344
345                 // Invalid output formats string
346                 if (empty($difference))
347                         return FALSE;
348
349                 // If only one output format was asked, don't put it in an array
350                 if (count($difference) === 1)
351                         return current($difference);
352
353                 // Return array
354                 return $difference;
355         }
356
357         /**
358          * Returns time difference between two timestamps, in the format:
359          * N year, N months, N weeks, N days, N hours, N minutes, and N seconds ago
360          *
361          * @param   integer       timestamp
362          * @param   integer       timestamp, defaults to the current time
363          * @param   string        formatting string
364          * @return  string
365          */
366         public static function timespan_string($time1, $time2 = NULL, $output = 'years,months,weeks,days,hours,minutes,seconds')
367         {
368                 if ($difference = date::timespan($time1, $time2, $output) AND is_array($difference))
369                 {
370                         // Determine the key of the last item in the array
371                         $last = end($difference);
372                         $last = key($difference);
373
374                         $span = array();
375                         foreach ($difference as $name => $amount)
376                         {
377                                 if ($amount === 0)
378                                 {
379                                         // Skip empty amounts
380                                         continue;
381                                 }
382
383                                 // Add the amount to the span
384                                 $span[] = ($name === $last ? ' and ' : ', ').$amount.' '.($amount === 1 ? inflector::singular($name) : $name);
385                         }
386
387                         // If the difference is less than 60 seconds, remove the preceding and.
388                         if (count($span) === 1)
389                         {
390                                 $span[0] = ltrim($span[0], 'and ');
391                         }
392
393                         // Replace difference by making the span into a string
394                         $difference = trim(implode('', $span), ',');
395                 }
396                 elseif (is_int($difference))
397                 {
398                         // Single-value return
399                         $difference = $difference.' '.($difference === 1 ? inflector::singular($output) : $output);
400                 }
401
402                 return $difference;
403         }
404
405 } // End date