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