]> jfr.im git - irc/SurrealServices/srsv.git/blob - branches/erry-devel/SrSv/Time.pm
initial commit of erry's Insp work.
[irc/SurrealServices/srsv.git] / branches / erry-devel / SrSv / Time.pm
1 # This file is part of SurrealServices.
2 #
3 # SurrealServices is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
7 #
8 # SurrealServices is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with SurrealServices; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
17 package SrSv::Time;
18
19 use strict;
20 use integer;
21 use Time::Local;
22
23 use Exporter 'import';
24 BEGIN { our @EXPORT = qw( @months @days
25 gmtime2 tz_time gmt_date local_date
26 time_ago time_rel time_rel_long_all
27 parse_time split_time
28 get_nextday get_nextday_time get_monthdays
29 get_nexthour get_nexthour_time
30 )
31 }
32
33 our @months = ( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' );
34 our @days = ( 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' );
35
36 sub _time_text($) {
37 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime(shift);
38 return $mday.'/'.$months[$mon].'/'. substr($year, -2, 2).' '.
39 sprintf("%02d:%02d", $hour, $min);
40 }
41
42 sub gmtime2(;$) {
43 my ($time) = @_;
44 $time = time() unless $time;
45 return _time_text($time) . ' GMT';
46 }
47
48 sub tz_time($;$) {
49 my ($tzoffset, $time) = @_;
50 return _time_text(($time ? $time : time()) + tz_to_offset($tzoffset));
51 }
52
53 sub tz_to_offset($) {
54 my ($offset) = @_;
55 # offset is a signed integer corresponding to 1/4 hr increments
56 # or 900 seconds (15 minutes)
57 return ($offset * 900);
58 }
59
60 sub _date_text($) {
61 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime(shift);
62 return (!wantarray ? ($year+1900).' '.$months[$mon].' '.$mday : ($year + 1900, $mon+1, $months[$mon], $mday));
63 }
64
65 sub gmt_date(;$) {
66 my ($time) = @_;
67 $time = time() unless $time;
68 return _date_text($time);
69 }
70
71 sub local_date($;$) {
72 my ($tzoffset, $time) = @_;
73 return _date_text(($time ? $time : time()) + tz_to_offset($tzoffset));
74 }
75
76 sub parse_time($) {
77 my ($str) = @_;
78 my $out;
79 $str =~ s/^\+//;
80 $str = lc($str);
81
82 my @vals = split(/(?<!\d)(?=\d+\w)/, $str);
83
84 foreach my $val (@vals) {
85 $val =~ /(\d+)(\w)/;
86 my ($num, $pos) = ($1, $2);
87
88 if($pos eq 'w') { $num *= (86400*7) }
89 elsif($pos eq 'd') { $num *= 86400 }
90 elsif($pos eq 'h') { $num *= 3600 }
91 elsif($pos eq 'm') { $num *= 60 }
92 elsif($pos ne 's') { return undef }
93
94 $out += $num;
95 }
96
97 return $out;
98 }
99
100 sub split_time($) {
101 no integer; # We might want to pass in a float value for $difference
102 my ($difference) = @_;
103 my ($weeks, $days, $hours, $minutes, $seconds);
104 $seconds = $difference % 60;
105 $difference = ($difference - $seconds) / 60;
106 $minutes = $difference % 60;
107 $difference = ($difference - $minutes) / 60;
108 $hours = $difference % 24;
109 $difference = ($difference - $hours) / 24;
110 $days = $difference % 7;
111 $weeks = ($difference - $days) / 7;
112
113 return ($weeks, $days, $hours, $minutes, $seconds);
114 }
115
116 sub time_ago($;$) {
117 return time_rel(time() - $_[0], $_[1]);
118 }
119
120 sub time_rel($;$) {
121 my ($time, $all) = @_;
122
123 if ($time >= 2419200) { # 86400 * 7 * 4
124 my ($years, $months, $weeks, $days) = __time_rel_long(time() - $time);
125 if($years or $months or $weeks or $days) {
126 my $text = '';
127 if($years) {
128 $text = "$years year".($years !=1 ? 's' : '');
129 }
130 if($months) {
131 $text .= (length($text) ? ' ' : '')."$months month".($months !=1 ? 's' : '');
132 if ($years && !$all) {
133 return $text;
134 }
135 }
136 if($weeks) {
137 $text .= (length($text) ? ' ' : '')."$weeks week".($weeks !=1 ? 's' : '');
138 if ($months && !$all) {
139 return $text;
140 }
141 }
142 if($days) {
143 $text .= (length($text) ? ' ' : '')."$days day".($days !=1 ? 's' : '');
144 =cut
145 if ($weeks && !$all) {
146 return $text;
147 }
148 =cut
149 }
150 return $text;
151 =cut
152 return ( $years ? "$years year".($years !=1 ? 's' : '') : '' ).
153 ( $months ? ($years ? ', ' : '')."$months month".( $months!=1 ? 's' : '' ) : '').
154 ( $weeks ? (($years or $months) ? ', ' : '')."$weeks week".( $weeks!=1 ? 's' : '' ) : '').
155 ( $days ? (($months or $years or $weeks) ? ', ' : '')."$days day".($days!=1 ? 's' : '') : '' )
156 ;
157 =cut
158 }
159 }
160
161 my ($weeks, $days, $hours, $minutes, $seconds) = split_time($time);
162
163 my $text;
164 # if($time >= 604800) { # 86400 * 7 }
165 if($weeks) {
166 $text = "$weeks week".($weeks!=1 ? 's' : '');
167 =cut
168 return "$weeks week".
169 ($weeks!=1 ? 's' : '').
170 ", $days day".
171 ($days!=1 ? 's' : '');
172 =cut
173 }
174 if($days) {
175 $text .= (length($text) ? ' ' : '')."$days day".($days!=1 ? 's' : '');
176 return $text if $weeks && !$all;
177 =cut
178 return "$days day".
179 ($days!=1 ? 's' : '').
180 ", $hours hour".
181 ($hours!=1 ? 's' : '');
182 =cut
183 }
184 if($hours) {
185 $text .= (length($text) ? ' ' : '')."$hours hour".($hours!=1 ? 's' : '');
186 return $text if $days && !$all;
187 =cut
188 return "$hours hour".
189 ($hours!=1 ? 's' : '').
190 ", $minutes minute".
191 ($minutes!=1 ? 's' : '');
192 =cut
193 }
194 if($minutes) {
195 $text .= (length($text) ? ' ' : '')."$minutes minute".($minutes!=1 ? 's' : '');
196 return $text if $hours && !$all;
197 =cut return "$minutes minute".
198 ($minutes!=1 ? 's' : '').
199 ", $seconds second".
200 ($seconds!=1 ? 's' : '');
201 =cut
202 }
203 if($seconds) {
204 $text .= (length($text) ? ' ' : '')."$seconds second".($seconds!=1 ? 's' : '');
205 =cut
206 return "$seconds second".
207 ($seconds!=1 ? 's' : '');
208 =cut
209 }
210 return $text;
211 }
212
213 # This is for cases over 4 weeks, when we need years, months, weeks, and days
214 sub __time_rel_long($;$) {
215 my ($lesser_time, $greater_time) = @_;
216 $greater_time = time() unless $greater_time;
217
218 my ($sec1, $min1, $hour1, $mday1, $month1, $year1, undef, undef, undef) = gmtime($lesser_time);
219 my ($sec2, $min2, $hour2, $mday2, $month2, $year2, undef, undef, undef) = gmtime($greater_time);
220
221 my ($result_years, $result_months, $result_weeks, $result_days,
222 $result_hours, $result_mins, $result_secs);
223 $result_secs = $sec2 - $sec1;
224 $result_mins = $min2 - $min1;
225 if($result_secs < 0) {
226 $result_secs += 60; $result_mins--;
227 }
228 $result_hours = $hour2 - $hour1;
229 if($result_mins < 0) {
230 $result_mins += 60; $result_hours--;
231 }
232 $result_days = $mday2 - $mday1;
233 if($result_hours < 0) {
234 $result_hours += 24; $result_days--;
235 }
236 $result_months = $month2 - $month1;
237 if($result_days < 0) {
238 $result_days += get_monthdays(
239 ($month2 == 0 ? 11 : $month2 - 1),
240 ($month2 == 0 ? $year2 - 1: $year2));
241 $result_months--;
242 }
243 # The following division relies on integer division, as 'use integer' is decl'd above.
244 $result_weeks = $result_days / 7;
245 $result_days = $result_days % 7;
246 $result_years = $year2 - $year1;
247 if($result_months < 0) {
248 $result_months += 12; $result_years--
249 }
250 return ($result_years, $result_months, $result_weeks, $result_days, $result_hours, $result_mins, $result_secs);
251 }
252
253 # Apologize about the unreadability, but the alternative is about 4 times as long
254 # This is for use when we want as precise a time-difference as possible.
255 sub time_rel_long_all($;$) {
256 my ($lesser_time, $greater_time) = @_;
257 $greater_time = time() unless $greater_time;
258 my ($years, $months, $weeks, $days, $hours, $minutes, $seconds) = __time_rel_long($lesser_time);
259 return ( $years ? "$years year".($years !=1 ? 's' : '') : '' ).
260 ( $months ? ($years ? ', ' : '')."$months month".( $months!=1 ? 's' : '' ) : '').
261 ( $weeks ? (($years or $months) ? ', ' : '')."$weeks week".( $weeks!=1 ? 's' : '' ) : '').
262 ( $days ? (($months or $years or $weeks) ? ', ' : '')."$days day".($days!=1 ? 's' : '') : '' ).
263 ( $hours ? (($days or $months or $years or $weeks) ? ', ' : '')."$hours hour".($hours!=1 ? 's' : '') : '' ).
264 ( $minutes ? (($hours or $days or $months or $years or $weeks) ? ', ' : '')."$minutes minute".($minutes!=1 ? 's' : '') : '' ).
265 ( $seconds ? (($minutes or $days or $months or $years or $weeks) ? ', ' : '')."$seconds second".($seconds!=1 ? 's' : '') : '' )
266 ;
267
268 }
269
270 sub get_nextday($$$) {
271 my ($mday, $mon, $year) = @_;
272 $year += 1900 if $year < 1582; #Gregorian calendar was somewhere around here...
273
274 my $monthdays = get_monthdays($mon, $year);
275 $mday++;
276 if($mday > $monthdays) {
277 $mday %= $monthdays;
278 $mon++;
279 }
280 if($mon >= 12) {
281 $mon %= 12;
282 $year++;
283 }
284 return ($mday, $mon, $year);
285 }
286 sub get_nextday_time(;$) {
287 my ($time) = @_;
288 $time = time() unless $time;
289 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($time);
290 return Time::Local::timegm(0,0,0,get_nextday($mday, $mon, $year));
291 }
292
293 sub get_nexthour($$$$) {
294 my ($hour, $mday, $mon, $year) = @_;
295 # $minute++;
296 # if($minute >= 60) {
297 # $minute %= 60;
298 # $hour++;
299 # }
300 $hour++;
301 if($hour >= 24) {
302 $hour %= 24;
303 ($mday, $mon, $year) = get_nextday($mday, $mon, $year)
304 }
305 return ($hour, $mday, $mon, $year);
306 }
307 sub get_nexthour_time(;$) {
308 my ($time) = @_;
309 $time = time() unless $time;
310 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($time);
311 return Time::Local::timegm(0,0,get_nexthour($hour, $mday, $mon, $year));
312 }
313
314 # This function is only correct/valid for Gregorian dates.
315 # Not IVLIAN dates.
316 sub get_monthdays {
317 # $month is 0-11 not 1-12
318 my ($month, $year) = @_;
319 sub m30($) { return 30; }
320 sub m31($) { return 31; }
321 sub mFeb($) {
322 my ($year) = @_;
323 if(($year % 100 and !($year % 4)) or !($year % 400)) {
324 return 29;
325 } else {
326 return 28;
327 }
328 }
329 # this is the common table, but note +1 below
330 # as gmtime() and friends return months from 0-11 not 1-12
331 my %months = (
332 1 => \&m31,
333 3 => \&m31,
334 5 => \&m31,
335 7 => \&m31,
336 8 => \&m31,
337 10 => \&m31,
338 12 => \&m31,
339
340 4 => \&m30,
341 6 => \&m30,
342 9 => \&m30,
343 11 => \&m30,
344
345 2 => \&mFeb,
346 );
347
348 $year += 1900 if $year < 1582; #Gregorian calendar was somewhere around here...
349 return $months{$month+1}($year);
350 }
351
352 1;