3
* Time Helper class file.
7
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
8
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
10
* Licensed under The MIT License
11
* Redistributions of files must retain the above copyright notice.
13
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
14
* @link http://cakephp.org CakePHP(tm) Project
16
* @subpackage cake.cake.libs.view.helpers
17
* @since CakePHP(tm) v 0.10.0.1076
18
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
22
* Time Helper class for easy use of time data.
24
* Manipulation of time data.
27
* @subpackage cake.cake.libs.view.helpers
28
* @link http://book.cakephp.org/view/1470/Time
30
class TimeHelper extends AppHelper {
33
* Converts a string representing the format for the function strftime and returns a
34
* windows safe and i18n aware format.
36
* @param string $format Format with specifiers for strftime function.
37
* Accepts the special specifier %S which mimics th modifier S for date()
38
* @param string UNIX timestamp
39
* @return string windows safe and date() function compatible format for strftime
42
function convertSpecifiers($format, $time = null) {
46
$this->__time = $time;
47
return preg_replace_callback('/\%(\w+)/', array($this, '__translateSpecifier'), $format);
51
* Auxiliary function to translate a matched specifier element from a regular expresion into
52
* a windows safe and i18n aware specifier
54
* @param array $specifier match from regular expression
55
* @return string converted element
58
function __translateSpecifier($specifier) {
59
switch ($specifier[1]) {
61
$abday = __c('abday', 5, true);
62
if (is_array($abday)) {
63
return $abday[date('w', $this->__time)];
67
$day = __c('day',5,true);
69
return $day[date('w', $this->__time)];
73
$format = __c('d_t_fmt',5,true);
74
if ($format != 'd_t_fmt') {
75
return $this->convertSpecifiers($format, $this->__time);
79
return sprintf("%02d", date('Y', $this->__time) / 100);
83
return date('jS', $this->__time);
86
$months = __c('abmon', 5, true);
87
if (is_array($months)) {
88
return $months[date('n', $this->__time) -1];
92
$months = __c('mon',5,true);
93
if (is_array($months)) {
94
return $months[date('n', $this->__time) -1];
101
$default = array('am' => 0, 'pm' => 1);
102
$meridiem = $default[date('a',$this->__time)];
103
$format = __c('am_pm', 5, true);
104
if (is_array($format)) {
105
$meridiem = $format[$meridiem];
106
return ($specifier[1] == 'P') ? strtolower($meridiem) : strtoupper($meridiem);
110
$complete = __c('t_fmt_ampm', 5, true);
111
if ($complete != 't_fmt_ampm') {
112
return str_replace('%p',$this->__translateSpecifier(array('%p', 'p')),$complete);
116
return date('H:i', $this->__time);
122
return ($weekDay = date('w', $this->__time)) ? $weekDay : 7;
124
$format = __c('d_fmt', 5, true);
125
if ($format != 'd_fmt') {
126
return $this->convertSpecifiers($format, $this->__time);
130
$format = __c('t_fmt',5,true);
131
if ($format != 't_fmt') {
132
return $this->convertSpecifiers($format, $this->__time);
136
return $specifier[0];
140
* Converts given time (in server's time zone) to user's local time, given his/her offset from GMT.
142
* @param string $serverTime UNIX timestamp
143
* @param int $userOffset User's offset from GMT (in hours)
144
* @return string UNIX timestamp
147
function convert($serverTime, $userOffset) {
148
$serverOffset = $this->serverOffset();
149
$gmtTime = $serverTime - $serverOffset;
150
$userTime = $gmtTime + $userOffset * (60*60);
155
* Returns server's offset from GMT in seconds.
160
function serverOffset() {
161
return date('Z', time());
165
* Returns a UNIX timestamp, given either a UNIX timestamp or a valid strtotime() date string.
167
* @param string $dateString Datetime string
168
* @param int $userOffset User's offset from GMT (in hours)
169
* @return string Parsed timestamp
171
* @link http://book.cakephp.org/view/1471/Formatting
173
function fromString($dateString, $userOffset = null) {
174
if (empty($dateString)) {
177
if (is_integer($dateString) || is_numeric($dateString)) {
178
$date = intval($dateString);
180
$date = strtotime($dateString);
182
if ($userOffset !== null) {
183
return $this->convert($date, $userOffset);
192
* Returns a nicely formatted date string for given Datetime string.
194
* @param string $dateString Datetime string or Unix timestamp
195
* @param int $userOffset User's offset from GMT (in hours)
196
* @return string Formatted date string
198
* @link http://book.cakephp.org/view/1471/Formatting
200
function nice($dateString = null, $userOffset = null) {
201
if ($dateString != null) {
202
$date = $this->fromString($dateString, $userOffset);
206
$format = $this->convertSpecifiers('%a, %b %eS %Y, %H:%M', $date);
207
return strftime($format, $date);
211
* Returns a formatted descriptive date string for given datetime string.
213
* If the given date is today, the returned string could be "Today, 16:54".
214
* If the given date was yesterday, the returned string could be "Yesterday, 16:54".
215
* If $dateString's year is the current year, the returned string does not
216
* include mention of the year.
218
* @param string $dateString Datetime string or Unix timestamp
219
* @param int $userOffset User's offset from GMT (in hours)
220
* @return string Described, relative date string
222
* @link http://book.cakephp.org/view/1471/Formatting
224
function niceShort($dateString = null, $userOffset = null) {
225
$date = $dateString ? $this->fromString($dateString, $userOffset) : time();
227
$y = $this->isThisYear($date) ? '' : ' %Y';
229
if ($this->isToday($date)) {
230
$ret = sprintf(__('Today, %s',true), strftime("%H:%M", $date));
231
} elseif ($this->wasYesterday($date)) {
232
$ret = sprintf(__('Yesterday, %s',true), strftime("%H:%M", $date));
234
$format = $this->convertSpecifiers("%b %eS{$y}, %H:%M", $date);
235
$ret = strftime($format, $date);
242
* Returns a partial SQL string to search for all records between two dates.
244
* @param string $dateString Datetime string or Unix timestamp
245
* @param string $end Datetime string or Unix timestamp
246
* @param string $fieldName Name of database field to compare with
247
* @param int $userOffset User's offset from GMT (in hours)
248
* @return string Partial SQL string.
250
* @link http://book.cakephp.org/view/1471/Formatting
252
function daysAsSql($begin, $end, $fieldName, $userOffset = null) {
253
$begin = $this->fromString($begin, $userOffset);
254
$end = $this->fromString($end, $userOffset);
255
$begin = date('Y-m-d', $begin) . ' 00:00:00';
256
$end = date('Y-m-d', $end) . ' 23:59:59';
258
return "($fieldName >= '$begin') AND ($fieldName <= '$end')";
262
* Returns a partial SQL string to search for all records between two times
263
* occurring on the same day.
265
* @param string $dateString Datetime string or Unix timestamp
266
* @param string $fieldName Name of database field to compare with
267
* @param int $userOffset User's offset from GMT (in hours)
268
* @return string Partial SQL string.
270
* @link http://book.cakephp.org/view/1471/Formatting
272
function dayAsSql($dateString, $fieldName, $userOffset = null) {
273
$date = $this->fromString($dateString, $userOffset);
274
return $this->daysAsSql($dateString, $dateString, $fieldName);
278
* Returns true if given datetime string is today.
280
* @param string $dateString Datetime string or Unix timestamp
281
* @param int $userOffset User's offset from GMT (in hours)
282
* @return boolean True if datetime string is today
285
function isToday($dateString, $userOffset = null) {
286
$date = $this->fromString($dateString, $userOffset);
287
return date('Y-m-d', $date) == date('Y-m-d', time());
291
* Returns true if given datetime string is within this week
292
* @param string $dateString
293
* @param int $userOffset User's offset from GMT (in hours)
294
* @return boolean True if datetime string is within current week
296
* @link http://book.cakephp.org/view/1472/Testing-Time
298
function isThisWeek($dateString, $userOffset = null) {
299
$date = $this->fromString($dateString, $userOffset);
300
return date('W Y', $date) == date('W Y', time());
304
* Returns true if given datetime string is within this month
305
* @param string $dateString
306
* @param int $userOffset User's offset from GMT (in hours)
307
* @return boolean True if datetime string is within current month
309
* @link http://book.cakephp.org/view/1472/Testing-Time
311
function isThisMonth($dateString, $userOffset = null) {
312
$date = $this->fromString($dateString);
313
return date('m Y',$date) == date('m Y', time());
317
* Returns true if given datetime string is within current year.
319
* @param string $dateString Datetime string or Unix timestamp
320
* @return boolean True if datetime string is within current year
322
* @link http://book.cakephp.org/view/1472/Testing-Time
324
function isThisYear($dateString, $userOffset = null) {
325
$date = $this->fromString($dateString, $userOffset);
326
return date('Y', $date) == date('Y', time());
330
* Returns true if given datetime string was yesterday.
332
* @param string $dateString Datetime string or Unix timestamp
333
* @param int $userOffset User's offset from GMT (in hours)
334
* @return boolean True if datetime string was yesterday
336
* @link http://book.cakephp.org/view/1472/Testing-Time
339
function wasYesterday($dateString, $userOffset = null) {
340
$date = $this->fromString($dateString, $userOffset);
341
return date('Y-m-d', $date) == date('Y-m-d', strtotime('yesterday'));
345
* Returns true if given datetime string is tomorrow.
347
* @param string $dateString Datetime string or Unix timestamp
348
* @param int $userOffset User's offset from GMT (in hours)
349
* @return boolean True if datetime string was yesterday
351
* @link http://book.cakephp.org/view/1472/Testing-Time
353
function isTomorrow($dateString, $userOffset = null) {
354
$date = $this->fromString($dateString, $userOffset);
355
return date('Y-m-d', $date) == date('Y-m-d', strtotime('tomorrow'));
359
* Returns the quarter
361
* @param string $dateString
362
* @param boolean $range if true returns a range in Y-m-d format
363
* @return boolean True if datetime string is within current week
365
* @link http://book.cakephp.org/view/1471/Formatting
367
function toQuarter($dateString, $range = false) {
368
$time = $this->fromString($dateString);
369
$date = ceil(date('m', $time) / 3);
371
if ($range === true) {
375
if ($range !== false) {
376
$year = date('Y', $time);
380
$date = array($year.'-01-01', $year.'-03-31');
383
$date = array($year.'-04-01', $year.'-06-30');
386
$date = array($year.'-07-01', $year.'-09-30');
389
$date = array($year.'-10-01', $year.'-12-31');
397
* Returns a UNIX timestamp from a textual datetime description. Wrapper for PHP function strtotime().
399
* @param string $dateString Datetime string to be represented as a Unix timestamp
400
* @param int $userOffset User's offset from GMT (in hours)
401
* @return integer Unix timestamp
403
* @link http://book.cakephp.org/view/1471/Formatting
405
function toUnix($dateString, $userOffset = null) {
406
return $this->fromString($dateString, $userOffset);
410
* Returns a date formatted for Atom RSS feeds.
412
* @param string $dateString Datetime string or Unix timestamp
413
* @param int $userOffset User's offset from GMT (in hours)
414
* @return string Formatted date string
416
* @link http://book.cakephp.org/view/1471/Formatting
418
function toAtom($dateString, $userOffset = null) {
419
$date = $this->fromString($dateString, $userOffset);
420
return date('Y-m-d\TH:i:s\Z', $date);
424
* Formats date for RSS feeds
426
* @param string $dateString Datetime string or Unix timestamp
427
* @param int $userOffset User's offset from GMT (in hours)
428
* @return string Formatted date string
430
* @link http://book.cakephp.org/view/1471/Formatting
432
function toRSS($dateString, $userOffset = null) {
433
$date = $this->fromString($dateString, $userOffset);
434
return date("r", $date);
438
* Returns either a relative date or a formatted date depending
439
* on the difference between the current time and given datetime.
440
* $datetime should be in a <i>strtotime</i> - parsable format, like MySQL's datetime datatype.
444
* - `format` => a fall back format if the relative time is longer than the duration specified by end
445
* - `end` => The end of relative time telling
446
* - `userOffset` => Users offset from GMT (in hours)
448
* Relative dates look something like this:
449
* 3 weeks, 4 days ago
452
* Default date formatting is d/m/yy e.g: on 18/2/09
454
* The returned string includes 'ago' or 'on' and assumes you'll properly add a word
455
* like 'Posted ' before the function output.
457
* @param string $dateString Datetime string or Unix timestamp
458
* @param array $options Default format if timestamp is used in $dateString
459
* @return string Relative time string.
461
* @link http://book.cakephp.org/view/1471/Formatting
463
function timeAgoInWords($dateTime, $options = array()) {
465
if (is_array($options) && isset($options['userOffset'])) {
466
$userOffset = $options['userOffset'];
469
if (!is_null($userOffset)) {
470
$now = $this->convert(time(), $userOffset);
472
$inSeconds = $this->fromString($dateTime, $userOffset);
473
$backwards = ($inSeconds > $now);
478
if (is_array($options)) {
479
if (isset($options['format'])) {
480
$format = $options['format'];
481
unset($options['format']);
483
if (isset($options['end'])) {
484
$end = $options['end'];
485
unset($options['end']);
492
$futureTime = $inSeconds;
496
$pastTime = $inSeconds;
498
$diff = $futureTime - $pastTime;
500
// If more than a week, then take into account the length of months
501
if ($diff >= 604800) {
505
list($future['H'], $future['i'], $future['s'], $future['d'], $future['m'], $future['Y']) = explode('/', date('H/i/s/d/m/Y', $futureTime));
507
list($past['H'], $past['i'], $past['s'], $past['d'], $past['m'], $past['Y']) = explode('/', date('H/i/s/d/m/Y', $pastTime));
508
$years = $months = $weeks = $days = $hours = $minutes = $seconds = 0;
510
if ($future['Y'] == $past['Y'] && $future['m'] == $past['m']) {
514
if ($future['Y'] == $past['Y']) {
515
$months = $future['m'] - $past['m'];
517
$years = $future['Y'] - $past['Y'];
518
$months = $future['m'] + ((12 * $years) - $past['m']);
521
$years = floor($months / 12);
522
$months = $months - ($years * 12);
525
if ($future['m'] < $past['m'] && $future['Y'] - $past['Y'] == 1) {
531
if ($future['d'] >= $past['d']) {
532
$days = $future['d'] - $past['d'];
534
$daysInPastMonth = date('t', $pastTime);
535
$daysInFutureMonth = date('t', mktime(0, 0, 0, $future['m'] - 1, 1, $future['Y']));
538
$days = ($daysInPastMonth - $past['d']) + $future['d'];
540
$days = ($daysInFutureMonth - $past['d']) + $future['d'];
543
if ($future['m'] != $past['m']) {
548
if ($months == 0 && $years >= 1 && $diff < ($years * 31536000)) {
555
$months = $months - 12;
559
$weeks = floor($days / 7);
560
$days = $days - ($weeks * 7);
563
$years = $months = $weeks = 0;
564
$days = floor($diff / 86400);
566
$diff = $diff - ($days * 86400);
568
$hours = floor($diff / 3600);
569
$diff = $diff - ($hours * 3600);
571
$minutes = floor($diff / 60);
572
$diff = $diff - ($minutes * 60);
576
$diff = $futureTime - $pastTime;
578
if ($diff > abs($now - $this->fromString($end))) {
579
$relativeDate = sprintf(__('on %s',true), date($format, $inSeconds));
582
// years and months and days
583
$relativeDate .= ($relativeDate ? ', ' : '') . $years . ' ' . __n('year', 'years', $years, true);
584
$relativeDate .= $months > 0 ? ($relativeDate ? ', ' : '') . $months . ' ' . __n('month', 'months', $months, true) : '';
585
$relativeDate .= $weeks > 0 ? ($relativeDate ? ', ' : '') . $weeks . ' ' . __n('week', 'weeks', $weeks, true) : '';
586
$relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . $days . ' ' . __n('day', 'days', $days, true) : '';
587
} elseif (abs($months) > 0) {
588
// months, weeks and days
589
$relativeDate .= ($relativeDate ? ', ' : '') . $months . ' ' . __n('month', 'months', $months, true);
590
$relativeDate .= $weeks > 0 ? ($relativeDate ? ', ' : '') . $weeks . ' ' . __n('week', 'weeks', $weeks, true) : '';
591
$relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . $days . ' ' . __n('day', 'days', $days, true) : '';
592
} elseif (abs($weeks) > 0) {
594
$relativeDate .= ($relativeDate ? ', ' : '') . $weeks . ' ' . __n('week', 'weeks', $weeks, true);
595
$relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . $days . ' ' . __n('day', 'days', $days, true) : '';
596
} elseif (abs($days) > 0) {
598
$relativeDate .= ($relativeDate ? ', ' : '') . $days . ' ' . __n('day', 'days', $days, true);
599
$relativeDate .= $hours > 0 ? ($relativeDate ? ', ' : '') . $hours . ' ' . __n('hour', 'hours', $hours, true) : '';
600
} elseif (abs($hours) > 0) {
602
$relativeDate .= ($relativeDate ? ', ' : '') . $hours . ' ' . __n('hour', 'hours', $hours, true);
603
$relativeDate .= $minutes > 0 ? ($relativeDate ? ', ' : '') . $minutes . ' ' . __n('minute', 'minutes', $minutes, true) : '';
604
} elseif (abs($minutes) > 0) {
606
$relativeDate .= ($relativeDate ? ', ' : '') . $minutes . ' ' . __n('minute', 'minutes', $minutes, true);
609
$relativeDate .= ($relativeDate ? ', ' : '') . $seconds . ' ' . __n('second', 'seconds', $seconds, true);
613
$relativeDate = sprintf(__('%s ago', true), $relativeDate);
616
return $relativeDate;
620
* Alias for timeAgoInWords
622
* @param mixed $dateTime Datetime string (strtotime-compatible) or Unix timestamp
623
* @param mixed $options Default format string, if timestamp is used in $dateTime, or an array of options to be passed
624
* on to timeAgoInWords().
625
* @return string Relative time string.
626
* @see TimeHelper::timeAgoInWords
628
* @deprecated This method alias will be removed in future versions.
629
* @link http://book.cakephp.org/view/1471/Formatting
631
function relativeTime($dateTime, $options = array()) {
632
return $this->timeAgoInWords($dateTime, $options);
636
* Returns true if specified datetime was within the interval specified, else false.
638
* @param mixed $timeInterval the numeric value with space then time type.
639
* Example of valid types: 6 hours, 2 days, 1 minute.
640
* @param mixed $dateString the datestring or unix timestamp to compare
641
* @param int $userOffset User's offset from GMT (in hours)
644
* @link http://book.cakephp.org/view/1472/Testing-Time
646
function wasWithinLast($timeInterval, $dateString, $userOffset = null) {
647
$tmp = str_replace(' ', '', $timeInterval);
648
if (is_numeric($tmp)) {
649
$timeInterval = $tmp . ' ' . __('days', true);
652
$date = $this->fromString($dateString, $userOffset);
653
$interval = $this->fromString('-'.$timeInterval);
655
if ($date >= $interval && $date <= time()) {
663
* Returns gmt, given either a UNIX timestamp or a valid strtotime() date string.
665
* @param string $dateString Datetime string
666
* @return string Formatted date string
668
* @link http://book.cakephp.org/view/1471/Formatting
670
function gmt($string = null) {
671
if ($string != null) {
672
$string = $this->fromString($string);
676
$string = $this->fromString($string);
677
$hour = intval(date("G", $string));
678
$minute = intval(date("i", $string));
679
$second = intval(date("s", $string));
680
$month = intval(date("n", $string));
681
$day = intval(date("j", $string));
682
$year = intval(date("Y", $string));
684
return gmmktime($hour, $minute, $second, $month, $day, $year);
688
* Returns a formatted date string, given either a UNIX timestamp or a valid strtotime() date string.
689
* This function also accepts a time string and a format string as first and second parameters.
690
* In that case this function behaves as a wrapper for TimeHelper::i18nFormat()
692
* @param string $format date format string (or a DateTime string)
693
* @param string $dateString Datetime string (or a date format string)
694
* @param boolean $invalid flag to ignore results of fromString == false
695
* @param int $userOffset User's offset from GMT (in hours)
696
* @return string Formatted date string
699
function format($format, $date = null, $invalid = false, $userOffset = null) {
700
$time = $this->fromString($date, $userOffset);
701
$_time = $this->fromString($format, $userOffset);
703
if (is_numeric($_time) && $time === false) {
705
return $this->i18nFormat($_time, $format, $invalid, $userOffset);
707
if ($time === false && $invalid !== false) {
710
return date($format, $time);
714
* Returns a formatted date string, given either a UNIX timestamp or a valid strtotime() date string.
715
* It take in account the default date format for the current language if a LC_TIME file is used.
717
* @param string $dateString Datetime string
718
* @param string $format strftime format string.
719
* @param boolean $invalid flag to ignore results of fromString == false
720
* @param int $userOffset User's offset from GMT (in hours)
721
* @return string Formatted and translated date string @access public
724
function i18nFormat($date, $format = null, $invalid = false, $userOffset = null) {
725
$date = $this->fromString($date, $userOffset);
726
if ($date === false && $invalid !== false) {
729
if (empty($format)) {
732
$format = $this->convertSpecifiers($format, $date);
733
return strftime($format, $date);