DatetimeLib.php 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138
  1. <?php
  2. App::uses('TimeLib', 'Tools.Utility');
  3. /**
  4. * TODO: merge with TimeLib some day?
  5. *
  6. *
  7. * 2011-03-03 ms
  8. */
  9. class DatetimeLib extends TimeLib {
  10. protected static $userOffset = null;
  11. protected static $daylightSavings = false;
  12. /*
  13. public static function __construct() {
  14. $i18n = Configure::read('Localization');
  15. if (!empty($i18n['time_offset'])) {
  16. self::$userOffset = (int)$i18n['time_offset'];
  17. }
  18. if (!empty($i18n['daylight_savings'])) {
  19. self::$daylightSavings = (bool)$i18n['daylight_savings'];
  20. }
  21. }
  22. */
  23. /** custom stuff **/
  24. /**
  25. * calculate the difference between two dates
  26. * should only be used for < month (due to the different month lenghts it gets fuzzy)
  27. * @param mixed $start (db format or timestamp)
  28. * @param mixex §end (db format or timestamp)
  29. * @return int: the distance in seconds
  30. * 2011-03-03 ms
  31. */
  32. public static function difference($startTime = null, $endTime = null, $options = array()) {
  33. if (!is_int($startTime)) {
  34. $startTime = strtotime($startTime);
  35. }
  36. if (!is_int($endTime)) {
  37. $endTime = strtotime($endTime);
  38. }
  39. //@FIXME: make it work for > month
  40. return abs($endTime - $startTime);
  41. }
  42. /**
  43. * @param start date (if empty, use today)
  44. * @param end date (if empty, use today)
  45. * start and end cannot be both empty!
  46. * @param accuracy (year only = 0, incl months/days = 2)
  47. * if > 0, returns array!!! ('days'=>x,'months'=>y,'years'=>z)
  48. *
  49. * does this work too?
  50. $now = mktime(0,0,0,date("m"),date("d"),date("Y"));
  51. $birth = mktime(0,0,0,$monat,$tag,$jahr);
  52. $age = intval(($now - $birth) / (3600 * 24 * 365));
  53. * @return int age (0 if both timestamps are equal or empty, -1 on invalid dates)
  54. * 2009-03-12 ms
  55. */
  56. public static function age($start = null, $end = null, $accuracy = 0) {
  57. $age = 0;
  58. if (empty($start) && empty($end) || $start == $end) {
  59. return 0;
  60. }
  61. if (empty($start)) {
  62. list($yearS, $monthS, $dayS) = explode('-', date(FORMAT_DB_DATE));
  63. } else {
  64. $startDate = self::fromString($start);
  65. $yearS = date('Y', $startDate);
  66. $monthS = date('m', $startDate);
  67. $dayS = date('d', $startDate);
  68. if (!checkdate($monthS, $dayS, $yearS)) {
  69. return -1;
  70. }
  71. }
  72. if (empty($end)) {
  73. list($yearE, $monthE, $dayE) = explode('-', date(FORMAT_DB_DATE));
  74. } else {
  75. $endDate = self::fromString($end);
  76. $yearE = date('Y', $endDate);
  77. $monthE = date('m', $endDate);
  78. $dayE = date('d', $endDate);
  79. if (!checkdate($monthE, $dayE, $yearE)) {
  80. return -1;
  81. }
  82. }
  83. //$startDate = mktime(0,0,0,$monthS,$dayS,$yearS);
  84. //$endDate = mktime(0,0,0,$monthE,$dayE,$yearE);
  85. //$age = intval(($endDate - $startDate) / (3600 * 24 * 365));
  86. //$age = self::timef($endDate-$startDate, 'Y'); # !!! timef function
  87. $n_tag = $dayE;
  88. $n_monat = $monthE;
  89. $n_jahr = $yearE;
  90. $g_tag = $dayS;
  91. $g_monat = $monthS;
  92. $g_jahr = $yearS;
  93. $g_date = mktime(0, 0, 0, $g_tag, $g_monat, $g_jahr);
  94. if (($n_monat>$g_monat)||(($n_monat == $g_monat)&&($n_tag>$g_tag))||(($n_monat == $g_monat)&&($n_tag==$g_tag))) {
  95. $age = $n_jahr-$g_jahr; // is correct if one already had his birthday this year
  96. } else {
  97. $age = $n_jahr-$g_jahr-1; // is correct if one didnt have his birthday yet in this year
  98. }
  99. return $age;
  100. //TODO: test this short method
  101. //return (date("Y",time()) - $val);
  102. }
  103. /**
  104. * try to return the age only with the year available
  105. * can be e.g. 22/23
  106. * @param int $year
  107. * @param int $month (optional)
  108. * 2011-03-11 ms
  109. */
  110. public static function ageByYear($year, $month = null) {
  111. if ($month === null) {
  112. $maxAge = self::age(mktime(0,0,0,1,1,$year));
  113. $minAge = self::age(mktime(23,59,59,12,31,$year));
  114. $ages = array_unique(array($minAge, $maxAge));
  115. return implode('/', $ages);
  116. }
  117. if (date('n') == $month) {
  118. $maxAge = self::age(mktime(0, 0, 0, $month, 1, $year));
  119. $minAge = self::age(mktime(23, 59, 59, $month, self::daysInMonth($year, $month), $year));
  120. $ages = array_unique(array($minAge, $maxAge));
  121. return implode('/', $ages);
  122. }
  123. return self::age(mktime(0, 0, 0, $month, 1, $year));
  124. }
  125. /**
  126. * 2011-11-22 lb
  127. */
  128. public static function ageByHoroscope($year, $sign) {
  129. App::uses('ZodiacLib', 'Tools.Misc');
  130. $Zodiac = new ZodiacLib();
  131. $range = $Zodiac->getRange($sign);
  132. // undefined
  133. if ($sign == ZodiacLib::SIGN_CAPRICORN) {
  134. return array(date('Y') - $year - 1, date('Y') - $year);
  135. }
  136. // not over
  137. elseif($range[0][0] > date('m') || ($range[0][0] == date('m') && $range[0][1] > date('d'))) {
  138. return date('Y') - $year - 1;
  139. }
  140. // over
  141. elseif ($range[1][0] < date('m') || ($range[1][0] == date('m') && $range[1][1] <= date('d'))) {
  142. return date('Y') - $year;
  143. } else {
  144. return array(date('Y') - $year - 1, date('Y') - $year);
  145. }
  146. }
  147. /**
  148. * rounded age depended on steps (e.g. age 16 with steps = 10 => "11-20")
  149. * @FIXME
  150. * TODO: move to helper?
  151. * 2011-04-07 ms
  152. */
  153. public static function ageRange($year, $month = null, $day = null, $steps = 1) {
  154. if ($month == null && $day == null) {
  155. $age = date('Y') - $year - 1;
  156. } elseif ($day == null) {
  157. if ($month >= date('m'))
  158. $age = date('Y') - $year - 1;
  159. else
  160. $age = date('Y') - $year;
  161. } else {
  162. if ($month > date('m') || ($month == date('m') && $day > date('d')))
  163. $age = date('Y') - $year - 1;
  164. else
  165. $age = date('Y') - $year;
  166. }
  167. if ($age % $steps == 0) {
  168. $lowerRange = $age - $steps + 1;
  169. $upperRange = $age;
  170. } else {
  171. $lowerRange = $age - ($age % $steps) + 1;
  172. $upperRange = $age - ($age % $steps) + $steps;
  173. }
  174. if ($lowerRange == $upperRange)
  175. return $upperRange;
  176. else
  177. return array($lowerRange, $upperRange);
  178. }
  179. /**
  180. * return the days of a given month
  181. * @param int $year
  182. * @param int $month
  183. * 2011-11-03 ms
  184. */
  185. public static function daysInMonth($year, $month) {
  186. return date("t", mktime(0, 0, 0, $month, 1, $year));
  187. }
  188. /**
  189. * Calendar Week (current week of the year)
  190. * @param date in DB format - if none is passed, current day is used
  191. * @param int relative - weeks relative to the date (+1 next, -1 previous etc)
  192. * @TODO: use timestamp - or make the function able to use timestamps at least (besides dateString)
  193. *
  194. * Mit date('W', $time) (großes W!) bekommst die ISO6801-Wochennummer des angegebenen Zeitpunkts, das entspricht der Europäischen Kalenderwoche - mit einer Ausnahme: Daten die zur letzten Kalenderwoche des vorherigen Jahres gehören, liefern die 0 zurück; in dem Fall solltest du dann die KW des 31.12. des Vorjahres ermitteln.
  195. */
  196. public static function cweek($dateString = null, $relative = 0) {
  197. //$time = self::fromString($dateString);
  198. if (!empty($dateString)) {
  199. //pr ($dateString);
  200. $date = explode(' ', $dateString);
  201. list ($y, $m, $d) = explode('-', $date[0]);
  202. $t = mktime(0, 0, 0, $m, $d, $y);
  203. } else {
  204. $d = date('d');
  205. $m = date('m');
  206. $y = date('Y');
  207. $t = time();
  208. }
  209. $relative = (int)$relative;
  210. if ($relative != 0) {
  211. $t += WEEK*$relative; // 1day * 7 * relativeWeeks
  212. }
  213. if (0==($kw=date('W', $t))) {
  214. $kw = 1+date($t-DAY*date('w', $t), 'W');
  215. $y--;
  216. }
  217. //echo "Der $d.$m.$y liegt in der Kalenderwoche $kw/$y";
  218. return $kw.'/'.$y;
  219. }
  220. /**
  221. * return the timestamp to a day in a specific cweek
  222. * 0=sunday to 7=saturday (default)
  223. * @return timestamp of the weekDay
  224. * @FIXME: offset
  225. * not needed, use localDate!
  226. */
  227. public static function cweekDay($cweek, $year, $day, $offset = 0) {
  228. $cweekBeginning = self::cweekBeginning($year, $cweek);
  229. return $cweekBeginning + $day * DAY;
  230. }
  231. /**
  232. * @FIXME ???
  233. * Get number of days since the start of the week.
  234. * 1 = monday, 7 = sunday ? should be 0=sunday to 7=saturday (default)
  235. * @param int $num Number of day.
  236. * @return int Days since the start of the week.
  237. */
  238. public static function cweekMod($num, $offset = 0) {
  239. $base = 7;
  240. return ($num - $base*floor($num/$base));
  241. }
  242. /**
  243. * calculate the beginning of a calenderweek
  244. * if no cweek is given get the beginning of the first week of the year
  245. * @param year (format xxxx)
  246. * @param cweek (optional, defaults to first, range 1...52/53)
  247. * 2011-03-07 ms
  248. */
  249. public static function cweekBeginning($year, $cweek = null) {
  250. if ((int)$cweek <= 1 || (int)$cweek > self::cweeks($year)) {
  251. $first = mktime(0,0,0,1,1, $year);
  252. $wtag = date('w', $first);
  253. if ($wtag<=4) {
  254. /*Donnerstag oder kleiner: auf den Montag zurückrechnen.*/
  255. $firstmonday = mktime(0,0,0,1,1-($wtag-1),$year);
  256. } elseif ($wtag!=1) {
  257. /*auf den Montag nach vorne rechnen.*/
  258. $firstmonday = mktime(0,0,0,1,1+(7-$wtag+1),$year);
  259. } else {
  260. $firstmonday = $first;
  261. }
  262. return $firstmonday;
  263. }
  264. $monday = strtotime($year.'W'.str_pad($cweek, 2, '0', STR_PAD_LEFT).'1');
  265. return $monday;
  266. }
  267. /**
  268. * calculate the ending of a calenderweek
  269. * if no cweek is given get the ending of the last week of the year
  270. * @param year (format xxxx)
  271. * @param cweek (optional, defaults to last, range 1...52/53)
  272. * 2011-03-07 ms
  273. */
  274. public static function cweekEnding($year, $cweek = null) {
  275. if ((int)$cweek < 1 || (int)$cweek >= self::cweeks($year)) {
  276. return self::cweekBeginning($year+1)-1;
  277. }
  278. return self::cweekBeginning($year, intval($cweek)+1)-1;
  279. }
  280. /**
  281. * calculate the amount of calender weeks in a year
  282. * @param year (format xxxx, defaults to current year)
  283. * @return int: 52 or 53
  284. * 2011-03-07 ms
  285. */
  286. public static function cweeks($year = null) {
  287. if ($year === null) {
  288. $year = date('Y');
  289. }
  290. return date('W', mktime(23, 59, 59, 12, 28, $year));
  291. }
  292. /**
  293. * @param year (format xxxx, defaults to current year)
  294. * @return bool $success
  295. * 2012-02-17 ms
  296. */
  297. public static function isLeapYear($year) {
  298. if ($year % 4 != 0) {
  299. return false;
  300. }
  301. if ($year % 400 == 0) {
  302. return true;
  303. }
  304. if ($year > 1582 && $year % 100 == 0) {
  305. # if gregorian calendar (>1582), century not-divisible by 400 is not leap
  306. return false;
  307. }
  308. return true;
  309. }
  310. /**
  311. * get the age bounds (min, max) as timestamp that would result in the given age(s)
  312. * note: expects valid age (> 0 and < 120)
  313. * @param $firstAge
  314. * @param $secondAge (defaults to first one if not specified)
  315. * @return array('min'=>$min, 'max'=>$max);
  316. * 2011-07-06 ms
  317. */
  318. public static function ageBounds($firstAge, $secondAge = null, $returnAsString = false, $relativeTime = null) {
  319. if ($secondAge === null) {
  320. $secondAge = $firstAge;
  321. }
  322. //TODO: other relative time then today should work as well
  323. $max = mktime(23, 23, 59, date('m'), date('d'), date('Y')-$firstAge); // time()-($firstAge+1)*YEAR;
  324. $min = mktime(0, 0, 1, date('m'), date('d')+1, date('Y')-$secondAge-1); // time()+DAY-$secondAge*YEAR;
  325. if ($returnAsString) {
  326. $max = date(FORMAT_DB_DATE, $max);
  327. $min = date(FORMAT_DB_DATE, $min);
  328. }
  329. return array('min'=>$min, 'max'=>$max);
  330. }
  331. /**
  332. * for birthdays etc
  333. * @param date
  334. * @param string days with +-
  335. * @param options
  336. * 2011-03-03 ms
  337. */
  338. public static function isInRange($dateString, $seconds, $options = array()) {
  339. //$newDate = is_int($dateString) ? $dateString : strtotime($dateString);
  340. //$newDate += $seconds;
  341. $newDate = time();
  342. return self::difference($dateString, $newDate) <= $seconds;
  343. }
  344. /**
  345. * outputs Date(time) Sting nicely formatted (+ localized!)
  346. * @param string $dateString,
  347. * @param string $format (YYYY-MM-DD, DD.MM.YYYY)
  348. * @param array $options
  349. * - userOffset: User's offset from GMT (in hours)
  350. * - default (defaults to "-----")
  351. * 2009-03-31 ms
  352. */
  353. public static function localDate($dateString = null, $format = null, $options = array()) {
  354. $defaults = array('default'=>'-----', 'userOffset'=>self::$userOffset);
  355. $options = array_merge($defaults, $options);
  356. $date = null;
  357. if ($dateString !== null) {
  358. $date = self::fromString($dateString, $options['userOffset']);
  359. }
  360. if ($date === null || $date === false || $date <= 0) {
  361. return $options['default'];
  362. }
  363. if ($format === null) {
  364. if (is_int($dateString) || strpos($dateString, ' ') !== false) {
  365. $format = FORMAT_LOCAL_YMDHM;
  366. } else {
  367. $format = FORMAT_LOCAL_YMD;
  368. }
  369. }
  370. return strftime($format, $date);
  371. }
  372. /**
  373. * outputs Date(time) Sting nicely formatted
  374. * @param string $dateString,
  375. * @param string $format (YYYY-MM-DD, DD.MM.YYYY)
  376. * @param array $options
  377. * - userOffset: User's offset from GMT (in hours)
  378. * - default (defaults to "-----")
  379. * 2009-03-31 ms
  380. */
  381. public static function niceDate($dateString = null, $format = null, $options = array()) {
  382. $defaults = array('default'=>'-----', 'userOffset'=>self::$userOffset);
  383. $options = array_merge($defaults, $options);
  384. $date = null;
  385. if ($dateString !== null) {
  386. $date = self::fromString($dateString, $options['userOffset']);
  387. }
  388. if ($date === null || $date === false || $date <= 0) {
  389. return $options['default'];
  390. }
  391. if ($format === null) {
  392. if (is_int($dateString) || strpos($dateString, ' ') !== false) {
  393. $format = FORMAT_NICE_YMDHM;
  394. } else {
  395. $format = FORMAT_NICE_YMD;
  396. }
  397. }
  398. $ret = date($format, $date);
  399. if (!empty($options['oclock']) && $options['oclock']) {
  400. switch ($format) {
  401. case FORMAT_NICE_YMDHM:
  402. case FORMAT_NICE_YMDHMS:
  403. case FORMAT_NICE_YMDHM:
  404. case FORMAT_NICE_HM:
  405. case FORMAT_NICE_HMS:
  406. $ret .= ' '.__('o\'clock');
  407. break;
  408. }
  409. }
  410. return $ret;
  411. }
  412. /**
  413. * return the translation to a specific week day
  414. * @param int $day:
  415. * 0=sunday to 7=saturday (default numbers)
  416. * @param bool $abbr (if abbreviation should be returned)
  417. * @param offset: 0-6 (defaults to 0) [1 => 1=monday to 7=sunday]
  418. * @return string $translatedText
  419. * 2011-12-07 ms
  420. */
  421. public static function day($day, $abbr = false, $offset = 0) {
  422. $days = array(
  423. 'long' => array(
  424. 'Sunday',
  425. 'Monday',
  426. 'Tuesday',
  427. 'Wednesday',
  428. 'Thursday',
  429. 'Friday',
  430. 'Saturday'
  431. ),
  432. 'short' => array(
  433. 'Sun',
  434. 'Mon',
  435. 'Tue',
  436. 'Wed',
  437. 'Thu',
  438. 'Fri',
  439. 'Sat'
  440. )
  441. );
  442. $day = (int) $day;
  443. pr($day);
  444. if ($offset) {
  445. $day = ($day + $offset) % 7;
  446. }
  447. pr($day);
  448. if ($abbr) {
  449. return __($days['short'][$day]);
  450. }
  451. return __($days['long'][$day]);
  452. }
  453. /**
  454. * return the translation to a specific week day
  455. * @param int $month:
  456. * 1..12
  457. * @param bool $abbr (if abbreviation should be returned)
  458. * @param array $options
  459. * - appendDot (only for 3 letter abbr; defaults to false)
  460. * @return string $translatedText
  461. * 2011-12-07 ms
  462. */
  463. public static function month($month, $abbr = false, $options = array()) {
  464. $months = array(
  465. 'long' => array(
  466. 'January',
  467. 'February',
  468. 'March',
  469. 'April',
  470. 'May',
  471. 'June',
  472. 'July',
  473. 'August',
  474. 'September',
  475. 'October',
  476. 'November',
  477. 'December'
  478. ),
  479. 'short' => array(
  480. 'Jan',
  481. 'Feb',
  482. 'Mar',
  483. 'Apr',
  484. 'May',
  485. 'Jun',
  486. 'Jul',
  487. 'Aug',
  488. 'Sep',
  489. 'Oct',
  490. 'Nov',
  491. 'Dec'
  492. ),
  493. );
  494. $month = (int) ($month - 1);
  495. if (!$abbr) {
  496. return __($months['long'][$month]);
  497. }
  498. $monthName = __($months['short'][$month]);
  499. if (!empty($options['appendDot']) && strlen(__($months['long'][$month])) > 3) {
  500. $monthName .= '.';
  501. }
  502. return $monthName;
  503. }
  504. /**
  505. * @return array (for forms etc)
  506. */
  507. public static function months($monthKeys = array(), $options = array()) {
  508. if (!$monthKeys) {
  509. $monthKeys = range(1, 12);
  510. }
  511. $res = array();
  512. $abbr = isset($options['abbr']) ? $options['abbr'] : false;
  513. foreach ($monthKeys as $key) {
  514. $res[str_pad($key, 2, '0', STR_PAD_LEFT)] = self::month($key, $abbr, $options);
  515. }
  516. return $res;
  517. }
  518. /**
  519. * weekdays
  520. * @return array (for forms etc)
  521. */
  522. public static function days($dayKeys = array(), $options = array()) {
  523. if (!$dayKeys) {
  524. $dayKeys = range(0, 6);
  525. }
  526. $res = array();
  527. $abbr = isset($options['abbr']) ? $options['abbr'] : false;
  528. $offset = isset($options['offset']) ? $options['offset'] : 0;
  529. foreach ($dayKeys as $key) {
  530. $res[$key] = self::day($key, $abbr, $offset);
  531. }
  532. return $res;
  533. }
  534. /**
  535. * can convert time from one unit to another
  536. * @param int INT | time
  537. * @param from CHAR
  538. * @param to CHAR
  539. * @param options: acc=>INT [accuracy], showZero=>BOOL, returnArray=>BOOL
  540. * 2008-11-06 ms
  541. */
  542. public static function convertTime($int, $from, $to, $options = array()) {
  543. $accuracy = 0; # 0 = only the "to"-element, 1..n = higher accurancy
  544. $showZero = false; # show only the non-zero elements
  545. $returnArray = false; # return as array instead of as string
  546. if (!empty($options)) {
  547. if (isset($options['acc'])) {
  548. $accuracy = (int)$options['acc'];
  549. }
  550. if (isset($options['showZero'])) {
  551. $showZero = (int)$options['showZero'];
  552. }
  553. if (isset($options['returnArray'])) {
  554. $return = ($options['returnArray']===true?true:false);
  555. }
  556. }
  557. $times = array(
  558. 's'=>'0',
  559. 'm'=>'1',
  560. 'h'=>'2',
  561. 'd'=>'3',
  562. 'w'=>'4',
  563. 'm'=>'5',
  564. 'y'=>'6',
  565. );
  566. $options = array(
  567. '0'=>array(
  568. 'steps'=>array('1'=>60,'2'=>3600,'3'=>86400,'4'=>86400*7,'5'=>86400*30,'6'=>86400*365),
  569. 'down'=>0,
  570. 'up'=>60,
  571. 'short'=>'s',
  572. 'long'=>'seconds'
  573. ),
  574. '1'=>array(
  575. 'steps'=>array('0'=>60,'2'=>60,'3'=>60*24,'4'=>60*24*7,'5'=>60*24*30,'6'=>60*24*365),
  576. 'down'=>60,
  577. 'up'=>60,
  578. 'short'=>'m',
  579. 'long'=>'minutes'
  580. ),
  581. '2'=>array(
  582. 'steps'=>array('0'=>3600,'1'=>60,'3'=>24,'4'=>24*7,'5'=>24*30,'6'=>24*365),
  583. 'down'=>60,
  584. 'up'=>24,
  585. 'short'=>'h',
  586. 'long'=>'hours'
  587. ),
  588. '3'=>array(
  589. 'steps'=>array('0'=>86400,'1'=>3600,'2'=>24,'4'=>7,'5'=>30,'6'=>365),
  590. 'down'=>24,
  591. 'up'=>7,
  592. 'short'=>'d',
  593. 'long'=>'days'
  594. ),
  595. '4'=>array(
  596. 'steps'=>array('0'=>86400*7,'1'=>60*24*7,'2'=>24*7,'3'=>7,'5'=>4.2,'6'=>52),
  597. 'down'=>7,
  598. 'up'=>4.2,
  599. 'short'=>'w',
  600. 'long'=>'weeks'
  601. ),
  602. '5'=>array(
  603. 'steps'=>array('0'=>86400*30,'1'=>60*24*30,'2'=>24*30,'3'=>30,'4'=>4.2,'6'=>12),
  604. 'down'=>4.2,
  605. 'up'=>12,
  606. 'short'=>'m',
  607. 'long'=>'months'
  608. ),
  609. '6'=>array(
  610. 'steps'=>array('0'=>86400*365,'1'=>60*24*365,'2'=>24*365,'3'=>365,'4'=>52,'5'=>12),
  611. 'down'=>12,
  612. 'up'=>0,
  613. 'short'=>'y',
  614. 'long'=>'years'
  615. ),
  616. );
  617. //echo $options[0]['steps']['4'];
  618. if (array_key_exists($from,$times) && array_key_exists($to,$times)) {
  619. $begin = $times[$from];
  620. $end = $times[$to];
  621. //echo $begin-$end.BR;
  622. }
  623. $minuten = $int;
  624. if ($minuten<60) {
  625. return $minuten.'min';
  626. }
  627. $calculated = floor($minuten/60)."h ".($minuten%60)."min";
  628. if ($returnArray) {
  629. // return as array
  630. } else {
  631. // convert to the desired string
  632. }
  633. return $calculated;
  634. }
  635. /**
  636. * @deprecated
  637. * NICHT TESTEN!
  638. */
  639. public static function otherOne() {
  640. $day = floor($anz_sekunden/86400);
  641. $hours = floor(($anz_sekunden-(floor($anz_sekunden/86400)*86400))/3600);
  642. $minutes = floor(($anz_sekunden-(floor($anz_sekunden/3600)*3600))/60);
  643. $seconds = floor($anz_sekunden-(floor($anz_sekunden/60))*60);
  644. if ($day < 10) {
  645. $day = '0'.$day;
  646. }
  647. if ($hours < 10) {
  648. $hours = '0'.$hours;
  649. }
  650. if ($minutes < 10) {
  651. $minutes = '0'.$minutes;
  652. }
  653. if ($seconds < 10) {
  654. $seconds = '0'.$seconds;
  655. }
  656. if ($day > 0) {
  657. $zeit_ausgabe = $day.":".$hours.":".$minutes.":".$seconds;
  658. } else {
  659. $zeit_ausgabe = $hours.":".$minutes.":".$seconds." h";
  660. }
  661. }
  662. /**
  663. * Returns the difference between a time and now in a "fuzzy" way.
  664. * Note that unlike [span], the "local" timestamp will always be the
  665. * current time. Displaying a fuzzy time instead of a date is usually
  666. * faster to read and understand.
  667. *
  668. * $span = fuzzy(time() - 10); // "moments ago"
  669. * $span = fuzzy(time() + 20); // "in moments"
  670. *
  671. * @param integer "remote" timestamp
  672. * @return string
  673. */
  674. public static function fuzzy($timestamp) {
  675. // Determine the difference in seconds
  676. $offset = abs(time() - $timestamp);
  677. return self::fuzzyFromOffset($offset, $timestamp <= time());
  678. }
  679. /**
  680. * @param int $offset in seconds
  681. * @param boolean $past (defaults to null: return plain text)
  682. * - new: if not boolean but a string use this as translating text
  683. * @return string $text (i18n!)
  684. * 2011-03-06 ms
  685. */
  686. public static function fuzzyFromOffset($offset, $past = null) {
  687. if ($offset <= MINUTE) {
  688. $span = 'moments';
  689. } elseif ($offset < (MINUTE * 20)) {
  690. $span = 'a few minutes';
  691. } elseif ($offset < HOUR) {
  692. $span = 'less than an hour';
  693. } elseif ($offset < (HOUR * 4)) {
  694. $span = 'a couple of hours';
  695. } elseif ($offset < DAY) {
  696. $span = 'less than a day';
  697. } elseif ($offset < (DAY * 2)) {
  698. $span = 'about a day';
  699. } elseif ($offset < (DAY * 4)) {
  700. $span = 'a couple of days';
  701. } elseif ($offset < WEEK) {
  702. $span = 'less than a week';
  703. } elseif ($offset < (WEEK * 2)) {
  704. $span = 'about a week';
  705. } elseif ($offset < MONTH) {
  706. $span = 'less than a month';
  707. } elseif ($offset < (MONTH * 2)) {
  708. $span = 'about a month';
  709. } elseif ($offset < (MONTH * 4)) {
  710. $span = 'a couple of months';
  711. } elseif ($offset < YEAR) {
  712. $span = 'less than a year';
  713. } elseif ($offset < (YEAR * 2)) {
  714. $span = 'about a year';
  715. } elseif ($offset < (YEAR * 4)) {
  716. $span = 'a couple of years';
  717. } elseif ($offset < (YEAR * 8)) {
  718. $span = 'a few years';
  719. } elseif ($offset < (YEAR * 12)) {
  720. $span = 'about a decade';
  721. } elseif ($offset < (YEAR * 24)) {
  722. $span = 'a couple of decades';
  723. } elseif ($offset < (YEAR * 64)) {
  724. $span = 'several decades';
  725. } else {
  726. $span = 'a long time';
  727. }
  728. if ($past === true) {
  729. // This is in the past
  730. return __('%s ago', __($span));
  731. } elseif ($past === false) {
  732. // This in the future
  733. return __('in %s', __($span));
  734. } elseif ($past !== null) {
  735. // Custom translation
  736. return __($past, __($span));
  737. }
  738. return __($span);
  739. }
  740. /**
  741. * time length to human readable format
  742. * @param int $seconds
  743. * @param string format: format
  744. * @param options
  745. * - boolean v: verbose
  746. * - boolean zero: if false: 0 days 5 hours => 5 hours etc.
  747. * - int: accuracy (how many sub-formats displayed?) //TODO
  748. * 2009-11-21 ms
  749. * @see timeAgoInWords()
  750. */
  751. public static function lengthOfTime($seconds, $format = null, $options = array()) {
  752. $defaults = array('verbose'=>true, 'zero'=>false, 'separator'=>', ', 'default'=>'');
  753. $ret = '';
  754. $j = 0;
  755. $options = array_merge($defaults, $options);
  756. if (!$options['verbose']) {
  757. $s = array(
  758. 'm' => 'mth',
  759. 'd' => 'd',
  760. 'h' => 'h',
  761. 'i' => 'm',
  762. 's' => 's'
  763. );
  764. $p = $s;
  765. } else {
  766. $s = array(
  767. 'm' => ' '.__('Month'), # translated
  768. 'd' => ' '.__('Day'),
  769. 'h' => ' '.__('Hour'),
  770. 'i' => ' '.__('Minute'),
  771. 's' => ' '.__('Second'),
  772. );
  773. $p = array (
  774. 'm' => ' '.__('Months'), # translated
  775. 'd' => ' '.__('Days'),
  776. 'h' => ' '.__('Hours'),
  777. 'i' => ' '.__('Minutes'),
  778. 's' => ' '.__('Seconds'),
  779. );
  780. }
  781. if (!isset($format)) {
  782. //if (floor($seconds / MONTH) > 0) $format = "Md";
  783. if (floor($seconds / DAY) > 0) $format = "Dh";
  784. elseif (floor($seconds / 3600) > 0) $format = "Hi";
  785. elseif (floor($seconds / 60) > 0) $format = "Is";
  786. else $format = "S";
  787. }
  788. for ($i = 0; $i < mb_strlen($format); $i++) {
  789. switch (mb_substr($format, $i, 1)) {
  790. case 'D':
  791. $str = floor($seconds / 86400);
  792. break;
  793. case 'd':
  794. $str = floor($seconds / 86400 % 30);
  795. break;
  796. case 'H':
  797. $str = floor($seconds / 3600);
  798. break;
  799. case 'h':
  800. $str = floor($seconds / 3600 % 24);
  801. break;
  802. case 'I':
  803. $str = floor($seconds / 60);
  804. break;
  805. case 'i':
  806. $str = floor($seconds / 60 % 60);
  807. break;
  808. case 'S':
  809. $str = $seconds;
  810. break;
  811. case 's':
  812. $str = floor($seconds % 60);
  813. break;
  814. default:
  815. return "";
  816. break;
  817. }
  818. if ($str > 0 || $j > 0 || $options['zero'] || $i == mb_strlen($format) - 1) {
  819. if ($j>0) {
  820. $ret .= $options['separator'];
  821. }
  822. $j++;
  823. $x = mb_strtolower(mb_substr($format, $i, 1));
  824. if ($str == 1) {
  825. $ret .= $str . $s[$x];
  826. } else {
  827. $title = $p[$x];
  828. if (!empty($options['plural'])) {
  829. if (mb_substr($title, -1, 1) == 'e') {
  830. $title .= $options['plural'];
  831. }
  832. }
  833. $ret .= $str . $title;
  834. }
  835. }
  836. }
  837. return $ret;
  838. }
  839. /**
  840. * time relative to NOW in human readable format - absolute (negative as well as positive)
  841. * //TODO: make "now" adjustable
  842. * @param mixed $datestring
  843. * @param string format: format
  844. * @param options
  845. * - default, separator
  846. * - boolean zero: if false: 0 days 5 hours => 5 hours etc.
  847. * - verbose/past/future: string with %s or boolean true/false
  848. * 2009-11-21 ms
  849. */
  850. public static function relLengthOfTime($dateString, $format = null, $options = array()) {
  851. if ($dateString != null) {
  852. $userOffset = null;
  853. $sec = time() - self::fromString($dateString, $userOffset);
  854. $type = ($sec > 0)?-1:(($sec < 0)?1:0);
  855. $sec = abs($sec);
  856. } else {
  857. $sec = 0;
  858. $type = 0;
  859. }
  860. $defaults = array('verbose'=>__('justNow'), 'zero'=>false,'separator'=>', ', 'future'=>__('In %s'), 'past'=>__('%s ago'),'default'=>'');
  861. $options = array_merge($defaults, $options);
  862. $ret = self::lengthOfTime($sec, $format, $options);
  863. if ($type == 1) {
  864. if ($options['future'] !== false) {
  865. return sprintf($options['future'], $ret);
  866. }
  867. return array('future'=>$ret);
  868. } elseif ($type == -1) {
  869. if ($options['past'] !== false) {
  870. return sprintf($options['past'], $ret);
  871. }
  872. return array('past'=>$ret);
  873. } else {
  874. if ($options['verbose'] !== false) {
  875. return $options['verbose'];
  876. }
  877. //return array('now'=>true);
  878. }
  879. return $options['default'];
  880. }
  881. /**
  882. * Returns true if given datetime string was day before yesterday.
  883. *
  884. * @param string $dateString Datetime string or Unix timestamp
  885. * @param int $userOffset User's offset from GMT (in hours)
  886. * @return boolean True if datetime string was day before yesterday
  887. */
  888. public static function wasDayBeforeYesterday($dateString, $userOffset = null) {
  889. $date = self::fromString($dateString, $userOffset);
  890. return date(FORMAT_DB_DATE, $date) == date(FORMAT_DB_DATE, time()-2*DAY);
  891. }
  892. /**
  893. * Returns true if given datetime string is the day after tomorrow.
  894. *
  895. * @param string $dateString Datetime string or Unix timestamp
  896. * @param int $userOffset User's offset from GMT (in hours)
  897. * @return boolean True if datetime string is day after tomorrow
  898. */
  899. public static function isDayAfterTomorrow($dateString, $userOffset = null) {
  900. $date = self::fromString($dateString, $userOffset);
  901. return date(FORMAT_DB_DATE, $date) == date(FORMAT_DB_DATE, time()+2*DAY);
  902. }
  903. /**
  904. * Returns true if given datetime string is not today AND is in the future.
  905. *
  906. * @param string $dateString Datetime string or Unix timestamp
  907. * @param int $userOffset User's offset from GMT (in hours)
  908. * @return boolean True if datetime is not today AND is in the future
  909. */
  910. public static function isNotTodayAndInTheFuture($dateString, $userOffset = null) {
  911. $date = self::fromString($dateString, $userOffset);
  912. return date(FORMAT_DB_DATE, $date) > date(FORMAT_DB_DATE, time());
  913. }
  914. /**
  915. * Returns true if given datetime string is not now AND is in the future.
  916. *
  917. * @param string $dateString Datetime string or Unix timestamp
  918. * @param int $userOffset User's offset from GMT (in hours)
  919. * @return boolean True if datetime is not today AND is in the future
  920. */
  921. public static function isInTheFuture($dateString, $userOffset = null) {
  922. $date = self::fromString($dateString, $userOffset);
  923. return date(FORMAT_DB_DATETIME, $date) > date(FORMAT_DB_DATETIME, time());
  924. }
  925. /**
  926. * try to parse date from various input formats
  927. * - DD.MM.YYYY, DD/MM/YYYY, YYYY-MM-DD, YYYY, YYYY-MM, ...
  928. * - i18n: Today, Yesterday, Tomorrow
  929. * @param string $date to parse
  930. * @param format to parse (null = auto)
  931. * @param type
  932. * - start: first second of this interval
  933. * - end: last second of this interval
  934. * @return int timestamp
  935. * 2011-11-19 ms
  936. */
  937. public static function parseLocalizedDate($date, $format = null, $type = 'start') {
  938. $date = trim($date);
  939. echo returns($date);
  940. $i18n = array(
  941. strtolower(__('Today')) => array('start'=>date(FORMAT_DB_DATETIME, mktime(0, 0, 0, date('m'), date('d'), date('Y'))), 'end'=>date(FORMAT_DB_DATETIME, mktime(23, 59, 59, date('m'), date('d'), date('Y')))),
  942. strtolower(__('Tomorrow')) => array('start'=>date(FORMAT_DB_DATETIME, mktime(0, 0, 0, date('m'), date('d'), date('Y'))+DAY), 'end'=>date(FORMAT_DB_DATETIME, mktime(23, 59, 59, date('m'), date('d'), date('Y'))+DAY)),
  943. strtolower(__('Yesterday')) => array('start'=>date(FORMAT_DB_DATETIME, mktime(0, 0, 0, date('m'), date('d'), date('Y'))-DAY), 'end'=>date(FORMAT_DB_DATETIME, mktime(23, 59, 59, date('m'), date('d'), date('Y'))-DAY)),
  944. strtolower(__('The day after tomorrow')) => array('start'=>date(FORMAT_DB_DATETIME, mktime(0, 0, 0, date('m'), date('d'), date('Y'))+2*DAY), 'end'=>date(FORMAT_DB_DATETIME, mktime(23, 59, 59, date('m'), date('d'), date('Y'))+2*DAY)),
  945. strtolower(__('The day before yesterday')) => array('start'=>date(FORMAT_DB_DATETIME, mktime(0, 0, 0, date('m'), date('d'), date('Y'))-2*DAY), 'end'=>date(FORMAT_DB_DATETIME, mktime(23, 59, 59, date('m'), date('d'), date('Y'))-2*DAY)),
  946. );
  947. if (isset($i18n[strtolower($date)])) {
  948. return $i18n[strtolower($date)][$type];
  949. }
  950. if ($format) {
  951. $res = DateTime::createFromFormat($format, $date);
  952. $res = $res->format(FORMAT_DB_DATE).' '.($type=='end'?'23:59:59':'00:00:00');
  953. return $res;
  954. }
  955. if (strpos($date, '.') !== false) {
  956. $explode = explode('.', $date, 3);
  957. $explode = array_reverse($explode);
  958. } elseif (strpos($date, '/') !== false) {
  959. $explode = explode('/', $date, 3);
  960. $explode = array_reverse($explode);
  961. } elseif (strpos($date, '-') !== false) {
  962. $explode = explode('-', $date, 3);
  963. } else {
  964. $explode = array($date);
  965. }
  966. if (isset($explode)) {
  967. for ($i = 0; $i < count($explode); $i++) {
  968. $explode[$i] = str_pad($explode[$i], 2, '0', STR_PAD_LEFT);
  969. }
  970. $explode[0] = str_pad($explode[0], 4, '20', STR_PAD_LEFT);
  971. if (count($explode) === 3) {
  972. return implode('-', $explode).' '.($type=='end'?'23:59:59':'00:00:00');
  973. } elseif (count($explode) === 2) {
  974. return implode('-', $explode).'-'.($type=='end'?self::daysInMonth($explode[0], $explode[1]):'01').' '.($type=='end'?'23:59:59':'00:00:00');
  975. } else {
  976. return $explode[0].'-'.($type=='end'?'12':'01').'-'.($type=='end'?'31':'01').' '.($type=='end'?'23:59:59':'00:00:00');
  977. }
  978. }
  979. return false;
  980. }
  981. /**
  982. * @param string $searchString to parse
  983. * @param array $options
  984. * - separator (defaults to space [ ])
  985. * - format (defaults to Y-m-d H:i:s)
  986. * @return array $period [0=>min, 1=>max]
  987. * 2011-11-18 ms
  988. */
  989. public static function period($string, $options = array()) {
  990. if (strpos($string, ' ') !== false) {
  991. $filters = explode(' ', $string);
  992. $filters = array(array_shift($filters), array_pop($filters));
  993. } else {
  994. $filters = array($string, $string);
  995. }
  996. $min = $filters[0];
  997. $max = $filters[1];
  998. //$x = preg_match('/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/', $date, $date_parts);
  999. //$x = Datetime::createFromFormat('Y-m-d', $string);
  1000. //die(returns($x));
  1001. //$actualDateTime = new DateTime($min);
  1002. //$actualDateTime->add(new DateInterval('P1M'));
  1003. $min = self::parseLocalizedDate($min);
  1004. $max = self::parseLocalizedDate($max, null, 'end');
  1005. //die($actualDateTime->format('Y-m-d'));
  1006. //$searchParameters['conditions']['Coupon.date'] = $actualDateTime->format('Y-m-d');
  1007. /*
  1008. if ($min == $max) {
  1009. if (strlen($max) > 8) {
  1010. $max = date(FORMAT_DB_DATE, strtotime($max)+DAY);
  1011. } elseif (strlen($max) > 5) {
  1012. $max = date(FORMAT_DB_DATE, strtotime($max)+MONTH);
  1013. } else {
  1014. $max = date(FORMAT_DB_DATE, strtotime($max)+YEAR+MONTH);
  1015. }
  1016. }
  1017. $min = date(FORMAT_DB_DATE, strtotime($min));
  1018. $max = date(FORMAT_DB_DATE, strtotime($max));
  1019. */
  1020. return array($min, $max);
  1021. }
  1022. /**
  1023. * @param string $searchString to parse
  1024. * @param string $fieldname (Model.field)
  1025. * @param array $options (see DatetimeLib::period)
  1026. * @return string $query SQL Query
  1027. * 2011-11-18 ms
  1028. */
  1029. public static function periodAsSql($string, $fieldName, $options = array()) {
  1030. $period = self::period($string, $options);
  1031. return self::daysAsSql($period[0], $period[1], $fieldName);
  1032. }
  1033. }