1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
20: if (!class_exists('Multibyte')) {
21: App::import('Core', 'Multibyte');
22: }
23:
24: 25: 26: 27: 28: 29: 30: 31: 32:
33: class TimeHelper extends AppHelper {
34:
35: 36: 37: 38: 39: 40: 41: 42: 43: 44:
45: function convertSpecifiers($format, $time = null) {
46: if (!$time) {
47: $time = time();
48: }
49: $this->__time = $time;
50: return preg_replace_callback('/\%(\w+)/', array($this, '__translateSpecifier'), $format);
51: }
52:
53: 54: 55: 56: 57: 58: 59: 60:
61: function __translateSpecifier($specifier) {
62: switch ($specifier[1]) {
63: case 'a':
64: $abday = __c('abday', 5, true);
65: if (is_array($abday)) {
66: return $abday[date('w', $this->__time)];
67: }
68: break;
69: case 'A':
70: $day = __c('day',5,true);
71: if (is_array($day)) {
72: return $day[date('w', $this->__time)];
73: }
74: break;
75: case 'c':
76: $format = __c('d_t_fmt',5,true);
77: if ($format != 'd_t_fmt') {
78: return $this->convertSpecifiers($format, $this->__time);
79: }
80: break;
81: case 'C':
82: return sprintf("%02d", date('Y', $this->__time) / 100);
83: case 'D':
84: return '%m/%d/%y';
85: case 'e':
86: if (DS === '/') {
87: return '%e';
88: }
89: $day = date('j', $this->__time);
90: if ($day < 10) {
91: $day = ' ' . $day;
92: }
93: return $day;
94: case 'eS' :
95: return date('jS', $this->__time);
96: case 'b':
97: case 'h':
98: $months = __c('abmon', 5, true);
99: if (is_array($months)) {
100: return $months[date('n', $this->__time) -1];
101: }
102: return '%b';
103: case 'B':
104: $months = __c('mon',5,true);
105: if (is_array($months)) {
106: return $months[date('n', $this->__time) -1];
107: }
108: break;
109: case 'n':
110: return "\n";
111: case 'p':
112: case 'P':
113: $default = array('am' => 0, 'pm' => 1);
114: $meridiem = $default[date('a',$this->__time)];
115: $format = __c('am_pm', 5, true);
116: if (is_array($format)) {
117: $meridiem = $format[$meridiem];
118: return ($specifier[1] == 'P') ? strtolower($meridiem) : strtoupper($meridiem);
119: }
120: break;
121: case 'r':
122: $complete = __c('t_fmt_ampm', 5, true);
123: if ($complete != 't_fmt_ampm') {
124: return str_replace('%p',$this->__translateSpecifier(array('%p', 'p')),$complete);
125: }
126: break;
127: case 'R':
128: return date('H:i', $this->__time);
129: case 't':
130: return "\t";
131: case 'T':
132: return '%H:%M:%S';
133: case 'u':
134: return ($weekDay = date('w', $this->__time)) ? $weekDay : 7;
135: case 'x':
136: $format = __c('d_fmt', 5, true);
137: if ($format != 'd_fmt') {
138: return $this->convertSpecifiers($format, $this->__time);
139: }
140: break;
141: case 'X':
142: $format = __c('t_fmt',5,true);
143: if ($format != 't_fmt') {
144: return $this->convertSpecifiers($format, $this->__time);
145: }
146: break;
147: }
148: return $specifier[0];
149: }
150:
151: 152: 153: 154: 155: 156: 157: 158:
159: function convert($serverTime, $userOffset) {
160: $serverOffset = $this->serverOffset();
161: $gmtTime = $serverTime - $serverOffset;
162: $userTime = $gmtTime + $userOffset * (60*60);
163: return $userTime;
164: }
165:
166: 167: 168: 169: 170: 171:
172: function serverOffset() {
173: return date('Z', time());
174: }
175:
176: 177: 178: 179: 180: 181: 182: 183: 184:
185: function fromString($dateString, $userOffset = null) {
186: if (empty($dateString)) {
187: return false;
188: }
189: if (is_integer($dateString) || is_numeric($dateString)) {
190: $date = intval($dateString);
191: } else {
192: $date = strtotime($dateString);
193: }
194: if ($userOffset !== null) {
195: return $this->convert($date, $userOffset);
196: }
197: if ($date === -1) {
198: return false;
199: }
200: return $date;
201: }
202:
203: 204: 205: 206: 207: 208: 209: 210: 211:
212: function nice($dateString = null, $userOffset = null) {
213: if ($dateString != null) {
214: $date = $this->fromString($dateString, $userOffset);
215: } else {
216: $date = time();
217: }
218: $format = $this->convertSpecifiers('%a, %b %eS %Y, %H:%M', $date);
219: return $this->_strftime($format, $date);
220: }
221:
222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235:
236: function niceShort($dateString = null, $userOffset = null) {
237: $date = $dateString ? $this->fromString($dateString, $userOffset) : time();
238:
239: $y = $this->isThisYear($date) ? '' : ' %Y';
240:
241: if ($this->isToday($dateString, $userOffset)) {
242: $ret = sprintf(__('Today, %s',true), $this->_strftime("%H:%M", $date));
243: } elseif ($this->wasYesterday($dateString, $userOffset)) {
244: $ret = sprintf(__('Yesterday, %s',true), $this->_strftime("%H:%M", $date));
245: } else {
246: $format = $this->convertSpecifiers("%b %eS{$y}, %H:%M", $date);
247: $ret = $this->_strftime($format, $date);
248: }
249:
250: return $ret;
251: }
252:
253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263:
264: function daysAsSql($begin, $end, $fieldName, $userOffset = null) {
265: $begin = $this->fromString($begin, $userOffset);
266: $end = $this->fromString($end, $userOffset);
267: $begin = date('Y-m-d', $begin) . ' 00:00:00';
268: $end = date('Y-m-d', $end) . ' 23:59:59';
269:
270: return "($fieldName >= '$begin') AND ($fieldName <= '$end')";
271: }
272:
273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283:
284: function dayAsSql($dateString, $fieldName, $userOffset = null) {
285: $date = $this->fromString($dateString, $userOffset);
286: return $this->daysAsSql($dateString, $dateString, $fieldName);
287: }
288:
289: 290: 291: 292: 293: 294: 295: 296:
297: function isToday($dateString, $userOffset = null) {
298: $date = $this->fromString($dateString, $userOffset);
299: return date('Y-m-d', $date) == date('Y-m-d', time());
300: }
301:
302: 303: 304: 305: 306: 307: 308: 309:
310: function isThisWeek($dateString, $userOffset = null) {
311: $date = $this->fromString($dateString, $userOffset);
312: return date('W Y', $date) == date('W Y', time());
313: }
314:
315: 316: 317: 318: 319: 320: 321: 322:
323: function isThisMonth($dateString, $userOffset = null) {
324: $date = $this->fromString($dateString);
325: return date('m Y',$date) == date('m Y', time());
326: }
327:
328: 329: 330: 331: 332: 333: 334: 335:
336: function isThisYear($dateString, $userOffset = null) {
337: $date = $this->fromString($dateString, $userOffset);
338: return date('Y', $date) == date('Y', time());
339: }
340:
341: 342: 343: 344: 345: 346: 347: 348: 349: 350:
351: function wasYesterday($dateString, $userOffset = null) {
352: $date = $this->fromString($dateString, $userOffset);
353: return date('Y-m-d', $date) == date('Y-m-d', strtotime('yesterday'));
354: }
355:
356: 357: 358: 359: 360: 361: 362: 363: 364:
365: function isTomorrow($dateString, $userOffset = null) {
366: $date = $this->fromString($dateString, $userOffset);
367: return date('Y-m-d', $date) == date('Y-m-d', strtotime('tomorrow'));
368: }
369:
370: 371: 372: 373: 374: 375: 376: 377: 378:
379: function toQuarter($dateString, $range = false) {
380: $time = $this->fromString($dateString);
381: $date = ceil(date('m', $time) / 3);
382:
383: if ($range === true) {
384: $range = 'Y-m-d';
385: }
386:
387: if ($range !== false) {
388: $year = date('Y', $time);
389:
390: switch ($date) {
391: case 1:
392: $date = array($year.'-01-01', $year.'-03-31');
393: break;
394: case 2:
395: $date = array($year.'-04-01', $year.'-06-30');
396: break;
397: case 3:
398: $date = array($year.'-07-01', $year.'-09-30');
399: break;
400: case 4:
401: $date = array($year.'-10-01', $year.'-12-31');
402: break;
403: }
404: }
405: return $date;
406: }
407:
408: 409: 410: 411: 412: 413: 414: 415: 416:
417: function toUnix($dateString, $userOffset = null) {
418: return $this->fromString($dateString, $userOffset);
419: }
420:
421: 422: 423: 424: 425: 426: 427: 428: 429:
430: function toAtom($dateString, $userOffset = null) {
431: $date = $this->fromString($dateString, $userOffset);
432: return date('Y-m-d\TH:i:s\Z', $date);
433: }
434:
435: 436: 437: 438: 439: 440: 441: 442: 443:
444: function toRSS($dateString, $userOffset = null) {
445: $date = $this->fromString($dateString, $userOffset);
446:
447: if(!is_null($userOffset)) {
448: if($userOffset == 0) {
449: $timezone = '+0000';
450: } else {
451: $hours = (int) floor(abs($userOffset));
452: $minutes = (int) (fmod(abs($userOffset), $hours) * 60);
453: $timezone = ($userOffset < 0 ? '-' : '+') . str_pad($hours, 2, '0', STR_PAD_LEFT) . str_pad($minutes, 2, '0', STR_PAD_LEFT);
454: }
455: return date('D, d M Y H:i:s', $date) . ' ' . $timezone;
456: }
457: return date("r", $date);
458: }
459:
460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485:
486: function timeAgoInWords($dateTime, $options = array()) {
487: $userOffset = null;
488: if (is_array($options) && isset($options['userOffset'])) {
489: $userOffset = $options['userOffset'];
490: }
491: $now = time();
492: if (!is_null($userOffset)) {
493: $now = $this->convert(time(), $userOffset);
494: }
495: $inSeconds = $this->fromString($dateTime, $userOffset);
496: $backwards = ($inSeconds > $now);
497:
498: $format = 'j/n/y';
499: $end = '+1 month';
500:
501: if (is_array($options)) {
502: if (isset($options['format'])) {
503: $format = $options['format'];
504: unset($options['format']);
505: }
506: if (isset($options['end'])) {
507: $end = $options['end'];
508: unset($options['end']);
509: }
510: } else {
511: $format = $options;
512: }
513:
514: if ($backwards) {
515: $futureTime = $inSeconds;
516: $pastTime = $now;
517: } else {
518: $futureTime = $now;
519: $pastTime = $inSeconds;
520: }
521: $diff = $futureTime - $pastTime;
522:
523:
524: if ($diff >= 604800) {
525: $current = array();
526: $date = array();
527:
528: list($future['H'], $future['i'], $future['s'], $future['d'], $future['m'], $future['Y']) = explode('/', date('H/i/s/d/m/Y', $futureTime));
529:
530: list($past['H'], $past['i'], $past['s'], $past['d'], $past['m'], $past['Y']) = explode('/', date('H/i/s/d/m/Y', $pastTime));
531: $years = $months = $weeks = $days = $hours = $minutes = $seconds = 0;
532:
533: if ($future['Y'] == $past['Y'] && $future['m'] == $past['m']) {
534: $months = 0;
535: $years = 0;
536: } else {
537: if ($future['Y'] == $past['Y']) {
538: $months = $future['m'] - $past['m'];
539: } else {
540: $years = $future['Y'] - $past['Y'];
541: $months = $future['m'] + ((12 * $years) - $past['m']);
542:
543: if ($months >= 12) {
544: $years = floor($months / 12);
545: $months = $months - ($years * 12);
546: }
547:
548: if ($future['m'] < $past['m'] && $future['Y'] - $past['Y'] == 1) {
549: $years --;
550: }
551: }
552: }
553:
554: if ($future['d'] >= $past['d']) {
555: $days = $future['d'] - $past['d'];
556: } else {
557: $daysInPastMonth = date('t', $pastTime);
558: $daysInFutureMonth = date('t', mktime(0, 0, 0, $future['m'] - 1, 1, $future['Y']));
559:
560: if (!$backwards) {
561: $days = ($daysInPastMonth - $past['d']) + $future['d'];
562: } else {
563: $days = ($daysInFutureMonth - $past['d']) + $future['d'];
564: }
565:
566: if ($future['m'] != $past['m']) {
567: $months --;
568: }
569: }
570:
571: if ($months == 0 && $years >= 1 && $diff < ($years * 31536000)) {
572: $months = 11;
573: $years --;
574: }
575:
576: if ($months >= 12) {
577: $years = $years + 1;
578: $months = $months - 12;
579: }
580:
581: if ($days >= 7) {
582: $weeks = floor($days / 7);
583: $days = $days - ($weeks * 7);
584: }
585: } else {
586: $years = $months = $weeks = 0;
587: $days = floor($diff / 86400);
588:
589: $diff = $diff - ($days * 86400);
590:
591: $hours = floor($diff / 3600);
592: $diff = $diff - ($hours * 3600);
593:
594: $minutes = floor($diff / 60);
595: $diff = $diff - ($minutes * 60);
596: $seconds = $diff;
597: }
598: $relativeDate = '';
599: $diff = $futureTime - $pastTime;
600:
601: if ($diff > abs($now - $this->fromString($end))) {
602: $relativeDate = sprintf(__('on %s',true), date($format, $inSeconds));
603: } else {
604: if ($years > 0) {
605:
606: $relativeDate .= ($relativeDate ? ', ' : '') . sprintf(__n('%d year', '%d years', $years, true), $years);
607: $relativeDate .= $months > 0 ? ($relativeDate ? ', ' : '') . sprintf(__n('%d month', '%d months', $months, true), $months) : '';
608: $relativeDate .= $weeks > 0 ? ($relativeDate ? ', ' : '') . sprintf(__n('%d week', '%d weeks', $weeks, true), $weeks) : '';
609: $relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . sprintf(__n('%d day', '%d days', $days, true), $days) : '';
610: } elseif (abs($months) > 0) {
611:
612: $relativeDate .= ($relativeDate ? ', ' : '') . sprintf(__n('%d month', '%d months', $months, true), $months);
613: $relativeDate .= $weeks > 0 ? ($relativeDate ? ', ' : '') . sprintf(__n('%d week', '%d weeks', $weeks, true), $weeks) : '';
614: $relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . sprintf(__n('%d day', '%d days', $days, true), $days) : '';
615: } elseif (abs($weeks) > 0) {
616:
617: $relativeDate .= ($relativeDate ? ', ' : '') . sprintf(__n('%d week', '%d weeks', $weeks, true), $weeks);
618: $relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . sprintf(__n('%d day', '%d days', $days, true), $days) : '';
619: } elseif (abs($days) > 0) {
620:
621: $relativeDate .= ($relativeDate ? ', ' : '') . sprintf(__n('%d day', '%d days', $days, true), $days);
622: $relativeDate .= $hours > 0 ? ($relativeDate ? ', ' : '') . sprintf(__n('%d hour', '%d hours', $hours, true), $hours) : '';
623: } elseif (abs($hours) > 0) {
624:
625: $relativeDate .= ($relativeDate ? ', ' : '') . sprintf(__n('%d hour', '%d hours', $hours, true), $hours);
626: $relativeDate .= $minutes > 0 ? ($relativeDate ? ', ' : '') . sprintf(__n('%d minute', '%d minutes', $minutes, true), $minutes) : '';
627: } elseif (abs($minutes) > 0) {
628:
629: $relativeDate .= ($relativeDate ? ', ' : '') . sprintf(__n('%d minute', '%d minutes', $minutes, true), $minutes);
630: } else {
631:
632: $relativeDate .= ($relativeDate ? ', ' : '') . sprintf(__n('%d second', '%d seconds', $seconds, true), $seconds);
633: }
634:
635: if (!$backwards) {
636: $relativeDate = sprintf(__('%s ago', true), $relativeDate);
637: }
638: }
639: return $relativeDate;
640: }
641:
642: 643: 644: 645: 646: 647: 648: 649: 650: 651: 652: 653:
654: function relativeTime($dateTime, $options = array()) {
655: return $this->timeAgoInWords($dateTime, $options);
656: }
657:
658: 659: 660: 661: 662: 663: 664: 665: 666: 667: 668:
669: function wasWithinLast($timeInterval, $dateString, $userOffset = null) {
670: $tmp = str_replace(' ', '', $timeInterval);
671: if (is_numeric($tmp)) {
672: $timeInterval = $tmp . ' ' . __('days', true);
673: }
674:
675: $date = $this->fromString($dateString, $userOffset);
676: $interval = $this->fromString('-'.$timeInterval);
677:
678: if ($date >= $interval && $date <= time()) {
679: return true;
680: }
681:
682: return false;
683: }
684:
685: 686: 687: 688: 689: 690: 691: 692:
693: function gmt($string = null) {
694: if ($string != null) {
695: $string = $this->fromString($string);
696: } else {
697: $string = time();
698: }
699: $string = $this->fromString($string);
700: $hour = intval(date("G", $string));
701: $minute = intval(date("i", $string));
702: $second = intval(date("s", $string));
703: $month = intval(date("n", $string));
704: $day = intval(date("j", $string));
705: $year = intval(date("Y", $string));
706:
707: return gmmktime($hour, $minute, $second, $month, $day, $year);
708: }
709:
710: 711: 712: 713: 714: 715: 716: 717: 718: 719: 720: 721:
722: function format($format, $date = null, $invalid = false, $userOffset = null) {
723: $time = $this->fromString($date, $userOffset);
724: $_time = $this->fromString($format, $userOffset);
725:
726: if (is_numeric($_time) && $time === false) {
727: $format = $date;
728: return $this->i18nFormat($_time, $format, $invalid, $userOffset);
729: }
730: if ($time === false && $invalid !== false) {
731: return $invalid;
732: }
733: if ($time === false) {
734: return '';
735: }
736: return date($format, $time);
737: }
738:
739: 740: 741: 742: 743: 744: 745: 746: 747: 748: 749:
750: function i18nFormat($date, $format = null, $invalid = false, $userOffset = null) {
751: $date = $this->fromString($date, $userOffset);
752: if ($date === false && $invalid !== false) {
753: return $invalid;
754: }
755: if (empty($format)) {
756: $format = '%x';
757: }
758: $format = $this->convertSpecifiers($format, $date);
759: return $this->_strftime($format, $date);
760: }
761:
762: 763: 764: 765: 766: 767: 768: 769: 770:
771: function _strftime($format, $date) {
772: $format = strftime($format, $date);
773: $encoding = Configure::read('App.encoding');
774:
775: if (!empty($encoding) && $encoding === 'UTF-8') {
776: if (function_exists('mb_check_encoding')) {
777: $valid = mb_check_encoding($format, $encoding);
778: } else {
779: $valid = !Multibyte::checkMultibyte($format);
780: }
781: if (!$valid) {
782: $format = utf8_encode($format);
783: }
784: }
785: return $format;
786: }
787: }
788: