PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/system/classes/kohana/date.php

https://bitbucket.org/emolina/asesores
PHP | 566 lines | 293 code | 67 blank | 206 comment | 27 complexity | 964186a43303d83671fe3a23949a6cea MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php defined('SYSPATH') or die('No direct script access.');
  2. /**
  3. * Date helper.
  4. *
  5. * @package Kohana
  6. * @category Helpers
  7. * @author Kohana Team
  8. * @copyright (c) 2007-2010 Kohana Team
  9. * @license http://kohanaframework.org/license
  10. */
  11. class Kohana_Date {
  12. // Second amounts for various time increments
  13. const YEAR = 31556926;
  14. const MONTH = 2629744;
  15. const WEEK = 604800;
  16. const DAY = 86400;
  17. const HOUR = 3600;
  18. const MINUTE = 60;
  19. /**
  20. * Default timestamp format for formatted_time
  21. * @var string
  22. */
  23. public static $timestamp_format = 'Y-m-d H:i:s';
  24. /**
  25. * Timezone for formatted_time
  26. * @link http://uk2.php.net/manual/en/timezones.php
  27. * @var string
  28. */
  29. public static $timezone;
  30. /**
  31. * Returns the offset (in seconds) between two time zones. Use this to
  32. * display dates to users in different time zones.
  33. *
  34. * $seconds = Date::offset('America/Chicago', 'GMT');
  35. *
  36. * [!!] A list of time zones that PHP supports can be found at
  37. * <http://php.net/timezones>.
  38. *
  39. * @param string timezone that to find the offset of
  40. * @param string timezone used as the baseline
  41. * @param mixed UNIX timestamp or date string
  42. * @return integer
  43. */
  44. public static function offset($remote, $local = NULL, $now = NULL)
  45. {
  46. if ($local === NULL)
  47. {
  48. // Use the default timezone
  49. $local = date_default_timezone_get();
  50. }
  51. if (is_int($now))
  52. {
  53. // Convert the timestamp into a string
  54. $now = date(DateTime::RFC2822, $now);
  55. }
  56. // Create timezone objects
  57. $zone_remote = new DateTimeZone($remote);
  58. $zone_local = new DateTimeZone($local);
  59. // Create date objects from timezones
  60. $time_remote = new DateTime($now, $zone_remote);
  61. $time_local = new DateTime($now, $zone_local);
  62. // Find the offset
  63. $offset = $zone_remote->getOffset($time_remote) - $zone_local->getOffset($time_local);
  64. return $offset;
  65. }
  66. /**
  67. * Number of seconds in a minute, incrementing by a step. Typically used as
  68. * a shortcut for generating a list that can used in a form.
  69. *
  70. * $seconds = Date::seconds(); // 01, 02, 03, ..., 58, 59, 60
  71. *
  72. * @param integer amount to increment each step by, 1 to 30
  73. * @param integer start value
  74. * @param integer end value
  75. * @return array A mirrored (foo => foo) array from 1-60.
  76. */
  77. public static function seconds($step = 1, $start = 0, $end = 60)
  78. {
  79. // Always integer
  80. $step = (int) $step;
  81. $seconds = array();
  82. for ($i = $start; $i < $end; $i += $step)
  83. {
  84. $seconds[$i] = sprintf('%02d', $i);
  85. }
  86. return $seconds;
  87. }
  88. /**
  89. * Number of minutes in an hour, incrementing by a step. Typically used as
  90. * a shortcut for generating a list that can be used in a form.
  91. *
  92. * $minutes = Date::minutes(); // 05, 10, 15, ..., 50, 55, 60
  93. *
  94. * @uses Date::seconds
  95. * @param integer amount to increment each step by, 1 to 30
  96. * @return array A mirrored (foo => foo) array from 1-60.
  97. */
  98. public static function minutes($step = 5)
  99. {
  100. // Because there are the same number of minutes as seconds in this set,
  101. // we choose to re-use seconds(), rather than creating an entirely new
  102. // function. Shhhh, it's cheating! ;) There are several more of these
  103. // in the following methods.
  104. return Date::seconds($step);
  105. }
  106. /**
  107. * Number of hours in a day. Typically used as a shortcut for generating a
  108. * list that can be used in a form.
  109. *
  110. * $hours = Date::hours(); // 01, 02, 03, ..., 10, 11, 12
  111. *
  112. * @param integer amount to increment each step by
  113. * @param boolean use 24-hour time
  114. * @param integer the hour to start at
  115. * @return array A mirrored (foo => foo) array from start-12 or start-23.
  116. */
  117. public static function hours($step = 1, $long = FALSE, $start = NULL)
  118. {
  119. // Default values
  120. $step = (int) $step;
  121. $long = (bool) $long;
  122. $hours = array();
  123. // Set the default start if none was specified.
  124. if ($start === NULL)
  125. {
  126. $start = ($long === FALSE) ? 1 : 0;
  127. }
  128. $hours = array();
  129. // 24-hour time has 24 hours, instead of 12
  130. $size = ($long === TRUE) ? 23 : 12;
  131. for ($i = $start; $i <= $size; $i += $step)
  132. {
  133. $hours[$i] = (string) $i;
  134. }
  135. return $hours;
  136. }
  137. /**
  138. * Returns AM or PM, based on a given hour (in 24 hour format).
  139. *
  140. * $type = Date::ampm(12); // PM
  141. * $type = Date::ampm(1); // AM
  142. *
  143. * @param integer number of the hour
  144. * @return string
  145. */
  146. public static function ampm($hour)
  147. {
  148. // Always integer
  149. $hour = (int) $hour;
  150. return ($hour > 11) ? 'PM' : 'AM';
  151. }
  152. /**
  153. * Adjusts a non-24-hour number into a 24-hour number.
  154. *
  155. * $hour = Date::adjust(3, 'pm'); // 15
  156. *
  157. * @param integer hour to adjust
  158. * @param string AM or PM
  159. * @return string
  160. */
  161. public static function adjust($hour, $ampm)
  162. {
  163. $hour = (int) $hour;
  164. $ampm = strtolower($ampm);
  165. switch ($ampm)
  166. {
  167. case 'am':
  168. if ($hour == 12)
  169. {
  170. $hour = 0;
  171. }
  172. break;
  173. case 'pm':
  174. if ($hour < 12)
  175. {
  176. $hour += 12;
  177. }
  178. break;
  179. }
  180. return sprintf('%02d', $hour);
  181. }
  182. /**
  183. * Number of days in a given month and year. Typically used as a shortcut
  184. * for generating a list that can be used in a form.
  185. *
  186. * Date::days(4, 2010); // 1, 2, 3, ..., 28, 29, 30
  187. *
  188. * @param integer number of month
  189. * @param integer number of year to check month, defaults to the current year
  190. * @return array A mirrored (foo => foo) array of the days.
  191. */
  192. public static function days($month, $year = FALSE)
  193. {
  194. static $months;
  195. if ($year === FALSE)
  196. {
  197. // Use the current year by default
  198. $year = date('Y');
  199. }
  200. // Always integers
  201. $month = (int) $month;
  202. $year = (int) $year;
  203. // We use caching for months, because time functions are used
  204. if (empty($months[$year][$month]))
  205. {
  206. $months[$year][$month] = array();
  207. // Use date to find the number of days in the given month
  208. $total = date('t', mktime(1, 0, 0, $month, 1, $year)) + 1;
  209. for ($i = 1; $i < $total; $i++)
  210. {
  211. $months[$year][$month][$i] = (string) $i;
  212. }
  213. }
  214. return $months[$year][$month];
  215. }
  216. /**
  217. * Number of months in a year. Typically used as a shortcut for generating
  218. * a list that can be used in a form.
  219. *
  220. * Date::months(); // 01, 02, 03, ..., 10, 11, 12
  221. *
  222. * @uses Date::hours
  223. * @return array A mirrored (foo => foo) array from 1-12.
  224. */
  225. public static function months()
  226. {
  227. return Date::hours();
  228. }
  229. /**
  230. * Returns an array of years between a starting and ending year. By default,
  231. * the the current year - 5 and current year + 5 will be used. Typically used
  232. * as a shortcut for generating a list that can be used in a form.
  233. *
  234. * $years = Date::years(2000, 2010); // 2000, 2001, ..., 2009, 2010
  235. *
  236. * @param integer starting year (default is current year - 5)
  237. * @param integer ending year (default is current year + 5)
  238. * @return array
  239. */
  240. public static function years($start = FALSE, $end = FALSE)
  241. {
  242. // Default values
  243. $start = ($start === FALSE) ? (date('Y') - 5) : (int) $start;
  244. $end = ($end === FALSE) ? (date('Y') + 5) : (int) $end;
  245. $years = array();
  246. for ($i = $start; $i <= $end; $i++)
  247. {
  248. $years[$i] = (string) $i;
  249. }
  250. return $years;
  251. }
  252. /**
  253. * Returns time difference between two timestamps, in human readable format.
  254. * If the second timestamp is not given, the current time will be used.
  255. * Also consider using [Date::fuzzy_span] when displaying a span.
  256. *
  257. * $span = Date::span(60, 182, 'minutes,seconds'); // array('minutes' => 2, 'seconds' => 2)
  258. * $span = Date::span(60, 182, 'minutes'); // 2
  259. *
  260. * @param integer timestamp to find the span of
  261. * @param integer timestamp to use as the baseline
  262. * @param string formatting string
  263. * @return string when only a single output is requested
  264. * @return array associative list of all outputs requested
  265. */
  266. public static function span($remote, $local = NULL, $output = 'years,months,weeks,days,hours,minutes,seconds')
  267. {
  268. // Normalize output
  269. $output = trim(strtolower( (string) $output));
  270. if ( ! $output)
  271. {
  272. // Invalid output
  273. return FALSE;
  274. }
  275. // Array with the output formats
  276. $output = preg_split('/[^a-z]+/', $output);
  277. // Convert the list of outputs to an associative array
  278. $output = array_combine($output, array_fill(0, count($output), 0));
  279. // Make the output values into keys
  280. extract(array_flip($output), EXTR_SKIP);
  281. if ($local === NULL)
  282. {
  283. // Calculate the span from the current time
  284. $local = time();
  285. }
  286. // Calculate timespan (seconds)
  287. $timespan = abs($remote - $local);
  288. if (isset($output['years']))
  289. {
  290. $timespan -= Date::YEAR * ($output['years'] = (int) floor($timespan / Date::YEAR));
  291. }
  292. if (isset($output['months']))
  293. {
  294. $timespan -= Date::MONTH * ($output['months'] = (int) floor($timespan / Date::MONTH));
  295. }
  296. if (isset($output['weeks']))
  297. {
  298. $timespan -= Date::WEEK * ($output['weeks'] = (int) floor($timespan / Date::WEEK));
  299. }
  300. if (isset($output['days']))
  301. {
  302. $timespan -= Date::DAY * ($output['days'] = (int) floor($timespan / Date::DAY));
  303. }
  304. if (isset($output['hours']))
  305. {
  306. $timespan -= Date::HOUR * ($output['hours'] = (int) floor($timespan / Date::HOUR));
  307. }
  308. if (isset($output['minutes']))
  309. {
  310. $timespan -= Date::MINUTE * ($output['minutes'] = (int) floor($timespan / Date::MINUTE));
  311. }
  312. // Seconds ago, 1
  313. if (isset($output['seconds']))
  314. {
  315. $output['seconds'] = $timespan;
  316. }
  317. if (count($output) === 1)
  318. {
  319. // Only a single output was requested, return it
  320. return array_pop($output);
  321. }
  322. // Return array
  323. return $output;
  324. }
  325. /**
  326. * Returns the difference between a time and now in a "fuzzy" way.
  327. * Displaying a fuzzy time instead of a date is usually faster to read and understand.
  328. *
  329. * $span = Date::fuzzy_span(time() - 10); // "moments ago"
  330. * $span = Date::fuzzy_span(time() + 20); // "in moments"
  331. *
  332. * A second parameter is available to manually set the "local" timestamp,
  333. * however this parameter shouldn't be needed in normal usage and is only
  334. * included for unit tests
  335. *
  336. * @param integer "remote" timestamp
  337. * @param integer "local" timestamp, defaults to time()
  338. * @return string
  339. */
  340. public static function fuzzy_span($timestamp, $local_timestamp = NULL)
  341. {
  342. $local_timestamp = ($local_timestamp === NULL) ? time() : (int) $local_timestamp;
  343. // Determine the difference in seconds
  344. $offset = abs($local_timestamp - $timestamp);
  345. if ($offset <= Date::MINUTE)
  346. {
  347. $span = 'moments';
  348. }
  349. elseif ($offset < (Date::MINUTE * 20))
  350. {
  351. $span = 'a few minutes';
  352. }
  353. elseif ($offset < Date::HOUR)
  354. {
  355. $span = 'less than an hour';
  356. }
  357. elseif ($offset < (Date::HOUR * 4))
  358. {
  359. $span = 'a couple of hours';
  360. }
  361. elseif ($offset < Date::DAY)
  362. {
  363. $span = 'less than a day';
  364. }
  365. elseif ($offset < (Date::DAY * 2))
  366. {
  367. $span = 'about a day';
  368. }
  369. elseif ($offset < (Date::DAY * 4))
  370. {
  371. $span = 'a couple of days';
  372. }
  373. elseif ($offset < Date::WEEK)
  374. {
  375. $span = 'less than a week';
  376. }
  377. elseif ($offset < (Date::WEEK * 2))
  378. {
  379. $span = 'about a week';
  380. }
  381. elseif ($offset < Date::MONTH)
  382. {
  383. $span = 'less than a month';
  384. }
  385. elseif ($offset < (Date::MONTH * 2))
  386. {
  387. $span = 'about a month';
  388. }
  389. elseif ($offset < (Date::MONTH * 4))
  390. {
  391. $span = 'a couple of months';
  392. }
  393. elseif ($offset < Date::YEAR)
  394. {
  395. $span = 'less than a year';
  396. }
  397. elseif ($offset < (Date::YEAR * 2))
  398. {
  399. $span = 'about a year';
  400. }
  401. elseif ($offset < (Date::YEAR * 4))
  402. {
  403. $span = 'a couple of years';
  404. }
  405. elseif ($offset < (Date::YEAR * 8))
  406. {
  407. $span = 'a few years';
  408. }
  409. elseif ($offset < (Date::YEAR * 12))
  410. {
  411. $span = 'about a decade';
  412. }
  413. elseif ($offset < (Date::YEAR * 24))
  414. {
  415. $span = 'a couple of decades';
  416. }
  417. elseif ($offset < (Date::YEAR * 64))
  418. {
  419. $span = 'several decades';
  420. }
  421. else
  422. {
  423. $span = 'a long time';
  424. }
  425. if ($timestamp <= $local_timestamp)
  426. {
  427. // This is in the past
  428. return $span.' ago';
  429. }
  430. else
  431. {
  432. // This in the future
  433. return 'in '.$span;
  434. }
  435. }
  436. /**
  437. * Converts a UNIX timestamp to DOS format. There are very few cases where
  438. * this is needed, but some binary formats use it (eg: zip files.)
  439. * Converting the other direction is done using {@link Date::dos2unix}.
  440. *
  441. * $dos = Date::unix2dos($unix);
  442. *
  443. * @param integer UNIX timestamp
  444. * @return integer
  445. */
  446. public static function unix2dos($timestamp = FALSE)
  447. {
  448. $timestamp = ($timestamp === FALSE) ? getdate() : getdate($timestamp);
  449. if ($timestamp['year'] < 1980)
  450. {
  451. return (1 << 21 | 1 << 16);
  452. }
  453. $timestamp['year'] -= 1980;
  454. // What voodoo is this? I have no idea... Geert can explain it though,
  455. // and that's good enough for me.
  456. return ($timestamp['year'] << 25 | $timestamp['mon'] << 21 |
  457. $timestamp['mday'] << 16 | $timestamp['hours'] << 11 |
  458. $timestamp['minutes'] << 5 | $timestamp['seconds'] >> 1);
  459. }
  460. /**
  461. * Converts a DOS timestamp to UNIX format.There are very few cases where
  462. * this is needed, but some binary formats use it (eg: zip files.)
  463. * Converting the other direction is done using {@link Date::unix2dos}.
  464. *
  465. * $unix = Date::dos2unix($dos);
  466. *
  467. * @param integer DOS timestamp
  468. * @return integer
  469. */
  470. public static function dos2unix($timestamp = FALSE)
  471. {
  472. $sec = 2 * ($timestamp & 0x1f);
  473. $min = ($timestamp >> 5) & 0x3f;
  474. $hrs = ($timestamp >> 11) & 0x1f;
  475. $day = ($timestamp >> 16) & 0x1f;
  476. $mon = ($timestamp >> 21) & 0x0f;
  477. $year = ($timestamp >> 25) & 0x7f;
  478. return mktime($hrs, $min, $sec, $mon, $day, $year + 1980);
  479. }
  480. /**
  481. * Returns a date/time string with the specified timestamp format
  482. *
  483. * $time = Date::formatted_time('5 minutes ago');
  484. *
  485. * @see http://php.net/manual/en/datetime.construct.php
  486. * @param string datetime_str datetime string
  487. * @param string timestamp_format timestamp format
  488. * @return string
  489. */
  490. public static function formatted_time($datetime_str = 'now', $timestamp_format = NULL, $timezone = NULL)
  491. {
  492. $timestamp_format = ($timestamp_format == NULL) ? Date::$timestamp_format : $timestamp_format;
  493. $timezone = ($timezone === NULL) ? Date::$timezone : $timezone;
  494. $time = new DateTime($datetime_str, new DateTimeZone(
  495. $timezone ? $timezone : date_default_timezone_get()
  496. ));
  497. return $time->format($timestamp_format);
  498. }
  499. } // End date