Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | package Date::Manip; |
2 | # Copyright (c) 1995-2003 Sullivan Beck. All rights reserved. | |
3 | # This program is free software; you can redistribute it and/or modify it | |
4 | # under the same terms as Perl itself. | |
5 | ||
6 | ########################################################################### | |
7 | ########################################################################### | |
8 | ||
9 | use vars qw($OS %Lang %Holiday %Events %Curr %Cnf %Zone $VERSION @ISA @EXPORT); | |
10 | ||
11 | # Determine the type of OS... | |
12 | $OS="Unix"; | |
13 | $OS="Windows" if ((defined $^O and | |
14 | $^O =~ /MSWin32/i || | |
15 | $^O =~ /Windows_95/i || | |
16 | $^O =~ /Windows_NT/i) || | |
17 | (defined $ENV{OS} and | |
18 | $ENV{OS} =~ /MSWin32/i || | |
19 | $ENV{OS} =~ /Windows_95/i || | |
20 | $ENV{OS} =~ /Windows_NT/i)); | |
21 | $OS="Netware" if (defined $^O and | |
22 | $^O =~ /NetWare/i); | |
23 | $OS="Mac" if ((defined $^O and | |
24 | $^O =~ /MacOS/i) || | |
25 | (defined $ENV{OS} and | |
26 | $ENV{OS} =~ /MacOS/i)); | |
27 | $OS="MPE" if (defined $^O and | |
28 | $^O =~ /MPE/i); | |
29 | $OS="OS2" if (defined $^O and | |
30 | $^O =~ /os2/i); | |
31 | $OS="VMS" if (defined $^O and | |
32 | $^O =~ /VMS/i); | |
33 | ||
34 | # Determine if we're doing taint checking | |
35 | $Date::Manip::NoTaint = eval { local $^W; unlink "$^X$^T"; 1 }; | |
36 | ||
37 | ########################################################################### | |
38 | # CUSTOMIZATION | |
39 | ########################################################################### | |
40 | # | |
41 | # See the section of the POD documentation section CUSTOMIZING DATE::MANIP | |
42 | # below for a complete description of each of these variables. | |
43 | ||
44 | ||
45 | # Location of a the global config file. Tilde (~) expansions are allowed. | |
46 | # This should be set in Date_Init arguments. | |
47 | $Cnf{"GlobalCnf"}=""; | |
48 | $Cnf{"IgnoreGlobalCnf"}=""; | |
49 | ||
50 | # Name of a personal config file and the path to search for it. Tilde (~) | |
51 | # expansions are allowed. This should be set in Date_Init arguments or in | |
52 | # the global config file. | |
53 | ||
54 | @Date::Manip::DatePath=(); | |
55 | if ($OS eq "Windows") { | |
56 | $Cnf{"PathSep"} = ";"; | |
57 | $Cnf{"PersonalCnf"} = "Manip.cnf"; | |
58 | $Cnf{"PersonalCnfPath"} = "."; | |
59 | ||
60 | } elsif ($OS eq "Netware") { | |
61 | $Cnf{"PathSep"} = ";"; | |
62 | $Cnf{"PersonalCnf"} = "Manip.cnf"; | |
63 | $Cnf{"PersonalCnfPath"} = "."; | |
64 | ||
65 | } elsif ($OS eq "MPE") { | |
66 | $Cnf{"PathSep"} = ":"; | |
67 | $Cnf{"PersonalCnf"} = "Manip.cnf"; | |
68 | $Cnf{"PersonalCnfPath"} = "."; | |
69 | ||
70 | } elsif ($OS eq "OS2") { | |
71 | $Cnf{"PathSep"} = ":"; | |
72 | $Cnf{"PersonalCnf"} = "Manip.cnf"; | |
73 | $Cnf{"PersonalCnfPath"} = "."; | |
74 | ||
75 | } elsif ($OS eq "Mac") { | |
76 | $Cnf{"PathSep"} = ":"; | |
77 | $Cnf{"PersonalCnf"} = "Manip.cnf"; | |
78 | $Cnf{"PersonalCnfPath"} = "."; | |
79 | ||
80 | } elsif ($OS eq "VMS") { | |
81 | # VMS doesn't like files starting with "." | |
82 | $Cnf{"PathSep"} = "\n"; | |
83 | $Cnf{"PersonalCnf"} = "Manip.cnf"; | |
84 | $Cnf{"PersonalCnfPath"} = ".\n~"; | |
85 | ||
86 | } else { | |
87 | # Unix | |
88 | $Cnf{"PathSep"} = ":"; | |
89 | $Cnf{"PersonalCnf"} = ".DateManip.cnf"; | |
90 | $Cnf{"PersonalCnfPath"} = ".:~"; | |
91 | @Date::Manip::DatePath=qw(/bin /usr/bin /usr/local/bin); | |
92 | } | |
93 | ||
94 | ### Date::Manip variables set in the global or personal config file | |
95 | ||
96 | # Which language to use when parsing dates. | |
97 | $Cnf{"Language"}="English"; | |
98 | ||
99 | # 12/10 = Dec 10 (US) or Oct 12 (anything else) | |
100 | $Cnf{"DateFormat"}="US"; | |
101 | ||
102 | # Local timezone | |
103 | $Cnf{"TZ"}=""; | |
104 | ||
105 | # Timezone to work in (""=local, "IGNORE", or a timezone) | |
106 | $Cnf{"ConvTZ"}=""; | |
107 | ||
108 | # Date::Manip internal format (0=YYYYMMDDHH:MN:SS, 1=YYYYHHMMDDHHMNSS) | |
109 | $Cnf{"Internal"}=0; | |
110 | ||
111 | # First day of the week (1=monday, 7=sunday). ISO 8601 says monday. | |
112 | $Cnf{"FirstDay"}=1; | |
113 | ||
114 | # First and last day of the work week (1=monday, 7=sunday) | |
115 | $Cnf{"WorkWeekBeg"}=1; | |
116 | $Cnf{"WorkWeekEnd"}=5; | |
117 | ||
118 | # If non-nil, a work day is treated as 24 hours long (WorkDayBeg/WorkDayEnd | |
119 | # ignored) | |
120 | $Cnf{"WorkDay24Hr"}=0; | |
121 | ||
122 | # Start and end time of the work day (any time format allowed, seconds | |
123 | # ignored) | |
124 | $Cnf{"WorkDayBeg"}="08:00"; | |
125 | $Cnf{"WorkDayEnd"}="17:00"; | |
126 | ||
127 | # If "today" is a holiday, we look either to "tomorrow" or "yesterday" for | |
128 | # the nearest business day. By default, we'll always look "tomorrow" | |
129 | # first. | |
130 | $Cnf{"TomorrowFirst"}=1; | |
131 | ||
132 | # Erase the old holidays | |
133 | $Cnf{"EraseHolidays"}=""; | |
134 | ||
135 | # Set this to non-zero to be produce completely backwards compatible deltas | |
136 | $Cnf{"DeltaSigns"}=0; | |
137 | ||
138 | # If this is 0, use the ISO 8601 standard that Jan 4 is in week 1. If 1, | |
139 | # make week 1 contain Jan 1. | |
140 | $Cnf{"Jan1Week1"}=0; | |
141 | ||
142 | # 2 digit years fall into the 100 year period given by [ CURR-N, | |
143 | # CURR+(99-N) ] where N is 0-99. Default behavior is 89, but other useful | |
144 | # numbers might be 0 (forced to be this year or later) and 99 (forced to be | |
145 | # this year or earlier). It can also be set to "c" (current century) or | |
146 | # "cNN" (i.e. c18 forces the year to bet 1800-1899). Also accepts the | |
147 | # form cNNNN to give the 100 year period NNNN to NNNN+99. | |
148 | $Cnf{"YYtoYYYY"}=89; | |
149 | ||
150 | # Set this to 1 if you want a long-running script to always update the | |
151 | # timezone. This will slow Date::Manip down. Read the POD documentation. | |
152 | $Cnf{"UpdateCurrTZ"}=0; | |
153 | ||
154 | # Use an international character set. | |
155 | $Cnf{"IntCharSet"}=0; | |
156 | ||
157 | # Use this to force the current date to be set to this: | |
158 | $Cnf{"ForceDate"}=""; | |
159 | ||
160 | ########################################################################### | |
161 | ||
162 | require 5.000; | |
163 | require Exporter; | |
164 | @ISA = qw(Exporter); | |
165 | @EXPORT = qw( | |
166 | DateManipVersion | |
167 | Date_Init | |
168 | ParseDateString | |
169 | ParseDate | |
170 | ParseRecur | |
171 | Date_Cmp | |
172 | DateCalc | |
173 | ParseDateDelta | |
174 | UnixDate | |
175 | Delta_Format | |
176 | Date_GetPrev | |
177 | Date_GetNext | |
178 | Date_SetTime | |
179 | Date_SetDateField | |
180 | Date_IsHoliday | |
181 | Events_List | |
182 | ||
183 | Date_DaysInMonth | |
184 | Date_DayOfWeek | |
185 | Date_SecsSince1970 | |
186 | Date_SecsSince1970GMT | |
187 | Date_DaysSince1BC | |
188 | Date_DayOfYear | |
189 | Date_DaysInYear | |
190 | Date_WeekOfYear | |
191 | Date_LeapYear | |
192 | Date_DaySuffix | |
193 | Date_ConvTZ | |
194 | Date_TimeZone | |
195 | Date_IsWorkDay | |
196 | Date_NextWorkDay | |
197 | Date_PrevWorkDay | |
198 | Date_NearestWorkDay | |
199 | Date_NthDayOfYear | |
200 | ); | |
201 | use strict; | |
202 | use integer; | |
203 | use Carp; | |
204 | ||
205 | use IO::File; | |
206 | ||
207 | $VERSION="5.42"; | |
208 | ||
209 | ######################################################################## | |
210 | ######################################################################## | |
211 | ||
212 | $Curr{"InitLang"} = 1; # Whether a language is being init'ed | |
213 | $Curr{"InitDone"} = 0; # Whether Init_Date has been called | |
214 | $Curr{"InitFilesRead"} = 0; | |
215 | $Curr{"ResetWorkDay"} = 1; | |
216 | $Curr{"Debug"} = ""; | |
217 | $Curr{"DebugVal"} = ""; | |
218 | ||
219 | $Holiday{"year"} = 0; | |
220 | $Holiday{"dates"} = {}; | |
221 | $Holiday{"desc"} = {}; | |
222 | ||
223 | $Events{"raw"} = []; | |
224 | $Events{"parsed"} = 0; | |
225 | $Events{"dates"} = []; | |
226 | $Events{"recur"} = []; | |
227 | ||
228 | ######################################################################## | |
229 | ######################################################################## | |
230 | # THESE ARE THE MAIN ROUTINES | |
231 | ######################################################################## | |
232 | ######################################################################## | |
233 | ||
234 | # Get rid of a problem with old versions of perl | |
235 | no strict "vars"; | |
236 | # This sorts from longest to shortest element | |
237 | sub sortByLength { | |
238 | return (length $b <=> length $a); | |
239 | } | |
240 | use strict "vars"; | |
241 | ||
242 | sub DateManipVersion { | |
243 | print "DEBUG: DateManipVersion\n" if ($Curr{"Debug"} =~ /trace/); | |
244 | return $VERSION; | |
245 | } | |
246 | ||
247 | sub Date_Init { | |
248 | print "DEBUG: Date_Init\n" if ($Curr{"Debug"} =~ /trace/); | |
249 | $Curr{"Debug"}=""; | |
250 | ||
251 | my(@args)=@_; | |
252 | $Curr{"InitDone"}=1; | |
253 | local($_)=(); | |
254 | my($internal,$firstday)=(); | |
255 | my($var,$val,$file,@tmp)=(); | |
256 | ||
257 | # InitFilesRead = 0 : no conf files read yet | |
258 | # 1 : global read, no personal read | |
259 | # 2 : personal read | |
260 | ||
261 | $Cnf{"EraseHolidays"}=0; | |
262 | foreach (@args) { | |
263 | s/\s*$//; | |
264 | s/^\s*//; | |
265 | /^(\S+) \s* = \s* (.+)$/x; | |
266 | ($var,$val)=($1,$2); | |
267 | if ($var =~ /^GlobalCnf$/i) { | |
268 | $Cnf{"GlobalCnf"}=$val; | |
269 | if ($val) { | |
270 | $Curr{"InitFilesRead"}=0; | |
271 | &EraseHolidays(); | |
272 | } | |
273 | } elsif ($var =~ /^PathSep$/i) { | |
274 | $Cnf{"PathSep"}=$val; | |
275 | } elsif ($var =~ /^PersonalCnf$/i) { | |
276 | $Cnf{"PersonalCnf"}=$val; | |
277 | $Curr{"InitFilesRead"}=1 if ($Curr{"InitFilesRead"}==2); | |
278 | } elsif ($var =~ /^PersonalCnfPath$/i) { | |
279 | $Cnf{"PersonalCnfPath"}=$val; | |
280 | $Curr{"InitFilesRead"}=1 if ($Curr{"InitFilesRead"}==2); | |
281 | } elsif ($var =~ /^IgnoreGlobalCnf$/i) { | |
282 | $Curr{"InitFilesRead"}=1 if ($Curr{"InitFilesRead"}==0); | |
283 | $Cnf{"IgnoreGlobalCnf"}=1; | |
284 | } elsif ($var =~ /^EraseHolidays$/i) { | |
285 | &EraseHolidays(); | |
286 | } else { | |
287 | push(@tmp,$_); | |
288 | } | |
289 | } | |
290 | @args=@tmp; | |
291 | ||
292 | # Read global config file | |
293 | if ($Curr{"InitFilesRead"}<1 && ! $Cnf{"IgnoreGlobalCnf"}) { | |
294 | $Curr{"InitFilesRead"}=1; | |
295 | ||
296 | if ($Cnf{"GlobalCnf"}) { | |
297 | $file=&ExpandTilde($Cnf{"GlobalCnf"}); | |
298 | &Date_InitFile($file) if ($file); | |
299 | } | |
300 | } | |
301 | ||
302 | # Read personal config file | |
303 | if ($Curr{"InitFilesRead"}<2) { | |
304 | $Curr{"InitFilesRead"}=2; | |
305 | ||
306 | if ($Cnf{"PersonalCnf"} and $Cnf{"PersonalCnfPath"}) { | |
307 | $file=&SearchPath($Cnf{"PersonalCnf"},$Cnf{"PersonalCnfPath"},"r"); | |
308 | &Date_InitFile($file) if ($file); | |
309 | } | |
310 | } | |
311 | ||
312 | foreach (@args) { | |
313 | s/\s*$//; | |
314 | s/^\s*//; | |
315 | /^(\S+) \s* = \s* (.*)$/x; | |
316 | ($var,$val)=($1,$2); | |
317 | $val="" if (! defined $val); | |
318 | &Date_SetConfigVariable($var,$val); | |
319 | } | |
320 | ||
321 | confess "ERROR: Unknown FirstDay in Date::Manip.\n" | |
322 | if (! &IsInt($Cnf{"FirstDay"},1,7)); | |
323 | confess "ERROR: Unknown WorkWeekBeg in Date::Manip.\n" | |
324 | if (! &IsInt($Cnf{"WorkWeekBeg"},1,7)); | |
325 | confess "ERROR: Unknown WorkWeekEnd in Date::Manip.\n" | |
326 | if (! &IsInt($Cnf{"WorkWeekEnd"},1,7)); | |
327 | confess "ERROR: Invalid WorkWeek in Date::Manip.\n" | |
328 | if ($Cnf{"WorkWeekEnd"} <= $Cnf{"WorkWeekBeg"}); | |
329 | ||
330 | my(%lang, | |
331 | $tmp,%tmp,$tmp2,@tmp2, | |
332 | $i,$j,@tmp3, | |
333 | $zonesrfc,@zones)=(); | |
334 | ||
335 | my($L)=$Cnf{"Language"}; | |
336 | ||
337 | if ($Curr{"InitLang"}) { | |
338 | $Curr{"InitLang"}=0; | |
339 | ||
340 | if ($L eq "English") { | |
341 | &Date_Init_English(\%lang); | |
342 | ||
343 | } elsif ($L eq "French") { | |
344 | &Date_Init_French(\%lang); | |
345 | ||
346 | } elsif ($L eq "Swedish") { | |
347 | &Date_Init_Swedish(\%lang); | |
348 | ||
349 | } elsif ($L eq "German") { | |
350 | &Date_Init_German(\%lang); | |
351 | ||
352 | } elsif ($L eq "Polish") { | |
353 | &Date_Init_Polish(\%lang); | |
354 | ||
355 | } elsif ($L eq "Dutch" || | |
356 | $L eq "Nederlands") { | |
357 | &Date_Init_Dutch(\%lang); | |
358 | ||
359 | } elsif ($L eq "Spanish") { | |
360 | &Date_Init_Spanish(\%lang); | |
361 | ||
362 | } elsif ($L eq "Portuguese") { | |
363 | &Date_Init_Portuguese(\%lang); | |
364 | ||
365 | } elsif ($L eq "Romanian") { | |
366 | &Date_Init_Romanian(\%lang); | |
367 | ||
368 | } elsif ($L eq "Italian") { | |
369 | &Date_Init_Italian(\%lang); | |
370 | ||
371 | } elsif ($L eq "Russian") { | |
372 | &Date_Init_Russian(\%lang); | |
373 | ||
374 | } elsif ($L eq "Turkish") { | |
375 | &Date_Init_Turkish(\%lang); | |
376 | ||
377 | } elsif ($L eq "Danish") { | |
378 | &Date_Init_Danish(\%lang); | |
379 | ||
380 | } else { | |
381 | confess "ERROR: Unknown language in Date::Manip.\n"; | |
382 | } | |
383 | ||
384 | # variables for months | |
385 | # Month = "(jan|january|feb|february ... )" | |
386 | # MonL = [ "Jan","Feb",... ] | |
387 | # MonthL = [ "January","February", ... ] | |
388 | # MonthH = { "january"=>1, "jan"=>1, ... } | |
389 | ||
390 | $Lang{$L}{"MonthH"}={}; | |
391 | $Lang{$L}{"MonthL"}=[]; | |
392 | $Lang{$L}{"MonL"}=[]; | |
393 | &Date_InitLists([$lang{"month_name"}, | |
394 | $lang{"month_abb"}], | |
395 | \$Lang{$L}{"Month"},"lc,sort,back", | |
396 | [$Lang{$L}{"MonthL"}, | |
397 | $Lang{$L}{"MonL"}], | |
398 | [$Lang{$L}{"MonthH"},1]); | |
399 | ||
400 | # variables for day of week | |
401 | # Week = "(mon|monday|tue|tuesday ... )" | |
402 | # WL = [ "M","T",... ] | |
403 | # WkL = [ "Mon","Tue",... ] | |
404 | # WeekL = [ "Monday","Tudesday",... ] | |
405 | # WeekH = { "monday"=>1,"mon"=>1,"m"=>1,... } | |
406 | ||
407 | $Lang{$L}{"WeekH"}={}; | |
408 | $Lang{$L}{"WeekL"}=[]; | |
409 | $Lang{$L}{"WkL"}=[]; | |
410 | $Lang{$L}{"WL"}=[]; | |
411 | &Date_InitLists([$lang{"day_name"}, | |
412 | $lang{"day_abb"}], | |
413 | \$Lang{$L}{"Week"},"lc,sort,back", | |
414 | [$Lang{$L}{"WeekL"}, | |
415 | $Lang{$L}{"WkL"}], | |
416 | [$Lang{$L}{"WeekH"},1]); | |
417 | &Date_InitLists([$lang{"day_char"}], | |
418 | "","lc", | |
419 | [$Lang{$L}{"WL"}], | |
420 | [\%tmp,1]); | |
421 | %{ $Lang{$L}{"WeekH"} } = | |
422 | (%{ $Lang{$L}{"WeekH"} },%tmp); | |
423 | ||
424 | # variables for last | |
425 | # Last = "(last)" | |
426 | # LastL = [ "last" ] | |
427 | # Each = "(each)" | |
428 | # EachL = [ "each" ] | |
429 | # variables for day of month | |
430 | # DoM = "(1st|first ... 31st)" | |
431 | # DoML = [ "1st","2nd",... "31st" ] | |
432 | # DoMH = { "1st"=>1,"first"=>1, ... "31st"=>31 } | |
433 | # variables for week of month | |
434 | # WoM = "(1st|first| ... 5th|last)" | |
435 | # WoMH = { "1st"=>1, ... "5th"=>5,"last"=>-1 } | |
436 | ||
437 | $Lang{$L}{"LastL"}=$lang{"last"}; | |
438 | &Date_InitStrings($lang{"last"}, | |
439 | \$Lang{$L}{"Last"},"lc,sort"); | |
440 | ||
441 | $Lang{$L}{"EachL"}=$lang{"each"}; | |
442 | &Date_InitStrings($lang{"each"}, | |
443 | \$Lang{$L}{"Each"},"lc,sort"); | |
444 | ||
445 | $Lang{$L}{"DoMH"}={}; | |
446 | $Lang{$L}{"DoML"}=[]; | |
447 | &Date_InitLists([$lang{"num_suff"}, | |
448 | $lang{"num_word"}], | |
449 | \$Lang{$L}{"DoM"},"lc,sort,back,escape", | |
450 | [$Lang{$L}{"DoML"}, | |
451 | \@tmp], | |
452 | [$Lang{$L}{"DoMH"},1]); | |
453 | ||
454 | @tmp=(); | |
455 | foreach $tmp (keys %{ $Lang{$L}{"DoMH"} }) { | |
456 | $tmp2=$Lang{$L}{"DoMH"}{$tmp}; | |
457 | if ($tmp2<6) { | |
458 | $Lang{$L}{"WoMH"}{$tmp} = $tmp2; | |
459 | push(@tmp,$tmp); | |
460 | } | |
461 | } | |
462 | foreach $tmp (@{ $Lang{$L}{"LastL"} }) { | |
463 | $Lang{$L}{"WoMH"}{$tmp} = -1; | |
464 | push(@tmp,$tmp); | |
465 | } | |
466 | &Date_InitStrings(\@tmp,\$Lang{$L}{"WoM"}, | |
467 | "lc,sort,back,escape"); | |
468 | ||
469 | # variables for AM or PM | |
470 | # AM = "(am)" | |
471 | # PM = "(pm)" | |
472 | # AmPm = "(am|pm)" | |
473 | # AMstr = "AM" | |
474 | # PMstr = "PM" | |
475 | ||
476 | &Date_InitStrings($lang{"am"},\$Lang{$L}{"AM"},"lc,sort,escape"); | |
477 | &Date_InitStrings($lang{"pm"},\$Lang{$L}{"PM"},"lc,sort,escape"); | |
478 | &Date_InitStrings([ @{$lang{"am"}},@{$lang{"pm"}} ],\$Lang{$L}{"AmPm"}, | |
479 | "lc,back,sort,escape"); | |
480 | $Lang{$L}{"AMstr"}=$lang{"am"}[0]; | |
481 | $Lang{$L}{"PMstr"}=$lang{"pm"}[0]; | |
482 | ||
483 | # variables for expressions used in parsing deltas | |
484 | # Yabb = "(?:y|yr|year|years)" | |
485 | # Mabb = similar for months | |
486 | # Wabb = similar for weeks | |
487 | # Dabb = similar for days | |
488 | # Habb = similar for hours | |
489 | # MNabb = similar for minutes | |
490 | # Sabb = similar for seconds | |
491 | # Repl = { "abb"=>"replacement" } | |
492 | # Whenever an abbreviation could potentially refer to two different | |
493 | # strings (M standing for Minutes or Months), the abbreviation must | |
494 | # be listed in Repl instead of in the appropriate Xabb values. This | |
495 | # only applies to abbreviations which are substrings of other values | |
496 | # (so there is no confusion between Mn and Month). | |
497 | ||
498 | &Date_InitStrings($lang{"years"} ,\$Lang{$L}{"Yabb"}, "lc,sort"); | |
499 | &Date_InitStrings($lang{"months"} ,\$Lang{$L}{"Mabb"}, "lc,sort"); | |
500 | &Date_InitStrings($lang{"weeks"} ,\$Lang{$L}{"Wabb"}, "lc,sort"); | |
501 | &Date_InitStrings($lang{"days"} ,\$Lang{$L}{"Dabb"}, "lc,sort"); | |
502 | &Date_InitStrings($lang{"hours"} ,\$Lang{$L}{"Habb"}, "lc,sort"); | |
503 | &Date_InitStrings($lang{"minutes"},\$Lang{$L}{"MNabb"},"lc,sort"); | |
504 | &Date_InitStrings($lang{"seconds"},\$Lang{$L}{"Sabb"}, "lc,sort"); | |
505 | $Lang{$L}{"Repl"}={}; | |
506 | &Date_InitHash($lang{"replace"},undef,"lc",$Lang{$L}{"Repl"}); | |
507 | ||
508 | # variables for special dates that are offsets from now | |
509 | # Now = "(now|today)" | |
510 | # Offset = "(yesterday|tomorrow)" | |
511 | # OffsetH = { "yesterday"=>"-0:0:0:1:0:0:0",... ] | |
512 | # Times = "(noon|midnight)" | |
513 | # TimesH = { "noon"=>"12:00:00","midnight"=>"00:00:00" } | |
514 | # SepHM = hour/minute separator | |
515 | # SepMS = minute/second separator | |
516 | # SepSS = second/fraction separator | |
517 | ||
518 | $Lang{$L}{"TimesH"}={}; | |
519 | &Date_InitHash($lang{"times"}, | |
520 | \$Lang{$L}{"Times"},"lc,sort,back", | |
521 | $Lang{$L}{"TimesH"}); | |
522 | &Date_InitStrings($lang{"now"},\$Lang{$L}{"Now"},"lc,sort"); | |
523 | $Lang{$L}{"OffsetH"}={}; | |
524 | &Date_InitHash($lang{"offset"}, | |
525 | \$Lang{$L}{"Offset"},"lc,sort,back", | |
526 | $Lang{$L}{"OffsetH"}); | |
527 | $Lang{$L}{"SepHM"}=$lang{"sephm"}; | |
528 | $Lang{$L}{"SepMS"}=$lang{"sepms"}; | |
529 | $Lang{$L}{"SepSS"}=$lang{"sepss"}; | |
530 | ||
531 | # variables for time zones | |
532 | # zones = regular expression with all zone names (EST) | |
533 | # n2o = a hash of all parsable zone names with their offsets | |
534 | # tzones = reguar expression with all tzdata timezones (US/Eastern) | |
535 | # tz2z = hash of all tzdata timezones to full timezone (EST#EDT) | |
536 | ||
537 | $zonesrfc= | |
538 | "idlw -1200 ". # International Date Line West | |
539 | "nt -1100 ". # Nome | |
540 | "hst -1000 ". # Hawaii Standard | |
541 | "cat -1000 ". # Central Alaska | |
542 | "ahst -1000 ". # Alaska-Hawaii Standard | |
543 | "akst -0900 ". # Alaska Standard | |
544 | "yst -0900 ". # Yukon Standard | |
545 | "hdt -0900 ". # Hawaii Daylight | |
546 | "akdt -0800 ". # Alaska Daylight | |
547 | "ydt -0800 ". # Yukon Daylight | |
548 | "pst -0800 ". # Pacific Standard | |
549 | "pdt -0700 ". # Pacific Daylight | |
550 | "mst -0700 ". # Mountain Standard | |
551 | "mdt -0600 ". # Mountain Daylight | |
552 | "cst -0600 ". # Central Standard | |
553 | "cdt -0500 ". # Central Daylight | |
554 | "est -0500 ". # Eastern Standard | |
555 | "act -0500 ". # Brazil, Acre | |
556 | "sat -0400 ". # Chile | |
557 | "bot -0400 ". # Bolivia | |
558 | "amt -0400 ". # Brazil, Amazon | |
559 | "acst -0400 ". # Brazil, Acre Daylight | |
560 | "edt -0400 ". # Eastern Daylight | |
561 | "ast -0400 ". # Atlantic Standard | |
562 | #"nst -0330 ". # Newfoundland Standard nst=North Sumatra +0630 | |
563 | "nft -0330 ". # Newfoundland | |
564 | #"gst -0300 ". # Greenland Standard gst=Guam Standard +1000 | |
565 | #"bst -0300 ". # Brazil Standard bst=British Summer +0100 | |
566 | "brt -0300 ". # Brazil Standard (official time) | |
567 | "brst -0300 ". # Brazil Standard | |
568 | "adt -0300 ". # Atlantic Daylight | |
569 | "art -0300 ". # Argentina | |
570 | "amst -0300 ". # Brazil, Amazon Daylight | |
571 | "ndt -0230 ". # Newfoundland Daylight | |
572 | "brst -0200 ". # Brazil Daylight (official time) | |
573 | "fnt -0200 ". # Brazil, Fernando de Noronha | |
574 | "at -0200 ". # Azores | |
575 | "wat -0100 ". # West Africa | |
576 | "fnst -0100 ". # Brazil, Fernando de Noronha Daylight | |
577 | "gmt +0000 ". # Greenwich Mean | |
578 | "ut +0000 ". # Universal | |
579 | "utc +0000 ". # Universal (Coordinated) | |
580 | "wet +0000 ". # Western European | |
581 | "cet +0100 ". # Central European | |
582 | "fwt +0100 ". # French Winter | |
583 | "met +0100 ". # Middle European | |
584 | "mez +0100 ". # Middle European | |
585 | "mewt +0100 ". # Middle European Winter | |
586 | "swt +0100 ". # Swedish Winter | |
587 | "bst +0100 ". # British Summer bst=Brazil standard -0300 | |
588 | "gb +0100 ". # GMT with daylight savings | |
589 | "west +0000 ". # Western European Daylight | |
590 | "eet +0200 ". # Eastern Europe, USSR Zone 1 | |
591 | "cest +0200 ". # Central European Summer | |
592 | "fst +0200 ". # French Summer | |
593 | "ist +0200 ". # Israel standard | |
594 | "mest +0200 ". # Middle European Summer | |
595 | "mesz +0200 ". # Middle European Summer | |
596 | "metdst +0200 ". # An alias for mest used by HP-UX | |
597 | "sast +0200 ". # South African Standard | |
598 | "sst +0200 ". # Swedish Summer sst=South Sumatra +0700 | |
599 | "bt +0300 ". # Baghdad, USSR Zone 2 | |
600 | "eest +0300 ". # Eastern Europe Summer | |
601 | "eetedt +0300 ". # Eastern Europe, USSR Zone 1 | |
602 | "idt +0300 ". # Israel Daylight | |
603 | "msk +0300 ". # Moscow | |
604 | "eat +0300 ". # East Africa | |
605 | "it +0330 ". # Iran | |
606 | "zp4 +0400 ". # USSR Zone 3 | |
607 | "msd +0400 ". # Moscow Daylight | |
608 | "zp5 +0500 ". # USSR Zone 4 | |
609 | "ist +0530 ". # Indian Standard | |
610 | "zp6 +0600 ". # USSR Zone 5 | |
611 | "novst +0600 ". # Novosibirsk time zone, Russia | |
612 | "nst +0630 ". # North Sumatra nst=Newfoundland Std -0330 | |
613 | #"sst +0700 ". # South Sumatra, USSR Zone 6 sst=Swedish Summer +0200 | |
614 | "javt +0700 ". # Java | |
615 | "hkt +0800 ". # Hong Kong | |
616 | "sgt +0800 ". # Singapore | |
617 | "cct +0800 ". # China Coast, USSR Zone 7 | |
618 | "awst +0800 ". # Australian Western Standard | |
619 | "wst +0800 ". # West Australian Standard | |
620 | "pht +0800 ". # Asia Manila | |
621 | "kst +0900 ". # Republic of Korea | |
622 | "jst +0900 ". # Japan Standard, USSR Zone 8 | |
623 | "rok +0900 ". # Republic of Korea | |
624 | "acst +0930 ". # Australian Central Standard | |
625 | "cast +0930 ". # Central Australian Standard | |
626 | "aest +1000 ". # Australian Eastern Standard | |
627 | "east +1000 ". # Eastern Australian Standard | |
628 | "gst +1000 ". # Guam Standard, USSR Zone 9 gst=Greenland Std -0300 | |
629 | "acdt +1030 ". # Australian Central Daylight | |
630 | "cadt +1030 ". # Central Australian Daylight | |
631 | "aedt +1100 ". # Australian Eastern Daylight | |
632 | "eadt +1100 ". # Eastern Australian Daylight | |
633 | "idle +1200 ". # International Date Line East | |
634 | "nzst +1200 ". # New Zealand Standard | |
635 | "nzt +1200 ". # New Zealand | |
636 | "nzdt +1300 ". # New Zealand Daylight | |
637 | "z +0000 ". | |
638 | "a +0100 b +0200 c +0300 d +0400 e +0500 f +0600 g +0700 h +0800 ". | |
639 | "i +0900 k +1000 l +1100 m +1200 ". | |
640 | "n -0100 o -0200 p -0300 q -0400 r -0500 s -0600 t -0700 u -0800 ". | |
641 | "v -0900 w -1000 x -1100 y -1200"; | |
642 | ||
643 | $Zone{"n2o"} = {}; | |
644 | ($Zone{"zones"},%{ $Zone{"n2o"} })= | |
645 | &Date_Regexp($zonesrfc,"sort,lc,under,back", | |
646 | "keys"); | |
647 | ||
648 | $tmp= | |
649 | "US/Pacific PST8PDT ". | |
650 | "US/Mountain MST7MDT ". | |
651 | "US/Central CST6CDT ". | |
652 | "US/Eastern EST5EDT ". | |
653 | "Canada/Pacific PST8PDT ". | |
654 | "Canada/Mountain MST7MDT ". | |
655 | "Canada/Central CST6CDT ". | |
656 | "Canada/Eastern EST5EDT"; | |
657 | ||
658 | $Zone{"tz2z"} = {}; | |
659 | ($Zone{"tzones"},%{ $Zone{"tz2z"} })= | |
660 | &Date_Regexp($tmp,"lc,under,back","keys"); | |
661 | $Cnf{"TZ"}=&Date_TimeZone; | |
662 | ||
663 | # misc. variables | |
664 | # At = "(?:at)" | |
665 | # Of = "(?:in|of)" | |
666 | # On = "(?:on)" | |
667 | # Future = "(?:in)" | |
668 | # Later = "(?:later)" | |
669 | # Past = "(?:ago)" | |
670 | # Next = "(?:next)" | |
671 | # Prev = "(?:last|previous)" | |
672 | ||
673 | &Date_InitStrings($lang{"at"}, \$Lang{$L}{"At"}, "lc,sort"); | |
674 | &Date_InitStrings($lang{"on"}, \$Lang{$L}{"On"}, "lc,sort"); | |
675 | &Date_InitStrings($lang{"future"},\$Lang{$L}{"Future"}, "lc,sort"); | |
676 | &Date_InitStrings($lang{"later"}, \$Lang{$L}{"Later"}, "lc,sort"); | |
677 | &Date_InitStrings($lang{"past"}, \$Lang{$L}{"Past"}, "lc,sort"); | |
678 | &Date_InitStrings($lang{"next"}, \$Lang{$L}{"Next"}, "lc,sort"); | |
679 | &Date_InitStrings($lang{"prev"}, \$Lang{$L}{"Prev"}, "lc,sort"); | |
680 | &Date_InitStrings($lang{"of"}, \$Lang{$L}{"Of"}, "lc,sort"); | |
681 | ||
682 | # calc mode variables | |
683 | # Approx = "(?:approximately)" | |
684 | # Exact = "(?:exactly)" | |
685 | # Business = "(?:business)" | |
686 | ||
687 | &Date_InitStrings($lang{"exact"}, \$Lang{$L}{"Exact"}, "lc,sort"); | |
688 | &Date_InitStrings($lang{"approx"}, \$Lang{$L}{"Approx"}, "lc,sort"); | |
689 | &Date_InitStrings($lang{"business"},\$Lang{$L}{"Business"},"lc,sort"); | |
690 | ||
691 | ############### END OF LANGUAGE INITIALIZATION | |
692 | } | |
693 | ||
694 | if ($Curr{"ResetWorkDay"}) { | |
695 | my($h1,$m1,$h2,$m2)=(); | |
696 | if ($Cnf{"WorkDay24Hr"}) { | |
697 | ($Curr{"WDBh"},$Curr{"WDBm"})=(0,0); | |
698 | ($Curr{"WDEh"},$Curr{"WDEm"})=(24,0); | |
699 | $Curr{"WDlen"}=24*60; | |
700 | $Cnf{"WorkDayBeg"}="00:00"; | |
701 | $Cnf{"WorkDayEnd"}="23:59"; | |
702 | ||
703 | } else { | |
704 | confess "ERROR: Invalid WorkDayBeg in Date::Manip.\n" | |
705 | if (! (($h1,$m1)=&CheckTime($Cnf{"WorkDayBeg"}))); | |
706 | $Cnf{"WorkDayBeg"}="$h1:$m1"; | |
707 | confess "ERROR: Invalid WorkDayEnd in Date::Manip.\n" | |
708 | if (! (($h2,$m2)=&CheckTime($Cnf{"WorkDayEnd"}))); | |
709 | $Cnf{"WorkDayEnd"}="$h2:$m2"; | |
710 | ||
711 | ($Curr{"WDBh"},$Curr{"WDBm"})=($h1,$m1); | |
712 | ($Curr{"WDEh"},$Curr{"WDEm"})=($h2,$m2); | |
713 | ||
714 | # Work day length = h1:m1 or 0:len (len minutes) | |
715 | $h1=$h2-$h1; | |
716 | $m1=$m2-$m1; | |
717 | if ($m1<0) { | |
718 | $h1--; | |
719 | $m1+=60; | |
720 | } | |
721 | $Curr{"WDlen"}=$h1*60+$m1; | |
722 | } | |
723 | $Curr{"ResetWorkDay"}=0; | |
724 | } | |
725 | ||
726 | # current time | |
727 | my($s,$mn,$h,$d,$m,$y,$wday,$yday,$isdst,$ampm,$wk)=(); | |
728 | if ($Cnf{"ForceDate"}=~ | |
729 | /^(\d{4})-(\d{2})-(\d{2})-(\d{2}):(\d{2}):(\d{2})$/) { | |
730 | ($y,$m,$d,$h,$mn,$s)=($1,$2,$3,$4,$5,$6); | |
731 | } else { | |
732 | ($s,$mn,$h,$d,$m,$y,$wday,$yday,$isdst)=localtime(time); | |
733 | $y+=1900; | |
734 | $m++; | |
735 | } | |
736 | &Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk); | |
737 | $Curr{"Y"}=$y; | |
738 | $Curr{"M"}=$m; | |
739 | $Curr{"D"}=$d; | |
740 | $Curr{"H"}=$h; | |
741 | $Curr{"Mn"}=$mn; | |
742 | $Curr{"S"}=$s; | |
743 | $Curr{"AmPm"}=$ampm; | |
744 | $Curr{"Now"}=&Date_Join($y,$m,$d,$h,$mn,$s); | |
745 | ||
746 | $Curr{"Debug"}=$Curr{"DebugVal"}; | |
747 | ||
748 | # If we're in array context, let's return a list of config variables | |
749 | # that could be passed to Date_Init to get the same state as we're | |
750 | # currently in. | |
751 | if (wantarray) { | |
752 | # Some special variables that have to be in a specific order | |
753 | my(@special)=qw(IgnoreGlobalCnf GlobalCnf PersonalCnf PersonalCnfPath); | |
754 | my(%tmp)=map { $_,1 } @special; | |
755 | my(@tmp,$key,$val); | |
756 | foreach $key (@special) { | |
757 | $val=$Cnf{$key}; | |
758 | push(@tmp,"$key=$val"); | |
759 | } | |
760 | foreach $key (keys %Cnf) { | |
761 | next if (exists $tmp{$key}); | |
762 | $val=$Cnf{$key}; | |
763 | push(@tmp,"$key=$val"); | |
764 | } | |
765 | return @tmp; | |
766 | } | |
767 | return (); | |
768 | } | |
769 | ||
770 | sub ParseDateString { | |
771 | print "DEBUG: ParseDateString\n" if ($Curr{"Debug"} =~ /trace/); | |
772 | local($_)=@_; | |
773 | return "" if (! $_); | |
774 | ||
775 | my($y,$m,$d,$h,$mn,$s,$i,$wofm,$dofw,$wk,$tmp,$z,$num,$err,$iso,$ampm)=(); | |
776 | my($date,$z2,$delta,$from,$falsefrom,$to,$which,$midnight)=(); | |
777 | ||
778 | # We only need to reinitialize if we have to determine what NOW is. | |
779 | &Date_Init() if (! $Curr{"InitDone"} or $Cnf{"UpdateCurrTZ"}); | |
780 | ||
781 | my($L)=$Cnf{"Language"}; | |
782 | my($type)=$Cnf{"DateFormat"}; | |
783 | ||
784 | # Mode is set in DateCalc. ParseDate only overrides it if the string | |
785 | # contains a mode. | |
786 | if ($Lang{$L}{"Exact"} && | |
787 | s/$Lang{$L}{"Exact"}//) { | |
788 | $Curr{"Mode"}=0; | |
789 | } elsif ($Lang{$L}{"Approx"} && | |
790 | s/$Lang{$L}{"Approx"}//) { | |
791 | $Curr{"Mode"}=1; | |
792 | } elsif ($Lang{$L}{"Business"} && | |
793 | s/$Lang{$L}{"Business"}//) { | |
794 | $Curr{"Mode"}=2; | |
795 | } elsif (! exists $Curr{"Mode"}) { | |
796 | $Curr{"Mode"}=0; | |
797 | } | |
798 | ||
799 | # Unfortunately, some deltas can be parsed as dates. An example is | |
800 | # 1 second == 1 2nd == 1 2 | |
801 | # But, some dates can be parsed as deltas. The most important being: | |
802 | # 1998010101:00:00 | |
803 | # We'll check to see if a "date" can be parsed as a delta. If so, we'll | |
804 | # assume that it is a delta (since they are much simpler, it is much | |
805 | # less likely that we'll mistake a delta for a date than vice versa) | |
806 | # unless it is an ISO-8601 date. | |
807 | # | |
808 | # This is important because we are using DateCalc to test whether a | |
809 | # string is a date or a delta. Dates are tested first, so we need to | |
810 | # be able to pass a delta into this routine and have it correctly NOT | |
811 | # interpreted as a date. | |
812 | # | |
813 | # We will insist that the string contain something other than digits and | |
814 | # colons so that the following will get correctly interpreted as a date | |
815 | # rather than a delta: | |
816 | # 12:30 | |
817 | # 19980101 | |
818 | ||
819 | $delta=""; | |
820 | $delta=&ParseDateDelta($_) if (/[^:0-9]/); | |
821 | ||
822 | # Put parse in a simple loop for an easy exit. | |
823 | PARSE: { | |
824 | my(@tmp)=&Date_Split($_); | |
825 | if (@tmp) { | |
826 | ($y,$m,$d,$h,$mn,$s)=@tmp; | |
827 | last PARSE; | |
828 | } | |
829 | ||
830 | # Fundamental regular expressions | |
831 | ||
832 | my($month)=$Lang{$L}{"Month"}; # (jan|january|...) | |
833 | my(%month)=%{ $Lang{$L}{"MonthH"} }; # { jan=>1, ... } | |
834 | my($week)=$Lang{$L}{"Week"}; # (mon|monday|...) | |
835 | my(%week)=%{ $Lang{$L}{"WeekH"} }; # { mon=>1, monday=>1, ... } | |
836 | my($wom)=$Lang{$L}{"WoM"}; # (1st|...|fifth|last) | |
837 | my(%wom)=%{ $Lang{$L}{"WoMH"} }; # { 1st=>1,... fifth=>5,last=>-1 } | |
838 | my($dom)=$Lang{$L}{"DoM"}; # (1st|first|...31st) | |
839 | my(%dom)=%{ $Lang{$L}{"DoMH"} }; # { 1st=>1, first=>1, ... } | |
840 | my($ampmexp)=$Lang{$L}{"AmPm"}; # (am|pm) | |
841 | my($timeexp)=$Lang{$L}{"Times"}; # (noon|midnight) | |
842 | my($now)=$Lang{$L}{"Now"}; # (now|today) | |
843 | my($offset)=$Lang{$L}{"Offset"}; # (yesterday|tomorrow) | |
844 | my($zone)=$Zone{"zones"} . '(?:\s+|$)'; # (edt|est|...)\s+ | |
845 | my($day)='\s*'.$Lang{$L}{"Dabb"}; # \s*(?:d|day|days) | |
846 | my($mabb)='\s*'.$Lang{$L}{"Mabb"}; # \s*(?:mon|month|months) | |
847 | my($wkabb)='\s*'.$Lang{$L}{"Wabb"}; # \s*(?:w|wk|week|weeks) | |
848 | my($next)='\s*'.$Lang{$L}{"Next"}; # \s*(?:next) | |
849 | my($prev)='\s*'.$Lang{$L}{"Prev"}; # \s*(?:last|previous) | |
850 | my($past)='\s*'.$Lang{$L}{"Past"}; # \s*(?:ago) | |
851 | my($future)='\s*'.$Lang{$L}{"Future"}; # \s*(?:in) | |
852 | my($later)='\s*'.$Lang{$L}{"Later"}; # \s*(?:later) | |
853 | my($at)=$Lang{$L}{"At"}; # (?:at) | |
854 | my($of)='\s*'.$Lang{$L}{"Of"}; # \s*(?:in|of) | |
855 | my($on)='(?:\s*'.$Lang{$L}{"On"}.'\s*|\s+)'; | |
856 | # \s*(?:on)\s* or \s+ | |
857 | my($last)='\s*'.$Lang{$L}{"Last"}; # \s*(?:last) | |
858 | my($hm)=$Lang{$L}{"SepHM"}; # : | |
859 | my($ms)=$Lang{$L}{"SepMS"}; # : | |
860 | my($ss)=$Lang{$L}{"SepSS"}; # . | |
861 | ||
862 | # Other regular expressions | |
863 | ||
864 | my($D4)='(\d{4})'; # 4 digits (yr) | |
865 | my($YY)='(\d{4}|\d{2})'; # 2 or 4 digits (yr) | |
866 | my($DD)='(\d{2})'; # 2 digits (mon/day/hr/min/sec) | |
867 | my($D) ='(\d{1,2})'; # 1 or 2 digit (mon/day/hr) | |
868 | my($FS)="(?:$ss\\d+)?"; # fractional secs | |
869 | my($sep)='[\/.-]'; # non-ISO8601 m/d/yy separators | |
870 | # absolute time zone +0700 (GMT) | |
871 | my($hzone)='(?:[0-1][0-9]|2[0-3])'; # 00 - 23 | |
872 | my($mzone)='(?:[0-5][0-9])'; # 00 - 59 | |
873 | my($zone2)='(?:\s*([+-](?:'."$hzone$mzone|$hzone:$mzone|$hzone))". | |
874 | # +0700 +07:00 -07 | |
875 | '(?:\s*\([^)]+\))?)'; # (GMT) | |
876 | ||
877 | # A regular expression for the time EXCEPT for the hour part | |
878 | my($mnsec)="$hm$DD(?:$ms$DD$FS)?(?:\\s*$ampmexp)?"; | |
879 | ||
880 | # A special regular expression for /YYYY:HH:MN:SS used by Apache | |
881 | my($apachetime)='(/\d{4}):' . "$DD$hm$DD$ms$DD"; | |
882 | ||
883 | my($time)=""; | |
884 | $ampm=""; | |
885 | $date=""; | |
886 | ||
887 | # Substitute all special time expressions. | |
888 | if (/(^|[^a-z])$timeexp($|[^a-z])/i) { | |
889 | $tmp=$2; | |
890 | $tmp=$Lang{$L}{"TimesH"}{lc($tmp)}; | |
891 | s/(^|[^a-z])$timeexp($|[^a-z])/$1 $tmp $3/i; | |
892 | } | |
893 | ||
894 | # Remove some punctuation | |
895 | s/[,]/ /g; | |
896 | ||
897 | # Make sure that ...7EST works (i.e. a timezone immediately following | |
898 | # a digit. | |
899 | s/(\d)$zone(\s+|$|[0-9])/$1 $2$3/i; | |
900 | $zone = '\s+'.$zone; | |
901 | ||
902 | # Remove the time | |
903 | $iso=1; | |
904 | $midnight=0; | |
905 | $from="24${hm}00(?:${ms}00)?"; | |
906 | $falsefrom="${hm}24${ms}00"; # Don't trap XX:24:00 | |
907 | $to="00${hm}00${ms}00"; | |
908 | $midnight=1 if (!/$falsefrom/ && s/$from/$to/); | |
909 | ||
910 | $h=$mn=$s=0; | |
911 | if (/$D$mnsec/i || /$ampmexp/i) { | |
912 | $iso=0; | |
913 | $tmp=0; | |
914 | $tmp=1 if (/$mnsec$zone2?\s*$/i); # or /$mnsec$zone/ ?? | |
915 | $tmp=0 if (/$ampmexp/i); | |
916 | if (s/$apachetime$zone()/$1 /i || | |
917 | s/$apachetime$zone2?/$1 /i || | |
918 | s/(^|[^a-z])$at\s*$D$mnsec$zone()/$1 /i || | |
919 | s/(^|[^a-z])$at\s*$D$mnsec$zone2?/$1 /i || | |
920 | s/(^|[^0-9])(\d)$mnsec$zone()/$1 /i || | |
921 | s/(^|[^0-9])(\d)$mnsec$zone2?/$1 /i || | |
922 | (s/(t)$D$mnsec$zone()/$1 /i and (($iso=-$tmp) || 1)) || | |
923 | (s/(t)$D$mnsec$zone2?/$1 /i and (($iso=-$tmp) || 1)) || | |
924 | (s/()$DD$mnsec$zone()/ /i and (($iso=$tmp) || 1)) || | |
925 | (s/()$DD$mnsec$zone2?/ /i and (($iso=$tmp) || 1)) || | |
926 | s/(^|$at\s*|\s+)$D()()\s*$ampmexp$zone()/ /i || | |
927 | s/(^|$at\s*|\s+)$D()()\s*$ampmexp$zone2?/ /i || | |
928 | 0 | |
929 | ) { | |
930 | ($h,$mn,$s,$ampm,$z,$z2)=($2,$3,$4,$5,$6,$7); | |
931 | if (defined ($z)) { | |
932 | if ($z =~ /^[+-]\d{2}:\d{2}$/) { | |
933 | $z=~ s/://; | |
934 | } elsif ($z =~ /^[+-]\d{2}$/) { | |
935 | $z .= "00"; | |
936 | } | |
937 | } | |
938 | $time=1; | |
939 | &Date_TimeCheck(\$h,\$mn,\$s,\$ampm); | |
940 | $y=$m=$d=""; | |
941 | # We're going to be calling TimeCheck again below (when we check the | |
942 | # final date), so get rid of $ampm so that we don't have an error | |
943 | # due to "15:30:00 PM". It'll get reset below. | |
944 | $ampm=""; | |
945 | if (/^\s*$/) { | |
946 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
947 | last PARSE; | |
948 | } | |
949 | } | |
950 | } | |
951 | $time=0 if ($time ne "1"); | |
952 | s/\s+$//; | |
953 | s/^\s+//; | |
954 | ||
955 | # dateTtime ISO 8601 formats | |
956 | my($orig)=$_; | |
957 | s/t$//i if ($iso<0); | |
958 | ||
959 | # Parse ISO 8601 dates now (which may still have a zone stuck to it). | |
960 | if ( ($iso && /^([0-9-]+(?:W[0-9-]+)?)$zone?$/i) || | |
961 | ($iso && /^([0-9-]+(?:W[0-9-]+)?)$zone2?$/i) || | |
962 | ($iso && /^([0-9-]+(?:T[0-9-]+)?)$zone?$/i) || | |
963 | ($iso && /^([0-9-]+(?:T[0-9-]+)?)$zone2?$/i) || | |
964 | 0) { | |
965 | ||
966 | # ISO 8601 dates | |
967 | ($_,$z,$z2) = ($1,$2); | |
968 | s,-, ,g; # Change all ISO8601 seps to spaces | |
969 | s/^\s+//; | |
970 | s/\s+$//; | |
971 | ||
972 | if (/^$D4\s*$DD\s*$DD\s*t?$DD(?:$DD(?:$DD(\d*))?)?$/i || | |
973 | /^$DD\s+$DD\s*$DD\s*t?$DD(?:$DD(?:$DD(\d*))?)?$/i || | |
974 | 0 | |
975 | ) { | |
976 | # ISO 8601 Dates with times | |
977 | # YYYYMMDDHHMNSSFFFF... | |
978 | # YYYYMMDDHHMNSS | |
979 | # YYYYMMDDHHMN | |
980 | # YYYYMMDDHH | |
981 | # YY MMDDHHMNSSFFFF... | |
982 | # YY MMDDHHMNSS | |
983 | # YY MMDDHHMN | |
984 | # YY MMDDHH | |
985 | ($y,$m,$d,$h,$mn,$s,$tmp)=($1,$2,$3,$4,$5,$6,$7); | |
986 | if ($h==24 && (! defined $mn || $mn==0) && (! defined $s || $s==0)) { | |
987 | $h=0; | |
988 | $midnight=1; | |
989 | } | |
990 | $z = "" if (! defined $h); | |
991 | return "" if ($time && defined $h); | |
992 | last PARSE; | |
993 | ||
994 | } elsif (/^$D4(?:\s*$DD(?:\s*$DD)?)?$/ || | |
995 | /^$DD(?:\s+$DD(?:\s*$DD)?)?$/) { | |
996 | # ISO 8601 Dates | |
997 | # YYYYMMDD | |
998 | # YYYYMM | |
999 | # YYYY | |
1000 | # YY MMDD | |
1001 | # YY MM | |
1002 | # YY | |
1003 | ($y,$m,$d)=($1,$2,$3); | |
1004 | last PARSE; | |
1005 | ||
1006 | } elsif (/^$YY\s+$D\s+$D/) { | |
1007 | # YY-M-D | |
1008 | ($y,$m,$d)=($1,$2,$3); | |
1009 | last PARSE; | |
1010 | ||
1011 | } elsif (/^$YY\s*W$DD\s*(\d)?$/i) { | |
1012 | # YY-W##-D | |
1013 | ($y,$wofm,$dofw)=($1,$2,$3); | |
1014 | ($y,$m,$d)=&Date_NthWeekOfYear($y,$wofm,$dofw); | |
1015 | last PARSE; | |
1016 | ||
1017 | } elsif (/^$D4\s*(\d{3})$/ || | |
1018 | /^$DD\s*(\d{3})$/) { | |
1019 | # YYDOY | |
1020 | ($y,$which)=($1,$2); | |
1021 | ($y,$m,$d)=&Date_NthDayOfYear($y,$which); | |
1022 | last PARSE; | |
1023 | ||
1024 | } elsif ($iso<0) { | |
1025 | # We confused something like 1999/August12:00:00 | |
1026 | # with a dateTtime format | |
1027 | $_=$orig; | |
1028 | ||
1029 | } else { | |
1030 | return ""; | |
1031 | } | |
1032 | } | |
1033 | ||
1034 | # All deltas that are not ISO-8601 dates are NOT dates. | |
1035 | return "" if ($Curr{"InCalc"} && $delta); | |
1036 | if ($delta) { | |
1037 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1038 | return &DateCalc_DateDelta($Curr{"Now"},$delta); | |
1039 | } | |
1040 | ||
1041 | # Check for some special types of dates (next, prev) | |
1042 | foreach $from (keys %{ $Lang{$L}{"Repl"} }) { | |
1043 | $to=$Lang{$L}{"Repl"}{$from}; | |
1044 | s/(^|[^a-z])$from($|[^a-z])/$1$to$2/i; | |
1045 | } | |
1046 | if (/$wom/i || /$future/i || /$later/i || /$past/i || | |
1047 | /$next/i || /$prev/i || /^$week$/i || /$wkabb/i) { | |
1048 | $tmp=0; | |
1049 | ||
1050 | if (/^$wom\s*$week$of\s*$month\s*$YY?$/i) { | |
1051 | # last friday in October 95 | |
1052 | ($wofm,$dofw,$m,$y)=($1,$2,$3,$4); | |
1053 | # fix $m, $y | |
1054 | return "" if (&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk)); | |
1055 | $dofw=$week{lc($dofw)}; | |
1056 | $wofm=$wom{lc($wofm)}; | |
1057 | # Get the first day of the month | |
1058 | $date=&Date_Join($y,$m,1,$h,$mn,$s); | |
1059 | if ($wofm==-1) { | |
1060 | $date=&DateCalc_DateDelta($date,"+0:1:0:0:0:0:0",\$err,0); | |
1061 | $date=&Date_GetPrev($date,$dofw,0); | |
1062 | } else { | |
1063 | for ($i=0; $i<$wofm; $i++) { | |
1064 | if ($i==0) { | |
1065 | $date=&Date_GetNext($date,$dofw,1); | |
1066 | } else { | |
1067 | $date=&Date_GetNext($date,$dofw,0); | |
1068 | } | |
1069 | } | |
1070 | } | |
1071 | last PARSE; | |
1072 | ||
1073 | } elsif (/^$last$day$of\s*$month(?:$of?\s*$YY)?/i) { | |
1074 | # last day in month | |
1075 | ($m,$y)=($1,$2); | |
1076 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1077 | $y=&Date_FixYear($y) if (! defined $y or length($y)<4); | |
1078 | $m=$month{lc($m)}; | |
1079 | $d=&Date_DaysInMonth($m,$y); | |
1080 | last PARSE; | |
1081 | ||
1082 | } elsif (/^$week$/i) { | |
1083 | # friday | |
1084 | ($dofw)=($1); | |
1085 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1086 | $date=&Date_GetPrev($Curr{"Now"},$Cnf{"FirstDay"},1); | |
1087 | $date=&Date_GetNext($date,$dofw,1,$h,$mn,$s); | |
1088 | last PARSE; | |
1089 | ||
1090 | } elsif (/^$next\s*$week$/i) { | |
1091 | # next friday | |
1092 | ($dofw)=($1); | |
1093 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1094 | $date=&Date_GetNext($Curr{"Now"},$dofw,0,$h,$mn,$s); | |
1095 | last PARSE; | |
1096 | ||
1097 | } elsif (/^$prev\s*$week$/i) { | |
1098 | # last friday | |
1099 | ($dofw)=($1); | |
1100 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1101 | $date=&Date_GetPrev($Curr{"Now"},$dofw,0,$h,$mn,$s); | |
1102 | last PARSE; | |
1103 | ||
1104 | } elsif (/^$next$wkabb$/i) { | |
1105 | # next week | |
1106 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1107 | $date=&DateCalc_DateDelta($Curr{"Now"},"+0:0:1:0:0:0:0",\$err,0); | |
1108 | $date=&Date_SetTime($date,$h,$mn,$s) if (defined $h); | |
1109 | last PARSE; | |
1110 | } elsif (/^$prev$wkabb$/i) { | |
1111 | # last week | |
1112 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1113 | $date=&DateCalc_DateDelta($Curr{"Now"},"-0:0:1:0:0:0:0",\$err,0); | |
1114 | $date=&Date_SetTime($date,$h,$mn,$s) if (defined $h); | |
1115 | last PARSE; | |
1116 | ||
1117 | } elsif (/^$next$mabb$/i) { | |
1118 | # next month | |
1119 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1120 | $date=&DateCalc_DateDelta($Curr{"Now"},"+0:1:0:0:0:0:0",\$err,0); | |
1121 | $date=&Date_SetTime($date,$h,$mn,$s) if (defined $h); | |
1122 | last PARSE; | |
1123 | } elsif (/^$prev$mabb$/i) { | |
1124 | # last month | |
1125 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1126 | $date=&DateCalc_DateDelta($Curr{"Now"},"-0:1:0:0:0:0:0",\$err,0); | |
1127 | $date=&Date_SetTime($date,$h,$mn,$s) if (defined $h); | |
1128 | last PARSE; | |
1129 | ||
1130 | } elsif (/^$future\s*(\d+)$day$/i || | |
1131 | /^(\d+)$day$later$/i) { | |
1132 | # in 2 days | |
1133 | # 2 days later | |
1134 | ($num)=($1); | |
1135 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1136 | $date=&DateCalc_DateDelta($Curr{"Now"},"+0:0:0:$num:0:0:0", | |
1137 | \$err,0); | |
1138 | $date=&Date_SetTime($date,$h,$mn,$s) if (defined $h); | |
1139 | last PARSE; | |
1140 | } elsif (/^(\d+)$day$past$/i) { | |
1141 | # 2 days ago | |
1142 | ($num)=($1); | |
1143 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1144 | $date=&DateCalc_DateDelta($Curr{"Now"},"-0:0:0:$num:0:0:0", | |
1145 | \$err,0); | |
1146 | $date=&Date_SetTime($date,$h,$mn,$s) if (defined $h); | |
1147 | last PARSE; | |
1148 | ||
1149 | } elsif (/^$future\s*(\d+)$wkabb$/i || | |
1150 | /^(\d+)$wkabb$later$/i) { | |
1151 | # in 2 weeks | |
1152 | # 2 weeks later | |
1153 | ($num)=($1); | |
1154 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1155 | $date=&DateCalc_DateDelta($Curr{"Now"},"+0:0:$num:0:0:0:0", | |
1156 | \$err,0); | |
1157 | $date=&Date_SetTime($date,$h,$mn,$s) if (defined $h); | |
1158 | last PARSE; | |
1159 | } elsif (/^(\d+)$wkabb$past$/i) { | |
1160 | # 2 weeks ago | |
1161 | ($num)=($1); | |
1162 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1163 | $date=&DateCalc_DateDelta($Curr{"Now"},"-0:0:$num:0:0:0:0", | |
1164 | \$err,0); | |
1165 | $date=&Date_SetTime($date,$h,$mn,$s) if (defined $h); | |
1166 | last PARSE; | |
1167 | ||
1168 | } elsif (/^$future\s*(\d+)$mabb$/i || | |
1169 | /^(\d+)$mabb$later$/i) { | |
1170 | # in 2 months | |
1171 | # 2 months later | |
1172 | ($num)=($1); | |
1173 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1174 | $date=&DateCalc_DateDelta($Curr{"Now"},"+0:$num:0:0:0:0:0", | |
1175 | \$err,0); | |
1176 | $date=&Date_SetTime($date,$h,$mn,$s) if (defined $h); | |
1177 | last PARSE; | |
1178 | } elsif (/^(\d+)$mabb$past$/i) { | |
1179 | # 2 months ago | |
1180 | ($num)=($1); | |
1181 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1182 | $date=&DateCalc_DateDelta($Curr{"Now"},"-0:$num:0:0:0:0:0", | |
1183 | \$err,0); | |
1184 | $date=&Date_SetTime($date,$h,$mn,$s) if (defined $h); | |
1185 | last PARSE; | |
1186 | ||
1187 | } elsif (/^$week$future\s*(\d+)$wkabb$/i || | |
1188 | /^$week\s*(\d+)$wkabb$later$/i) { | |
1189 | # friday in 2 weeks | |
1190 | # friday 2 weeks later | |
1191 | ($dofw,$num)=($1,$2); | |
1192 | $tmp="+"; | |
1193 | } elsif (/^$week\s*(\d+)$wkabb$past$/i) { | |
1194 | # friday 2 weeks ago | |
1195 | ($dofw,$num)=($1,$2); | |
1196 | $tmp="-"; | |
1197 | } elsif (/^$future\s*(\d+)$wkabb$on$week$/i || | |
1198 | /^(\d+)$wkabb$later$on$week$/i) { | |
1199 | # in 2 weeks on friday | |
1200 | # 2 weeks later on friday | |
1201 | ($num,$dofw)=($1,$2); | |
1202 | $tmp="+" | |
1203 | } elsif (/^(\d+)$wkabb$past$on$week$/i) { | |
1204 | # 2 weeks ago on friday | |
1205 | ($num,$dofw)=($1,$2); | |
1206 | $tmp="-"; | |
1207 | } elsif (/^$week\s*$wkabb$/i) { | |
1208 | # monday week (British date: in 1 week on monday) | |
1209 | $dofw=$1; | |
1210 | $num=1; | |
1211 | $tmp="+"; | |
1212 | } elsif (/^$now\s*$wkabb$/i) { | |
1213 | # today week (British date: 1 week from today) | |
1214 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1215 | $date=&DateCalc_DateDelta($Curr{"Now"},"+0:0:1:0:0:0:0",\$err,0); | |
1216 | $date=&Date_SetTime($date,$h,$mn,$s) if (defined $h); | |
1217 | last PARSE; | |
1218 | } elsif (/^$offset\s*$wkabb$/i) { | |
1219 | # tomorrow week (British date: 1 week from tomorrow) | |
1220 | ($offset)=($1); | |
1221 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1222 | $offset=$Lang{$L}{"OffsetH"}{lc($offset)}; | |
1223 | $date=&DateCalc_DateDelta($Curr{"Now"},$offset,\$err,0); | |
1224 | $date=&DateCalc_DateDelta($date,"+0:0:1:0:0:0:0",\$err,0); | |
1225 | if ($time) { | |
1226 | return "" | |
1227 | if (&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk)); | |
1228 | $date=&Date_SetTime($date,$h,$mn,$s); | |
1229 | } | |
1230 | last PARSE; | |
1231 | } | |
1232 | ||
1233 | if ($tmp) { | |
1234 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1235 | $date=&DateCalc_DateDelta($Curr{"Now"}, | |
1236 | $tmp . "0:0:$num:0:0:0:0",\$err,0); | |
1237 | $date=&Date_GetPrev($date,$Cnf{"FirstDay"},1); | |
1238 | $date=&Date_GetNext($date,$dofw,1,$h,$mn,$s); | |
1239 | last PARSE; | |
1240 | } | |
1241 | } | |
1242 | ||
1243 | # Change (2nd, second) to 2 | |
1244 | $tmp=0; | |
1245 | if (/(^|[^a-z0-9])$dom($|[^a-z0-9])/i) { | |
1246 | if (/^\s*$dom\s*$/) { | |
1247 | ($d)=($1); | |
1248 | $d=$dom{lc($d)}; | |
1249 | $m=$Curr{"M"}; | |
1250 | last PARSE; | |
1251 | } | |
1252 | my $from = $2; | |
1253 | my $to = $dom{ lc($from) }; | |
1254 | s/(^|[^a-z])$from($|[^a-z])/$1 $to $2/i; | |
1255 | s/^\s+//; | |
1256 | s/\s+$//; | |
1257 | } | |
1258 | ||
1259 | # Another set of special dates (Nth week) | |
1260 | if (/^$D\s*$week(?:$of?\s*$YY)?$/i) { | |
1261 | # 22nd sunday in 1996 | |
1262 | ($which,$dofw,$y)=($1,$2,$3); | |
1263 | $y=$Curr{"Y"} if (! $y); | |
1264 | $y--; # previous year | |
1265 | $tmp=&Date_GetNext("$y-12-31",$dofw,0); | |
1266 | if ($which>1) { | |
1267 | $tmp=&DateCalc_DateDelta($tmp,"+0:0:".($which-1).":0:0:0:0",\$err,0); | |
1268 | } | |
1269 | ($y,$m,$d)=(&Date_Split($tmp, 1))[0..2]; | |
1270 | last PARSE; | |
1271 | } elsif (/^$week$wkabb\s*$D(?:$of?\s*$YY)?$/i || | |
1272 | /^$week\s*$D$wkabb(?:$of?\s*$YY)?$/i) { | |
1273 | # sunday week 22 in 1996 | |
1274 | # sunday 22nd week in 1996 | |
1275 | ($dofw,$which,$y)=($1,$2,$3); | |
1276 | ($y,$m,$d)=&Date_NthWeekOfYear($y,$which,$dofw); | |
1277 | last PARSE; | |
1278 | } | |
1279 | ||
1280 | # Get rid of day of week | |
1281 | if (/(^|[^a-z])$week($|[^a-z])/i) { | |
1282 | $wk=$2; | |
1283 | (s/(^|[^a-z])$week,/$1 /i) || | |
1284 | s/(^|[^a-z])$week($|[^a-z])/$1 $3/i; | |
1285 | s/^\s+//; | |
1286 | s/\s+$//; | |
1287 | } | |
1288 | ||
1289 | { | |
1290 | # So that we can handle negative epoch times, let's convert | |
1291 | # things like "epoch -" to "epochNEGATIVE " before we strip out | |
1292 | # the $sep chars, which include '-'. | |
1293 | s,epoch\s*-,epochNEGATIVE ,g; | |
1294 | ||
1295 | # Non-ISO8601 dates | |
1296 | s,\s*$sep\s*, ,g; # change all non-ISO8601 seps to spaces | |
1297 | s,^\s*,,; # remove leading/trailing space | |
1298 | s,\s*$,,; | |
1299 | ||
1300 | if (/^$D\s+$D(?:\s+$YY)?$/) { | |
1301 | # MM DD YY (DD MM YY non-US) | |
1302 | ($m,$d,$y)=($1,$2,$3); | |
1303 | ($m,$d)=($d,$m) if ($type ne "US"); | |
1304 | last PARSE; | |
1305 | ||
1306 | } elsif (/^$D4\s*$D\s*$D$/) { | |
1307 | # YYYY MM DD | |
1308 | ($y,$m,$d)=($1,$2,$3); | |
1309 | last PARSE; | |
1310 | ||
1311 | } elsif (s/(^|[^a-z])$month($|[^a-z])/$1 $3/i) { | |
1312 | ($m)=($2); | |
1313 | ||
1314 | if (/^\s*$D(?:\s+$YY)?\s*$/) { | |
1315 | # mmm DD YY | |
1316 | # DD mmm YY | |
1317 | # DD YY mmm | |
1318 | ($d,$y)=($1,$2); | |
1319 | last PARSE; | |
1320 | ||
1321 | } elsif (/^\s*$D$D4\s*$/) { | |
1322 | # mmm DD YYYY | |
1323 | # DD mmm YYYY | |
1324 | # DD YYYY mmm | |
1325 | ($d,$y)=($1,$2); | |
1326 | last PARSE; | |
1327 | ||
1328 | } elsif (/^\s*$D4\s*$D\s*$/) { | |
1329 | # mmm YYYY DD | |
1330 | # YYYY mmm DD | |
1331 | # YYYY DD mmm | |
1332 | ($y,$d)=($1,$2); | |
1333 | last PARSE; | |
1334 | ||
1335 | } elsif (/^\s*$D4\s*$/) { | |
1336 | # mmm YYYY | |
1337 | # YYYY mmm | |
1338 | ($y,$d)=($1,1); | |
1339 | last PARSE; | |
1340 | ||
1341 | } else { | |
1342 | return ""; | |
1343 | } | |
1344 | ||
1345 | } elsif (/^epochNEGATIVE (\d+)$/) { | |
1346 | $s=$1; | |
1347 | $date=&DateCalc("1970-01-01 00:00 GMT","-0:0:$s"); | |
1348 | } elsif (/^epoch\s*(\d+)$/i) { | |
1349 | $s=$1; | |
1350 | $date=&DateCalc("1970-01-01 00:00 GMT","+0:0:$s"); | |
1351 | ||
1352 | } elsif (/^$now$/i) { | |
1353 | # now, today | |
1354 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1355 | $date=$Curr{"Now"}; | |
1356 | if ($time) { | |
1357 | return "" | |
1358 | if (&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk)); | |
1359 | $date=&Date_SetTime($date,$h,$mn,$s); | |
1360 | } | |
1361 | last PARSE; | |
1362 | ||
1363 | } elsif (/^$offset$/i) { | |
1364 | # yesterday, tomorrow | |
1365 | ($offset)=($1); | |
1366 | &Date_Init() if (! $Cnf{"UpdateCurrTZ"}); | |
1367 | $offset=$Lang{$L}{"OffsetH"}{lc($offset)}; | |
1368 | $date=&DateCalc_DateDelta($Curr{"Now"},$offset,\$err,0); | |
1369 | if ($time) { | |
1370 | return "" | |
1371 | if (&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk)); | |
1372 | $date=&Date_SetTime($date,$h,$mn,$s); | |
1373 | } | |
1374 | last PARSE; | |
1375 | ||
1376 | } else { | |
1377 | return ""; | |
1378 | } | |
1379 | } | |
1380 | } | |
1381 | ||
1382 | if (! $date) { | |
1383 | return "" if (&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk)); | |
1384 | $date=&Date_Join($y,$m,$d,$h,$mn,$s); | |
1385 | } | |
1386 | $date=&Date_ConvTZ($date,$z); | |
1387 | if ($midnight) { | |
1388 | $date=&DateCalc_DateDelta($date,"+0:0:0:1:0:0:0"); | |
1389 | } | |
1390 | return $date; | |
1391 | } | |
1392 | ||
1393 | sub ParseDate { | |
1394 | print "DEBUG: ParseDate\n" if ($Curr{"Debug"} =~ /trace/); | |
1395 | &Date_Init() if (! $Curr{"InitDone"}); | |
1396 | my($args,@args,@a,$ref,$date)=(); | |
1397 | @a=@_; | |
1398 | ||
1399 | # @a : is the list of args to ParseDate. Currently, only one argument | |
1400 | # is allowed and it must be a scalar (or a reference to a scalar) | |
1401 | # or a reference to an array. | |
1402 | ||
1403 | if ($#a!=0) { | |
1404 | print "ERROR: Invalid number of arguments to ParseDate.\n"; | |
1405 | return ""; | |
1406 | } | |
1407 | $args=$a[0]; | |
1408 | $ref=ref $args; | |
1409 | if (! $ref) { | |
1410 | return $args if (&Date_Split($args)); | |
1411 | @args=($args); | |
1412 | } elsif ($ref eq "ARRAY") { | |
1413 | @args=@$args; | |
1414 | } elsif ($ref eq "SCALAR") { | |
1415 | return $$args if (&Date_Split($$args)); | |
1416 | @args=($$args); | |
1417 | } else { | |
1418 | print "ERROR: Invalid arguments to ParseDate.\n"; | |
1419 | return ""; | |
1420 | } | |
1421 | @a=@args; | |
1422 | ||
1423 | # @args : a list containing all the arguments (dereferenced if appropriate) | |
1424 | # @a : a list containing all the arguments currently being examined | |
1425 | # $ref : nil, "SCALAR", or "ARRAY" depending on whether a scalar, a | |
1426 | # reference to a scalar, or a reference to an array was passed in | |
1427 | # $args : the scalar or refererence passed in | |
1428 | ||
1429 | PARSE: while($#a>=0) { | |
1430 | $date=join(" ",@a); | |
1431 | $date=&ParseDateString($date); | |
1432 | last if ($date); | |
1433 | pop(@a); | |
1434 | } # PARSE | |
1435 | ||
1436 | splice(@args,0,$#a + 1); | |
1437 | @$args= @args if (defined $ref and $ref eq "ARRAY"); | |
1438 | $date; | |
1439 | } | |
1440 | ||
1441 | sub Date_Cmp { | |
1442 | my($D1,$D2)=@_; | |
1443 | my($date1)=&ParseDateString($D1); | |
1444 | my($date2)=&ParseDateString($D2); | |
1445 | return $date1 cmp $date2; | |
1446 | } | |
1447 | ||
1448 | # **NOTE** | |
1449 | # The calc routines all call parse routines, so it is never necessary to | |
1450 | # call Date_Init in the calc routines. | |
1451 | sub DateCalc { | |
1452 | print "DEBUG: DateCalc\n" if ($Curr{"Debug"} =~ /trace/); | |
1453 | my($D1,$D2,@arg)=@_; | |
1454 | my($ref,$err,$errref,$mode)=(); | |
1455 | ||
1456 | $errref=shift(@arg); | |
1457 | $ref=0; | |
1458 | if (defined $errref) { | |
1459 | if (ref $errref) { | |
1460 | $mode=shift(@arg); | |
1461 | $ref=1; | |
1462 | } else { | |
1463 | $mode=$errref; | |
1464 | $errref=""; | |
1465 | } | |
1466 | } | |
1467 | ||
1468 | my(@date,@delta,$ret,$tmp,$old)=(); | |
1469 | ||
1470 | if (defined $mode and $mode>=0 and $mode<=3) { | |
1471 | $Curr{"Mode"}=$mode; | |
1472 | } else { | |
1473 | $Curr{"Mode"}=0; | |
1474 | } | |
1475 | ||
1476 | $old=$Curr{"InCalc"}; | |
1477 | $Curr{"InCalc"}=1; | |
1478 | ||
1479 | if ($tmp=&ParseDateString($D1)) { | |
1480 | # If we've already parsed the date, we don't want to do it a second | |
1481 | # time (so we don't convert timezones twice). | |
1482 | if (&Date_Split($D1)) { | |
1483 | push(@date,$D1); | |
1484 | } else { | |
1485 | push(@date,$tmp); | |
1486 | } | |
1487 | } elsif ($tmp=&ParseDateDelta($D1)) { | |
1488 | push(@delta,$tmp); | |
1489 | } else { | |
1490 | $$errref=1 if ($ref); | |
1491 | return; | |
1492 | } | |
1493 | ||
1494 | if ($tmp=&ParseDateString($D2)) { | |
1495 | if (&Date_Split($D2)) { | |
1496 | push(@date,$D2); | |
1497 | } else { | |
1498 | push(@date,$tmp); | |
1499 | } | |
1500 | } elsif ($tmp=&ParseDateDelta($D2)) { | |
1501 | push(@delta,$tmp); | |
1502 | } else { | |
1503 | $$errref=2 if ($ref); | |
1504 | return; | |
1505 | } | |
1506 | $mode=$Curr{"Mode"}; | |
1507 | $Curr{"InCalc"}=$old; | |
1508 | ||
1509 | if ($#date==1) { | |
1510 | $ret=&DateCalc_DateDate(@date,$mode); | |
1511 | } elsif ($#date==0) { | |
1512 | $ret=&DateCalc_DateDelta(@date,@delta,\$err,$mode); | |
1513 | $$errref=$err if ($ref); | |
1514 | } else { | |
1515 | $ret=&DateCalc_DeltaDelta(@delta,$mode); | |
1516 | } | |
1517 | $ret; | |
1518 | } | |
1519 | ||
1520 | sub ParseDateDelta { | |
1521 | print "DEBUG: ParseDateDelta\n" if ($Curr{"Debug"} =~ /trace/); | |
1522 | my($args,@args,@a,$ref)=(); | |
1523 | local($_)=(); | |
1524 | @a=@_; | |
1525 | ||
1526 | # @a : is the list of args to ParseDateDelta. Currently, only one argument | |
1527 | # is allowed and it must be a scalar (or a reference to a scalar) | |
1528 | # or a reference to an array. | |
1529 | ||
1530 | if ($#a!=0) { | |
1531 | print "ERROR: Invalid number of arguments to ParseDateDelta.\n"; | |
1532 | return ""; | |
1533 | } | |
1534 | $args=$a[0]; | |
1535 | $ref=ref $args; | |
1536 | if (! $ref) { | |
1537 | @args=($args); | |
1538 | } elsif ($ref eq "ARRAY") { | |
1539 | @args=@$args; | |
1540 | } elsif ($ref eq "SCALAR") { | |
1541 | @args=($$args); | |
1542 | } else { | |
1543 | print "ERROR: Invalid arguments to ParseDateDelta.\n"; | |
1544 | return ""; | |
1545 | } | |
1546 | @a=@args; | |
1547 | ||
1548 | # @args : a list containing all the arguments (dereferenced if appropriate) | |
1549 | # @a : a list containing all the arguments currently being examined | |
1550 | # $ref : nil, "SCALAR", or "ARRAY" depending on whether a scalar, a | |
1551 | # reference to a scalar, or a reference to an array was passed in | |
1552 | # $args : the scalar or refererence passed in | |
1553 | ||
1554 | my(@colon,@delta,$delta,$dir,$colon,$sign,$val)=(); | |
1555 | my($len,$tmp,$tmp2,$tmpl)=(); | |
1556 | my($from,$to)=(); | |
1557 | my($workweek)=$Cnf{"WorkWeekEnd"}-$Cnf{"WorkWeekBeg"}+1; | |
1558 | ||
1559 | &Date_Init() if (! $Curr{"InitDone"}); | |
1560 | # A sign can be a sequence of zero or more + and - signs, this | |
1561 | # allows for deltas like '+ -2 days'. | |
1562 | my($signexp)='((?:[+-]\s*)*)'; | |
1563 | my($numexp)='(\d+)'; | |
1564 | my($exp1)="(?: \\s* $signexp \\s* $numexp \\s*)"; | |
1565 | my($yexp,$mexp,$wexp,$dexp,$hexp,$mnexp,$sexp,$i)=(); | |
1566 | $yexp=$mexp=$wexp=$dexp=$hexp=$mnexp=$sexp="()()"; | |
1567 | $yexp ="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"Yabb"} .")?"; | |
1568 | $mexp ="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"Mabb"} .")?"; | |
1569 | $wexp ="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"Wabb"} .")?"; | |
1570 | $dexp ="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"Dabb"} .")?"; | |
1571 | $hexp ="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"Habb"} .")?"; | |
1572 | $mnexp="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"MNabb"}.")?"; | |
1573 | $sexp ="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"Sabb"} ."?)?"; | |
1574 | my($future)=$Lang{$Cnf{"Language"}}{"Future"}; | |
1575 | my($later)=$Lang{$Cnf{"Language"}}{"Later"}; | |
1576 | my($past)=$Lang{$Cnf{"Language"}}{"Past"}; | |
1577 | ||
1578 | $delta=""; | |
1579 | PARSE: while (@a) { | |
1580 | $_ = join(" ", grep {defined;} @a); | |
1581 | s/\s+$//; | |
1582 | last if ($_ eq ""); | |
1583 | ||
1584 | # Mode is set in DateCalc. ParseDateDelta only overrides it if the | |
1585 | # string contains a mode. | |
1586 | if ($Lang{$Cnf{"Language"}}{"Exact"} && | |
1587 | s/$Lang{$Cnf{"Language"}}{"Exact"}//) { | |
1588 | $Curr{"Mode"}=0; | |
1589 | } elsif ($Lang{$Cnf{"Language"}}{"Approx"} && | |
1590 | s/$Lang{$Cnf{"Language"}}{"Approx"}//) { | |
1591 | $Curr{"Mode"}=1; | |
1592 | } elsif ($Lang{$Cnf{"Language"}}{"Business"} && | |
1593 | s/$Lang{$Cnf{"Language"}}{"Business"}//) { | |
1594 | $Curr{"Mode"}=2; | |
1595 | } elsif (! exists $Curr{"Mode"}) { | |
1596 | $Curr{"Mode"}=0; | |
1597 | } | |
1598 | $workweek=7 if ($Curr{"Mode"} != 2); | |
1599 | ||
1600 | foreach $from (keys %{ $Lang{$Cnf{"Language"}}{"Repl"} }) { | |
1601 | $to=$Lang{$Cnf{"Language"}}{"Repl"}{$from}; | |
1602 | s/(^|[^a-z])$from($|[^a-z])/$1$to$2/i; | |
1603 | } | |
1604 | ||
1605 | # in or ago | |
1606 | # | |
1607 | # We need to make sure that $later, $future, and $past don't contain each | |
1608 | # other... Romanian pointed this out where $past is "in urma" and $future | |
1609 | # is "in". When they do, we have to take this into account. | |
1610 | # $len length of best match (greatest wins) | |
1611 | # $tmp string after best match | |
1612 | # $dir direction (prior, after) of best match | |
1613 | # | |
1614 | # $tmp2 string before/after current match | |
1615 | # $tmpl length of current match | |
1616 | ||
1617 | $len=0; | |
1618 | $tmp=$_; | |
1619 | $dir=1; | |
1620 | ||
1621 | $tmp2=$_; | |
1622 | if ($tmp2 =~ s/(^|[^a-z])($future)($|[^a-z])/$1 $3/i) { | |
1623 | $tmpl=length($2); | |
1624 | if ($tmpl>$len) { | |
1625 | $tmp=$tmp2; | |
1626 | $dir=1; | |
1627 | $len=$tmpl; | |
1628 | } | |
1629 | } | |
1630 | ||
1631 | $tmp2=$_; | |
1632 | if ($tmp2 =~ s/(^|[^a-z])($later)($|[^a-z])/$1 $3/i) { | |
1633 | $tmpl=length($2); | |
1634 | if ($tmpl>$len) { | |
1635 | $tmp=$tmp2; | |
1636 | $dir=1; | |
1637 | $len=$tmpl; | |
1638 | } | |
1639 | } | |
1640 | ||
1641 | $tmp2=$_; | |
1642 | if ($tmp2 =~ s/(^|[^a-z])($past)($|[^a-z])/$1 $3/i) { | |
1643 | $tmpl=length($2); | |
1644 | if ($tmpl>$len) { | |
1645 | $tmp=$tmp2; | |
1646 | $dir=-1; | |
1647 | $len=$tmpl; | |
1648 | } | |
1649 | } | |
1650 | ||
1651 | $_ = $tmp; | |
1652 | s/\s*$//; | |
1653 | ||
1654 | # the colon part of the delta | |
1655 | $colon=""; | |
1656 | if (s/($signexp?$numexp?(:($signexp?$numexp)?){1,6})$//) { | |
1657 | $colon=$1; | |
1658 | s/\s+$//; | |
1659 | } | |
1660 | @colon=split(/:/,$colon); | |
1661 | ||
1662 | # the non-colon part of the delta | |
1663 | $sign="+"; | |
1664 | @delta=(); | |
1665 | $i=6; | |
1666 | foreach $exp1 ($yexp,$mexp,$wexp,$dexp,$hexp,$mnexp,$sexp) { | |
1667 | last if ($#colon>=$i--); | |
1668 | $val=0; | |
1669 | if (s/^$exp1//ix) { | |
1670 | $val=$2 if ($2); | |
1671 | $sign=$1 if ($1); | |
1672 | } | |
1673 | ||
1674 | # Collapse a sign like '+ -' into a single character like '-', | |
1675 | # by counting the occurrences of '-'. | |
1676 | # | |
1677 | $sign =~ s/\s+//g; | |
1678 | $sign =~ tr/+//d; | |
1679 | my $count = ($sign =~ tr/-//d); | |
1680 | die "bad characters in sign: $sign" if length $sign; | |
1681 | $sign = $count % 2 ? '-' : '+'; | |
1682 | ||
1683 | push(@delta,"$sign$val"); | |
1684 | } | |
1685 | if (! /^\s*$/) { | |
1686 | pop(@a); | |
1687 | next PARSE; | |
1688 | } | |
1689 | ||
1690 | # make sure that the colon part has a sign | |
1691 | for ($i=0; $i<=$#colon; $i++) { | |
1692 | $val=0; | |
1693 | if ($colon[$i] =~ /^$signexp$numexp?/) { | |
1694 | $val=$2 if ($2); | |
1695 | $sign=$1 if ($1); | |
1696 | } | |
1697 | $colon[$i] = "$sign$val"; | |
1698 | } | |
1699 | ||
1700 | # combine the two | |
1701 | push(@delta,@colon); | |
1702 | if ($dir<0) { | |
1703 | for ($i=0; $i<=$#delta; $i++) { | |
1704 | $delta[$i] =~ tr/-+/+-/; | |
1705 | } | |
1706 | } | |
1707 | ||
1708 | # form the delta and shift off the valid part | |
1709 | $delta=join(":",@delta); | |
1710 | splice(@args,0,$#a+1); | |
1711 | @$args=@args if (defined $ref and $ref eq "ARRAY"); | |
1712 | last PARSE; | |
1713 | } | |
1714 | ||
1715 | $delta=&Delta_Normalize($delta,$Curr{"Mode"}); | |
1716 | return $delta; | |
1717 | } | |
1718 | ||
1719 | sub UnixDate { | |
1720 | print "DEBUG: UnixDate\n" if ($Curr{"Debug"} =~ /trace/); | |
1721 | my($date,@format)=@_; | |
1722 | local($_)=(); | |
1723 | my($format,%f,$out,@out,$c,$date1,$date2,$tmp)=(); | |
1724 | my($scalar)=(); | |
1725 | $date=&ParseDateString($date); | |
1726 | return if (! $date); | |
1727 | ||
1728 | my($y,$m,$d,$h,$mn,$s)=($f{"Y"},$f{"m"},$f{"d"},$f{"H"},$f{"M"},$f{"S"})= | |
1729 | &Date_Split($date, 1); | |
1730 | $f{"y"}=substr $f{"Y"},2; | |
1731 | &Date_Init() if (! $Curr{"InitDone"}); | |
1732 | ||
1733 | if (! wantarray) { | |
1734 | $format=join(" ",@format); | |
1735 | @format=($format); | |
1736 | $scalar=1; | |
1737 | } | |
1738 | ||
1739 | # month, week | |
1740 | $_=$m; | |
1741 | s/^0//; | |
1742 | $f{"b"}=$f{"h"}=$Lang{$Cnf{"Language"}}{"MonL"}[$_-1]; | |
1743 | $f{"B"}=$Lang{$Cnf{"Language"}}{"MonthL"}[$_-1]; | |
1744 | $_=$m; | |
1745 | s/^0/ /; | |
1746 | $f{"f"}=$_; | |
1747 | $f{"U"}=&Date_WeekOfYear($m,$d,$y,7); | |
1748 | $f{"W"}=&Date_WeekOfYear($m,$d,$y,1); | |
1749 | ||
1750 | # check week 52,53 and 0 | |
1751 | $f{"G"}=$f{"L"}=$y; | |
1752 | if ($f{"W"}>=52 || $f{"U"}>=52) { | |
1753 | my($dd,$mm,$yy)=($d,$m,$y); | |
1754 | $dd+=7; | |
1755 | if ($dd>31) { | |
1756 | $dd-=31; | |
1757 | $mm=1; | |
1758 | $yy++; | |
1759 | if (&Date_WeekOfYear($mm,$dd,$yy,1)==2) { | |
1760 | $f{"G"}=$yy; | |
1761 | $f{"W"}=1; | |
1762 | } | |
1763 | if (&Date_WeekOfYear($mm,$dd,$yy,7)==2) { | |
1764 | $f{"L"}=$yy; | |
1765 | $f{"U"}=1; | |
1766 | } | |
1767 | } | |
1768 | } | |
1769 | if ($f{"W"}==0) { | |
1770 | my($dd,$mm,$yy)=($d,$m,$y); | |
1771 | $dd-=7; | |
1772 | $dd+=31 if ($dd<1); | |
1773 | $yy--; | |
1774 | $mm=12; | |
1775 | $f{"G"}=$yy; | |
1776 | $f{"W"}=&Date_WeekOfYear($mm,$dd,$yy,1)+1; | |
1777 | } | |
1778 | if ($f{"U"}==0) { | |
1779 | my($dd,$mm,$yy)=($d,$m,$y); | |
1780 | $dd-=7; | |
1781 | $dd+=31 if ($dd<1); | |
1782 | $yy--; | |
1783 | $mm=12; | |
1784 | $f{"L"}=$yy; | |
1785 | $f{"U"}=&Date_WeekOfYear($mm,$dd,$yy,7)+1; | |
1786 | } | |
1787 | ||
1788 | $f{"U"}="0".$f{"U"} if (length $f{"U"} < 2); | |
1789 | $f{"W"}="0".$f{"W"} if (length $f{"W"} < 2); | |
1790 | ||
1791 | # day | |
1792 | $f{"j"}=&Date_DayOfYear($m,$d,$y); | |
1793 | $f{"j"} = "0" . $f{"j"} while (length($f{"j"})<3); | |
1794 | $_=$d; | |
1795 | s/^0/ /; | |
1796 | $f{"e"}=$_; | |
1797 | $f{"w"}=&Date_DayOfWeek($m,$d,$y); | |
1798 | $f{"v"}=$Lang{$Cnf{"Language"}}{"WL"}[$f{"w"}-1]; | |
1799 | $f{"v"}=" ".$f{"v"} if (length $f{"v"} < 2); | |
1800 | $f{"a"}=$Lang{$Cnf{"Language"}}{"WkL"}[$f{"w"}-1]; | |
1801 | $f{"A"}=$Lang{$Cnf{"Language"}}{"WeekL"}[$f{"w"}-1]; | |
1802 | $f{"E"}=&Date_DaySuffix($f{"e"}); | |
1803 | ||
1804 | # hour | |
1805 | $_=$h; | |
1806 | s/^0/ /; | |
1807 | $f{"k"}=$_; | |
1808 | $f{"i"}=$f{"k"}+1; | |
1809 | $f{"i"}=$f{"k"}; | |
1810 | $f{"i"}=12 if ($f{"k"}==0); | |
1811 | $f{"i"}=$f{"k"}-12 if ($f{"k"}>12); | |
1812 | $f{"i"}=$f{"i"}-12 if ($f{"i"}>12); | |
1813 | $f{"i"}=" ".$f{"i"} if (length($f{"i"})<2); | |
1814 | $f{"I"}=$f{"i"}; | |
1815 | $f{"I"}=~ s/^ /0/; | |
1816 | $f{"p"}=$Lang{$Cnf{"Language"}}{"AMstr"}; | |
1817 | $f{"p"}=$Lang{$Cnf{"Language"}}{"PMstr"} if ($f{"k"}>11); | |
1818 | ||
1819 | # minute, second, timezone | |
1820 | $f{"o"}=&Date_SecsSince1970($m,$d,$y,$h,$mn,$s); | |
1821 | $f{"s"}=&Date_SecsSince1970GMT($m,$d,$y,$h,$mn,$s); | |
1822 | $f{"Z"}=($Cnf{"ConvTZ"} eq "IGNORE" or $Cnf{"ConvTZ"} eq "") ? | |
1823 | $Cnf{"TZ"} : $Cnf{"ConvTZ"}; | |
1824 | $f{"z"}=($f{"Z"}=~/^[+-]\d{4}/) ? $f{"Z"} : ($Zone{"n2o"}{lc $f{"Z"}} || ""); | |
1825 | ||
1826 | # date, time | |
1827 | $f{"c"}=qq|$f{"a"} $f{"b"} $f{"e"} $h:$mn:$s $y|; | |
1828 | $f{"C"}=$f{"u"}= | |
1829 | qq|$f{"a"} $f{"b"} $f{"e"} $h:$mn:$s $f{"z"} $y|; | |
1830 | $f{"g"}=qq|$f{"a"}, $d $f{"b"} $y $h:$mn:$s $f{"z"}|; | |
1831 | $f{"D"}=$f{"x"}=qq|$m/$d/$f{"y"}|; | |
1832 | $f{"r"}=qq|$f{"I"}:$mn:$s $f{"p"}|; | |
1833 | $f{"R"}=qq|$h:$mn|; | |
1834 | $f{"T"}=$f{"X"}=qq|$h:$mn:$s|; | |
1835 | $f{"V"}=qq|$m$d$h$mn$f{"y"}|; | |
1836 | $f{"Q"}="$y$m$d"; | |
1837 | $f{"q"}=qq|$y$m$d$h$mn$s|; | |
1838 | $f{"P"}=qq|$y$m$d$h:$mn:$s|; | |
1839 | $f{"F"}=qq|$f{"A"}, $f{"B"} $f{"e"}, $f{"Y"}|; | |
1840 | if ($f{"W"}==0) { | |
1841 | $y--; | |
1842 | $tmp=&Date_WeekOfYear(12,31,$y,1); | |
1843 | $tmp="0$tmp" if (length($tmp) < 2); | |
1844 | $f{"J"}=qq|$y-W$tmp-$f{"w"}|; | |
1845 | } else { | |
1846 | $f{"J"}=qq|$f{"G"}-W$f{"W"}-$f{"w"}|; | |
1847 | } | |
1848 | $f{"K"}=qq|$y-$f{"j"}|; | |
1849 | # %l is a special case. Since it requires the use of the calculator | |
1850 | # which requires this routine, an infinite recursion results. To get | |
1851 | # around this, %l is NOT determined every time this is called so the | |
1852 | # recursion breaks. | |
1853 | ||
1854 | # other formats | |
1855 | $f{"n"}="\n"; | |
1856 | $f{"t"}="\t"; | |
1857 | $f{"%"}="%"; | |
1858 | $f{"+"}="+"; | |
1859 | ||
1860 | foreach $format (@format) { | |
1861 | $format=reverse($format); | |
1862 | $out=""; | |
1863 | while ($format ne "") { | |
1864 | $c=chop($format); | |
1865 | if ($c eq "%") { | |
1866 | $c=chop($format); | |
1867 | if ($c eq "l") { | |
1868 | &Date_Init(); | |
1869 | $date1=&DateCalc_DateDelta($Curr{"Now"},"-0:6:0:0:0:0:0"); | |
1870 | $date2=&DateCalc_DateDelta($Curr{"Now"},"+0:6:0:0:0:0:0"); | |
1871 | if (&Date_Cmp($date,$date1)>=0 && &Date_Cmp($date,$date2)<=0) { | |
1872 | $f{"l"}=qq|$f{"b"} $f{"e"} $h:$mn|; | |
1873 | } else { | |
1874 | $f{"l"}=qq|$f{"b"} $f{"e"} $f{"Y"}|; | |
1875 | } | |
1876 | $out .= $f{"$c"}; | |
1877 | } elsif (exists $f{"$c"}) { | |
1878 | $out .= $f{"$c"}; | |
1879 | } else { | |
1880 | $out .= $c; | |
1881 | } | |
1882 | } else { | |
1883 | $out .= $c; | |
1884 | } | |
1885 | } | |
1886 | push(@out,$out); | |
1887 | } | |
1888 | if ($scalar) { | |
1889 | return $out[0]; | |
1890 | } else { | |
1891 | return (@out); | |
1892 | } | |
1893 | } | |
1894 | ||
1895 | # Can't be in "use integer" because we're doing decimal arithmatic | |
1896 | no integer; | |
1897 | sub Delta_Format { | |
1898 | print "DEBUG: Delta_Format\n" if ($Curr{"Debug"} =~ /trace/); | |
1899 | my($delta,$dec,@format)=@_; | |
1900 | $delta=&ParseDateDelta($delta); | |
1901 | return "" if (! $delta); | |
1902 | my(@out,%f,$out,$c1,$c2,$scalar,$format)=(); | |
1903 | local($_)=$delta; | |
1904 | my($y,$M,$w,$d,$h,$m,$s)=&Delta_Split($delta); | |
1905 | # Get rid of positive signs. | |
1906 | ($y,$M,$w,$d,$h,$m,$s)=map { 1*$_; }($y,$M,$w,$d,$h,$m,$s); | |
1907 | ||
1908 | if (defined $dec && $dec>0) { | |
1909 | $dec="%." . ($dec*1) . "f"; | |
1910 | } else { | |
1911 | $dec="%f"; | |
1912 | } | |
1913 | ||
1914 | if (! wantarray) { | |
1915 | $format=join(" ",@format); | |
1916 | @format=($format); | |
1917 | $scalar=1; | |
1918 | } | |
1919 | ||
1920 | # Length of each unit in seconds | |
1921 | my($sl,$ml,$hl,$dl,$wl,$yl)=(); | |
1922 | $sl = 1; | |
1923 | $ml = $sl*60; | |
1924 | $hl = $ml*60; | |
1925 | $dl = $hl*24; | |
1926 | $wl = $dl*7; | |
1927 | $yl = $dl*365.25; | |
1928 | ||
1929 | # The decimal amount of each unit contained in all smaller units | |
1930 | my($yd,$Md,$sd,$md,$hd,$dd,$wd)=(); | |
1931 | if ($M) { | |
1932 | $yd = $M/12; | |
1933 | $Md = 0; | |
1934 | } else { | |
1935 | $yd = ($w*$wl + $d*$dl + $h*$hl + $m*$ml + $s*$sl)/$yl; | |
1936 | $Md = 0; | |
1937 | } | |
1938 | ||
1939 | $wd = ($d*$dl + $h*$hl + $m*$ml + $s*$sl)/$wl; | |
1940 | $dd = ($h*$hl + $m*$ml + $s*$sl)/$dl; | |
1941 | $hd = ($m*$ml + $s*$sl)/$hl; | |
1942 | $md = ($s*$sl)/$ml; | |
1943 | $sd = 0; | |
1944 | ||
1945 | # The amount of each unit contained in higher units. | |
1946 | my($yh,$Mh,$sh,$mh,$hh,$dh,$wh)=(); | |
1947 | $yh = 0; | |
1948 | ||
1949 | if ($M) { | |
1950 | $Mh = ($yh+$y)*12; | |
1951 | $wh = 0; | |
1952 | $dh = ($wh+$w)*7; | |
1953 | } else { | |
1954 | $Mh = 0; | |
1955 | $wh = ($yh+$y)*365.25/7; | |
1956 | $dh = ($yh+$y)*365.25 + $w*7; | |
1957 | } | |
1958 | ||
1959 | $hh = ($dh+$d)*24; | |
1960 | $mh = ($hh+$h)*60; | |
1961 | $sh = ($mh+$m)*60; | |
1962 | ||
1963 | # Set up the formats | |
1964 | ||
1965 | $f{"yv"} = $y; | |
1966 | $f{"Mv"} = $M; | |
1967 | $f{"wv"} = $w; | |
1968 | $f{"dv"} = $d; | |
1969 | $f{"hv"} = $h; | |
1970 | $f{"mv"} = $m; | |
1971 | $f{"sv"} = $s; | |
1972 | ||
1973 | $f{"yh"} = $y+$yh; | |
1974 | $f{"Mh"} = $M+$Mh; | |
1975 | $f{"wh"} = $w+$wh; | |
1976 | $f{"dh"} = $d+$dh; | |
1977 | $f{"hh"} = $h+$hh; | |
1978 | $f{"mh"} = $m+$mh; | |
1979 | $f{"sh"} = $s+$sh; | |
1980 | ||
1981 | $f{"yd"} = sprintf($dec,$y+$yd); | |
1982 | $f{"Md"} = sprintf($dec,$M+$Md); | |
1983 | $f{"wd"} = sprintf($dec,$w+$wd); | |
1984 | $f{"dd"} = sprintf($dec,$d+$dd); | |
1985 | $f{"hd"} = sprintf($dec,$h+$hd); | |
1986 | $f{"md"} = sprintf($dec,$m+$md); | |
1987 | $f{"sd"} = sprintf($dec,$s+$sd); | |
1988 | ||
1989 | $f{"yt"} = sprintf($dec,$yh+$y+$yd); | |
1990 | $f{"Mt"} = sprintf($dec,$Mh+$M+$Md); | |
1991 | $f{"wt"} = sprintf($dec,$wh+$w+$wd); | |
1992 | $f{"dt"} = sprintf($dec,$dh+$d+$dd); | |
1993 | $f{"ht"} = sprintf($dec,$hh+$h+$hd); | |
1994 | $f{"mt"} = sprintf($dec,$mh+$m+$md); | |
1995 | $f{"st"} = sprintf($dec,$sh+$s+$sd); | |
1996 | ||
1997 | $f{"%"} = "%"; | |
1998 | ||
1999 | foreach $format (@format) { | |
2000 | $format=reverse($format); | |
2001 | $out=""; | |
2002 | PARSE: while ($format) { | |
2003 | $c1=chop($format); | |
2004 | if ($c1 eq "%") { | |
2005 | $c1=chop($format); | |
2006 | if (exists($f{$c1})) { | |
2007 | $out .= $f{$c1}; | |
2008 | next PARSE; | |
2009 | } | |
2010 | $c2=chop($format); | |
2011 | if (exists($f{"$c1$c2"})) { | |
2012 | $out .= $f{"$c1$c2"}; | |
2013 | next PARSE; | |
2014 | } | |
2015 | $out .= $c1; | |
2016 | $format .= $c2; | |
2017 | } else { | |
2018 | $out .= $c1; | |
2019 | } | |
2020 | } | |
2021 | push(@out,$out); | |
2022 | } | |
2023 | if ($scalar) { | |
2024 | return $out[0]; | |
2025 | } else { | |
2026 | return (@out); | |
2027 | } | |
2028 | } | |
2029 | use integer; | |
2030 | ||
2031 | sub ParseRecur { | |
2032 | print "DEBUG: ParseRecur\n" if ($Curr{"Debug"} =~ /trace/); | |
2033 | &Date_Init() if (! $Curr{"InitDone"}); | |
2034 | ||
2035 | my($recur,$dateb,$date0,$date1,$flag)=@_; | |
2036 | local($_)=$recur; | |
2037 | ||
2038 | my($recur_0,$recur_1,@recur0,@recur1)=(); | |
2039 | my(@tmp,$tmp,$each,$num,$y,$m,$d,$w,$h,$mn,$s,$delta,$y0,$y1,$yb)=(); | |
2040 | my($yy,$n,$dd,@d,@tmp2,$date,@date,@w,@tmp3,@m,@y,$tmp2,$d2,@flags)=(); | |
2041 | ||
2042 | # $date0, $date1, $dateb, $flag : passed in (these are always the final say | |
2043 | # in determining whether a date matches a | |
2044 | # recurrence IF they are present. | |
2045 | # $date_b, $date_0, $date_1 : if a value can be determined from the | |
2046 | # $flag_t recurrence, they are stored here. | |
2047 | # | |
2048 | # If values can be determined from the recurrence AND are passed in, the | |
2049 | # following are used: | |
2050 | # max($date0,$date_0) i.e. the later of the two dates | |
2051 | # min($date1,$date_1) i.e. the earlier of the two dates | |
2052 | # | |
2053 | # The base date that is used is the first one defined from | |
2054 | # $dateb $date_b | |
2055 | # The base date is only used if necessary (as determined by the recur). | |
2056 | # For example, "every other friday" requires a base date, but "2nd | |
2057 | # friday of every month" doesn't. | |
2058 | ||
2059 | my($date_b,$date_0,$date_1,$flag_t); | |
2060 | ||
2061 | # | |
2062 | # Check the arguments passed in. | |
2063 | # | |
2064 | ||
2065 | $date0="" if (! defined $date0); | |
2066 | $date1="" if (! defined $date1); | |
2067 | $dateb="" if (! defined $dateb); | |
2068 | $flag ="" if (! defined $flag); | |
2069 | ||
2070 | if ($dateb) { | |
2071 | $dateb=&ParseDateString($dateb); | |
2072 | return "" if (! $dateb); | |
2073 | } | |
2074 | if ($date0) { | |
2075 | $date0=&ParseDateString($date0); | |
2076 | return "" if (! $date0); | |
2077 | } | |
2078 | if ($date1) { | |
2079 | $date1=&ParseDateString($date1); | |
2080 | return "" if (! $date1); | |
2081 | } | |
2082 | ||
2083 | # | |
2084 | # Parse the recur. $date_b, $date_0, and $date_e are values obtained | |
2085 | # from the recur. | |
2086 | # | |
2087 | ||
2088 | @tmp=&Recur_Split($_); | |
2089 | ||
2090 | if (@tmp) { | |
2091 | ($recur_0,$recur_1,$flag_t,$date_b,$date_0,$date_1)=@tmp; | |
2092 | $recur_0 = "" if (! defined $recur_0); | |
2093 | $recur_1 = "" if (! defined $recur_1); | |
2094 | $flag_t = "" if (! defined $flag_t); | |
2095 | $date_b = "" if (! defined $date_b); | |
2096 | $date_0 = "" if (! defined $date_0); | |
2097 | $date_1 = "" if (! defined $date_1); | |
2098 | ||
2099 | @recur0 = split(/:/,$recur_0); | |
2100 | @recur1 = split(/:/,$recur_1); | |
2101 | return "" if ($#recur0 + $#recur1 + 2 != 7); | |
2102 | ||
2103 | if ($date_b) { | |
2104 | $date_b=&ParseDateString($date_b); | |
2105 | return "" if (! $date_b); | |
2106 | } | |
2107 | if ($date_0) { | |
2108 | $date_0=&ParseDateString($date_0); | |
2109 | return "" if (! $date_0); | |
2110 | } | |
2111 | if ($date_1) { | |
2112 | $date_1=&ParseDateString($date_1); | |
2113 | return "" if (! $date_1); | |
2114 | } | |
2115 | ||
2116 | } else { | |
2117 | ||
2118 | my($mmm)='\s*'.$Lang{$Cnf{"Language"}}{"Month"}; # \s*(jan|january|...) | |
2119 | my(%mmm)=%{ $Lang{$Cnf{"Language"}}{"MonthH"} }; # { jan=>1, ... } | |
2120 | my($wkexp)='\s*'.$Lang{$Cnf{"Language"}}{"Week"}; # \s*(mon|monday|...) | |
2121 | my(%week)=%{ $Lang{$Cnf{"Language"}}{"WeekH"} }; # { monday=>1, ... } | |
2122 | my($day)='\s*'.$Lang{$Cnf{"Language"}}{"Dabb"}; # \s*(?:d|day|days) | |
2123 | my($month)='\s*'.$Lang{$Cnf{"Language"}}{"Mabb"}; # \s*(?:mon|month|months) | |
2124 | my($week)='\s*'.$Lang{$Cnf{"Language"}}{"Wabb"}; # \s*(?:w|wk|week|weeks) | |
2125 | my($daysexp)=$Lang{$Cnf{"Language"}}{"DoM"}; # (1st|first|...31st) | |
2126 | my(%dayshash)=%{ $Lang{$Cnf{"Language"}}{"DoMH"} }; | |
2127 | # { 1st=>1,first=>1,...} | |
2128 | my($of)='\s*'.$Lang{$Cnf{"Language"}}{"Of"}; # \s*(?:in|of) | |
2129 | my($lastexp)=$Lang{$Cnf{"Language"}}{"Last"}; # (?:last) | |
2130 | my($each)=$Lang{$Cnf{"Language"}}{"Each"}; # (?:each|every) | |
2131 | ||
2132 | my($D)='\s*(\d+)'; | |
2133 | my($Y)='\s*(\d{4}|\d{2})'; | |
2134 | ||
2135 | # Change 1st to 1 | |
2136 | if (/(^|[^a-z])$daysexp($|[^a-z])/i) { | |
2137 | $tmp=lc($2); | |
2138 | $tmp=$dayshash{"$tmp"}; | |
2139 | s/(^|[^a-z])$daysexp($|[^a-z])/$1 $tmp $3/i; | |
2140 | } | |
2141 | s/\s*$//; | |
2142 | ||
2143 | # Get rid of "each" | |
2144 | if (/(^|[^a-z])$each($|[^a-z])/i) { | |
2145 | s/(^|[^a-z])$each($|[^a-z])/$1 $2/i; | |
2146 | $each=1; | |
2147 | } else { | |
2148 | $each=0; | |
2149 | } | |
2150 | ||
2151 | if ($each) { | |
2152 | ||
2153 | if (/^$D?$day(?:$of$mmm?$Y)?$/i || | |
2154 | /^$D?$day(?:$of$mmm())?$/i) { | |
2155 | # every [2nd] day in [june] 1997 | |
2156 | # every [2nd] day [in june] | |
2157 | ($num,$m,$y)=($1,$2,$3); | |
2158 | $num=1 if (! defined $num); | |
2159 | $m="" if (! defined $m); | |
2160 | $y="" if (! defined $y); | |
2161 | ||
2162 | $y=$Curr{"Y"} if (! $y); | |
2163 | if ($m) { | |
2164 | $m=$mmm{lc($m)}; | |
2165 | $date_0=&Date_Join($y,$m,1,0,0,0); | |
2166 | $date_1=&DateCalc_DateDelta($date_0,"+0:1:0:0:0:0:0",0); | |
2167 | } else { | |
2168 | $date_0=&Date_Join($y, 1,1,0,0,0); | |
2169 | $date_1=&Date_Join($y+1,1,1,0,0,0); | |
2170 | } | |
2171 | $date_b=&DateCalc($date_0,"-0:0:0:1:0:0:0",0); | |
2172 | @recur0=(0,0,0,$num,0,0,0); | |
2173 | @recur1=(); | |
2174 | ||
2175 | } elsif (/^$D$day?$of$month(?:$of?$Y)?$/) { | |
2176 | # 2nd [day] of every month [in 1997] | |
2177 | ($num,$y)=($1,$2); | |
2178 | $y=$Curr{"Y"} if (! $y); | |
2179 | ||
2180 | $date_0=&Date_Join($y, 1,1,0,0,0); | |
2181 | $date_1=&Date_Join($y+1,1,1,0,0,0); | |
2182 | $date_b=$date_0; | |
2183 | ||
2184 | @recur0=(0,1,0); | |
2185 | @recur1=($num,0,0,0); | |
2186 | ||
2187 | } elsif (/^$D$wkexp$of$month(?:$of?$Y)?$/ || | |
2188 | /^($lastexp)$wkexp$of$month(?:$of?$Y)?$/) { | |
2189 | # 2nd tuesday of every month [in 1997] | |
2190 | # last tuesday of every month [in 1997] | |
2191 | ($num,$d,$y)=($1,$2,$3); | |
2192 | $y=$Curr{"Y"} if (! $y); | |
2193 | $d=$week{lc($d)}; | |
2194 | $num=-1 if ($num !~ /^$D$/); | |
2195 | ||
2196 | $date_0=&Date_Join($y,1,1,0,0,0); | |
2197 | $date_1=&Date_Join($y+1,1,1,0,0,0); | |
2198 | $date_b=$date_0; | |
2199 | ||
2200 | @recur0=(0,1); | |
2201 | @recur1=($num,$d,0,0,0); | |
2202 | ||
2203 | } elsif (/^$D?$wkexp(?:$of$mmm?$Y)?$/i || | |
2204 | /^$D?$wkexp(?:$of$mmm())?$/i) { | |
2205 | # every tuesday in june 1997 | |
2206 | # every 2nd tuesday in june 1997 | |
2207 | ($num,$d,$m,$y)=($1,$2,$3,$4); | |
2208 | $y=$Curr{"Y"} if (! $y); | |
2209 | $num=1 if (! defined $num); | |
2210 | $m="" if (! defined $m); | |
2211 | $d=$week{lc($d)}; | |
2212 | ||
2213 | if ($m) { | |
2214 | $m=$mmm{lc($m)}; | |
2215 | $date_0=&Date_Join($y,$m,1,0,0,0); | |
2216 | $date_1=&DateCalc_DateDelta($date_0,"+0:1:0:0:0:0:0",0); | |
2217 | } else { | |
2218 | $date_0=&Date_Join($y,1,1,0,0,0); | |
2219 | $date_1=&Date_Join($y+1,1,1,0,0,0); | |
2220 | } | |
2221 | $date_b=&DateCalc($date_0,"-0:0:0:1:0:0:0",0); | |
2222 | ||
2223 | @recur0=(0,0,$num); | |
2224 | @recur1=($d,0,0,0); | |
2225 | ||
2226 | } else { | |
2227 | return ""; | |
2228 | } | |
2229 | ||
2230 | $date_0="" if ($date0); | |
2231 | $date_1="" if ($date1); | |
2232 | } else { | |
2233 | return ""; | |
2234 | } | |
2235 | } | |
2236 | ||
2237 | # | |
2238 | # Override with any values passed in | |
2239 | # | |
2240 | ||
2241 | if ($date0 && $date_0) { | |
2242 | $date0=( &Date_Cmp($date0,$date_0) > 1 ? $date0 : $date_0); | |
2243 | } elsif ($date_0) { | |
2244 | $date0 = $date_0; | |
2245 | } | |
2246 | ||
2247 | if ($date1 && $date_1) { | |
2248 | $date1=( &Date_Cmp($date1,$date_1) > 1 ? $date_1 : $date1); | |
2249 | } elsif ($date_1) { | |
2250 | $date1 = $date_1; | |
2251 | } | |
2252 | ||
2253 | $dateb=$date_b if (! $dateb); | |
2254 | ||
2255 | if ($flag =~ s/^\+//) { | |
2256 | if ($flag_t) { | |
2257 | $flag="$flag_t,$flag"; | |
2258 | } | |
2259 | } | |
2260 | $flag =$flag_t if (! $flag && $flag_t); | |
2261 | ||
2262 | if (! wantarray) { | |
2263 | $tmp = join(":",@recur0); | |
2264 | $tmp .= "*" . join(":",@recur1) if (@recur1); | |
2265 | $tmp .= "*$flag*$dateb*$date0*$date1"; | |
2266 | return $tmp; | |
2267 | } | |
2268 | if (@recur0) { | |
2269 | return () if (! $date0 || ! $date1); # dateb is NOT required in all case | |
2270 | } | |
2271 | ||
2272 | # | |
2273 | # Some flags affect parsing. | |
2274 | # | |
2275 | ||
2276 | @flags = split(/,/,$flag); | |
2277 | my($MDn) = 0; | |
2278 | my($MWn) = 7; | |
2279 | my($f); | |
2280 | foreach $f (@flags) { | |
2281 | if ($f =~ /^MW([1-7])$/i) { | |
2282 | $MWn=$1; | |
2283 | $MDn=0; | |
2284 | ||
2285 | } elsif ($f =~ /^MD([1-7])$/i) { | |
2286 | $MDn=$1; | |
2287 | $MWn=0; | |
2288 | ||
2289 | } elsif ($f =~ /^EASTER$/i) { | |
2290 | ($y,$m,$w,$d,$h,$mn,$s)=(@recur0,@recur1); | |
2291 | # We want something that will return Jan 1 for the given years. | |
2292 | if ($#recur0==-1) { | |
2293 | @recur1=($y,1,0,1,$h,$mn,$s); | |
2294 | } elsif ($#recur0<=3) { | |
2295 | @recur0=($y,0,0,0); | |
2296 | @recur1=($h,$mn,$s); | |
2297 | } elsif ($#recur0==4) { | |
2298 | @recur0=($y,0,0,0,0); | |
2299 | @recur1=($mn,$s); | |
2300 | } elsif ($#recur0==5) { | |
2301 | @recur0=($y,0,0,0,0,0); | |
2302 | @recur1=($s); | |
2303 | } else { | |
2304 | @recur0=($y,0,0,0,0,0,0); | |
2305 | } | |
2306 | } | |
2307 | } | |
2308 | ||
2309 | # | |
2310 | # Determine the dates referenced by the recur. Also, fix the base date | |
2311 | # as necessary for the recurrences which require it. | |
2312 | # | |
2313 | ||
2314 | ($y,$m,$w,$d,$h,$mn,$s)=(@recur0,@recur1); | |
2315 | @y=@m=@w=@d=(); | |
2316 | my(@time)=($h,$mn,$s); | |
2317 | ||
2318 | RECUR: while (1) { | |
2319 | ||
2320 | if ($#recur0==-1) { | |
2321 | # * Y-M-W-D-H-MN-S | |
2322 | if ($y eq "0") { | |
2323 | push(@recur0,0); | |
2324 | shift(@recur1); | |
2325 | ||
2326 | } else { | |
2327 | @y=&ReturnList($y); | |
2328 | foreach $y (@y) { | |
2329 | $y=&Date_FixYear($y) if (length($y)==2); | |
2330 | return () if (length($y)!=4 || ! &IsInt($y)); | |
2331 | } | |
2332 | @y=sort { $a<=>$b } @y; | |
2333 | ||
2334 | $date0=&ParseDate("0000-01-01") if (! $date0); | |
2335 | $date1=&ParseDate("9999-12-31 23:59:59") if (! $date1); | |
2336 | ||
2337 | if ($m eq "0" and $w eq "0") { | |
2338 | # * Y-0-0-0-H-MN-S | |
2339 | # * Y-0-0-DOY-H-MN-S | |
2340 | if ($d eq "0") { | |
2341 | @d=(1); | |
2342 | } else { | |
2343 | @d=&ReturnList($d); | |
2344 | return () if (! @d); | |
2345 | foreach $d (@d) { | |
2346 | return () if (! &IsInt($d,1,366)); | |
2347 | } | |
2348 | @d=sort { $a<=>$b } (@d); | |
2349 | } | |
2350 | ||
2351 | @date=(); | |
2352 | foreach $yy (@y) { | |
2353 | foreach $d (@d) { | |
2354 | ($y,$m,$dd)=&Date_NthDayOfYear($yy,$d); | |
2355 | push(@date, &Date_Join($y,$m,$dd,0,0,0)); | |
2356 | } | |
2357 | } | |
2358 | last RECUR; | |
2359 | ||
2360 | } elsif ($w eq "0") { | |
2361 | # * Y-M-0-0-H-MN-S | |
2362 | # * Y-M-0-DOM-H-MN-S | |
2363 | ||
2364 | @m=&ReturnList($m); | |
2365 | return () if (! @m); | |
2366 | foreach $m (@m) { | |
2367 | return () if (! &IsInt($m,1,12)); | |
2368 | } | |
2369 | @m=sort { $a<=>$b } (@m); | |
2370 | ||
2371 | if ($d eq "0") { | |
2372 | @d=(1); | |
2373 | } else { | |
2374 | @d=&ReturnList($d); | |
2375 | return () if (! @d); | |
2376 | foreach $d (@d) { | |
2377 | return () if (! &IsInt($d,1,31)); | |
2378 | } | |
2379 | @d=sort { $a<=>$b } (@d); | |
2380 | } | |
2381 | ||
2382 | @date=(); | |
2383 | foreach $y (@y) { | |
2384 | foreach $m (@m) { | |
2385 | foreach $d (@d) { | |
2386 | $date=&Date_Join($y,$m,$d,0,0,0); | |
2387 | push(@date,$date) if ($d<29 || &Date_Split($date)); | |
2388 | } | |
2389 | } | |
2390 | } | |
2391 | last RECUR; | |
2392 | ||
2393 | } elsif ($m eq "0") { | |
2394 | # * Y-0-WOY-DOW-H-MN-S | |
2395 | # * Y-0-WOY-0-H-MN-S | |
2396 | @w=&ReturnList($w); | |
2397 | return () if (! @w); | |
2398 | foreach $w (@w) { | |
2399 | return () if (! &IsInt($w,1,53)); | |
2400 | } | |
2401 | ||
2402 | if ($d eq "0") { | |
2403 | @d=($Cnf{"FirstDay"}); | |
2404 | } else { | |
2405 | @d=&ReturnList($d); | |
2406 | return () if (! @d); | |
2407 | foreach $d (@d) { | |
2408 | return () if (! &IsInt($d,1,7)); | |
2409 | } | |
2410 | @d=sort { $a<=>$b } (@d); | |
2411 | } | |
2412 | ||
2413 | @date=(); | |
2414 | foreach $y (@y) { | |
2415 | foreach $w (@w) { | |
2416 | $w="0$w" if (length($w)==1); | |
2417 | foreach $d (@d) { | |
2418 | $date=&ParseDateString("$y-W$w-$d"); | |
2419 | push(@date,$date); | |
2420 | } | |
2421 | } | |
2422 | } | |
2423 | last RECUR; | |
2424 | ||
2425 | } else { | |
2426 | # * Y-M-WOM-DOW-H-MN-S | |
2427 | # * Y-M-WOM-0-H-MN-S | |
2428 | ||
2429 | @m=&ReturnList($m); | |
2430 | return () if (! @m); | |
2431 | foreach $m (@m) { | |
2432 | return () if (! &IsInt($m,1,12)); | |
2433 | } | |
2434 | @m=sort { $a<=>$b } (@m); | |
2435 | ||
2436 | @w=&ReturnList($w); | |
2437 | ||
2438 | if ($d eq "0") { | |
2439 | @d=(); | |
2440 | } else { | |
2441 | @d=&ReturnList($d); | |
2442 | } | |
2443 | ||
2444 | @date=&Date_Recur_WoM(\@y,\@m,\@w,\@d,$MWn,$MDn); | |
2445 | last RECUR; | |
2446 | } | |
2447 | } | |
2448 | } | |
2449 | ||
2450 | if ($#recur0==0) { | |
2451 | # Y * M-W-D-H-MN-S | |
2452 | $n=$y; | |
2453 | $n=1 if ($n==0); | |
2454 | ||
2455 | @m=&ReturnList($m); | |
2456 | return () if (! @m); | |
2457 | foreach $m (@m) { | |
2458 | return () if (! &IsInt($m,1,12)); | |
2459 | } | |
2460 | @m=sort { $a<=>$b } (@m); | |
2461 | ||
2462 | if ($m eq "0") { | |
2463 | # Y * 0-W-D-H-MN-S (equiv to Y-0 * W-D-H-MN-S) | |
2464 | push(@recur0,0); | |
2465 | shift(@recur1); | |
2466 | ||
2467 | } elsif ($w eq "0") { | |
2468 | # Y * M-0-DOM-H-MN-S | |
2469 | return () if (! $dateb); | |
2470 | $d=1 if ($d eq "0"); | |
2471 | ||
2472 | @d=&ReturnList($d); | |
2473 | return () if (! @d); | |
2474 | foreach $d (@d) { | |
2475 | return () if (! &IsInt($d,1,31)); | |
2476 | } | |
2477 | @d=sort { $a<=>$b } (@d); | |
2478 | ||
2479 | # We need to find years that are a multiple of $n from $y(base) | |
2480 | ($y0)=( &Date_Split($date0, 1) )[0]; | |
2481 | ($y1)=( &Date_Split($date1, 1) )[0]; | |
2482 | ($yb)=( &Date_Split($dateb, 1) )[0]; | |
2483 | @date=(); | |
2484 | for ($yy=$y0; $yy<=$y1; $yy++) { | |
2485 | if (($yy-$yb)%$n == 0) { | |
2486 | foreach $m (@m) { | |
2487 | foreach $d (@d) { | |
2488 | $date=&Date_Join($yy,$m,$d,0,0,0); | |
2489 | push(@date,$date) if ($d<29 || &Date_Split($date)); | |
2490 | } | |
2491 | } | |
2492 | } | |
2493 | } | |
2494 | last RECUR; | |
2495 | ||
2496 | } else { | |
2497 | # Y * M-WOM-DOW-H-MN-S | |
2498 | # Y * M-WOM-0-H-MN-S | |
2499 | return () if (! $dateb); | |
2500 | @m=&ReturnList($m); | |
2501 | @w=&ReturnList($w); | |
2502 | if ($d eq "0") { | |
2503 | @d=(); | |
2504 | } else { | |
2505 | @d=&ReturnList($d); | |
2506 | } | |
2507 | ||
2508 | ($y0)=( &Date_Split($date0, 1) )[0]; | |
2509 | ($y1)=( &Date_Split($date1, 1) )[0]; | |
2510 | ($yb)=( &Date_Split($dateb, 1) )[0]; | |
2511 | @y=(); | |
2512 | for ($yy=$y0; $yy<=$y1; $yy++) { | |
2513 | if (($yy-$yb)%$n == 0) { | |
2514 | push(@y,$yy); | |
2515 | } | |
2516 | } | |
2517 | ||
2518 | @date=&Date_Recur_WoM(\@y,\@m,\@w,\@d,$MWn,$MDn); | |
2519 | last RECUR; | |
2520 | } | |
2521 | } | |
2522 | ||
2523 | if ($#recur0==1) { | |
2524 | # Y-M * W-D-H-MN-S | |
2525 | ||
2526 | if ($w eq "0") { | |
2527 | # Y-M * 0-D-H-MN-S (equiv to Y-M-0 * D-H-MN-S) | |
2528 | push(@recur0,0); | |
2529 | shift(@recur1); | |
2530 | ||
2531 | } elsif ($m==0) { | |
2532 | # Y-0 * WOY-0-H-MN-S | |
2533 | # Y-0 * WOY-DOW-H-MN-S | |
2534 | return () if (! $dateb); | |
2535 | $n=$y; | |
2536 | $n=1 if ($n==0); | |
2537 | ||
2538 | @w=&ReturnList($w); | |
2539 | return () if (! @w); | |
2540 | foreach $w (@w) { | |
2541 | return () if (! &IsInt($w,1,53)); | |
2542 | } | |
2543 | ||
2544 | if ($d eq "0") { | |
2545 | @d=($Cnf{"FirstDay"}); | |
2546 | } else { | |
2547 | @d=&ReturnList($d); | |
2548 | return () if (! @d); | |
2549 | foreach $d (@d) { | |
2550 | return () if (! &IsInt($d,1,7)); | |
2551 | } | |
2552 | @d=sort { $a<=>$b } (@d); | |
2553 | } | |
2554 | ||
2555 | # We need to find years that are a multiple of $n from $y(base) | |
2556 | ($y0)=( &Date_Split($date0, 1) )[0]; | |
2557 | ($y1)=( &Date_Split($date1, 1) )[0]; | |
2558 | ($yb)=( &Date_Split($dateb, 1) )[0]; | |
2559 | @date=(); | |
2560 | for ($yy=$y0; $yy<=$y1; $yy++) { | |
2561 | if (($yy-$yb)%$n == 0) { | |
2562 | foreach $w (@w) { | |
2563 | $w="0$w" if (length($w)==1); | |
2564 | foreach $tmp (@d) { | |
2565 | $date=&ParseDateString("$yy-W$w-$tmp"); | |
2566 | push(@date,$date); | |
2567 | } | |
2568 | } | |
2569 | } | |
2570 | } | |
2571 | last RECUR; | |
2572 | ||
2573 | } else { | |
2574 | # Y-M * WOM-0-H-MN-S | |
2575 | # Y-M * WOM-DOW-H-MN-S | |
2576 | return () if (! $dateb); | |
2577 | @tmp=(@recur0); | |
2578 | push(@tmp,0) while ($#tmp<6); | |
2579 | $delta=join(":",@tmp); | |
2580 | @tmp=&Date_Recur($date0,$date1,$dateb,$delta); | |
2581 | ||
2582 | @w=&ReturnList($w); | |
2583 | @m=(); | |
2584 | if ($d eq "0") { | |
2585 | @d=(); | |
2586 | } else { | |
2587 | @d=&ReturnList($d); | |
2588 | } | |
2589 | ||
2590 | @date=&Date_Recur_WoM(\@tmp,\@m,\@w,\@d,$MWn,$MDn); | |
2591 | last RECUR; | |
2592 | } | |
2593 | } | |
2594 | ||
2595 | if ($#recur0==2) { | |
2596 | # Y-M-W * D-H-MN-S | |
2597 | ||
2598 | if ($d eq "0") { | |
2599 | # Y-M-W * 0-H-MN-S | |
2600 | return () if (! $dateb); | |
2601 | $y=1 if ($y==0 && $m==0 && $w==0); | |
2602 | $delta="$y:$m:$w:0:0:0:0"; | |
2603 | @date=&Date_Recur($date0,$date1,$dateb,$delta); | |
2604 | last RECUR; | |
2605 | ||
2606 | } elsif ($m==0 && $w==0) { | |
2607 | # Y-0-0 * DOY-H-MN-S | |
2608 | $y=1 if ($y==0); | |
2609 | $n=$y; | |
2610 | return () if (! $dateb && $y!=1); | |
2611 | ||
2612 | @d=&ReturnList($d); | |
2613 | return () if (! @d); | |
2614 | foreach $d (@d) { | |
2615 | return () if (! &IsInt($d,1,366)); | |
2616 | } | |
2617 | @d=sort { $a<=>$b } (@d); | |
2618 | ||
2619 | # We need to find years that are a multiple of $n from $y(base) | |
2620 | ($y0)=( &Date_Split($date0, 1) )[0]; | |
2621 | ($y1)=( &Date_Split($date1, 1) )[0]; | |
2622 | ($yb)=( &Date_Split($dateb, 1) )[0]; | |
2623 | @date=(); | |
2624 | for ($yy=$y0; $yy<=$y1; $yy++) { | |
2625 | if (($yy-$yb)%$n == 0) { | |
2626 | foreach $d (@d) { | |
2627 | ($y,$m,$dd)=&Date_NthDayOfYear($yy,$d); | |
2628 | push(@date, &Date_Join($y,$m,$dd,0,0,0)); | |
2629 | } | |
2630 | } | |
2631 | } | |
2632 | last RECUR; | |
2633 | ||
2634 | } elsif ($w>0) { | |
2635 | # Y-M-W * DOW-H-MN-S | |
2636 | return () if (! $dateb); | |
2637 | @tmp=(@recur0); | |
2638 | push(@tmp,0) while ($#tmp<6); | |
2639 | $delta=join(":",@tmp); | |
2640 | ||
2641 | @d=&ReturnList($d); | |
2642 | return () if (! @d); | |
2643 | foreach $d (@d) { | |
2644 | return () if (! &IsInt($d,1,7)); | |
2645 | } | |
2646 | ||
2647 | # Find out what DofW the basedate is. | |
2648 | @tmp2=&Date_Split($dateb, 1); | |
2649 | $tmp=&Date_DayOfWeek($tmp2[1],$tmp2[2],$tmp2[0]); | |
2650 | ||
2651 | @date=(); | |
2652 | foreach $d (@d) { | |
2653 | $date_b=$dateb; | |
2654 | # Move basedate to DOW | |
2655 | if ($d != $tmp) { | |
2656 | if (($tmp>=$Cnf{"FirstDay"} && $d<$Cnf{"FirstDay"}) || | |
2657 | ($tmp>=$Cnf{"FirstDay"} && $d>$tmp) || | |
2658 | ($tmp<$d && $d<$Cnf{"FirstDay"})) { | |
2659 | $date_b=&Date_GetNext($date_b,$d); | |
2660 | } else { | |
2661 | $date_b=&Date_GetPrev($date_b,$d); | |
2662 | } | |
2663 | } | |
2664 | push(@date,&Date_Recur($date0,$date1,$date_b,$delta)); | |
2665 | } | |
2666 | @date=sort(@date); | |
2667 | last RECUR; | |
2668 | ||
2669 | } elsif ($m>0) { | |
2670 | # Y-M-0 * DOM-H-MN-S | |
2671 | return () if (! $dateb); | |
2672 | @tmp=(@recur0); | |
2673 | push(@tmp,0) while ($#tmp<6); | |
2674 | $delta=join(":",@tmp); | |
2675 | ||
2676 | @d=&ReturnList($d); | |
2677 | return () if (! @d); | |
2678 | foreach $d (@d) { | |
2679 | return () if (! &IsInt($d,-31,31) || $d==0); | |
2680 | } | |
2681 | @d=sort { $a<=>$b } (@d); | |
2682 | ||
2683 | @tmp2=&Date_Recur($date0,$date1,$dateb,$delta); | |
2684 | @date=(); | |
2685 | foreach $date (@tmp2) { | |
2686 | ($y,$m)=( &Date_Split($date, 1) )[0..1]; | |
2687 | $tmp2=&Date_DaysInMonth($m,$y); | |
2688 | foreach $d (@d) { | |
2689 | $d2=$d; | |
2690 | $d2=$tmp2+1+$d if ($d<0); | |
2691 | push(@date,&Date_Join($y,$m,$d2,0,0,0)) if ($d2<=$tmp2); | |
2692 | } | |
2693 | } | |
2694 | @date=sort (@date); | |
2695 | last RECUR; | |
2696 | ||
2697 | } else { | |
2698 | return (); | |
2699 | } | |
2700 | } | |
2701 | ||
2702 | if ($#recur0>2) { | |
2703 | # Y-M-W-D * H-MN-S | |
2704 | # Y-M-W-D-H * MN-S | |
2705 | # Y-M-W-D-H-MN * S | |
2706 | # Y-M-W-D-H-S | |
2707 | return () if (! $dateb); | |
2708 | @tmp=(@recur0); | |
2709 | push(@tmp,0) while ($#tmp<6); | |
2710 | $delta=join(":",@tmp); | |
2711 | return () if ($delta !~ /[1-9]/); # return if "0:0:0:0:0:0:0" | |
2712 | @date=&Date_Recur($date0,$date1,$dateb,$delta); | |
2713 | if (@recur1) { | |
2714 | unshift(@recur1,-1) while ($#recur1<2); | |
2715 | @time=@recur1; | |
2716 | } else { | |
2717 | shift(@date); | |
2718 | pop(@date); | |
2719 | @time=(); | |
2720 | } | |
2721 | } | |
2722 | ||
2723 | last RECUR; | |
2724 | } | |
2725 | @date=&Date_RecurSetTime($date0,$date1,\@date,@time) if (@time); | |
2726 | ||
2727 | # | |
2728 | # We've got a list of dates. Operate on them with the flags. | |
2729 | # | |
2730 | ||
2731 | my($sign,$forw,$today,$df,$db,$work,$i); | |
2732 | if (@flags) { | |
2733 | FLAG: foreach $f (@flags) { | |
2734 | $f = uc($f); | |
2735 | ||
2736 | if ($f =~ /^(P|N)(D|T)([1-7])$/) { | |
2737 | @tmp=($1,$2,$3); | |
2738 | $forw =($tmp[0] eq "P" ? 0 : 1); | |
2739 | $today=($tmp[1] eq "D" ? 0 : 1); | |
2740 | $d=$tmp[2]; | |
2741 | @tmp=(); | |
2742 | foreach $date (@date) { | |
2743 | if ($forw) { | |
2744 | push(@tmp, &Date_GetNext($date,$d,$today)); | |
2745 | } else { | |
2746 | push(@tmp, &Date_GetPrev($date,$d,$today)); | |
2747 | } | |
2748 | } | |
2749 | @date=@tmp; | |
2750 | next FLAG; | |
2751 | } | |
2752 | ||
2753 | # We want to go forward exact amounts of time instead of | |
2754 | # business mode calculations so that we don't change the time | |
2755 | # (which may have been set in the recur). | |
2756 | if ($f =~ /^(F|B)(D|W)(\d+)$/) { | |
2757 | @tmp=($1,$2,$3); | |
2758 | $sign="+"; | |
2759 | $sign="-" if ($tmp[0] eq "B"); | |
2760 | $work=0; | |
2761 | $work=1 if ($tmp[1] eq "W"); | |
2762 | $n=$tmp[2]; | |
2763 | @tmp=(); | |
2764 | foreach $date (@date) { | |
2765 | for ($i=1; $i<=$n; $i++) { | |
2766 | while (1) { | |
2767 | $date=&DateCalc($date,"${sign}0:0:0:1:0:0:0"); | |
2768 | last if (! $work || &Date_IsWorkDay($date,0)); | |
2769 | } | |
2770 | } | |
2771 | push(@tmp,$date); | |
2772 | } | |
2773 | @date=@tmp; | |
2774 | next FLAG; | |
2775 | } | |
2776 | ||
2777 | if ($f =~ /^CW(N|P|D)$/ || $f =~ /^(N|P|D)W(D)$/) { | |
2778 | $tmp=$1; | |
2779 | my $noalt = $2 ? 1 : 0; | |
2780 | if ($tmp eq "N" || ($tmp eq "D" && $Cnf{"TomorrowFirst"})) { | |
2781 | $forw=1; | |
2782 | } else { | |
2783 | $forw=0; | |
2784 | } | |
2785 | ||
2786 | @tmp=(); | |
2787 | DATE: foreach $date (@date) { | |
2788 | $df=$db=$date; | |
2789 | if (&Date_IsWorkDay($date)) { | |
2790 | push(@tmp,$date); | |
2791 | next DATE; | |
2792 | } | |
2793 | while (1) { | |
2794 | if ($forw) { | |
2795 | $d=$df=&DateCalc($df,"+0:0:0:1:0:0:0"); | |
2796 | } else { | |
2797 | $d=$db=&DateCalc($db,"-0:0:0:1:0:0:0"); | |
2798 | } | |
2799 | if (&Date_IsWorkDay($d)) { | |
2800 | push(@tmp,$d); | |
2801 | next DATE; | |
2802 | } | |
2803 | $forw=1-$forw if (! $noalt); | |
2804 | } | |
2805 | } | |
2806 | @date=@tmp; | |
2807 | next FLAG; | |
2808 | } | |
2809 | ||
2810 | if ($f eq "EASTER") { | |
2811 | @tmp=(); | |
2812 | foreach $date (@date) { | |
2813 | ($y,$m,$d,$h,$mn,$s)=&Date_Split($date, 1); | |
2814 | ($m,$d)=&Date_Easter($y); | |
2815 | $date=&Date_Join($y,$m,$d,$h,$mn,$s); | |
2816 | next if (&Date_Cmp($date,$date0)<0 || | |
2817 | &Date_Cmp($date,$date1)>0); | |
2818 | push(@tmp,$date); | |
2819 | } | |
2820 | @date=@tmp; | |
2821 | } | |
2822 | } | |
2823 | @date = sort(@date); | |
2824 | } | |
2825 | @date; | |
2826 | } | |
2827 | ||
2828 | sub Date_GetPrev { | |
2829 | print "DEBUG: Date_GetPrev\n" if ($Curr{"Debug"} =~ /trace/); | |
2830 | my($date,$dow,$today,$hr,$min,$sec)=@_; | |
2831 | &Date_Init() if (! $Curr{"InitDone"}); | |
2832 | my($y,$m,$d,$h,$mn,$s,$err,$curr_dow,%dow,$num,$delta,$th,$tm,$ts, | |
2833 | $adjust,$curr)=(); | |
2834 | $hr="00" if (defined $hr && $hr eq "0"); | |
2835 | $min="00" if (defined $min && $min eq "0"); | |
2836 | $sec="00" if (defined $sec && $sec eq "0"); | |
2837 | ||
2838 | if (! &Date_Split($date)) { | |
2839 | $date=&ParseDateString($date); | |
2840 | return "" if (! $date); | |
2841 | } | |
2842 | $curr=$date; | |
2843 | ($y,$m,$d)=( &Date_Split($date, 1) )[0..2]; | |
2844 | ||
2845 | if ($dow) { | |
2846 | $curr_dow=&Date_DayOfWeek($m,$d,$y); | |
2847 | %dow=%{ $Lang{$Cnf{"Language"}}{"WeekH"} }; | |
2848 | if (&IsInt($dow)) { | |
2849 | return "" if ($dow<1 || $dow>7); | |
2850 | } else { | |
2851 | return "" if (! exists $dow{lc($dow)}); | |
2852 | $dow=$dow{lc($dow)}; | |
2853 | } | |
2854 | if ($dow == $curr_dow) { | |
2855 | $date=&DateCalc_DateDelta($date,"-0:0:1:0:0:0:0",\$err,0) if (! $today); | |
2856 | $adjust=1 if ($today==2); | |
2857 | } else { | |
2858 | $dow -= 7 if ($dow>$curr_dow); # make sure previous day is less | |
2859 | $num = $curr_dow - $dow; | |
2860 | $date=&DateCalc_DateDelta($date,"-0:0:0:$num:0:0:0",\$err,0); | |
2861 | } | |
2862 | $date=&Date_SetTime($date,$hr,$min,$sec) if (defined $hr); | |
2863 | $date=&DateCalc_DateDelta($date,"-0:0:1:0:0:0:0",\$err,0) | |
2864 | if ($adjust && &Date_Cmp($date,$curr)>0); | |
2865 | ||
2866 | } else { | |
2867 | ($h,$mn,$s)=( &Date_Split($date, 1) )[3..5]; | |
2868 | ($th,$tm,$ts)=&Date_ParseTime($hr,$min,$sec); | |
2869 | if ($hr) { | |
2870 | ($hr,$min,$sec)=($th,$tm,$ts); | |
2871 | $delta="-0:0:0:1:0:0:0"; | |
2872 | } elsif ($min) { | |
2873 | ($hr,$min,$sec)=($h,$tm,$ts); | |
2874 | $delta="-0:0:0:0:1:0:0"; | |
2875 | } elsif ($sec) { | |
2876 | ($hr,$min,$sec)=($h,$mn,$ts); | |
2877 | $delta="-0:0:0:0:0:1:0"; | |
2878 | } else { | |
2879 | confess "ERROR: invalid arguments in Date_GetPrev.\n"; | |
2880 | } | |
2881 | ||
2882 | $d=&Date_SetTime($date,$hr,$min,$sec); | |
2883 | if ($today) { | |
2884 | $d=&DateCalc_DateDelta($d,$delta,\$err,0) if (&Date_Cmp($d,$date)>0); | |
2885 | } else { | |
2886 | $d=&DateCalc_DateDelta($d,$delta,\$err,0) if (&Date_Cmp($d,$date)>=0); | |
2887 | } | |
2888 | $date=$d; | |
2889 | } | |
2890 | return $date; | |
2891 | } | |
2892 | ||
2893 | sub Date_GetNext { | |
2894 | print "DEBUG: Date_GetNext\n" if ($Curr{"Debug"} =~ /trace/); | |
2895 | my($date,$dow,$today,$hr,$min,$sec)=@_; | |
2896 | &Date_Init() if (! $Curr{"InitDone"}); | |
2897 | my($y,$m,$d,$h,$mn,$s,$err,$curr_dow,%dow,$num,$delta,$th,$tm,$ts, | |
2898 | $adjust,$curr)=(); | |
2899 | $hr="00" if (defined $hr && $hr eq "0"); | |
2900 | $min="00" if (defined $min && $min eq "0"); | |
2901 | $sec="00" if (defined $sec && $sec eq "0"); | |
2902 | ||
2903 | if (! &Date_Split($date)) { | |
2904 | $date=&ParseDateString($date); | |
2905 | return "" if (! $date); | |
2906 | } | |
2907 | $curr=$date; | |
2908 | ($y,$m,$d)=( &Date_Split($date, 1) )[0..2]; | |
2909 | ||
2910 | if ($dow) { | |
2911 | $curr_dow=&Date_DayOfWeek($m,$d,$y); | |
2912 | %dow=%{ $Lang{$Cnf{"Language"}}{"WeekH"} }; | |
2913 | if (&IsInt($dow)) { | |
2914 | return "" if ($dow<1 || $dow>7); | |
2915 | } else { | |
2916 | return "" if (! exists $dow{lc($dow)}); | |
2917 | $dow=$dow{lc($dow)}; | |
2918 | } | |
2919 | if ($dow == $curr_dow) { | |
2920 | $date=&DateCalc_DateDelta($date,"+0:0:1:0:0:0:0",\$err,0) if (! $today); | |
2921 | $adjust=1 if ($today==2); | |
2922 | } else { | |
2923 | $curr_dow -= 7 if ($curr_dow>$dow); # make sure next date is greater | |
2924 | $num = $dow - $curr_dow; | |
2925 | $date=&DateCalc_DateDelta($date,"+0:0:0:$num:0:0:0",\$err,0); | |
2926 | } | |
2927 | $date=&Date_SetTime($date,$hr,$min,$sec) if (defined $hr); | |
2928 | $date=&DateCalc_DateDelta($date,"+0:0:1:0:0:0:0",\$err,0) | |
2929 | if ($adjust && &Date_Cmp($date,$curr)<0); | |
2930 | ||
2931 | } else { | |
2932 | ($h,$mn,$s)=( &Date_Split($date, 1) )[3..5]; | |
2933 | ($th,$tm,$ts)=&Date_ParseTime($hr,$min,$sec); | |
2934 | if ($hr) { | |
2935 | ($hr,$min,$sec)=($th,$tm,$ts); | |
2936 | $delta="+0:0:0:1:0:0:0"; | |
2937 | } elsif ($min) { | |
2938 | ($hr,$min,$sec)=($h,$tm,$ts); | |
2939 | $delta="+0:0:0:0:1:0:0"; | |
2940 | } elsif ($sec) { | |
2941 | ($hr,$min,$sec)=($h,$mn,$ts); | |
2942 | $delta="+0:0:0:0:0:1:0"; | |
2943 | } else { | |
2944 | confess "ERROR: invalid arguments in Date_GetNext.\n"; | |
2945 | } | |
2946 | ||
2947 | $d=&Date_SetTime($date,$hr,$min,$sec); | |
2948 | if ($today) { | |
2949 | $d=&DateCalc_DateDelta($d,$delta,\$err,0) if (&Date_Cmp($d,$date)<0); | |
2950 | } else { | |
2951 | $d=&DateCalc_DateDelta($d,$delta,\$err,0) if (&Date_Cmp($d,$date)<1); | |
2952 | } | |
2953 | $date=$d; | |
2954 | } | |
2955 | ||
2956 | return $date; | |
2957 | } | |
2958 | ||
2959 | sub Date_IsHoliday { | |
2960 | print "DEBUG: Date_IsHoliday\n" if ($Curr{"Debug"} =~ /trace/); | |
2961 | my($date)=@_; | |
2962 | &Date_Init() if (! $Curr{"InitDone"}); | |
2963 | $date=&ParseDateString($date); | |
2964 | return undef if (! $date); | |
2965 | $date=&Date_SetTime($date,0,0,0); | |
2966 | my($y)=(&Date_Split($date, 1))[0]; | |
2967 | &Date_UpdateHolidays($y) if (! exists $Holiday{"dates"}{$y}); | |
2968 | return undef if (! exists $Holiday{"dates"}{$y}{$date}); | |
2969 | my($name)=$Holiday{"dates"}{$y}{$date}; | |
2970 | return "" if (! $name); | |
2971 | $name; | |
2972 | } | |
2973 | ||
2974 | sub Events_List { | |
2975 | print "DEBUG: Events_List\n" if ($Curr{"Debug"} =~ /trace/); | |
2976 | my(@args)=@_; | |
2977 | &Date_Init() if (! $Curr{"InitDone"}); | |
2978 | &Events_ParseRaw(); | |
2979 | ||
2980 | my($tmp,$date0,$date1,$flag); | |
2981 | $date0=&ParseDateString($args[0]); | |
2982 | warn "Invalid date $args[0]", return undef if (! $date0); | |
2983 | ||
2984 | if ($#args == 0) { | |
2985 | return &Events_Calc($date0); | |
2986 | } | |
2987 | ||
2988 | if ($args[1]) { | |
2989 | $date1=&ParseDateString($args[1]); | |
2990 | warn "Invalid date $args[1]\n", return undef if (! $date1); | |
2991 | if (&Date_Cmp($date0,$date1)>0) { | |
2992 | $tmp=$date1; | |
2993 | $date1=$date0; | |
2994 | $date0=$tmp; | |
2995 | } | |
2996 | } else { | |
2997 | $date0=&Date_SetTime($date0,"00:00:00"); | |
2998 | $date1=&DateCalc_DateDelta($date0,"+0:0:0:1:0:0:0"); | |
2999 | } | |
3000 | ||
3001 | $tmp=&Events_Calc($date0,$date1); | |
3002 | ||
3003 | $flag=$args[2]; | |
3004 | return $tmp if (! $flag); | |
3005 | ||
3006 | my(@tmp,%ret,$delta)=(); | |
3007 | @tmp=@$tmp; | |
3008 | push(@tmp,$date1); | |
3009 | ||
3010 | if ($flag==1) { | |
3011 | while ($#tmp>0) { | |
3012 | ($date0,$tmp)=splice(@tmp,0,2); | |
3013 | $date1=$tmp[0]; | |
3014 | $delta=&DateCalc_DateDate($date0,$date1); | |
3015 | foreach $flag (@$tmp) { | |
3016 | if (exists $ret{$flag}) { | |
3017 | $ret{$flag}=&DateCalc_DeltaDelta($ret{$flag},$delta); | |
3018 | } else { | |
3019 | $ret{$flag}=$delta; | |
3020 | } | |
3021 | } | |
3022 | } | |
3023 | return \%ret; | |
3024 | ||
3025 | } elsif ($flag==2) { | |
3026 | while ($#tmp>0) { | |
3027 | ($date0,$tmp)=splice(@tmp,0,2); | |
3028 | $date1=$tmp[0]; | |
3029 | $delta=&DateCalc_DateDate($date0,$date1); | |
3030 | $flag=join("+",sort @$tmp); | |
3031 | next if (! $flag); | |
3032 | if (exists $ret{$flag}) { | |
3033 | $ret{$flag}=&DateCalc_DeltaDelta($ret{$flag},$delta); | |
3034 | } else { | |
3035 | $ret{$flag}=$delta; | |
3036 | } | |
3037 | } | |
3038 | return \%ret; | |
3039 | } | |
3040 | ||
3041 | warn "Invalid flag $flag\n"; | |
3042 | return undef; | |
3043 | } | |
3044 | ||
3045 | ### | |
3046 | # NOTE: The following routines may be called in the routines below with very | |
3047 | # little time penalty. | |
3048 | ### | |
3049 | sub Date_SetTime { | |
3050 | print "DEBUG: Date_SetTime\n" if ($Curr{"Debug"} =~ /trace/); | |
3051 | my($date,$h,$mn,$s)=@_; | |
3052 | &Date_Init() if (! $Curr{"InitDone"}); | |
3053 | my($y,$m,$d)=(); | |
3054 | ||
3055 | if (! &Date_Split($date)) { | |
3056 | $date=&ParseDateString($date); | |
3057 | return "" if (! $date); | |
3058 | } | |
3059 | ||
3060 | ($y,$m,$d)=( &Date_Split($date, 1) )[0..2]; | |
3061 | ($h,$mn,$s)=&Date_ParseTime($h,$mn,$s); | |
3062 | ||
3063 | my($ampm,$wk); | |
3064 | return "" if (&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk)); | |
3065 | &Date_Join($y,$m,$d,$h,$mn,$s); | |
3066 | } | |
3067 | ||
3068 | sub Date_SetDateField { | |
3069 | print "DEBUG: Date_SetDateField\n" if ($Curr{"Debug"} =~ /trace/); | |
3070 | my($date,$field,$val,$nocheck)=@_; | |
3071 | my($y,$m,$d,$h,$mn,$s)=(); | |
3072 | $nocheck=0 if (! defined $nocheck); | |
3073 | ||
3074 | ($y,$m,$d,$h,$mn,$s)=&Date_Split($date); | |
3075 | ||
3076 | if (! $y) { | |
3077 | $date=&ParseDateString($date); | |
3078 | return "" if (! $date); | |
3079 | ($y,$m,$d,$h,$mn,$s)=&Date_Split($date, 1); | |
3080 | } | |
3081 | ||
3082 | if (lc($field) eq "y") { | |
3083 | $y=$val; | |
3084 | } elsif (lc($field) eq "m") { | |
3085 | $m=$val; | |
3086 | } elsif (lc($field) eq "d") { | |
3087 | $d=$val; | |
3088 | } elsif (lc($field) eq "h") { | |
3089 | $h=$val; | |
3090 | } elsif (lc($field) eq "mn") { | |
3091 | $mn=$val; | |
3092 | } elsif (lc($field) eq "s") { | |
3093 | $s=$val; | |
3094 | } else { | |
3095 | confess "ERROR: Date_SetDateField: invalid field: $field\n"; | |
3096 | } | |
3097 | ||
3098 | $date=&Date_Join($y,$m,$d,$h,$mn,$s); | |
3099 | return $date if ($nocheck || &Date_Split($date)); | |
3100 | return ""; | |
3101 | } | |
3102 | ||
3103 | ######################################################################## | |
3104 | # OTHER SUBROUTINES | |
3105 | ######################################################################## | |
3106 | # NOTE: These routines should not call any of the routines above as | |
3107 | # there will be a severe time penalty (and the possibility of | |
3108 | # infinite recursion). The last couple routines above are | |
3109 | # exceptions. | |
3110 | # NOTE: Date_Init is a special case. It should be called (conditionally) | |
3111 | # in every routine that uses any variable from the Date::Manip | |
3112 | # namespace. | |
3113 | ######################################################################## | |
3114 | ||
3115 | sub Date_DaysInMonth { | |
3116 | print "DEBUG: Date_DaysInMonth\n" if ($Curr{"Debug"} =~ /trace/); | |
3117 | my($m,$y)=@_; | |
3118 | $y=&Date_FixYear($y) if (length($y)!=4); | |
3119 | my(@d_in_m)=(0,31,28,31,30,31,30,31,31,30,31,30,31); | |
3120 | $d_in_m[2]=29 if (&Date_LeapYear($y)); | |
3121 | return $d_in_m[$m]; | |
3122 | } | |
3123 | ||
3124 | sub Date_DayOfWeek { | |
3125 | print "DEBUG: Date_DayOfWeek\n" if ($Curr{"Debug"} =~ /trace/); | |
3126 | my($m,$d,$y)=@_; | |
3127 | $y=&Date_FixYear($y) if (length($y)!=4); | |
3128 | my($dayofweek,$dec31)=(); | |
3129 | ||
3130 | $dec31=5; # Dec 31, 1BC was Friday | |
3131 | $dayofweek=(&Date_DaysSince1BC($m,$d,$y)+$dec31) % 7; | |
3132 | $dayofweek=7 if ($dayofweek==0); | |
3133 | return $dayofweek; | |
3134 | } | |
3135 | ||
3136 | # Can't be in "use integer" because the numbers are too big. | |
3137 | no integer; | |
3138 | sub Date_SecsSince1970 { | |
3139 | print "DEBUG: Date_SecsSince1970\n" if ($Curr{"Debug"} =~ /trace/); | |
3140 | my($m,$d,$y,$h,$mn,$s)=@_; | |
3141 | $y=&Date_FixYear($y) if (length($y)!=4); | |
3142 | my($sec_now,$sec_70)=(); | |
3143 | $sec_now=(&Date_DaysSince1BC($m,$d,$y)-1)*24*3600 + $h*3600 + $mn*60 + $s; | |
3144 | # $sec_70 =(&Date_DaysSince1BC(1,1,1970)-1)*24*3600; | |
3145 | $sec_70 =62167219200; | |
3146 | return ($sec_now-$sec_70); | |
3147 | } | |
3148 | ||
3149 | sub Date_SecsSince1970GMT { | |
3150 | print "DEBUG: Date_SecsSince1970GMT\n" if ($Curr{"Debug"} =~ /trace/); | |
3151 | my($m,$d,$y,$h,$mn,$s)=@_; | |
3152 | &Date_Init() if (! $Curr{"InitDone"}); | |
3153 | $y=&Date_FixYear($y) if (length($y)!=4); | |
3154 | ||
3155 | my($sec)=&Date_SecsSince1970($m,$d,$y,$h,$mn,$s); | |
3156 | return $sec if ($Cnf{"ConvTZ"} eq "IGNORE"); | |
3157 | ||
3158 | my($tz)=$Cnf{"ConvTZ"}; | |
3159 | $tz=$Cnf{"TZ"} if (! $tz); | |
3160 | $tz=$Zone{"n2o"}{lc($tz)} if ($tz !~ /^[+-]\d{4}$/); | |
3161 | ||
3162 | my($tzs)=1; | |
3163 | $tzs=-1 if ($tz<0); | |
3164 | $tz=~/.(..)(..)/; | |
3165 | my($tzh,$tzm)=($1,$2); | |
3166 | $sec - $tzs*($tzh*3600+$tzm*60); | |
3167 | } | |
3168 | use integer; | |
3169 | ||
3170 | sub Date_DaysSince1BC { | |
3171 | print "DEBUG: Date_DaysSince1BC\n" if ($Curr{"Debug"} =~ /trace/); | |
3172 | my($m,$d,$y)=@_; | |
3173 | $y=&Date_FixYear($y) if (length($y)!=4); | |
3174 | my($Ny,$N4,$N100,$N400,$dayofyear,$days)=(); | |
3175 | my($cc,$yy)=(); | |
3176 | ||
3177 | $y=~ /(\d{2})(\d{2})/; | |
3178 | ($cc,$yy)=($1,$2); | |
3179 | ||
3180 | # Number of full years since Dec 31, 1BC (counting the year 0000). | |
3181 | $Ny=$y; | |
3182 | ||
3183 | # Number of full 4th years (incl. 0000) since Dec 31, 1BC | |
3184 | $N4=($Ny-1)/4 + 1; | |
3185 | $N4=0 if ($y==0); | |
3186 | ||
3187 | # Number of full 100th years (incl. 0000) | |
3188 | $N100=$cc + 1; | |
3189 | $N100-- if ($yy==0); | |
3190 | $N100=0 if ($y==0); | |
3191 | ||
3192 | # Number of full 400th years (incl. 0000) | |
3193 | $N400=($N100-1)/4 + 1; | |
3194 | $N400=0 if ($y==0); | |
3195 | ||
3196 | $dayofyear=&Date_DayOfYear($m,$d,$y); | |
3197 | $days= $Ny*365 + $N4 - $N100 + $N400 + $dayofyear; | |
3198 | ||
3199 | return $days; | |
3200 | } | |
3201 | ||
3202 | sub Date_DayOfYear { | |
3203 | print "DEBUG: Date_DayOfYear\n" if ($Curr{"Debug"} =~ /trace/); | |
3204 | my($m,$d,$y)=@_; | |
3205 | $y=&Date_FixYear($y) if (length($y)!=4); | |
3206 | # DinM = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) | |
3207 | my(@days) = ( 0, 31, 59, 90,120,151,181,212,243,273,304,334,365); | |
3208 | my($ly)=0; | |
3209 | $ly=1 if ($m>2 && &Date_LeapYear($y)); | |
3210 | return ($days[$m-1]+$d+$ly); | |
3211 | } | |
3212 | ||
3213 | sub Date_DaysInYear { | |
3214 | print "DEBUG: Date_DaysInYear\n" if ($Curr{"Debug"} =~ /trace/); | |
3215 | my($y)=@_; | |
3216 | $y=&Date_FixYear($y) if (length($y)!=4); | |
3217 | return 366 if (&Date_LeapYear($y)); | |
3218 | return 365; | |
3219 | } | |
3220 | ||
3221 | sub Date_WeekOfYear { | |
3222 | print "DEBUG: Date_WeekOfYear\n" if ($Curr{"Debug"} =~ /trace/); | |
3223 | my($m,$d,$y,$f)=@_; | |
3224 | &Date_Init() if (! $Curr{"InitDone"}); | |
3225 | $y=&Date_FixYear($y) if (length($y)!=4); | |
3226 | ||
3227 | my($day,$dow,$doy)=(); | |
3228 | $doy=&Date_DayOfYear($m,$d,$y); | |
3229 | ||
3230 | # The current DayOfYear and DayOfWeek | |
3231 | if ($Cnf{"Jan1Week1"}) { | |
3232 | $day=1; | |
3233 | } else { | |
3234 | $day=4; | |
3235 | } | |
3236 | $dow=&Date_DayOfWeek(1,$day,$y); | |
3237 | ||
3238 | # Move back to the first day of week 1. | |
3239 | $f-=7 if ($f>$dow); | |
3240 | $day-= ($dow-$f); | |
3241 | ||
3242 | return 0 if ($day>$doy); # Day is in last week of previous year | |
3243 | return (($doy-$day)/7 + 1); | |
3244 | } | |
3245 | ||
3246 | sub Date_LeapYear { | |
3247 | print "DEBUG: Date_LeapYear\n" if ($Curr{"Debug"} =~ /trace/); | |
3248 | my($y)=@_; | |
3249 | $y=&Date_FixYear($y) if (length($y)!=4); | |
3250 | return 0 unless $y % 4 == 0; | |
3251 | return 1 unless $y % 100 == 0; | |
3252 | return 0 unless $y % 400 == 0; | |
3253 | return 1; | |
3254 | } | |
3255 | ||
3256 | sub Date_DaySuffix { | |
3257 | print "DEBUG: Date_DaySuffix\n" if ($Curr{"Debug"} =~ /trace/); | |
3258 | my($d)=@_; | |
3259 | &Date_Init() if (! $Curr{"InitDone"}); | |
3260 | return $Lang{$Cnf{"Language"}}{"DoML"}[$d-1]; | |
3261 | } | |
3262 | ||
3263 | sub Date_ConvTZ { | |
3264 | print "DEBUG: Date_ConvTZ\n" if ($Curr{"Debug"} =~ /trace/); | |
3265 | my($date,$from,$to)=@_; | |
3266 | if (not Date_Split($date)) { | |
3267 | croak "date passed in ('$date') is not a Date::Manip object"; | |
3268 | } | |
3269 | ||
3270 | &Date_Init() if (! $Curr{"InitDone"}); | |
3271 | my($gmt)=(); | |
3272 | ||
3273 | if (! $from) { | |
3274 | ||
3275 | if (! $to) { | |
3276 | # TZ -> ConvTZ | |
3277 | return $date if ($Cnf{"ConvTZ"} eq "IGNORE" or ! $Cnf{"ConvTZ"}); | |
3278 | $from=$Cnf{"TZ"}; | |
3279 | $to=$Cnf{"ConvTZ"}; | |
3280 | ||
3281 | } else { | |
3282 | # ConvTZ,TZ -> $to | |
3283 | $from=$Cnf{"ConvTZ"}; | |
3284 | $from=$Cnf{"TZ"} if (! $from); | |
3285 | } | |
3286 | ||
3287 | } else { | |
3288 | ||
3289 | if (! $to) { | |
3290 | # $from -> ConvTZ,TZ | |
3291 | return $date if ($Cnf{"ConvTZ"} eq "IGNORE"); | |
3292 | $to=$Cnf{"ConvTZ"}; | |
3293 | $to=$Cnf{"TZ"} if (! $to); | |
3294 | ||
3295 | } else { | |
3296 | # $from -> $to | |
3297 | } | |
3298 | } | |
3299 | ||
3300 | $to=$Zone{"n2o"}{lc($to)} | |
3301 | if (exists $Zone{"n2o"}{lc($to)}); | |
3302 | $from=$Zone{"n2o"}{lc($from)} | |
3303 | if (exists $Zone{"n2o"}{lc($from)}); | |
3304 | $gmt=$Zone{"n2o"}{"gmt"}; | |
3305 | ||
3306 | return $date if ($from !~ /^[+-]\d{4}$/ or $to !~ /^[+-]\d{4}$/); | |
3307 | return $date if ($from eq $to); | |
3308 | ||
3309 | my($s1,$h1,$m1,$s2,$h2,$m2,$d,$h,$m,$sign,$delta,$err,$yr,$mon,$sec)=(); | |
3310 | # We're going to try to do the calculation without calling DateCalc. | |
3311 | ($yr,$mon,$d,$h,$m,$sec)=&Date_Split($date, 1); | |
3312 | ||
3313 | # Convert $date from $from to GMT | |
3314 | $from=~/([+-])(\d{2})(\d{2})/; | |
3315 | ($s1,$h1,$m1)=($1,$2,$3); | |
3316 | $s1= ($s1 eq "-" ? "+" : "-"); # switch sign | |
3317 | $sign=$s1 . "1"; # + or - 1 | |
3318 | ||
3319 | # and from GMT to $to | |
3320 | $to=~/([+-])(\d{2})(\d{2})/; | |
3321 | ($s2,$h2,$m2)=($1,$2,$3); | |
3322 | ||
3323 | if ($s1 eq $s2) { | |
3324 | # Both the same sign | |
3325 | $m+= $sign*($m1+$m2); | |
3326 | $h+= $sign*($h1+$h2); | |
3327 | } else { | |
3328 | $sign=($s2 eq "-" ? +1 : -1) if ($h1<$h2 || ($h1==$h2 && $m1<$m2)); | |
3329 | $m+= $sign*($m1-$m2); | |
3330 | $h+= $sign*($h1-$h2); | |
3331 | } | |
3332 | ||
3333 | if ($m>59) { | |
3334 | $h+= $m/60; | |
3335 | $m-= ($m/60)*60; | |
3336 | } elsif ($m<0) { | |
3337 | $h+= ($m/60 - 1); | |
3338 | $m-= ($m/60 - 1)*60; | |
3339 | } | |
3340 | ||
3341 | if ($h>23) { | |
3342 | $delta=$h/24; | |
3343 | $h -= $delta*24; | |
3344 | if (($d + $delta) > 28) { | |
3345 | $date=&Date_Join($yr,$mon,$d,$h,$m,$sec); | |
3346 | return &DateCalc_DateDelta($date,"+0:0:0:$delta:0:0:0",\$err,0); | |
3347 | } | |
3348 | $d+= $delta; | |
3349 | } elsif ($h<0) { | |
3350 | $delta=-$h/24 + 1; | |
3351 | $h += $delta*24; | |
3352 | if (($d - $delta) < 1) { | |
3353 | $date=&Date_Join($yr,$mon,$d,$h,$m,$sec); | |
3354 | return &DateCalc_DateDelta($date,"-0:0:0:$delta:0:0:0",\$err,0); | |
3355 | } | |
3356 | $d-= $delta; | |
3357 | } | |
3358 | return &Date_Join($yr,$mon,$d,$h,$m,$sec); | |
3359 | } | |
3360 | ||
3361 | sub Date_TimeZone { | |
3362 | print "DEBUG: Date_TimeZone\n" if ($Curr{"Debug"} =~ /trace/); | |
3363 | my($null,$tz,@tz,$std,$dst,$time,$isdst,$tmp,$in)=(); | |
3364 | &Date_Init() if (! $Curr{"InitDone"}); | |
3365 | ||
3366 | # Get timezones from all of the relevant places | |
3367 | ||
3368 | push(@tz,$Cnf{"TZ"}) if (defined $Cnf{"TZ"}); # TZ config var | |
3369 | push(@tz,$ENV{"TZ"}) if (defined $ENV{"TZ"}); # TZ environ var | |
3370 | push(@tz,$ENV{'SYS$TIMEZONE_RULE'}) | |
3371 | if defined $ENV{'SYS$TIMEZONE_RULE'}; # VMS TZ environ var | |
3372 | push(@tz,$ENV{'SYS$TIMEZONE_NAME'}) | |
3373 | if defined $ENV{'SYS$TIMEZONE_NAME'}; # VMS TZ name environ var | |
3374 | push(@tz,$ENV{'UCX$TZ'}) | |
3375 | if defined $ENV{'UCX$TZ'}; # VMS TZ environ var | |
3376 | push(@tz,$ENV{'TCPIP$TZ'}) | |
3377 | if defined $ENV{'TCPIP$TZ'}; # VMS TZ environ var | |
3378 | ||
3379 | # The `date` command... if we're doing taint checking, we need to | |
3380 | # always call it with a full path... otherwise, use the user's path. | |
3381 | # | |
3382 | # Microsoft operating systems don't have a date command built in. Try | |
3383 | # to trap all the various ways of knowing we are on one of these systems. | |
3384 | # | |
3385 | # We'll try `date +%Z` first, and if that fails, we'll take just the | |
3386 | # `date` program and assume the output is of the format: | |
3387 | # Thu Aug 31 14:57:46 EDT 2000 | |
3388 | ||
3389 | unless (($^X =~ /perl\.exe$/i) or | |
3390 | ($OS eq "Windows") or | |
3391 | ($OS eq "Netware") or | |
3392 | ($OS eq "VMS")) { | |
3393 | if ($Date::Manip::NoTaint) { | |
3394 | if ($OS eq "VMS") { | |
3395 | $tz=$ENV{'SYS$TIMEZONE_NAME'}; | |
3396 | if (! $tz) { | |
3397 | $tz=$ENV{'MULTINET_TIMEZONE'}; | |
3398 | if (! $tz) { | |
3399 | $tz=$ENV{'SYS$TIMEZONE_DIFFERENTIAL'}/3600.; # e.g. '-4' for EDT | |
3400 | } | |
3401 | } | |
3402 | } else { | |
3403 | $tz=`date +%Z 2> /dev/null`; | |
3404 | chomp($tz); | |
3405 | if (! $tz) { | |
3406 | $tz=`date 2> /dev/null`; | |
3407 | chomp($tz); | |
3408 | $tz=(split(/\s+/,$tz))[4]; | |
3409 | } | |
3410 | } | |
3411 | push(@tz,$tz); | |
3412 | } else { | |
3413 | # We need to satisfy taint checking, but also look in all the | |
3414 | # directories in @DatePath. | |
3415 | # | |
3416 | local $ENV{PATH} = join(':', @Date::Manip::DatePath); | |
3417 | local $ENV{BASH_ENV} = ''; | |
3418 | $tz=`date +%Z 2> /dev/null`; | |
3419 | chomp($tz); | |
3420 | if (! $tz) { | |
3421 | $tz=`date 2> /dev/null`; | |
3422 | chomp($tz); | |
3423 | $tz=(split(/\s+/,$tz))[4]; | |
3424 | } | |
3425 | push(@tz,$tz); | |
3426 | } | |
3427 | } | |
3428 | ||
3429 | push(@tz,$main::TZ) if (defined $main::TZ); # $main::TZ | |
3430 | ||
3431 | if (-s "/etc/TIMEZONE") { # /etc/TIMEZONE | |
3432 | $in=new IO::File; | |
3433 | $in->open("/etc/TIMEZONE","r"); | |
3434 | while (! eof($in)) { | |
3435 | $tmp=<$in>; | |
3436 | if ($tmp =~ /^TZ\s*=\s*(.*?)\s*$/) { | |
3437 | push(@tz,$1); | |
3438 | last; | |
3439 | } | |
3440 | } | |
3441 | $in->close; | |
3442 | } | |
3443 | ||
3444 | if (-s "/etc/timezone") { # /etc/timezone | |
3445 | $in=new IO::File; | |
3446 | $in->open("/etc/timezone","r"); | |
3447 | while (! eof($in)) { | |
3448 | $tmp=<$in>; | |
3449 | next if ($tmp =~ /^\s*\043/); | |
3450 | chomp($tmp); | |
3451 | if ($tmp =~ /^\s*(.*?)\s*$/) { | |
3452 | push(@tz,$1); | |
3453 | last; | |
3454 | } | |
3455 | } | |
3456 | $in->close; | |
3457 | } | |
3458 | ||
3459 | # Now parse each one to find the first valid one. | |
3460 | foreach $tz (@tz) { | |
3461 | $tz =~ s/\s*$//; | |
3462 | $tz =~ s/^\s*//; | |
3463 | next if (! $tz); | |
3464 | ||
3465 | return uc($tz) | |
3466 | if (defined $Zone{"n2o"}{lc($tz)}); | |
3467 | ||
3468 | if ($tz =~ /^[+-]\d{4}$/) { | |
3469 | return $tz; | |
3470 | } elsif ($tz =~ /^([+-]\d{2})(?::(\d{2}))?$/) { | |
3471 | my($h,$m)=($1,$2); | |
3472 | $m="00" if (! $m); | |
3473 | return "$h$m"; | |
3474 | } | |
3475 | ||
3476 | # Handle US/Eastern format | |
3477 | if ($tz =~ /^$Zone{"tzones"}$/i) { | |
3478 | $tmp=lc $1; | |
3479 | $tz=$Zone{"tz2z"}{$tmp}; | |
3480 | } | |
3481 | ||
3482 | # Handle STD#DST# format (and STD-#DST-# formats) | |
3483 | if ($tz =~ /^([a-z]+)-?\d([a-z]+)-?\d?$/i) { | |
3484 | ($std,$dst)=($1,$2); | |
3485 | next if (! defined $Zone{"n2o"}{lc($std)} or | |
3486 | ! defined $Zone{"n2o"}{lc($dst)}); | |
3487 | $time = time(); | |
3488 | ($null,$null,$null,$null,$null,$null,$null,$null,$isdst) = | |
3489 | localtime($time); | |
3490 | return uc($dst) if ($isdst); | |
3491 | return uc($std); | |
3492 | } | |
3493 | } | |
3494 | ||
3495 | confess "ERROR: Date::Manip unable to determine TimeZone.\n"; | |
3496 | } | |
3497 | ||
3498 | # Returns 1 if $date is a work day. If $time is non-zero, the time is | |
3499 | # also checked to see if it falls within work hours. Returns "" if | |
3500 | # an invalid date is passed in. | |
3501 | sub Date_IsWorkDay { | |
3502 | print "DEBUG: Date_IsWorkDay\n" if ($Curr{"Debug"} =~ /trace/); | |
3503 | my($date,$time)=@_; | |
3504 | &Date_Init() if (! $Curr{"InitDone"}); | |
3505 | $date=&ParseDateString($date); | |
3506 | return "" if (! $date); | |
3507 | my($d)=$date; | |
3508 | $d=&Date_SetTime($date,$Cnf{"WorkDayBeg"}) if (! $time); | |
3509 | ||
3510 | my($y,$mon,$day,$tmp,$h,$m,$dow)=(); | |
3511 | ($y,$mon,$day,$h,$m,$tmp)=&Date_Split($d, 1); | |
3512 | $dow=&Date_DayOfWeek($mon,$day,$y); | |
3513 | ||
3514 | return 0 if ($dow<$Cnf{"WorkWeekBeg"} or | |
3515 | $dow>$Cnf{"WorkWeekEnd"} or | |
3516 | "$h:$m" lt $Cnf{"WorkDayBeg"} or | |
3517 | "$h:$m" gt $Cnf{"WorkDayEnd"}); | |
3518 | ||
3519 | if (! exists $Holiday{"dates"}{$y}) { | |
3520 | # There will be recursion problems if we ever end up here twice. | |
3521 | $Holiday{"dates"}{$y}={}; | |
3522 | &Date_UpdateHolidays($y) | |
3523 | } | |
3524 | $d=&Date_SetTime($date,"00:00:00"); | |
3525 | return 0 if (exists $Holiday{"dates"}{$y}{$d}); | |
3526 | 1; | |
3527 | } | |
3528 | ||
3529 | # Finds the day $off work days from now. If $time is passed in, we must | |
3530 | # also take into account the time of day. | |
3531 | # | |
3532 | # If $time is not passed in, day 0 is today (if today is a workday) or the | |
3533 | # next work day if it isn't. In any case, the time of day is unaffected. | |
3534 | # | |
3535 | # If $time is passed in, day 0 is now (if now is part of a workday) or the | |
3536 | # start of the very next work day. | |
3537 | sub Date_NextWorkDay { | |
3538 | print "DEBUG: Date_NextWorkDay\n" if ($Curr{"Debug"} =~ /trace/); | |
3539 | my($date,$off,$time)=@_; | |
3540 | &Date_Init() if (! $Curr{"InitDone"}); | |
3541 | $date=&ParseDateString($date); | |
3542 | my($err)=(); | |
3543 | ||
3544 | if (! &Date_IsWorkDay($date,$time)) { | |
3545 | if ($time) { | |
3546 | while (1) { | |
3547 | $date=&Date_GetNext($date,undef,0,$Cnf{"WorkDayBeg"}); | |
3548 | last if (&Date_IsWorkDay($date,$time)); | |
3549 | } | |
3550 | } else { | |
3551 | while (1) { | |
3552 | $date=&DateCalc_DateDelta($date,"+0:0:0:1:0:0:0",\$err,0); | |
3553 | last if (&Date_IsWorkDay($date,$time)); | |
3554 | } | |
3555 | } | |
3556 | } | |
3557 | ||
3558 | while ($off>0) { | |
3559 | while (1) { | |
3560 | $date=&DateCalc_DateDelta($date,"+0:0:0:1:0:0:0",\$err,0); | |
3561 | last if (&Date_IsWorkDay($date,$time)); | |
3562 | } | |
3563 | $off--; | |
3564 | } | |
3565 | ||
3566 | return $date; | |
3567 | } | |
3568 | ||
3569 | # Finds the day $off work days before now. If $time is passed in, we must | |
3570 | # also take into account the time of day. | |
3571 | # | |
3572 | # If $time is not passed in, day 0 is today (if today is a workday) or the | |
3573 | # previous work day if it isn't. In any case, the time of day is unaffected. | |
3574 | # | |
3575 | # If $time is passed in, day 0 is now (if now is part of a workday) or the | |
3576 | # end of the previous work period. Note that since the end of a work day | |
3577 | # will automatically be turned into the start of the next one, this time | |
3578 | # may actually be treated as AFTER the current time. | |
3579 | sub Date_PrevWorkDay { | |
3580 | print "DEBUG: Date_PrevWorkDay\n" if ($Curr{"Debug"} =~ /trace/); | |
3581 | my($date,$off,$time)=@_; | |
3582 | &Date_Init() if (! $Curr{"InitDone"}); | |
3583 | $date=&ParseDateString($date); | |
3584 | my($err)=(); | |
3585 | ||
3586 | if (! &Date_IsWorkDay($date,$time)) { | |
3587 | if ($time) { | |
3588 | while (1) { | |
3589 | $date=&Date_GetPrev($date,undef,0,$Cnf{"WorkDayEnd"}); | |
3590 | last if (&Date_IsWorkDay($date,$time)); | |
3591 | } | |
3592 | while (1) { | |
3593 | $date=&Date_GetNext($date,undef,0,$Cnf{"WorkDayBeg"}); | |
3594 | last if (&Date_IsWorkDay($date,$time)); | |
3595 | } | |
3596 | } else { | |
3597 | while (1) { | |
3598 | $date=&DateCalc_DateDelta($date,"-0:0:0:1:0:0:0",\$err,0); | |
3599 | last if (&Date_IsWorkDay($date,$time)); | |
3600 | } | |
3601 | } | |
3602 | } | |
3603 | ||
3604 | while ($off>0) { | |
3605 | while (1) { | |
3606 | $date=&DateCalc_DateDelta($date,"-0:0:0:1:0:0:0",\$err,0); | |
3607 | last if (&Date_IsWorkDay($date,$time)); | |
3608 | } | |
3609 | $off--; | |
3610 | } | |
3611 | ||
3612 | return $date; | |
3613 | } | |
3614 | ||
3615 | # This finds the nearest workday to $date. If $date is a workday, it | |
3616 | # is returned. | |
3617 | sub Date_NearestWorkDay { | |
3618 | print "DEBUG: Date_NearestWorkDay\n" if ($Curr{"Debug"} =~ /trace/); | |
3619 | my($date,$tomorrow)=@_; | |
3620 | &Date_Init() if (! $Curr{"InitDone"}); | |
3621 | $date=&ParseDateString($date); | |
3622 | my($a,$b,$dela,$delb,$err)=(); | |
3623 | $tomorrow=$Cnf{"TomorrowFirst"} if (! defined $tomorrow); | |
3624 | ||
3625 | return $date if (&Date_IsWorkDay($date)); | |
3626 | ||
3627 | # Find the nearest one. | |
3628 | if ($tomorrow) { | |
3629 | $dela="+0:0:0:1:0:0:0"; | |
3630 | $delb="-0:0:0:1:0:0:0"; | |
3631 | } else { | |
3632 | $dela="-0:0:0:1:0:0:0"; | |
3633 | $delb="+0:0:0:1:0:0:0"; | |
3634 | } | |
3635 | $a=$b=$date; | |
3636 | ||
3637 | while (1) { | |
3638 | $a=&DateCalc_DateDelta($a,$dela,\$err); | |
3639 | return $a if (&Date_IsWorkDay($a)); | |
3640 | $b=&DateCalc_DateDelta($b,$delb,\$err); | |
3641 | return $b if (&Date_IsWorkDay($b)); | |
3642 | } | |
3643 | } | |
3644 | ||
3645 | # &Date_NthDayOfYear($y,$n); | |
3646 | # Returns a list of (YYYY,MM,DD,HH,MM,SS) for the Nth day of the year. | |
3647 | sub Date_NthDayOfYear { | |
3648 | no integer; | |
3649 | print "DEBUG: Date_NthDayOfYear\n" if ($Curr{"Debug"} =~ /trace/); | |
3650 | my($y,$n)=@_; | |
3651 | $y=$Curr{"Y"} if (! $y); | |
3652 | $n=1 if (! defined $n or $n eq ""); | |
3653 | $n+=0; # to turn 023 into 23 | |
3654 | $y=&Date_FixYear($y) if (length($y)<4); | |
3655 | my $leap=&Date_LeapYear($y); | |
3656 | return () if ($n<1); | |
3657 | return () if ($n >= ($leap ? 367 : 366)); | |
3658 | ||
3659 | my(@d_in_m)=(31,28,31,30,31,30,31,31,30,31,30,31); | |
3660 | $d_in_m[1]=29 if ($leap); | |
3661 | ||
3662 | # Calculate the hours, minutes, and seconds into the day. | |
3663 | my $remain=($n - int($n))*24; | |
3664 | my $h=int($remain); | |
3665 | $remain=($remain - $h)*60; | |
3666 | my $mn=int($remain); | |
3667 | $remain=($remain - $mn)*60; | |
3668 | my $s=$remain; | |
3669 | ||
3670 | # Calculate the month and the day. | |
3671 | my($m,$d)=(0,0); | |
3672 | $n=int($n); | |
3673 | while ($n>0) { | |
3674 | $m++; | |
3675 | if ($n<=$d_in_m[0]) { | |
3676 | $d=int($n); | |
3677 | $n=0; | |
3678 | } else { | |
3679 | $n-= $d_in_m[0]; | |
3680 | shift(@d_in_m); | |
3681 | } | |
3682 | } | |
3683 | ||
3684 | ($y,$m,$d,$h,$mn,$s); | |
3685 | } | |
3686 | ||
3687 | ######################################################################## | |
3688 | # NOT FOR EXPORT | |
3689 | ######################################################################## | |
3690 | ||
3691 | # This is used in Date_Init to fill in a hash based on international | |
3692 | # data. It takes a list of keys and values and returns both a hash | |
3693 | # with these values and a regular expression of keys. | |
3694 | # | |
3695 | # IN: | |
3696 | # $data = [ key1 val1 key2 val2 ... ] | |
3697 | # $opts = lc : lowercase the keys in the regexp | |
3698 | # sort : sort (by length) the keys in the regexp | |
3699 | # back : create a regexp with a back reference | |
3700 | # escape : escape all strings in the regexp | |
3701 | # | |
3702 | # OUT: | |
3703 | # $regexp = '(?:key1|key2|...)' | |
3704 | # $hash = { key1=>val1 key2=>val2 ... } | |
3705 | ||
3706 | sub Date_InitHash { | |
3707 | print "DEBUG: Date_InitHash\n" if ($Curr{"Debug"} =~ /trace/); | |
3708 | my($data,$regexp,$opts,$hash)=@_; | |
3709 | my(@data)=@$data; | |
3710 | my($key,$val,@list)=(); | |
3711 | ||
3712 | # Parse the options | |
3713 | my($lc,$sort,$back,$escape)=(0,0,0,0); | |
3714 | $lc=1 if ($opts =~ /lc/i); | |
3715 | $sort=1 if ($opts =~ /sort/i); | |
3716 | $back=1 if ($opts =~ /back/i); | |
3717 | $escape=1 if ($opts =~ /escape/i); | |
3718 | ||
3719 | # Create the hash | |
3720 | while (@data) { | |
3721 | ($key,$val,@data)=@data; | |
3722 | $key=lc($key) if ($lc); | |
3723 | $$hash{$key}=$val; | |
3724 | } | |
3725 | ||
3726 | # Create the regular expression | |
3727 | if ($regexp) { | |
3728 | @list=keys(%$hash); | |
3729 | @list=sort sortByLength(@list) if ($sort); | |
3730 | if ($escape) { | |
3731 | foreach $val (@list) { | |
3732 | $val="\Q$val\E"; | |
3733 | } | |
3734 | } | |
3735 | if ($back) { | |
3736 | $$regexp="(" . join("|",@list) . ")"; | |
3737 | } else { | |
3738 | $$regexp="(?:" . join("|",@list) . ")"; | |
3739 | } | |
3740 | } | |
3741 | } | |
3742 | ||
3743 | # This is used in Date_Init to fill in regular expressions, lists, and | |
3744 | # hashes based on international data. It takes a list of lists which have | |
3745 | # to be stored as regular expressions (to find any element in the list), | |
3746 | # lists, and hashes (indicating the location in the lists). | |
3747 | # | |
3748 | # IN: | |
3749 | # $data = [ [ [ valA1 valA2 ... ][ valA1' valA2' ... ] ... ] | |
3750 | # [ [ valB1 valB2 ... ][ valB1' valB2' ... ] ... ] | |
3751 | # ... | |
3752 | # [ [ valZ1 valZ2 ... ] [valZ1' valZ1' ... ] ... ] ] | |
3753 | # $lists = [ \@listA \@listB ... \@listZ ] | |
3754 | # $opts = lc : lowercase the values in the regexp | |
3755 | # sort : sort (by length) the values in the regexp | |
3756 | # back : create a regexp with a back reference | |
3757 | # escape : escape all strings in the regexp | |
3758 | # $hash = [ \%hash, TYPE ] | |
3759 | # TYPE 0 : $hash{ valBn=>n-1 } | |
3760 | # TYPE 1 : $hash{ valBn=>n } | |
3761 | # | |
3762 | # OUT: | |
3763 | # $regexp = '(?:valA1|valA2|...|valB1|...)' | |
3764 | # $lists = [ [ valA1 valA2 ... ] # only the 1st list (or | |
3765 | # [ valB1 valB2 ... ] ... ] # 2nd for int. characters) | |
3766 | # $hash | |
3767 | ||
3768 | sub Date_InitLists { | |
3769 | print "DEBUG: Date_InitLists\n" if ($Curr{"Debug"} =~ /trace/); | |
3770 | my($data,$regexp,$opts,$lists,$hash)=@_; | |
3771 | my(@data)=@$data; | |
3772 | my(@lists)=@$lists; | |
3773 | my($i,@ele,$ele,@list,$j,$tmp)=(); | |
3774 | ||
3775 | # Parse the options | |
3776 | my($lc,$sort,$back,$escape)=(0,0,0,0); | |
3777 | $lc=1 if ($opts =~ /lc/i); | |
3778 | $sort=1 if ($opts =~ /sort/i); | |
3779 | $back=1 if ($opts =~ /back/i); | |
3780 | $escape=1 if ($opts =~ /escape/i); | |
3781 | ||
3782 | # Set each of the lists | |
3783 | if (@lists) { | |
3784 | confess "ERROR: Date_InitLists: lists must be 1 per data\n" | |
3785 | if ($#lists != $#data); | |
3786 | for ($i=0; $i<=$#data; $i++) { | |
3787 | @ele=@{ $data[$i] }; | |
3788 | if ($Cnf{"IntCharSet"} && $#ele>0) { | |
3789 | @{ $lists[$i] } = @{ $ele[1] }; | |
3790 | } else { | |
3791 | @{ $lists[$i] } = @{ $ele[0] }; | |
3792 | } | |
3793 | } | |
3794 | } | |
3795 | ||
3796 | # Create the hash | |
3797 | my($hashtype,$hashsave,%hash)=(); | |
3798 | if (@$hash) { | |
3799 | ($hash,$hashtype)=@$hash; | |
3800 | $hashsave=1; | |
3801 | } else { | |
3802 | $hashtype=0; | |
3803 | $hashsave=0; | |
3804 | } | |
3805 | for ($i=0; $i<=$#data; $i++) { | |
3806 | @ele=@{ $data[$i] }; | |
3807 | foreach $ele (@ele) { | |
3808 | @list = @{ $ele }; | |
3809 | for ($j=0; $j<=$#list; $j++) { | |
3810 | $tmp=$list[$j]; | |
3811 | next if (! $tmp); | |
3812 | $tmp=lc($tmp) if ($lc); | |
3813 | $hash{$tmp}= $j+$hashtype; | |
3814 | } | |
3815 | } | |
3816 | } | |
3817 | %$hash = %hash if ($hashsave); | |
3818 | ||
3819 | # Create the regular expression | |
3820 | if ($regexp) { | |
3821 | @list=keys(%hash); | |
3822 | @list=sort sortByLength(@list) if ($sort); | |
3823 | if ($escape) { | |
3824 | foreach $ele (@list) { | |
3825 | $ele="\Q$ele\E"; | |
3826 | } | |
3827 | } | |
3828 | if ($back) { | |
3829 | $$regexp="(" . join("|",@list) . ")"; | |
3830 | } else { | |
3831 | $$regexp="(?:" . join("|",@list) . ")"; | |
3832 | } | |
3833 | } | |
3834 | } | |
3835 | ||
3836 | # This is used in Date_Init to fill in regular expressions and lists based | |
3837 | # on international data. This takes a list of strings and returns a regular | |
3838 | # expression (to find any one of them). | |
3839 | # | |
3840 | # IN: | |
3841 | # $data = [ string1 string2 ... ] | |
3842 | # $opts = lc : lowercase the values in the regexp | |
3843 | # sort : sort (by length) the values in the regexp | |
3844 | # back : create a regexp with a back reference | |
3845 | # escape : escape all strings in the regexp | |
3846 | # | |
3847 | # OUT: | |
3848 | # $regexp = '(string1|string2|...)' | |
3849 | ||
3850 | sub Date_InitStrings { | |
3851 | print "DEBUG: Date_InitStrings\n" if ($Curr{"Debug"} =~ /trace/); | |
3852 | my($data,$regexp,$opts)=@_; | |
3853 | my(@list)=@{ $data }; | |
3854 | ||
3855 | # Parse the options | |
3856 | my($lc,$sort,$back,$escape)=(0,0,0,0); | |
3857 | $lc=1 if ($opts =~ /lc/i); | |
3858 | $sort=1 if ($opts =~ /sort/i); | |
3859 | $back=1 if ($opts =~ /back/i); | |
3860 | $escape=1 if ($opts =~ /escape/i); | |
3861 | ||
3862 | # Create the regular expression | |
3863 | my($ele)=(); | |
3864 | @list=sort sortByLength(@list) if ($sort); | |
3865 | if ($escape) { | |
3866 | foreach $ele (@list) { | |
3867 | $ele="\Q$ele\E"; | |
3868 | } | |
3869 | } | |
3870 | if ($back) { | |
3871 | $$regexp="(" . join("|",@list) . ")"; | |
3872 | } else { | |
3873 | $$regexp="(?:" . join("|",@list) . ")"; | |
3874 | } | |
3875 | $$regexp=lc($$regexp) if ($lc); | |
3876 | } | |
3877 | ||
3878 | # items is passed in (either as a space separated string, or a reference to | |
3879 | # a list) and a regular expression which matches any one of the items is | |
3880 | # prepared. The regular expression will be of one of the forms: | |
3881 | # "(a|b)" @list not empty, back option included | |
3882 | # "(?:a|b)" @list not empty | |
3883 | # "()" @list empty, back option included | |
3884 | # "" @list empty | |
3885 | # $options is a string which contains any of the following strings: | |
3886 | # back : the regular expression has a backreference | |
3887 | # opt : the regular expression is optional and a "?" is appended in | |
3888 | # the first two forms | |
3889 | # optws : the regular expression is optional and may be replaced by | |
3890 | # whitespace | |
3891 | # optWs : the regular expression is optional, but if not present, must | |
3892 | # be replaced by whitespace | |
3893 | # sort : the items in the list are sorted by length (longest first) | |
3894 | # lc : the string is lowercased | |
3895 | # under : any underscores are converted to spaces | |
3896 | # pre : it may be preceded by whitespace | |
3897 | # Pre : it must be preceded by whitespace | |
3898 | # PRE : it must be preceded by whitespace or the start | |
3899 | # post : it may be followed by whitespace | |
3900 | # Post : it must be followed by whitespace | |
3901 | # POST : it must be followed by whitespace or the end | |
3902 | # Spaces due to pre/post options will not be included in the back reference. | |
3903 | # | |
3904 | # If $array is included, then the elements will also be returned as a list. | |
3905 | # $array is a string which may contain any of the following: | |
3906 | # keys : treat the list as a hash and only the keys go into the regexp | |
3907 | # key0 : treat the list as the values of a hash with keys 0 .. N-1 | |
3908 | # key1 : treat the list as the values of a hash with keys 1 .. N | |
3909 | # val0 : treat the list as the keys of a hash with values 0 .. N-1 | |
3910 | # val1 : treat the list as the keys of a hash with values 1 .. N | |
3911 | ||
3912 | # &Date_InitLists([$lang{"month_name"},$lang{"month_abb"}], | |
3913 | # [\$Month,"lc,sort,back"], | |
3914 | # [\@Month,\@Mon], | |
3915 | # [\%Month,1]); | |
3916 | ||
3917 | # This is used in Date_Init to prepare regular expressions. A list of | |
3918 | # items is passed in (either as a space separated string, or a reference to | |
3919 | # a list) and a regular expression which matches any one of the items is | |
3920 | # prepared. The regular expression will be of one of the forms: | |
3921 | # "(a|b)" @list not empty, back option included | |
3922 | # "(?:a|b)" @list not empty | |
3923 | # "()" @list empty, back option included | |
3924 | # "" @list empty | |
3925 | # $options is a string which contains any of the following strings: | |
3926 | # back : the regular expression has a backreference | |
3927 | # opt : the regular expression is optional and a "?" is appended in | |
3928 | # the first two forms | |
3929 | # optws : the regular expression is optional and may be replaced by | |
3930 | # whitespace | |
3931 | # optWs : the regular expression is optional, but if not present, must | |
3932 | # be replaced by whitespace | |
3933 | # sort : the items in the list are sorted by length (longest first) | |
3934 | # lc : the string is lowercased | |
3935 | # under : any underscores are converted to spaces | |
3936 | # pre : it may be preceded by whitespace | |
3937 | # Pre : it must be preceded by whitespace | |
3938 | # PRE : it must be preceded by whitespace or the start | |
3939 | # post : it may be followed by whitespace | |
3940 | # Post : it must be followed by whitespace | |
3941 | # POST : it must be followed by whitespace or the end | |
3942 | # Spaces due to pre/post options will not be included in the back reference. | |
3943 | # | |
3944 | # If $array is included, then the elements will also be returned as a list. | |
3945 | # $array is a string which may contain any of the following: | |
3946 | # keys : treat the list as a hash and only the keys go into the regexp | |
3947 | # key0 : treat the list as the values of a hash with keys 0 .. N-1 | |
3948 | # key1 : treat the list as the values of a hash with keys 1 .. N | |
3949 | # val0 : treat the list as the keys of a hash with values 0 .. N-1 | |
3950 | # val1 : treat the list as the keys of a hash with values 1 .. N | |
3951 | sub Date_Regexp { | |
3952 | print "DEBUG: Date_Regexp\n" if ($Curr{"Debug"} =~ /trace/); | |
3953 | my($list,$options,$array)=@_; | |
3954 | my(@list,$ret,%hash,$i)=(); | |
3955 | local($_)=(); | |
3956 | $options="" if (! defined $options); | |
3957 | $array="" if (! defined $array); | |
3958 | ||
3959 | my($sort,$lc,$under)=(0,0,0); | |
3960 | $sort =1 if ($options =~ /sort/i); | |
3961 | $lc =1 if ($options =~ /lc/i); | |
3962 | $under=1 if ($options =~ /under/i); | |
3963 | my($back,$opt,$pre,$post,$ws)=("?:","","","",""); | |
3964 | $back ="" if ($options =~ /back/i); | |
3965 | $opt ="?" if ($options =~ /opt/i); | |
3966 | $pre ='\s*' if ($options =~ /pre/); | |
3967 | $pre ='\s+' if ($options =~ /Pre/); | |
3968 | $pre ='(?:\s+|^)' if ($options =~ /PRE/); | |
3969 | $post ='\s*' if ($options =~ /post/); | |
3970 | $post ='\s+' if ($options =~ /Post/); | |
3971 | $post ='(?:$|\s+)' if ($options =~ /POST/); | |
3972 | $ws ='\s*' if ($options =~ /optws/); | |
3973 | $ws ='\s+' if ($options =~ /optws/); | |
3974 | ||
3975 | my($hash,$keys,$key0,$key1,$val0,$val1)=(0,0,0,0,0,0); | |
3976 | $keys =1 if ($array =~ /keys/i); | |
3977 | $key0 =1 if ($array =~ /key0/i); | |
3978 | $key1 =1 if ($array =~ /key1/i); | |
3979 | $val0 =1 if ($array =~ /val0/i); | |
3980 | $val1 =1 if ($array =~ /val1/i); | |
3981 | $hash =1 if ($keys or $key0 or $key1 or $val0 or $val1); | |
3982 | ||
3983 | my($ref)=ref $list; | |
3984 | if (! $ref) { | |
3985 | $list =~ s/\s*$//; | |
3986 | $list =~ s/^\s*//; | |
3987 | $list =~ s/\s+/&&&/g; | |
3988 | } elsif ($ref eq "ARRAY") { | |
3989 | $list = join("&&&",@$list); | |
3990 | } else { | |
3991 | confess "ERROR: Date_Regexp.\n"; | |
3992 | } | |
3993 | ||
3994 | if (! $list) { | |
3995 | if ($back eq "") { | |
3996 | return "()"; | |
3997 | } else { | |
3998 | return ""; | |
3999 | } | |
4000 | } | |
4001 | ||
4002 | $list=lc($list) if ($lc); | |
4003 | $list=~ s/_/ /g if ($under); | |
4004 | @list=split(/&&&/,$list); | |
4005 | if ($keys) { | |
4006 | %hash=@list; | |
4007 | @list=keys %hash; | |
4008 | } elsif ($key0 or $key1 or $val0 or $val1) { | |
4009 | $i=0; | |
4010 | $i=1 if ($key1 or $val1); | |
4011 | if ($key0 or $key1) { | |
4012 | %hash= map { $_,$i++ } @list; | |
4013 | } else { | |
4014 | %hash= map { $i++,$_ } @list; | |
4015 | } | |
4016 | } | |
4017 | @list=sort sortByLength(@list) if ($sort); | |
4018 | ||
4019 | $ret="($back" . join("|",@list) . ")"; | |
4020 | $ret="(?:$pre$ret$post)" if ($pre or $post); | |
4021 | $ret.=$opt; | |
4022 | $ret="(?:$ret|$ws)" if ($ws); | |
4023 | ||
4024 | if ($array and $hash) { | |
4025 | return ($ret,%hash); | |
4026 | } elsif ($array) { | |
4027 | return ($ret,@list); | |
4028 | } else { | |
4029 | return $ret; | |
4030 | } | |
4031 | } | |
4032 | ||
4033 | # This will produce a delta with the correct number of signs. At most two | |
4034 | # signs will be in it normally (one before the year, and one in front of | |
4035 | # the day), but if appropriate, signs will be in front of all elements. | |
4036 | # Also, as many of the signs will be equivalent as possible. | |
4037 | sub Delta_Normalize { | |
4038 | print "DEBUG: Delta_Normalize\n" if ($Curr{"Debug"} =~ /trace/); | |
4039 | my($delta,$mode)=@_; | |
4040 | return "" if (! $delta); | |
4041 | return "+0:+0:+0:+0:+0:+0:+0" | |
4042 | if ($delta =~ /^([+-]?0+:){6}[+-]?0+$/ and $Cnf{"DeltaSigns"}); | |
4043 | return "+0:0:0:0:0:0:0" if ($delta =~ /^([+-]?0+:){6}[+-]?0+$/); | |
4044 | ||
4045 | my($tmp,$sign1,$sign2,$len)=(); | |
4046 | ||
4047 | # Calculate the length of the day in minutes | |
4048 | $len=24*60; | |
4049 | $len=$Curr{"WDlen"} if ($mode==2 || $mode==3); | |
4050 | ||
4051 | # We have to get the sign of every component explicitely so that a "-0" | |
4052 | # or "+0" doesn't get lost by treating it numerically (i.e. "-0:0:2" must | |
4053 | # be a negative delta). | |
4054 | ||
4055 | my($y,$mon,$w,$d,$h,$m,$s)=&Delta_Split($delta); | |
4056 | ||
4057 | # We need to make sure that the signs of all parts of a delta are the | |
4058 | # same. The easiest way to do this is to convert all of the large | |
4059 | # components to the smallest ones, then convert the smaller components | |
4060 | # back to the larger ones. | |
4061 | ||
4062 | # Do the year/month part | |
4063 | ||
4064 | $mon += $y*12; # convert y to m | |
4065 | $sign1="+"; | |
4066 | if ($mon<0) { | |
4067 | $mon *= -1; | |
4068 | $sign1="-"; | |
4069 | } | |
4070 | ||
4071 | $y = $mon/12; # convert m to y | |
4072 | $mon -= $y*12; | |
4073 | ||
4074 | $y=0 if ($y eq "-0"); # get around silly -0 problem | |
4075 | $mon=0 if ($mon eq "-0"); | |
4076 | ||
4077 | # Do the wk/day/hour/min/sec part | |
4078 | ||
4079 | { | |
4080 | # Unfortunately, $s is overflowing for dates more than ~70 years | |
4081 | # apart. | |
4082 | no integer; | |
4083 | ||
4084 | if ($mode==3 || $mode==2) { | |
4085 | $s += $d*$len*60 + $h*3600 + $m*60; # convert d/h/m to s | |
4086 | } else { | |
4087 | $s += ($d+7*$w)*$len*60 + $h*3600 + $m*60; # convert w/d/h/m to s | |
4088 | } | |
4089 | $sign2="+"; | |
4090 | if ($s<0) { | |
4091 | $s*=-1; | |
4092 | $sign2="-"; | |
4093 | } | |
4094 | ||
4095 | $m = int($s/60); # convert s to m | |
4096 | $s -= $m*60; | |
4097 | $d = int($m/$len); # convert m to d | |
4098 | $m -= $d*$len; | |
4099 | ||
4100 | # The rest should be fine. | |
4101 | } | |
4102 | $h = $m/60; # convert m to h | |
4103 | $m -= $h*60; | |
4104 | if ($mode == 3 || $mode == 2) { | |
4105 | $w = $w*1; # get around +0 problem | |
4106 | } else { | |
4107 | $w = $d/7; # convert d to w | |
4108 | $d -= $w*7; | |
4109 | } | |
4110 | ||
4111 | $w=0 if ($w eq "-0"); # get around silly -0 problem | |
4112 | $d=0 if ($d eq "-0"); | |
4113 | $h=0 if ($h eq "-0"); | |
4114 | $m=0 if ($m eq "-0"); | |
4115 | $s=0 if ($s eq "-0"); | |
4116 | ||
4117 | # Only include two signs if necessary | |
4118 | $sign1=$sign2 if ($y==0 and $mon==0); | |
4119 | $sign2=$sign1 if ($w==0 and $d==0 and $h==0 and $m==0 and $s==0); | |
4120 | $sign2="" if ($sign1 eq $sign2 and ! $Cnf{"DeltaSigns"}); | |
4121 | ||
4122 | if ($Cnf{"DeltaSigns"}) { | |
4123 | return "$sign1$y:$sign1$mon:$sign2$w:$sign2$d:$sign2$h:$sign2$m:$sign2$s"; | |
4124 | } else { | |
4125 | return "$sign1$y:$mon:$sign2$w:$d:$h:$m:$s"; | |
4126 | } | |
4127 | } | |
4128 | ||
4129 | # This checks a delta to make sure it is valid. If it is, it splits | |
4130 | # it and returns the elements with a sign on each. The 2nd argument | |
4131 | # specifies the default sign. Blank elements are set to 0. If the | |
4132 | # third element is non-nil, exactly 7 elements must be included. | |
4133 | sub Delta_Split { | |
4134 | print "DEBUG: Delta_Split\n" if ($Curr{"Debug"} =~ /trace/); | |
4135 | my($delta,$sign,$exact)=@_; | |
4136 | my(@delta)=split(/:/,$delta); | |
4137 | return () if ($exact and $#delta != 6); | |
4138 | my($i)=(); | |
4139 | $sign="+" if (! defined $sign); | |
4140 | for ($i=0; $i<=$#delta; $i++) { | |
4141 | $delta[$i]="0" if (! $delta[$i]); | |
4142 | return () if ($delta[$i] !~ /^[+-]?\d+$/); | |
4143 | $sign = ($delta[$i] =~ s/^([+-])// ? $1 : $sign); | |
4144 | $delta[$i] = $sign.$delta[$i]; | |
4145 | } | |
4146 | @delta; | |
4147 | } | |
4148 | ||
4149 | # Reads up to 3 arguments. $h may contain the time in any international | |
4150 | # format. Any empty elements are set to 0. | |
4151 | sub Date_ParseTime { | |
4152 | print "DEBUG: Date_ParseTime\n" if ($Curr{"Debug"} =~ /trace/); | |
4153 | my($h,$m,$s)=@_; | |
4154 | my($t)=&CheckTime("one"); | |
4155 | ||
4156 | if (defined $h and $h =~ /$t/) { | |
4157 | $h=$1; | |
4158 | $m=$2; | |
4159 | $s=$3 if (defined $3); | |
4160 | } | |
4161 | $h="00" if (! defined $h); | |
4162 | $m="00" if (! defined $m); | |
4163 | $s="00" if (! defined $s); | |
4164 | ||
4165 | ($h,$m,$s); | |
4166 | } | |
4167 | ||
4168 | # Forms a date with the 6 elements passed in (all of which must be defined). | |
4169 | # No check as to validity is made. | |
4170 | sub Date_Join { | |
4171 | print "DEBUG: Date_Join\n" if ($Curr{"Debug"} =~ /trace/); | |
4172 | foreach (0 .. $#_) { | |
4173 | croak "undefined arg $_ to Date_Join()" if not defined $_[$_]; | |
4174 | } | |
4175 | my($y,$m,$d,$h,$mn,$s)=@_; | |
4176 | my($ym,$md,$dh,$hmn,$mns)=(); | |
4177 | ||
4178 | if ($Cnf{"Internal"} == 0) { | |
4179 | $ym=$md=$dh=""; | |
4180 | $hmn=$mns=":"; | |
4181 | ||
4182 | } elsif ($Cnf{"Internal"} == 1) { | |
4183 | $ym=$md=$dh=$hmn=$mns=""; | |
4184 | ||
4185 | } elsif ($Cnf{"Internal"} == 2) { | |
4186 | $ym=$md="-"; | |
4187 | $dh=" "; | |
4188 | $hmn=$mns=":"; | |
4189 | ||
4190 | } else { | |
4191 | confess "ERROR: Invalid internal format in Date_Join.\n"; | |
4192 | } | |
4193 | $m="0$m" if (length($m)==1); | |
4194 | $d="0$d" if (length($d)==1); | |
4195 | $h="0$h" if (length($h)==1); | |
4196 | $mn="0$mn" if (length($mn)==1); | |
4197 | $s="0$s" if (length($s)==1); | |
4198 | "$y$ym$m$md$d$dh$h$hmn$mn$mns$s"; | |
4199 | } | |
4200 | ||
4201 | # This checks a time. If it is valid, it splits it and returns 3 elements. | |
4202 | # If "one" or "two" is passed in, a regexp with 1/2 or 2 digit hours is | |
4203 | # returned. | |
4204 | sub CheckTime { | |
4205 | print "DEBUG: CheckTime\n" if ($Curr{"Debug"} =~ /trace/); | |
4206 | my($time)=@_; | |
4207 | my($h)='(?:0?[0-9]|1[0-9]|2[0-3])'; | |
4208 | my($h2)='(?:0[0-9]|1[0-9]|2[0-3])'; | |
4209 | my($m)='[0-5][0-9]'; | |
4210 | my($s)=$m; | |
4211 | my($hm)="(?:". $Lang{$Cnf{"Language"}}{"SepHM"} ."|:)"; | |
4212 | my($ms)="(?:". $Lang{$Cnf{"Language"}}{"SepMS"} ."|:)"; | |
4213 | my($ss)=$Lang{$Cnf{"Language"}}{"SepSS"}; | |
4214 | my($t)="^($h)$hm($m)(?:$ms($s)(?:$ss\\d+)?)?\$"; | |
4215 | if ($time eq "one") { | |
4216 | return $t; | |
4217 | } elsif ($time eq "two") { | |
4218 | $t="^($h2)$hm($m)(?:$ms($s)(?:$ss\\d+)?)?\$"; | |
4219 | return $t; | |
4220 | } | |
4221 | ||
4222 | if ($time =~ /$t/i) { | |
4223 | ($h,$m,$s)=($1,$2,$3); | |
4224 | $h="0$h" if (length($h)<2); | |
4225 | $m="0$m" if (length($m)<2); | |
4226 | $s="00" if (! defined $s); | |
4227 | return ($h,$m,$s); | |
4228 | } else { | |
4229 | return (); | |
4230 | } | |
4231 | } | |
4232 | ||
4233 | # This checks a recurrence. If it is valid, it splits it and returns the | |
4234 | # elements. Otherwise, it returns an empty list. | |
4235 | # ($recur0,$recur1,$flags,$dateb,$date0,$date1)=&Recur_Split($recur); | |
4236 | sub Recur_Split { | |
4237 | print "DEBUG: Recur_Split\n" if ($Curr{"Debug"} =~ /trace/); | |
4238 | my($recur)=@_; | |
4239 | my(@ret,@tmp); | |
4240 | ||
4241 | my($R) = '(\*?(?:[-,0-9]+[:\*]){6}[-,0-9]+)'; | |
4242 | my($F) = '(?:\*([^*]*))'; | |
4243 | my($DB,$D0,$D1); | |
4244 | $DB=$D0=$D1=$F; | |
4245 | ||
4246 | if ($recur =~ /^$R$F?$DB?$D0?$D1?$/) { | |
4247 | @ret=($1,$2,$3,$4,$5); | |
4248 | @tmp=split(/\*/,shift(@ret)); | |
4249 | return () if ($#tmp>1); | |
4250 | return (@tmp,"",@ret) if ($#tmp==0); | |
4251 | return (@tmp,@ret); | |
4252 | } | |
4253 | return (); | |
4254 | } | |
4255 | ||
4256 | # This checks a date. If it is valid, it splits it and returns the elements. | |
4257 | # If no date is passed in, it returns a regular expression for the date. | |
4258 | # | |
4259 | # The optional second argument says 'I really expect this to be a | |
4260 | # valid Date::Manip object, please throw an exception if it is | |
4261 | # not'. Otherwise, errors are signalled by returning (). | |
4262 | # | |
4263 | sub Date_Split { | |
4264 | print "DEBUG: Date_Split\n" if ($Curr{"Debug"} =~ /trace/); | |
4265 | my($date, $definitely_valid)=@_; | |
4266 | $definitely_valid = 0 if not defined $definitely_valid; | |
4267 | my($ym,$md,$dh,$hmn,$mns)=(); | |
4268 | my($y)='(\d{4})'; | |
4269 | my($m)='(0[1-9]|1[0-2])'; | |
4270 | my($d)='(0[1-9]|[1-2][0-9]|3[0-1])'; | |
4271 | my($h)='([0-1][0-9]|2[0-3])'; | |
4272 | my($mn)='([0-5][0-9])'; | |
4273 | my($s)=$mn; | |
4274 | ||
4275 | if ($Cnf{"Internal"} == 0) { | |
4276 | $ym=$md=$dh=""; | |
4277 | $hmn=$mns=":"; | |
4278 | ||
4279 | } elsif ($Cnf{"Internal"} == 1) { | |
4280 | $ym=$md=$dh=$hmn=$mns=""; | |
4281 | ||
4282 | } elsif ($Cnf{"Internal"} == 2) { | |
4283 | $ym=$md="-"; | |
4284 | $dh=" "; | |
4285 | $hmn=$mns=":"; | |
4286 | ||
4287 | } else { | |
4288 | confess "ERROR: Invalid internal format in Date_Split.\n"; | |
4289 | } | |
4290 | ||
4291 | my($t)="^$y$ym$m$md$d$dh$h$hmn$mn$mns$s\$"; | |
4292 | ||
4293 | if (not defined $date or $date eq '') { | |
4294 | if ($definitely_valid) { | |
4295 | die "bad date '$date'"; | |
4296 | } else { | |
4297 | return $t; | |
4298 | } | |
4299 | } | |
4300 | ||
4301 | if ($date =~ /$t/) { | |
4302 | ($y,$m,$d,$h,$mn,$s)=($1,$2,$3,$4,$5,$6); | |
4303 | my(@d_in_m)=(0,31,28,31,30,31,30,31,31,30,31,30,31); | |
4304 | $d_in_m[2]=29 if (&Date_LeapYear($y)); | |
4305 | if ($d>$d_in_m[$m]) { | |
4306 | my $msg = "invalid date $date: day $d of month $m, but only $d_in_m[$m] days in that month"; | |
4307 | if ($definitely_valid) { | |
4308 | die $msg; | |
4309 | } | |
4310 | else { | |
4311 | warn $msg; | |
4312 | return (); | |
4313 | } | |
4314 | } | |
4315 | return ($y,$m,$d,$h,$mn,$s); | |
4316 | } | |
4317 | ||
4318 | if ($definitely_valid) { | |
4319 | die "invalid date $date: doesn't match regexp $t"; | |
4320 | } | |
4321 | return (); | |
4322 | } | |
4323 | ||
4324 | # This returns the date easter occurs on for a given year as ($month,$day). | |
4325 | # This is from the Calendar FAQ. | |
4326 | sub Date_Easter { | |
4327 | my($y)=@_; | |
4328 | $y=&Date_FixYear($y) if (length($y)==2); | |
4329 | ||
4330 | my($c) = $y/100; | |
4331 | my($g) = $y % 19; | |
4332 | my($k) = ($c-17)/25; | |
4333 | my($i) = ($c - $c/4 - ($c-$k)/3 + 19*$g + 15) % 30; | |
4334 | $i = $i - ($i/28)*(1 - ($i/28)*(29/($i+1))*((21-$g)/11)); | |
4335 | my($j) = ($y + $y/4 + $i + 2 - $c + $c/4) % 7; | |
4336 | my($l) = $i-$j; | |
4337 | my($m) = 3 + ($l+40)/44; | |
4338 | my($d) = $l + 28 - 31*($m/4); | |
4339 | return ($m,$d); | |
4340 | } | |
4341 | ||
4342 | # This takes a list of years, months, WeekOfMonth's, and optionally | |
4343 | # DayOfWeek's, and returns a list of dates. Optionally, a list of dates | |
4344 | # can be passed in as the 1st argument (with the 2nd argument the null list) | |
4345 | # and the year/month of these will be used. | |
4346 | # | |
4347 | # If $FDn is non-zero, the first week of the month contains the first | |
4348 | # occurence of this day (1=Monday). If $FIn is non-zero, the first week of | |
4349 | # the month contains the date (i.e. $FIn'th day of the month). | |
4350 | sub Date_Recur_WoM { | |
4351 | my($y,$m,$w,$d,$FDn,$FIn)=@_; | |
4352 | my(@y)=@$y; | |
4353 | my(@m)=@$m; | |
4354 | my(@w)=@$w; | |
4355 | my(@d)=@$d; | |
4356 | my($date0,$date1,@tmp,@date,$d0,$d1,@tmp2)=(); | |
4357 | ||
4358 | if (@m) { | |
4359 | @tmp=(); | |
4360 | foreach $y (@y) { | |
4361 | return () if (length($y)==1 || length($y)==3 || ! &IsInt($y,0,9999)); | |
4362 | $y=&Date_FixYear($y) if (length($y)==2); | |
4363 | push(@tmp,$y); | |
4364 | } | |
4365 | @y=sort { $a<=>$b } (@tmp); | |
4366 | ||
4367 | return () if (! @m); | |
4368 | foreach $m (@m) { | |
4369 | return () if (! &IsInt($m,1,12)); | |
4370 | } | |
4371 | @m=sort { $a<=>$b } (@m); | |
4372 | ||
4373 | @tmp=@tmp2=(); | |
4374 | foreach $y (@y) { | |
4375 | foreach $m (@m) { | |
4376 | push(@tmp,$y); | |
4377 | push(@tmp2,$m); | |
4378 | } | |
4379 | } | |
4380 | ||
4381 | @y=@tmp; | |
4382 | @m=@tmp2; | |
4383 | ||
4384 | } else { | |
4385 | foreach $d0 (@y) { | |
4386 | @tmp=&Date_Split($d0); | |
4387 | return () if (! @tmp); | |
4388 | push(@tmp2,$tmp[0]); | |
4389 | push(@m,$tmp[1]); | |
4390 | } | |
4391 | @y=@tmp2; | |
4392 | } | |
4393 | ||
4394 | return () if (! @w); | |
4395 | foreach $w (@w) { | |
4396 | return () if ($w==0 || ! &IsInt($w,-5,5)); | |
4397 | } | |
4398 | ||
4399 | if (@d) { | |
4400 | foreach $d (@d) { | |
4401 | return () if (! &IsInt($d,1,7)); | |
4402 | } | |
4403 | @d=sort { $a<=>$b } (@d); | |
4404 | } | |
4405 | ||
4406 | @date=(); | |
4407 | foreach $y (@y) { | |
4408 | $m=shift(@m); | |
4409 | ||
4410 | # Find 1st day of this month and next month | |
4411 | $date0=&Date_Join($y,$m,1,0,0,0); | |
4412 | $date1=&DateCalc($date0,"+0:1:0:0:0:0:0"); | |
4413 | ||
4414 | if (@d) { | |
4415 | foreach $d (@d) { | |
4416 | # Find 1st occurence of DOW (in both months) | |
4417 | $d0=&Date_GetNext($date0,$d,1); | |
4418 | $d1=&Date_GetNext($date1,$d,1); | |
4419 | ||
4420 | @tmp=(); | |
4421 | while (&Date_Cmp($d0,$d1)<0) { | |
4422 | push(@tmp,$d0); | |
4423 | $d0=&DateCalc($d0,"+0:0:1:0:0:0:0"); | |
4424 | } | |
4425 | ||
4426 | @tmp2=(); | |
4427 | foreach $w (@w) { | |
4428 | if ($w>0) { | |
4429 | push(@tmp2,$tmp[$w-1]); | |
4430 | } else { | |
4431 | push(@tmp2,$tmp[$#tmp+1+$w]); | |
4432 | } | |
4433 | } | |
4434 | @tmp2=sort(@tmp2); | |
4435 | push(@date,@tmp2); | |
4436 | } | |
4437 | ||
4438 | } else { | |
4439 | # Find 1st day of 1st week | |
4440 | if ($FDn != 0) { | |
4441 | $date0=&Date_GetNext($date0,$FDn,1); | |
4442 | } else { | |
4443 | $date0=&Date_Join($y,$m,$FIn,0,0,0); | |
4444 | } | |
4445 | $date0=&Date_GetPrev($date0,$Cnf{"FirstDay"},1); | |
4446 | ||
4447 | # Find 1st day of 1st week of next month | |
4448 | if ($FDn != 0) { | |
4449 | $date1=&Date_GetNext($date1,$FDn,1); | |
4450 | } else { | |
4451 | $date1=&DateCalc($date1,"+0:0:0:".($FIn-1).":0:0:0") if ($FIn>1); | |
4452 | } | |
4453 | $date1=&Date_GetPrev($date1,$Cnf{"FirstDay"},1); | |
4454 | ||
4455 | @tmp=(); | |
4456 | while (&Date_Cmp($date0,$date1)<0) { | |
4457 | push(@tmp,$date0); | |
4458 | $date0=&DateCalc($date0,"+0:0:1:0:0:0:0"); | |
4459 | } | |
4460 | ||
4461 | @tmp2=(); | |
4462 | foreach $w (@w) { | |
4463 | if ($w>0) { | |
4464 | push(@tmp2,$tmp[$w-1]); | |
4465 | } else { | |
4466 | push(@tmp2,$tmp[$#tmp+1+$w]); | |
4467 | } | |
4468 | } | |
4469 | @tmp2=sort(@tmp2); | |
4470 | push(@date,@tmp2); | |
4471 | } | |
4472 | } | |
4473 | ||
4474 | @date; | |
4475 | } | |
4476 | ||
4477 | # This returns a sorted list of dates formed by adding/subtracting | |
4478 | # $delta to $dateb in the range $date0<=$d<$dateb. The first date int | |
4479 | # the list is actually the first date<$date0 and the last date in the | |
4480 | # list is the first date>=$date1 (because sometimes the set part will | |
4481 | # move the date back into the range). | |
4482 | sub Date_Recur { | |
4483 | my($date0,$date1,$dateb,$delta)=@_; | |
4484 | my(@ret,$d)=(); | |
4485 | ||
4486 | while (&Date_Cmp($dateb,$date0)<0) { | |
4487 | $dateb=&DateCalc_DateDelta($dateb,$delta); | |
4488 | } | |
4489 | while (&Date_Cmp($dateb,$date1)>=0) { | |
4490 | $dateb=&DateCalc_DateDelta($dateb,"-$delta"); | |
4491 | } | |
4492 | ||
4493 | # Add the dates $date0..$dateb | |
4494 | $d=$dateb; | |
4495 | while (&Date_Cmp($d,$date0)>=0) { | |
4496 | unshift(@ret,$d); | |
4497 | $d=&DateCalc_DateDelta($d,"-$delta"); | |
4498 | } | |
4499 | # Add the first date earler than the range | |
4500 | unshift(@ret,$d); | |
4501 | ||
4502 | # Add the dates $dateb..$date1 | |
4503 | $d=&DateCalc_DateDelta($dateb,$delta); | |
4504 | while (&Date_Cmp($d,$date1)<0) { | |
4505 | push(@ret,$d); | |
4506 | $d=&DateCalc_DateDelta($d,$delta); | |
4507 | } | |
4508 | # Add the first date later than the range | |
4509 | push(@ret,$d); | |
4510 | ||
4511 | @ret; | |
4512 | } | |
4513 | ||
4514 | # This sets the values in each date of a recurrence. | |
4515 | # | |
4516 | # $h,$m,$s can each be values or lists "1-2,4". If any are equal to "-1", | |
4517 | # they are not set (and none of the larger elements are set). | |
4518 | sub Date_RecurSetTime { | |
4519 | my($date0,$date1,$dates,$h,$m,$s)=@_; | |
4520 | my(@dates)=@$dates; | |
4521 | my(@h,@m,@s,$date,@tmp)=(); | |
4522 | ||
4523 | $m="-1" if ($s eq "-1"); | |
4524 | $h="-1" if ($m eq "-1"); | |
4525 | ||
4526 | if ($h ne "-1") { | |
4527 | @h=&ReturnList($h); | |
4528 | return () if ! (@h); | |
4529 | @h=sort { $a<=>$b } (@h); | |
4530 | ||
4531 | @tmp=(); | |
4532 | foreach $date (@dates) { | |
4533 | foreach $h (@h) { | |
4534 | push(@tmp,&Date_SetDateField($date,"h",$h,1)); | |
4535 | } | |
4536 | } | |
4537 | @dates=@tmp; | |
4538 | } | |
4539 | ||
4540 | if ($m ne "-1") { | |
4541 | @m=&ReturnList($m); | |
4542 | return () if ! (@m); | |
4543 | @m=sort { $a<=>$b } (@m); | |
4544 | ||
4545 | @tmp=(); | |
4546 | foreach $date (@dates) { | |
4547 | foreach $m (@m) { | |
4548 | push(@tmp,&Date_SetDateField($date,"mn",$m,1)); | |
4549 | } | |
4550 | } | |
4551 | @dates=@tmp; | |
4552 | } | |
4553 | ||
4554 | if ($s ne "-1") { | |
4555 | @s=&ReturnList($s); | |
4556 | return () if ! (@s); | |
4557 | @s=sort { $a<=>$b } (@s); | |
4558 | ||
4559 | @tmp=(); | |
4560 | foreach $date (@dates) { | |
4561 | foreach $s (@s) { | |
4562 | push(@tmp,&Date_SetDateField($date,"s",$s,1)); | |
4563 | } | |
4564 | } | |
4565 | @dates=@tmp; | |
4566 | } | |
4567 | ||
4568 | @tmp=(); | |
4569 | foreach $date (@dates) { | |
4570 | push(@tmp,$date) if (&Date_Cmp($date,$date0)>=0 && | |
4571 | &Date_Cmp($date,$date1)<0 && | |
4572 | &Date_Split($date)); | |
4573 | } | |
4574 | ||
4575 | @tmp; | |
4576 | } | |
4577 | ||
4578 | sub DateCalc_DateDate { | |
4579 | print "DEBUG: DateCalc_DateDate\n" if ($Curr{"Debug"} =~ /trace/); | |
4580 | my($D1,$D2,$mode)=@_; | |
4581 | my(@d_in_m)=(0,31,28,31,30,31,30,31,31,30,31,30,31); | |
4582 | $mode=0 if (! defined $mode); | |
4583 | ||
4584 | # Exact mode | |
4585 | if ($mode==0) { | |
4586 | my($y1,$m1,$d1,$h1,$mn1,$s1)=&Date_Split($D1, 1); | |
4587 | my($y2,$m2,$d2,$h2,$mn2,$s2)=&Date_Split($D2, 1); | |
4588 | my($i,@delta,$d,$delta,$y)=(); | |
4589 | ||
4590 | # form the delta for hour/min/sec | |
4591 | $delta[4]=$h2-$h1; | |
4592 | $delta[5]=$mn2-$mn1; | |
4593 | $delta[6]=$s2-$s1; | |
4594 | ||
4595 | # form the delta for yr/mon/day | |
4596 | $delta[0]=$delta[1]=0; | |
4597 | $d=0; | |
4598 | if ($y2>$y1) { | |
4599 | $d=&Date_DaysInYear($y1) - &Date_DayOfYear($m1,$d1,$y1); | |
4600 | $d+=&Date_DayOfYear($m2,$d2,$y2); | |
4601 | for ($y=$y1+1; $y<$y2; $y++) { | |
4602 | $d+= &Date_DaysInYear($y); | |
4603 | } | |
4604 | } elsif ($y2<$y1) { | |
4605 | $d=&Date_DaysInYear($y2) - &Date_DayOfYear($m2,$d2,$y2); | |
4606 | $d+=&Date_DayOfYear($m1,$d1,$y1); | |
4607 | for ($y=$y2+1; $y<$y1; $y++) { | |
4608 | $d+= &Date_DaysInYear($y); | |
4609 | } | |
4610 | $d *= -1; | |
4611 | } else { | |
4612 | $d=&Date_DayOfYear($m2,$d2,$y2) - &Date_DayOfYear($m1,$d1,$y1); | |
4613 | } | |
4614 | $delta[2]=0; | |
4615 | $delta[3]=$d; | |
4616 | ||
4617 | for ($i=0; $i<7; $i++) { | |
4618 | $delta[$i]="+".$delta[$i] if ($delta[$i]>=0); | |
4619 | } | |
4620 | ||
4621 | $delta=join(":",@delta); | |
4622 | $delta=&Delta_Normalize($delta,0); | |
4623 | return $delta; | |
4624 | } | |
4625 | ||
4626 | my($date1,$date2)=($D1,$D2); | |
4627 | my($tmp,$sign,$err,@tmp)=(); | |
4628 | ||
4629 | # make sure both are work days | |
4630 | if ($mode==2 || $mode==3) { | |
4631 | $date1=&Date_NextWorkDay($date1,0,1); | |
4632 | $date2=&Date_NextWorkDay($date2,0,1); | |
4633 | } | |
4634 | ||
4635 | # make sure date1 comes before date2 | |
4636 | if (&Date_Cmp($date1,$date2)>0) { | |
4637 | $sign="-"; | |
4638 | $tmp=$date1; | |
4639 | $date1=$date2; | |
4640 | $date2=$tmp; | |
4641 | } else { | |
4642 | $sign="+"; | |
4643 | } | |
4644 | if (&Date_Cmp($date1,$date2)==0) { | |
4645 | return "+0:+0:+0:+0:+0:+0:+0" if ($Cnf{"DeltaSigns"}); | |
4646 | return "+0:0:0:0:0:0:0"; | |
4647 | } | |
4648 | ||
4649 | my($y1,$m1,$d1,$h1,$mn1,$s1)=&Date_Split($date1, 1); | |
4650 | my($y2,$m2,$d2,$h2,$mn2,$s2)=&Date_Split($date2, 1); | |
4651 | my($dy,$dm,$dw,$dd,$dh,$dmn,$ds,$ddd)=(0,0,0,0,0,0,0,0); | |
4652 | ||
4653 | if ($mode != 3) { | |
4654 | ||
4655 | # Do years | |
4656 | $dy=$y2-$y1; | |
4657 | $dm=0; | |
4658 | if ($dy>0) { | |
4659 | $tmp=&DateCalc_DateDelta($date1,"+$dy:0:0:0:0:0:0",\$err,0); | |
4660 | if (&Date_Cmp($tmp,$date2)>0) { | |
4661 | $dy--; | |
4662 | $tmp=$date1; | |
4663 | $tmp=&DateCalc_DateDelta($date1,"+$dy:0:0:0:0:0:0",\$err,0) | |
4664 | if ($dy>0); | |
4665 | $dm=12; | |
4666 | } | |
4667 | $date1=$tmp; | |
4668 | } | |
4669 | ||
4670 | # Do months | |
4671 | $dm+=$m2-$m1; | |
4672 | if ($dm>0) { | |
4673 | $tmp=&DateCalc_DateDelta($date1,"+0:$dm:0:0:0:0:0",\$err,0); | |
4674 | if (&Date_Cmp($tmp,$date2)>0) { | |
4675 | $dm--; | |
4676 | $tmp=$date1; | |
4677 | $tmp=&DateCalc_DateDelta($date1,"+0:$dm:0:0:0:0:0",\$err,0) | |
4678 | if ($dm>0); | |
4679 | } | |
4680 | $date1=$tmp; | |
4681 | } | |
4682 | ||
4683 | # At this point, check to see that we're on a business day again so that | |
4684 | # Aug 3 (Monday) -> Sep 3 (Sunday) -> Sep 4 (Monday) = 1 month | |
4685 | if ($mode==2) { | |
4686 | if (! &Date_IsWorkDay($date1,0)) { | |
4687 | $date1=&Date_NextWorkDay($date1,0,1); | |
4688 | } | |
4689 | } | |
4690 | } | |
4691 | ||
4692 | # Do days | |
4693 | if ($mode==2 || $mode==3) { | |
4694 | $dd=0; | |
4695 | while (1) { | |
4696 | $tmp=&Date_NextWorkDay($date1,1,1); | |
4697 | if (&Date_Cmp($tmp,$date2)<=0) { | |
4698 | $dd++; | |
4699 | $date1=$tmp; | |
4700 | } else { | |
4701 | last; | |
4702 | } | |
4703 | } | |
4704 | ||
4705 | } else { | |
4706 | ($y1,$m1,$d1)=( &Date_Split($date1, 1) )[0..2]; | |
4707 | $dd=0; | |
4708 | # If we're jumping across months, set $d1 to the first of the next month | |
4709 | # (or possibly the 0th of next month which is equivalent to the last day | |
4710 | # of this month) | |
4711 | if ($m1!=$m2) { | |
4712 | $d_in_m[2]=29 if (&Date_LeapYear($y1)); | |
4713 | $dd=$d_in_m[$m1]-$d1+1; | |
4714 | $d1=1; | |
4715 | $tmp=&DateCalc_DateDelta($date1,"+0:0:0:$dd:0:0:0",\$err,0); | |
4716 | if (&Date_Cmp($tmp,$date2)>0) { | |
4717 | $dd--; | |
4718 | $d1--; | |
4719 | $tmp=&DateCalc_DateDelta($date1,"+0:0:0:$dd:0:0:0",\$err,0); | |
4720 | } | |
4721 | $date1=$tmp; | |
4722 | } | |
4723 | ||
4724 | $ddd=0; | |
4725 | if ($d1<$d2) { | |
4726 | $ddd=$d2-$d1; | |
4727 | $tmp=&DateCalc_DateDelta($date1,"+0:0:0:$ddd:0:0:0",\$err,0); | |
4728 | if (&Date_Cmp($tmp,$date2)>0) { | |
4729 | $ddd--; | |
4730 | $tmp=&DateCalc_DateDelta($date1,"+0:0:0:$ddd:0:0:0",\$err,0); | |
4731 | } | |
4732 | $date1=$tmp; | |
4733 | } | |
4734 | $dd+=$ddd; | |
4735 | } | |
4736 | ||
4737 | # in business mode, make sure h1 comes before h2 (if not find delta between | |
4738 | # now and end of day and move to start of next business day) | |
4739 | $d1=( &Date_Split($date1, 1) )[2]; | |
4740 | $dh=$dmn=$ds=0; | |
4741 | if ($mode==2 || $mode==3 and $d1 != $d2) { | |
4742 | $tmp=&Date_SetTime($date1,$Cnf{"WorkDayEnd"}); | |
4743 | $tmp=&DateCalc_DateDelta($tmp,"+0:0:0:0:0:1:0") | |
4744 | if ($Cnf{"WorkDay24Hr"}); | |
4745 | $tmp=&DateCalc_DateDate($date1,$tmp,0); | |
4746 | ($tmp,$tmp,$tmp,$tmp,$dh,$dmn,$ds)=&Delta_Split($tmp); | |
4747 | $date1=&Date_NextWorkDay($date1,1,0); | |
4748 | $date1=&Date_SetTime($date1,$Cnf{"WorkDayBeg"}); | |
4749 | $d1=( &Date_Split($date1, 1) )[2]; | |
4750 | confess "ERROR: DateCalc DateDate Business.\n" if ($d1 != $d2); | |
4751 | } | |
4752 | ||
4753 | # Hours, minutes, seconds | |
4754 | $tmp=&DateCalc_DateDate($date1,$date2,0); | |
4755 | @tmp=&Delta_Split($tmp); | |
4756 | $dh += $tmp[4]; | |
4757 | $dmn += $tmp[5]; | |
4758 | $ds += $tmp[6]; | |
4759 | ||
4760 | $tmp="$sign$dy:$dm:0:$dd:$dh:$dmn:$ds"; | |
4761 | &Delta_Normalize($tmp,$mode); | |
4762 | } | |
4763 | ||
4764 | sub DateCalc_DeltaDelta { | |
4765 | print "DEBUG: DateCalc_DeltaDelta\n" if ($Curr{"Debug"} =~ /trace/); | |
4766 | my($D1,$D2,$mode)=@_; | |
4767 | my(@delta1,@delta2,$i,$delta,@delta)=(); | |
4768 | $mode=0 if (! defined $mode); | |
4769 | ||
4770 | @delta1=&Delta_Split($D1); | |
4771 | @delta2=&Delta_Split($D2); | |
4772 | for ($i=0; $i<7; $i++) { | |
4773 | $delta[$i]=$delta1[$i]+$delta2[$i]; | |
4774 | $delta[$i]="+".$delta[$i] if ($delta[$i]>=0); | |
4775 | } | |
4776 | ||
4777 | $delta=join(":",@delta); | |
4778 | $delta=&Delta_Normalize($delta,$mode); | |
4779 | return $delta; | |
4780 | } | |
4781 | ||
4782 | sub DateCalc_DateDelta { | |
4783 | print "DEBUG: DateCalc_DateDelta\n" if ($Curr{"Debug"} =~ /trace/); | |
4784 | my($D1,$D2,$errref,$mode)=@_; | |
4785 | my($date)=(); | |
4786 | my(@d_in_m)=(0,31,28,31,30,31,30,31,31,30,31,30,31); | |
4787 | my($h1,$m1,$h2,$m2,$len,$hh,$mm)=(); | |
4788 | $mode=0 if (! defined $mode); | |
4789 | ||
4790 | if ($mode==2 || $mode==3) { | |
4791 | $h1=$Curr{"WDBh"}; | |
4792 | $m1=$Curr{"WDBm"}; | |
4793 | $h2=$Curr{"WDEh"}; | |
4794 | $m2=$Curr{"WDEm"}; | |
4795 | $hh=$h2-$h1; | |
4796 | $mm=$m2-$m1; | |
4797 | if ($mm<0) { | |
4798 | $hh--; | |
4799 | $mm+=60; | |
4800 | } | |
4801 | } | |
4802 | ||
4803 | # Date, delta | |
4804 | my($y,$m,$d,$h,$mn,$s)=&Date_Split($D1, 1); | |
4805 | my($dy,$dm,$dw,$dd,$dh,$dmn,$ds)=&Delta_Split($D2); | |
4806 | ||
4807 | # do the month/year part | |
4808 | $y+=$dy; | |
4809 | while (length($y)<4) { | |
4810 | $y = "0$y"; | |
4811 | } | |
4812 | &ModuloAddition(-12,$dm,\$m,\$y); # -12 means 1-12 instead of 0-11 | |
4813 | $d_in_m[2]=29 if (&Date_LeapYear($y)); | |
4814 | ||
4815 | # if we have gone past the last day of a month, move the date back to | |
4816 | # the last day of the month | |
4817 | if ($d>$d_in_m[$m]) { | |
4818 | $d=$d_in_m[$m]; | |
4819 | } | |
4820 | ||
4821 | # do the week part | |
4822 | if ($mode==0 || $mode==1) { | |
4823 | $dd += $dw*7; | |
4824 | } else { | |
4825 | $date=&DateCalc_DateDelta(&Date_Join($y,$m,$d,$h,$mn,$s), | |
4826 | "+0:0:$dw:0:0:0:0",0); | |
4827 | ($y,$m,$d,$h,$mn,$s)=&Date_Split($date, 1); | |
4828 | } | |
4829 | ||
4830 | # in business mode, set the day to a work day at this point so the h/mn/s | |
4831 | # stuff will work out | |
4832 | if ($mode==2 || $mode==3) { | |
4833 | $d=$d_in_m[$m] if ($d>$d_in_m[$m]); | |
4834 | $date=&Date_NextWorkDay(&Date_Join($y,$m,$d,$h,$mn,$s),0,1); | |
4835 | ($y,$m,$d,$h,$mn,$s)=&Date_Split($date, 1); | |
4836 | } | |
4837 | ||
4838 | # seconds, minutes, hours | |
4839 | &ModuloAddition(60,$ds,\$s,\$mn); | |
4840 | if ($mode==2 || $mode==3) { | |
4841 | while (1) { | |
4842 | &ModuloAddition(60,$dmn,\$mn,\$h); | |
4843 | $h+= $dh; | |
4844 | ||
4845 | if ($h>$h2 or $h==$h2 && $mn>$m2) { | |
4846 | $dh=$h-$h2; | |
4847 | $dmn=$mn-$m2; | |
4848 | $h=$h1; | |
4849 | $mn=$m1; | |
4850 | $dd++; | |
4851 | ||
4852 | } elsif ($h<$h1 or $h==$h1 && $mn<$m1) { | |
4853 | $dh=$h-$h1; | |
4854 | $dmn=$m1-$mn; | |
4855 | $h=$h2; | |
4856 | $mn=$m2; | |
4857 | $dd--; | |
4858 | ||
4859 | } elsif ($h==$h2 && $mn==$m2) { | |
4860 | $dd++; | |
4861 | $dh=-$hh; | |
4862 | $dmn=-$mm; | |
4863 | ||
4864 | } else { | |
4865 | last; | |
4866 | } | |
4867 | } | |
4868 | ||
4869 | } else { | |
4870 | &ModuloAddition(60,$dmn,\$mn,\$h); | |
4871 | &ModuloAddition(24,$dh,\$h,\$d); | |
4872 | } | |
4873 | ||
4874 | # If we have just gone past the last day of the month, we need to make | |
4875 | # up for this: | |
4876 | if ($d>$d_in_m[$m]) { | |
4877 | $dd+= $d-$d_in_m[$m]; | |
4878 | $d=$d_in_m[$m]; | |
4879 | } | |
4880 | ||
4881 | # days | |
4882 | if ($mode==2 || $mode==3) { | |
4883 | if ($dd>=0) { | |
4884 | $date=&Date_NextWorkDay(&Date_Join($y,$m,$d,$h,$mn,$s),$dd,1); | |
4885 | } else { | |
4886 | $date=&Date_PrevWorkDay(&Date_Join($y,$m,$d,$h,$mn,$s),-$dd,1); | |
4887 | } | |
4888 | ($y,$m,$d,$h,$mn,$s)=&Date_Split($date, 1); | |
4889 | ||
4890 | } else { | |
4891 | $d_in_m[2]=29 if (&Date_LeapYear($y)); | |
4892 | $d=$d_in_m[$m] if ($d>$d_in_m[$m]); | |
4893 | $d += $dd; | |
4894 | while ($d<1) { | |
4895 | $m--; | |
4896 | if ($m==0) { | |
4897 | $m=12; | |
4898 | $y--; | |
4899 | if (&Date_LeapYear($y)) { | |
4900 | $d_in_m[2]=29; | |
4901 | } else { | |
4902 | $d_in_m[2]=28; | |
4903 | } | |
4904 | } | |
4905 | $d += $d_in_m[$m]; | |
4906 | } | |
4907 | while ($d>$d_in_m[$m]) { | |
4908 | $d -= $d_in_m[$m]; | |
4909 | $m++; | |
4910 | if ($m==13) { | |
4911 | $m=1; | |
4912 | $y++; | |
4913 | if (&Date_LeapYear($y)) { | |
4914 | $d_in_m[2]=29; | |
4915 | } else { | |
4916 | $d_in_m[2]=28; | |
4917 | } | |
4918 | } | |
4919 | } | |
4920 | } | |
4921 | ||
4922 | if ($y<0 or $y>9999) { | |
4923 | $$errref=3; | |
4924 | return; | |
4925 | } | |
4926 | &Date_Join($y,$m,$d,$h,$mn,$s); | |
4927 | } | |
4928 | ||
4929 | sub Date_UpdateHolidays { | |
4930 | print "DEBUG: Date_UpdateHolidays\n" if ($Curr{"Debug"} =~ /trace/); | |
4931 | my($year)=@_; | |
4932 | $Holiday{"year"}=$year; | |
4933 | $Holiday{"dates"}{$year}={}; | |
4934 | ||
4935 | my($date,$delta,$err)=(); | |
4936 | my($key,@tmp,$tmp); | |
4937 | ||
4938 | foreach $key (keys %{ $Holiday{"desc"} }) { | |
4939 | @tmp=&Recur_Split($key); | |
4940 | if (@tmp) { | |
4941 | $tmp=&ParseDateString("${year}010100:00:00"); | |
4942 | ($date)=&ParseRecur($key,$tmp,$tmp,($year+1)."-01-01"); | |
4943 | next if (! $date); | |
4944 | ||
4945 | } elsif ($key =~ /^(.*)([+-].*)$/) { | |
4946 | # Date +/- Delta | |
4947 | ($date,$delta)=($1,$2); | |
4948 | $tmp=&ParseDateString("$date $year"); | |
4949 | if ($tmp) { | |
4950 | $date=$tmp; | |
4951 | } else { | |
4952 | $date=&ParseDateString($date); | |
4953 | next if ($date !~ /^$year/); | |
4954 | } | |
4955 | $date=&DateCalc($date,$delta,\$err,0); | |
4956 | ||
4957 | } else { | |
4958 | # Date | |
4959 | $date=$key; | |
4960 | $tmp=&ParseDateString("$date $year"); | |
4961 | if ($tmp) { | |
4962 | $date=$tmp; | |
4963 | } else { | |
4964 | $date=&ParseDateString($date); | |
4965 | next if ($date !~ /^$year/); | |
4966 | } | |
4967 | } | |
4968 | $Holiday{"dates"}{$year}{$date}=$Holiday{"desc"}{$key}; | |
4969 | } | |
4970 | } | |
4971 | ||
4972 | # This sets a Date::Manip config variable. | |
4973 | sub Date_SetConfigVariable { | |
4974 | print "DEBUG: Date_SetConfigVariable\n" if ($Curr{"Debug"} =~ /trace/); | |
4975 | my($var,$val)=@_; | |
4976 | ||
4977 | # These are most appropriate for command line options instead of in files. | |
4978 | $Cnf{"PathSep"}=$val, return if ($var =~ /^PathSep$/i); | |
4979 | $Cnf{"PersonalCnf"}=$val, return if ($var =~ /^PersonalCnf$/i); | |
4980 | $Cnf{"PersonalCnfPath"}=$val, return if ($var =~ /^PersonalCnfPath$/i); | |
4981 | &EraseHolidays(), return if ($var =~ /^EraseHolidays$/i); | |
4982 | $Cnf{"IgnoreGlobalCnf"}=1, return if ($var =~ /^IgnoreGlobalCnf$/i); | |
4983 | $Cnf{"GlobalCnf"}=$val, return if ($var =~ /^GlobalCnf$/i); | |
4984 | ||
4985 | $Curr{"InitLang"}=1, | |
4986 | $Cnf{"Language"}=$val, return if ($var =~ /^Language$/i); | |
4987 | $Cnf{"DateFormat"}=$val, return if ($var =~ /^DateFormat$/i); | |
4988 | $Cnf{"TZ"}=$val, return if ($var =~ /^TZ$/i); | |
4989 | $Cnf{"ConvTZ"}=$val, return if ($var =~ /^ConvTZ$/i); | |
4990 | $Cnf{"Internal"}=$val, return if ($var =~ /^Internal$/i); | |
4991 | $Cnf{"FirstDay"}=$val, return if ($var =~ /^FirstDay$/i); | |
4992 | $Cnf{"WorkWeekBeg"}=$val, return if ($var =~ /^WorkWeekBeg$/i); | |
4993 | $Cnf{"WorkWeekEnd"}=$val, return if ($var =~ /^WorkWeekEnd$/i); | |
4994 | $Cnf{"WorkDayBeg"}=$val, | |
4995 | $Curr{"ResetWorkDay"}=1, return if ($var =~ /^WorkDayBeg$/i); | |
4996 | $Cnf{"WorkDayEnd"}=$val, | |
4997 | $Curr{"ResetWorkDay"}=1, return if ($var =~ /^WorkDayEnd$/i); | |
4998 | $Cnf{"WorkDay24Hr"}=$val, | |
4999 | $Curr{"ResetWorkDay"}=1, return if ($var =~ /^WorkDay24Hr$/i); | |
5000 | $Cnf{"DeltaSigns"}=$val, return if ($var =~ /^DeltaSigns$/i); | |
5001 | $Cnf{"Jan1Week1"}=$val, return if ($var =~ /^Jan1Week1$/i); | |
5002 | $Cnf{"YYtoYYYY"}=$val, return if ($var =~ /^YYtoYYYY$/i); | |
5003 | $Cnf{"UpdateCurrTZ"}=$val, return if ($var =~ /^UpdateCurrTZ$/i); | |
5004 | $Cnf{"IntCharSet"}=$val, return if ($var =~ /^IntCharSet$/i); | |
5005 | $Curr{"DebugVal"}=$val, return if ($var =~ /^Debug$/i); | |
5006 | $Cnf{"TomorrowFirst"}=$val, return if ($var =~ /^TomorrowFirst$/i); | |
5007 | $Cnf{"ForceDate"}=$val, return if ($var =~ /^ForceDate$/i); | |
5008 | ||
5009 | confess "ERROR: Unknown configuration variable $var in Date::Manip.\n"; | |
5010 | } | |
5011 | ||
5012 | sub EraseHolidays { | |
5013 | print "DEBUG: EraseHolidays\n" if ($Curr{"Debug"} =~ /trace/); | |
5014 | ||
5015 | $Cnf{"EraseHolidays"}=0; | |
5016 | delete $Holiday{"list"}; | |
5017 | $Holiday{"list"}={}; | |
5018 | delete $Holiday{"desc"}; | |
5019 | $Holiday{"desc"}={}; | |
5020 | $Holiday{"dates"}={}; | |
5021 | } | |
5022 | ||
5023 | # This returns a pointer to a list of times and events in the format | |
5024 | # [ date, [ events ], date, [ events ], ... ] | |
5025 | # where each list of events are events that are in effect at the date | |
5026 | # immediately preceding the list. | |
5027 | # | |
5028 | # This takes either one date or two dates as arguments. | |
5029 | sub Events_Calc { | |
5030 | print "DEBUG: Events_Calc\n" if ($Curr{"Debug"} =~ /trace/); | |
5031 | ||
5032 | my($date0,$date1)=@_; | |
5033 | ||
5034 | my($tmp); | |
5035 | $date0=&ParseDateString($date0); | |
5036 | return undef if (! $date0); | |
5037 | if ($date1) { | |
5038 | $date1=&ParseDateString($date1); | |
5039 | if (&Date_Cmp($date0,$date1)>0) { | |
5040 | $tmp=$date1; | |
5041 | $date1=$date0; | |
5042 | $date0=$tmp; | |
5043 | } | |
5044 | } else { | |
5045 | $date1=&DateCalc_DateDelta($date0,"+0:0:0:0:0:0:1"); | |
5046 | } | |
5047 | ||
5048 | # | |
5049 | # [ d0,d1,del,name ] => [ d0, d1+del ) | |
5050 | # [ d0,0,del,name ] => [ d0, d0+del ) | |
5051 | # | |
5052 | my(%ret,$d0,$d1,$del,$name,$c0,$c1); | |
5053 | my(@tmp)=@{ $Events{"dates"} }; | |
5054 | DATE: while (@tmp) { | |
5055 | ($d0,$d1,$del,$name)=splice(@tmp,0,4); | |
5056 | $d0=&ParseDateString($d0); | |
5057 | $d1=&ParseDateString($d1) if ($d1); | |
5058 | $del=&ParseDateDelta($del) if ($del); | |
5059 | if ($d1) { | |
5060 | if ($del) { | |
5061 | $d1=&DateCalc_DateDelta($d1,$del); | |
5062 | } | |
5063 | } else { | |
5064 | $d1=&DateCalc_DateDelta($d0,$del); | |
5065 | } | |
5066 | if (&Date_Cmp($d0,$d1)>0) { | |
5067 | $tmp=$d1; | |
5068 | $d1=$d0; | |
5069 | $d0=$tmp; | |
5070 | } | |
5071 | # [ date0,date1 ) | |
5072 | # [ d0,d1 ) OR [ d0,d1 ) | |
5073 | next DATE if (&Date_Cmp($d1,$date0)<=0 || | |
5074 | &Date_Cmp($d0,$date1)>=0); | |
5075 | # [ date0,date1 ) | |
5076 | # [ d0,d1 ) | |
5077 | # [ d0, d1 ) | |
5078 | if (&Date_Cmp($d0,$date0)<=0) { | |
5079 | push @{ $ret{$date0} },$name; | |
5080 | push @{ $ret{$d1} },"!$name" if (&Date_Cmp($d1,$date1)<0); | |
5081 | next DATE; | |
5082 | } | |
5083 | # [ date0,date1 ) | |
5084 | # [ d0,d1 ) | |
5085 | if (&Date_Cmp($d1,$date1)>=0) { | |
5086 | push @{ $ret{$d0} },$name; | |
5087 | next DATE; | |
5088 | } | |
5089 | # [ date0,date1 ) | |
5090 | # [ d0,d1 ) | |
5091 | push @{ $ret{$d0} },$name; | |
5092 | push @{ $ret{$d1} },"!$name"; | |
5093 | } | |
5094 | ||
5095 | # | |
5096 | # [ recur,delta0,delta1,name ] => [ {date-delta0},{date+delta1} ) | |
5097 | # | |
5098 | my($rec,$del0,$del1,@d); | |
5099 | @tmp=@{ $Events{"recur"} }; | |
5100 | RECUR: while (@tmp) { | |
5101 | ($rec,$del0,$del1,$name)=splice(@tmp,0,4); | |
5102 | @d=(); | |
5103 | ||
5104 | } | |
5105 | ||
5106 | # Sort them AND take into account the "!$name" entries. | |
5107 | my(%tmp,$date,@tmp2,@ret); | |
5108 | @d=sort { &Date_Cmp($a,$b) } keys %ret; | |
5109 | foreach $date (@d) { | |
5110 | @tmp=@{ $ret{$date} }; | |
5111 | @tmp2=(); | |
5112 | foreach $tmp (@tmp) { | |
5113 | push(@tmp2,$tmp), next if ($tmp =~ /^!/); | |
5114 | $tmp{$tmp}=1; | |
5115 | } | |
5116 | foreach $tmp (@tmp2) { | |
5117 | $tmp =~ s/^!//; | |
5118 | delete $tmp{$tmp}; | |
5119 | } | |
5120 | push(@ret,$date,[ keys %tmp ]); | |
5121 | } | |
5122 | ||
5123 | return \@ret; | |
5124 | } | |
5125 | ||
5126 | # This parses the raw events list | |
5127 | sub Events_ParseRaw { | |
5128 | print "DEBUG: Events_ParseRaw\n" if ($Curr{"Debug"} =~ /trace/); | |
5129 | ||
5130 | # Only need to be parsed once | |
5131 | my($force)=@_; | |
5132 | $Events{"parsed"}=0 if ($force); | |
5133 | return if ($Events{"parsed"}); | |
5134 | $Events{"parsed"}=1; | |
5135 | ||
5136 | my(@events)=@{ $Events{"raw"} }; | |
5137 | my($event,$name,@event,$date0,$date1,$tmp,$delta,$recur0,$recur1,@recur,$r, | |
5138 | $recur); | |
5139 | EVENT: while (@events) { | |
5140 | ($event,$name)=splice(@events,0,2); | |
5141 | @event=split(/\s*;\s*/,$event); | |
5142 | ||
5143 | if ($#event == 0) { | |
5144 | ||
5145 | if ($date0=&ParseDateString($event[0])) { | |
5146 | # | |
5147 | # date = event | |
5148 | # | |
5149 | $tmp=&ParseDateString("$event[0] 00:00:00"); | |
5150 | if ($tmp && $tmp eq $date0) { | |
5151 | $delta="+0:0:0:1:0:0:0"; | |
5152 | } else { | |
5153 | $delta="+0:0:0:0:1:0:0"; | |
5154 | } | |
5155 | push @{ $Events{"dates"} },($date0,0,$delta,$name); | |
5156 | ||
5157 | } elsif ($recur=&ParseRecur($event[0])) { | |
5158 | # | |
5159 | # recur = event | |
5160 | # | |
5161 | ($recur0,$recur1)=&Recur_Split($recur); | |
5162 | if ($recur0) { | |
5163 | if ($recur1) { | |
5164 | $r="$recur0:$recur1"; | |
5165 | } else { | |
5166 | $r=$recur0; | |
5167 | } | |
5168 | } else { | |
5169 | $r=$recur1; | |
5170 | } | |
5171 | (@recur)=split(/:/,$r); | |
5172 | if (pop(@recur)==0 && pop(@recur)==0 && pop(@recur)==0) { | |
5173 | $delta="+0:0:0:1:0:0:0"; | |
5174 | } else { | |
5175 | $delta="+0:0:0:0:1:0:0"; | |
5176 | } | |
5177 | push @{ $Events{"recur"} },($recur,0,$delta,$name); | |
5178 | ||
5179 | } else { | |
5180 | # ??? = event | |
5181 | warn "WARNING: illegal event ignored [ @event ]\n"; | |
5182 | next EVENT; | |
5183 | } | |
5184 | ||
5185 | } elsif ($#event == 1) { | |
5186 | ||
5187 | if ($date0=&ParseDateString($event[0])) { | |
5188 | ||
5189 | if ($date1=&ParseDateString($event[1])) { | |
5190 | # | |
5191 | # date ; date = event | |
5192 | # | |
5193 | $tmp=&ParseDateString("$event[1] 00:00:00"); | |
5194 | if ($tmp && $tmp eq $date1) { | |
5195 | $date1=&DateCalc_DateDelta($date1,"+0:0:0:1:0:0:0"); | |
5196 | } | |
5197 | push @{ $Events{"dates"} },($date0,$date1,0,$name); | |
5198 | ||
5199 | } elsif ($delta=&ParseDateDelta($event[1])) { | |
5200 | # | |
5201 | # date ; delta = event | |
5202 | # | |
5203 | push @{ $Events{"dates"} },($date0,0,$delta,$name); | |
5204 | ||
5205 | } else { | |
5206 | # date ; ??? = event | |
5207 | warn "WARNING: illegal event ignored [ @event ]\n"; | |
5208 | next EVENT; | |
5209 | } | |
5210 | ||
5211 | } elsif ($recur=&ParseRecur($event[0])) { | |
5212 | ||
5213 | if ($delta=&ParseDateDelta($event[1])) { | |
5214 | # | |
5215 | # recur ; delta = event | |
5216 | # | |
5217 | push @{ $Events{"recur"} },($recur,0,$delta,$name); | |
5218 | ||
5219 | } else { | |
5220 | # recur ; ??? = event | |
5221 | warn "WARNING: illegal event ignored [ @event ]\n"; | |
5222 | next EVENT; | |
5223 | } | |
5224 | ||
5225 | } else { | |
5226 | # ??? ; ??? = event | |
5227 | warn "WARNING: illegal event ignored [ @event ]\n"; | |
5228 | next EVENT; | |
5229 | } | |
5230 | ||
5231 | } else { | |
5232 | # date ; delta0 ; delta1 = event | |
5233 | # recur ; delta0 ; delta1 = event | |
5234 | # ??? ; ??? ; ??? ... = event | |
5235 | warn "WARNING: illegal event ignored [ @event ]\n"; | |
5236 | next EVENT; | |
5237 | } | |
5238 | } | |
5239 | } | |
5240 | ||
5241 | # This reads an init file. | |
5242 | sub Date_InitFile { | |
5243 | print "DEBUG: Date_InitFile\n" if ($Curr{"Debug"} =~ /trace/); | |
5244 | my($file)=@_; | |
5245 | my($in)=new IO::File; | |
5246 | local($_)=(); | |
5247 | my($section)="vars"; | |
5248 | my($var,$val,$recur,$name)=(); | |
5249 | ||
5250 | $in->open($file) || return; | |
5251 | while(defined ($_=<$in>)) { | |
5252 | chomp; | |
5253 | s/^\s+//; | |
5254 | s/\s+$//; | |
5255 | next if (! $_ or /^\#/); | |
5256 | ||
5257 | if (/^\*holiday/i) { | |
5258 | $section="holiday"; | |
5259 | &EraseHolidays() if ($section =~ /holiday/i && $Cnf{"EraseHolidays"}); | |
5260 | next; | |
5261 | } elsif (/^\*events/i) { | |
5262 | $section="events"; | |
5263 | next; | |
5264 | } | |
5265 | ||
5266 | if ($section =~ /var/i) { | |
5267 | confess "ERROR: invalid Date::Manip config file line.\n $_\n" | |
5268 | if (! /(.*\S)\s*=\s*(.*)$/); | |
5269 | ($var,$val)=($1,$2); | |
5270 | &Date_SetConfigVariable($var,$val); | |
5271 | ||
5272 | } elsif ($section =~ /holiday/i) { | |
5273 | confess "ERROR: invalid Date::Manip config file line.\n $_\n" | |
5274 | if (! /(.*\S)\s*=\s*(.*)$/); | |
5275 | ($recur,$name)=($1,$2); | |
5276 | $name="" if (! defined $name); | |
5277 | $Holiday{"desc"}{$recur}=$name; | |
5278 | ||
5279 | } elsif ($section =~ /events/i) { | |
5280 | confess "ERROR: invalid Date::Manip config file line.\n $_\n" | |
5281 | if (! /(.*\S)\s*=\s*(.*)$/); | |
5282 | ($val,$var)=($1,$2); | |
5283 | push @{ $Events{"raw"} },($val,$var); | |
5284 | ||
5285 | } else { | |
5286 | # A section not currently used by Date::Manip (but may be | |
5287 | # used by some extension to it). | |
5288 | next; | |
5289 | } | |
5290 | } | |
5291 | close($in); | |
5292 | } | |
5293 | ||
5294 | # $flag=&Date_TimeCheck(\$h,\$mn,\$s,\$ampm); | |
5295 | # Returns 1 if any of the fields are bad. All fields are optional, and | |
5296 | # all possible checks are done on the data. If a field is not passed in, | |
5297 | # it is set to default values. If data is missing, appropriate defaults | |
5298 | # are supplied. | |
5299 | sub Date_TimeCheck { | |
5300 | print "DEBUG: Date_TimeCheck\n" if ($Curr{"Debug"} =~ /trace/); | |
5301 | my($h,$mn,$s,$ampm)=@_; | |
5302 | my($tmp1,$tmp2,$tmp3)=(); | |
5303 | ||
5304 | $$h="" if (! defined $$h); | |
5305 | $$mn="" if (! defined $$mn); | |
5306 | $$s="" if (! defined $$s); | |
5307 | $$ampm="" if (! defined $$ampm); | |
5308 | $$ampm=uc($$ampm) if ($$ampm); | |
5309 | ||
5310 | # Check hour | |
5311 | $tmp1=$Lang{$Cnf{"Language"}}{"AmPm"}; | |
5312 | $tmp2=""; | |
5313 | if ($$ampm =~ /^$tmp1$/i) { | |
5314 | $tmp3=$Lang{$Cnf{"Language"}}{"AM"}; | |
5315 | $tmp2="AM" if ($$ampm =~ /^$tmp3$/i); | |
5316 | $tmp3=$Lang{$Cnf{"Language"}}{"PM"}; | |
5317 | $tmp2="PM" if ($$ampm =~ /^$tmp3$/i); | |
5318 | } elsif ($$ampm) { | |
5319 | return 1; | |
5320 | } | |
5321 | if ($tmp2 eq "AM" || $tmp2 eq "PM") { | |
5322 | $$h="0$$h" if (length($$h)==1); | |
5323 | return 1 if ($$h<1 || $$h>12); | |
5324 | $$h="00" if ($tmp2 eq "AM" and $$h==12); | |
5325 | $$h += 12 if ($tmp2 eq "PM" and $$h!=12); | |
5326 | } else { | |
5327 | $$h="00" if ($$h eq ""); | |
5328 | $$h="0$$h" if (length($$h)==1); | |
5329 | return 1 if (! &IsInt($$h,0,23)); | |
5330 | $tmp2="AM" if ($$h<12); | |
5331 | $tmp2="PM" if ($$h>=12); | |
5332 | } | |
5333 | $$ampm=$Lang{$Cnf{"Language"}}{"AMstr"}; | |
5334 | $$ampm=$Lang{$Cnf{"Language"}}{"PMstr"} if ($tmp2 eq "PM"); | |
5335 | ||
5336 | # Check minutes | |
5337 | $$mn="00" if ($$mn eq ""); | |
5338 | $$mn="0$$mn" if (length($$mn)==1); | |
5339 | return 1 if (! &IsInt($$mn,0,59)); | |
5340 | ||
5341 | # Check seconds | |
5342 | $$s="00" if ($$s eq ""); | |
5343 | $$s="0$$s" if (length($$s)==1); | |
5344 | return 1 if (! &IsInt($$s,0,59)); | |
5345 | ||
5346 | return 0; | |
5347 | } | |
5348 | ||
5349 | # $flag=&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk); | |
5350 | # Returns 1 if any of the fields are bad. All fields are optional, and | |
5351 | # all possible checks are done on the data. If a field is not passed in, | |
5352 | # it is set to default values. If data is missing, appropriate defaults | |
5353 | # are supplied. | |
5354 | # | |
5355 | # If the flag UpdateHolidays is set, the year is set to | |
5356 | # CurrHolidayYear. | |
5357 | sub Date_DateCheck { | |
5358 | print "DEBUG: Date_DateCheck\n" if ($Curr{"Debug"} =~ /trace/); | |
5359 | my($y,$m,$d,$h,$mn,$s,$ampm,$wk)=@_; | |
5360 | my($tmp1,$tmp2,$tmp3)=(); | |
5361 | ||
5362 | my(@d_in_m)=(0,31,28,31,30,31,30,31,31,30,31,30,31); | |
5363 | my($curr_y)=$Curr{"Y"}; | |
5364 | my($curr_m)=$Curr{"M"}; | |
5365 | my($curr_d)=$Curr{"D"}; | |
5366 | $$m=1, $$d=1 if (defined $$y and ! defined $$m and ! defined $$d); | |
5367 | $$y="" if (! defined $$y); | |
5368 | $$m="" if (! defined $$m); | |
5369 | $$d="" if (! defined $$d); | |
5370 | $$wk="" if (! defined $$wk); | |
5371 | $$d=$curr_d if ($$y eq "" and $$m eq "" and $$d eq ""); | |
5372 | ||
5373 | # Check year. | |
5374 | $$y=$curr_y if ($$y eq ""); | |
5375 | $$y=&Date_FixYear($$y) if (length($$y)<4); | |
5376 | return 1 if (! &IsInt($$y,0,9999)); | |
5377 | $d_in_m[2]=29 if (&Date_LeapYear($$y)); | |
5378 | ||
5379 | # Check month | |
5380 | $$m=$curr_m if ($$m eq ""); | |
5381 | $$m=$Lang{$Cnf{"Language"}}{"MonthH"}{lc($$m)} | |
5382 | if (exists $Lang{$Cnf{"Language"}}{"MonthH"}{lc($$m)}); | |
5383 | $$m="0$$m" if (length($$m)==1); | |
5384 | return 1 if (! &IsInt($$m,1,12)); | |
5385 | ||
5386 | # Check day | |
5387 | $$d="01" if ($$d eq ""); | |
5388 | $$d="0$$d" if (length($$d)==1); | |
5389 | return 1 if (! &IsInt($$d,1,$d_in_m[$$m])); | |
5390 | if ($$wk) { | |
5391 | $tmp1=&Date_DayOfWeek($$m,$$d,$$y); | |
5392 | $tmp2=$Lang{$Cnf{"Language"}}{"WeekH"}{lc($$wk)} | |
5393 | if (exists $Lang{$Cnf{"Language"}}{"WeekH"}{lc($$wk)}); | |
5394 | return 1 if ($tmp1 != $tmp2); | |
5395 | } | |
5396 | ||
5397 | return &Date_TimeCheck($h,$mn,$s,$ampm); | |
5398 | } | |
5399 | ||
5400 | # Takes a year in 2 digit form and returns it in 4 digit form | |
5401 | sub Date_FixYear { | |
5402 | print "DEBUG: Date_FixYear\n" if ($Curr{"Debug"} =~ /trace/); | |
5403 | my($y)=@_; | |
5404 | my($curr_y)=$Curr{"Y"}; | |
5405 | $y=$curr_y if (! defined $y or ! $y); | |
5406 | return $y if (length($y)==4); | |
5407 | confess "ERROR: Invalid year ($y)\n" if (length($y)!=2); | |
5408 | my($y1,$y2)=(); | |
5409 | ||
5410 | if (lc($Cnf{"YYtoYYYY"}) eq "c") { | |
5411 | $y1=substring($y,0,2); | |
5412 | $y="$y1$y"; | |
5413 | ||
5414 | } elsif ($Cnf{"YYtoYYYY"} =~ /^c(\d{2})$/i) { | |
5415 | $y1=$1; | |
5416 | $y="$y1$y"; | |
5417 | ||
5418 | } elsif ($Cnf{"YYtoYYYY"} =~ /^c(\d{2})(\d{2})$/i) { | |
5419 | $y1="$1$2"; | |
5420 | $y ="$1$y"; | |
5421 | $y += 100 if ($y<$y1); | |
5422 | ||
5423 | } else { | |
5424 | $y1=$curr_y-$Cnf{"YYtoYYYY"}; | |
5425 | $y2=$y1+99; | |
5426 | $y="19$y"; | |
5427 | while ($y<$y1) { | |
5428 | $y+=100; | |
5429 | } | |
5430 | while ($y>$y2) { | |
5431 | $y-=100; | |
5432 | } | |
5433 | } | |
5434 | $y; | |
5435 | } | |
5436 | ||
5437 | # &Date_NthWeekOfYear($y,$n); | |
5438 | # Returns a list of (YYYY,MM,DD) for the 1st day of the Nth week of the | |
5439 | # year. | |
5440 | # &Date_NthWeekOfYear($y,$n,$dow,$flag); | |
5441 | # Returns a list of (YYYY,MM,DD) for the Nth DoW of the year. If flag | |
5442 | # is nil, the first DoW of the year may actually be in the previous | |
5443 | # year (since the 1st week may include days from the previous year). | |
5444 | # If flag is non-nil, the 1st DoW of the year refers to the 1st one | |
5445 | # actually in the year | |
5446 | sub Date_NthWeekOfYear { | |
5447 | print "DEBUG: Date_NthWeekOfYear\n" if ($Curr{"Debug"} =~ /trace/); | |
5448 | my($y,$n,$dow,$flag)=@_; | |
5449 | my($m,$d,$err,$tmp,$date,%dow)=(); | |
5450 | $y=$Curr{"Y"} if (! defined $y or ! $y); | |
5451 | $n=1 if (! defined $n or $n eq ""); | |
5452 | return () if ($n<0 || $n>53); | |
5453 | if (defined $dow) { | |
5454 | $dow=lc($dow); | |
5455 | %dow=%{ $Lang{$Cnf{"Language"}}{"WeekH"} }; | |
5456 | $dow=$dow{$dow} if (exists $dow{$dow}); | |
5457 | return () if ($dow<1 || $dow>7); | |
5458 | $flag="" if (! defined $flag); | |
5459 | } else { | |
5460 | $dow=""; | |
5461 | $flag=""; | |
5462 | } | |
5463 | ||
5464 | $y=&Date_FixYear($y) if (length($y)<4); | |
5465 | if ($Cnf{"Jan1Week1"}) { | |
5466 | $date=&Date_Join($y,1,1,0,0,0); | |
5467 | } else { | |
5468 | $date=&Date_Join($y,1,4,0,0,0); | |
5469 | } | |
5470 | $date=&Date_GetPrev($date,$Cnf{"FirstDay"},1); | |
5471 | $date=&Date_GetNext($date,$dow,1) if ($dow ne ""); | |
5472 | ||
5473 | if ($flag) { | |
5474 | ($tmp)=&Date_Split($date, 1); | |
5475 | $n++ if ($tmp != $y); | |
5476 | } | |
5477 | ||
5478 | if ($n>1) { | |
5479 | $date=&DateCalc_DateDelta($date,"+0:0:". ($n-1) . ":0:0:0:0",\$err,0); | |
5480 | } elsif ($n==0) { | |
5481 | $date=&DateCalc_DateDelta($date,"-0:0:1:0:0:0:0",\$err,0); | |
5482 | } | |
5483 | ($y,$m,$d)=&Date_Split($date, 1); | |
5484 | ($y,$m,$d); | |
5485 | } | |
5486 | ||
5487 | ######################################################################## | |
5488 | # LANGUAGE INITIALIZATION | |
5489 | ######################################################################## | |
5490 | ||
5491 | # 8-bit international characters can be gotten by "\xXX". I don't know | |
5492 | # how to get 16-bit characters. I've got to read up on perllocale. | |
5493 | sub Char_8Bit { | |
5494 | my($hash)=@_; | |
5495 | ||
5496 | # grave ` | |
5497 | # A` 00c0 a` 00e0 | |
5498 | # E` 00c8 e` 00e8 | |
5499 | # I` 00cc i` 00ec | |
5500 | # O` 00d2 o` 00f2 | |
5501 | # U` 00d9 u` 00f9 | |
5502 | # W` 1e80 w` 1e81 | |
5503 | # Y` 1ef2 y` 1ef3 | |
5504 | ||
5505 | $$hash{"A`"} = "\xc0"; # LATIN CAPITAL LETTER A WITH GRAVE | |
5506 | $$hash{"E`"} = "\xc8"; # LATIN CAPITAL LETTER E WITH GRAVE | |
5507 | $$hash{"I`"} = "\xcc"; # LATIN CAPITAL LETTER I WITH GRAVE | |
5508 | $$hash{"O`"} = "\xd2"; # LATIN CAPITAL LETTER O WITH GRAVE | |
5509 | $$hash{"U`"} = "\xd9"; # LATIN CAPITAL LETTER U WITH GRAVE | |
5510 | $$hash{"a`"} = "\xe0"; # LATIN SMALL LETTER A WITH GRAVE | |
5511 | $$hash{"e`"} = "\xe8"; # LATIN SMALL LETTER E WITH GRAVE | |
5512 | $$hash{"i`"} = "\xec"; # LATIN SMALL LETTER I WITH GRAVE | |
5513 | $$hash{"o`"} = "\xf2"; # LATIN SMALL LETTER O WITH GRAVE | |
5514 | $$hash{"u`"} = "\xf9"; # LATIN SMALL LETTER U WITH GRAVE | |
5515 | ||
5516 | # acute ' | |
5517 | # A' 00c1 a' 00e1 | |
5518 | # C' 0106 c' 0107 | |
5519 | # E' 00c9 e' 00e9 | |
5520 | # I' 00cd i' 00ed | |
5521 | # L' 0139 l' 013a | |
5522 | # N' 0143 n' 0144 | |
5523 | # O' 00d3 o' 00f3 | |
5524 | # R' 0154 r' 0155 | |
5525 | # S' 015a s' 015b | |
5526 | # U' 00da u' 00fa | |
5527 | # W' 1e82 w' 1e83 | |
5528 | # Y' 00dd y' 00fd | |
5529 | # Z' 0179 z' 017a | |
5530 | ||
5531 | $$hash{"A'"} = "\xc1"; # LATIN CAPITAL LETTER A WITH ACUTE | |
5532 | $$hash{"E'"} = "\xc9"; # LATIN CAPITAL LETTER E WITH ACUTE | |
5533 | $$hash{"I'"} = "\xcd"; # LATIN CAPITAL LETTER I WITH ACUTE | |
5534 | $$hash{"O'"} = "\xd3"; # LATIN CAPITAL LETTER O WITH ACUTE | |
5535 | $$hash{"U'"} = "\xda"; # LATIN CAPITAL LETTER U WITH ACUTE | |
5536 | $$hash{"Y'"} = "\xdd"; # LATIN CAPITAL LETTER Y WITH ACUTE | |
5537 | $$hash{"a'"} = "\xe1"; # LATIN SMALL LETTER A WITH ACUTE | |
5538 | $$hash{"e'"} = "\xe9"; # LATIN SMALL LETTER E WITH ACUTE | |
5539 | $$hash{"i'"} = "\xed"; # LATIN SMALL LETTER I WITH ACUTE | |
5540 | $$hash{"o'"} = "\xf3"; # LATIN SMALL LETTER O WITH ACUTE | |
5541 | $$hash{"u'"} = "\xfa"; # LATIN SMALL LETTER U WITH ACUTE | |
5542 | $$hash{"y'"} = "\xfd"; # LATIN SMALL LETTER Y WITH ACUTE | |
5543 | ||
5544 | # double acute " " | |
5545 | # O" 0150 o" 0151 | |
5546 | # U" 0170 u" 0171 | |
5547 | ||
5548 | # circumflex ^ | |
5549 | # A^ 00c2 a^ 00e2 | |
5550 | # C^ 0108 c^ 0109 | |
5551 | # E^ 00ca e^ 00ea | |
5552 | # G^ 011c g^ 011d | |
5553 | # H^ 0124 h^ 0125 | |
5554 | # I^ 00ce i^ 00ee | |
5555 | # J^ 0134 j^ 0135 | |
5556 | # O^ 00d4 o^ 00f4 | |
5557 | # S^ 015c s^ 015d | |
5558 | # U^ 00db u^ 00fb | |
5559 | # W^ 0174 w^ 0175 | |
5560 | # Y^ 0176 y^ 0177 | |
5561 | ||
5562 | $$hash{"A^"} = "\xc2"; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX | |
5563 | $$hash{"E^"} = "\xca"; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX | |
5564 | $$hash{"I^"} = "\xce"; # LATIN CAPITAL LETTER I WITH CIRCUMFLEX | |
5565 | $$hash{"O^"} = "\xd4"; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX | |
5566 | $$hash{"U^"} = "\xdb"; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX | |
5567 | $$hash{"a^"} = "\xe2"; # LATIN SMALL LETTER A WITH CIRCUMFLEX | |
5568 | $$hash{"e^"} = "\xea"; # LATIN SMALL LETTER E WITH CIRCUMFLEX | |
5569 | $$hash{"i^"} = "\xee"; # LATIN SMALL LETTER I WITH CIRCUMFLEX | |
5570 | $$hash{"o^"} = "\xf4"; # LATIN SMALL LETTER O WITH CIRCUMFLEX | |
5571 | $$hash{"u^"} = "\xfb"; # LATIN SMALL LETTER U WITH CIRCUMFLEX | |
5572 | ||
5573 | # tilde ~ | |
5574 | # A~ 00c3 a~ 00e3 | |
5575 | # I~ 0128 i~ 0129 | |
5576 | # N~ 00d1 n~ 00f1 | |
5577 | # O~ 00d5 o~ 00f5 | |
5578 | # U~ 0168 u~ 0169 | |
5579 | ||
5580 | $$hash{"A~"} = "\xc3"; # LATIN CAPITAL LETTER A WITH TILDE | |
5581 | $$hash{"N~"} = "\xd1"; # LATIN CAPITAL LETTER N WITH TILDE | |
5582 | $$hash{"O~"} = "\xd5"; # LATIN CAPITAL LETTER O WITH TILDE | |
5583 | $$hash{"a~"} = "\xe3"; # LATIN SMALL LETTER A WITH TILDE | |
5584 | $$hash{"n~"} = "\xf1"; # LATIN SMALL LETTER N WITH TILDE | |
5585 | $$hash{"o~"} = "\xf5"; # LATIN SMALL LETTER O WITH TILDE | |
5586 | ||
5587 | # macron - | |
5588 | # A- 0100 a- 0101 | |
5589 | # E- 0112 e- 0113 | |
5590 | # I- 012a i- 012b | |
5591 | # O- 014c o- 014d | |
5592 | # U- 016a u- 016b | |
5593 | ||
5594 | # breve ( [half circle up] | |
5595 | # A( 0102 a( 0103 | |
5596 | # G( 011e g( 011f | |
5597 | # U( 016c u( 016d | |
5598 | ||
5599 | # dot . | |
5600 | # C. 010a c. 010b | |
5601 | # E. 0116 e. 0117 | |
5602 | # G. 0120 g. 0121 | |
5603 | # I. 0130 | |
5604 | # Z. 017b z. 017c | |
5605 | ||
5606 | # diaeresis : [side by side dots] | |
5607 | # A: 00c4 a: 00e4 | |
5608 | # E: 00cb e: 00eb | |
5609 | # I: 00cf i: 00ef | |
5610 | # O: 00d6 o: 00f6 | |
5611 | # U: 00dc u: 00fc | |
5612 | # W: 1e84 w: 1e85 | |
5613 | # Y: 0178 y: 00ff | |
5614 | ||
5615 | $$hash{"A:"} = "\xc4"; # LATIN CAPITAL LETTER A WITH DIAERESIS | |
5616 | $$hash{"E:"} = "\xcb"; # LATIN CAPITAL LETTER E WITH DIAERESIS | |
5617 | $$hash{"I:"} = "\xcf"; # LATIN CAPITAL LETTER I WITH DIAERESIS | |
5618 | $$hash{"O:"} = "\xd6"; # LATIN CAPITAL LETTER O WITH DIAERESIS | |
5619 | $$hash{"U:"} = "\xdc"; # LATIN CAPITAL LETTER U WITH DIAERESIS | |
5620 | $$hash{"a:"} = "\xe4"; # LATIN SMALL LETTER A WITH DIAERESIS | |
5621 | $$hash{"e:"} = "\xeb"; # LATIN SMALL LETTER E WITH DIAERESIS | |
5622 | $$hash{"i:"} = "\xef"; # LATIN SMALL LETTER I WITH DIAERESIS | |
5623 | $$hash{"o:"} = "\xf6"; # LATIN SMALL LETTER O WITH DIAERESIS | |
5624 | $$hash{"u:"} = "\xfc"; # LATIN SMALL LETTER U WITH DIAERESIS | |
5625 | $$hash{"y:"} = "\xff"; # LATIN SMALL LETTER Y WITH DIAERESIS | |
5626 | ||
5627 | # ring o | |
5628 | # U0 016e u0 016f | |
5629 | ||
5630 | # cedilla , [squiggle down and left below the letter] | |
5631 | # ,C 00c7 ,c 00e7 | |
5632 | # ,G 0122 ,g 0123 | |
5633 | # ,K 0136 ,k 0137 | |
5634 | # ,L 013b ,l 013c | |
5635 | # ,N 0145 ,n 0146 | |
5636 | # ,R 0156 ,r 0157 | |
5637 | # ,S 015e ,s 015f | |
5638 | # ,T 0162 ,t 0163 | |
5639 | ||
5640 | $$hash{",C"} = "\xc7"; # LATIN CAPITAL LETTER C WITH CEDILLA | |
5641 | $$hash{",c"} = "\xe7"; # LATIN SMALL LETTER C WITH CEDILLA | |
5642 | ||
5643 | # ogonek ; [squiggle down and right below the letter] | |
5644 | # A; 0104 a; 0105 | |
5645 | # E; 0118 e; 0119 | |
5646 | # I; 012e i; 012f | |
5647 | # U; 0172 u; 0173 | |
5648 | ||
5649 | # caron < [little v on top] | |
5650 | # A< 01cd a< 01ce | |
5651 | # C< 010c c< 010d | |
5652 | # D< 010e d< 010f | |
5653 | # E< 011a e< 011b | |
5654 | # L< 013d l< 013e | |
5655 | # N< 0147 n< 0148 | |
5656 | # R< 0158 r< 0159 | |
5657 | # S< 0160 s< 0161 | |
5658 | # T< 0164 t< 0165 | |
5659 | # Z< 017d z< 017e | |
5660 | ||
5661 | ||
5662 | # Other characters | |
5663 | ||
5664 | # First character is below, 2nd character is above | |
5665 | $$hash{"||"} = "\xa6"; # BROKEN BAR | |
5666 | $$hash{" :"} = "\xa8"; # DIAERESIS | |
5667 | $$hash{"-a"} = "\xaa"; # FEMININE ORDINAL INDICATOR | |
5668 | #$$hash{" -"}= "\xaf"; # MACRON (narrow bar) | |
5669 | $$hash{" -"} = "\xad"; # HYPHEN (wide bar) | |
5670 | $$hash{" o"} = "\xb0"; # DEGREE SIGN | |
5671 | $$hash{"-+"} = "\xb1"; # PLUS\342\200\220MINUS SIGN | |
5672 | $$hash{" 1"} = "\xb9"; # SUPERSCRIPT ONE | |
5673 | $$hash{" 2"} = "\xb2"; # SUPERSCRIPT TWO | |
5674 | $$hash{" 3"} = "\xb3"; # SUPERSCRIPT THREE | |
5675 | $$hash{" '"} = "\xb4"; # ACUTE ACCENT | |
5676 | $$hash{"-o"} = "\xba"; # MASCULINE ORDINAL INDICATOR | |
5677 | $$hash{" ."} = "\xb7"; # MIDDLE DOT | |
5678 | $$hash{", "} = "\xb8"; # CEDILLA | |
5679 | $$hash{"Ao"} = "\xc5"; # LATIN CAPITAL LETTER A WITH RING ABOVE | |
5680 | $$hash{"ao"} = "\xe5"; # LATIN SMALL LETTER A WITH RING ABOVE | |
5681 | $$hash{"ox"} = "\xf0"; # LATIN SMALL LETTER ETH | |
5682 | ||
5683 | # upside down characters | |
5684 | ||
5685 | $$hash{"ud!"} = "\xa1"; # INVERTED EXCLAMATION MARK | |
5686 | $$hash{"ud?"} = "\xbf"; # INVERTED QUESTION MARK | |
5687 | ||
5688 | # overlay characters | |
5689 | ||
5690 | $$hash{"X o"} = "\xa4"; # CURRENCY SIGN | |
5691 | $$hash{"Y ="} = "\xa5"; # YEN SIGN | |
5692 | $$hash{"S o"} = "\xa7"; # SECTION SIGN | |
5693 | $$hash{"O c"} = "\xa9"; # COPYRIGHT SIGN Copyright | |
5694 | $$hash{"O R"} = "\xae"; # REGISTERED SIGN | |
5695 | $$hash{"D -"} = "\xd0"; # LATIN CAPITAL LETTER ETH | |
5696 | $$hash{"O /"} = "\xd8"; # LATIN CAPITAL LETTER O WITH STROKE | |
5697 | $$hash{"o /"} = "\xf8"; # LATIN SMALL LETTER O WITH STROKE | |
5698 | ||
5699 | # special names | |
5700 | ||
5701 | $$hash{"1/4"} = "\xbc"; # VULGAR FRACTION ONE QUARTER | |
5702 | $$hash{"1/2"} = "\xbd"; # VULGAR FRACTION ONE HALF | |
5703 | $$hash{"3/4"} = "\xbe"; # VULGAR FRACTION THREE QUARTERS | |
5704 | $$hash{"<<"} = "\xab"; # LEFT POINTING DOUBLE ANGLE QUOTATION MARK | |
5705 | $$hash{">>"} = "\xbb"; # RIGHT POINTING DOUBLE ANGLE QUOTATION MARK | |
5706 | $$hash{"cent"}= "\xa2"; # CENT SIGN | |
5707 | $$hash{"lb"} = "\xa3"; # POUND SIGN | |
5708 | $$hash{"mu"} = "\xb5"; # MICRO SIGN | |
5709 | $$hash{"beta"}= "\xdf"; # LATIN SMALL LETTER SHARP S | |
5710 | $$hash{"para"}= "\xb6"; # PILCROW SIGN | |
5711 | $$hash{"-|"} = "\xac"; # NOT SIGN | |
5712 | $$hash{"AE"} = "\xc6"; # LATIN CAPITAL LETTER AE | |
5713 | $$hash{"ae"} = "\xe6"; # LATIN SMALL LETTER AE | |
5714 | $$hash{"x"} = "\xd7"; # MULTIPLICATION SIGN | |
5715 | $$hash{"P"} = "\xde"; # LATIN CAPITAL LETTER THORN | |
5716 | $$hash{"/"} = "\xf7"; # DIVISION SIGN | |
5717 | $$hash{"p"} = "\xfe"; # LATIN SMALL LETTER THORN | |
5718 | } | |
5719 | ||
5720 | # $hashref = &Date_Init_LANGUAGE; | |
5721 | # This returns a hash containing all of the initialization for a | |
5722 | # specific language. The hash elements are: | |
5723 | # | |
5724 | # @ month_name full month names January February ... | |
5725 | # @ month_abb month abbreviations Jan Feb ... | |
5726 | # @ day_name day names Monday Tuesday ... | |
5727 | # @ day_abb day abbreviations Mon Tue ... | |
5728 | # @ day_char day character abbrevs M T ... | |
5729 | # @ am AM notations | |
5730 | # @ pm PM notations | |
5731 | # | |
5732 | # @ num_suff number with suffix 1st 2nd ... | |
5733 | # @ num_word numbers spelled out first second ... | |
5734 | # | |
5735 | # $ now words which mean now now today ... | |
5736 | # $ last words which mean last last final ... | |
5737 | # $ each words which mean each each every ... | |
5738 | # $ of of (as in a member of) in of ... | |
5739 | # ex. 4th day OF June | |
5740 | # $ at at 4:00 at | |
5741 | # $ on on Sunday on | |
5742 | # $ future in the future in | |
5743 | # $ past in the past ago | |
5744 | # $ next next item next | |
5745 | # $ prev previous item last previous | |
5746 | # $ later 2 hours later | |
5747 | # | |
5748 | # % offset a hash of special dates { tomorrow->0:0:0:1:0:0:0 } | |
5749 | # % times a hash of times { noon->12:00:00 ... } | |
5750 | # | |
5751 | # $ years words for year y yr year ... | |
5752 | # $ months words for month | |
5753 | # $ weeks words for week | |
5754 | # $ days words for day | |
5755 | # $ hours words for hour | |
5756 | # $ minutes words for minute | |
5757 | # $ seconds words for second | |
5758 | # % replace | |
5759 | # The replace element is quite important, but a bit tricky. In | |
5760 | # English (and probably other languages), one of the abbreviations | |
5761 | # for the word month that would be nice is "m". The problem is that | |
5762 | # "m" matches the "m" in "minute" which causes the string to be | |
5763 | # improperly matched in some cases. Hence, the list of abbreviations | |
5764 | # for month is given as: | |
5765 | # "mon month months" | |
5766 | # In order to allow you to enter "m", replacements can be done. | |
5767 | # $replace is a list of pairs of words which are matched and replaced | |
5768 | # AS ENTIRE WORDS. Having $replace equal to "m"->"month" means that | |
5769 | # the entire word "m" will be replaced with "month". This allows the | |
5770 | # desired abbreviation to be used. Make sure that replace contains | |
5771 | # an even number of words (i.e. all must be pairs). Any time a | |
5772 | # desired abbreviation matches the start of any other, it has to go | |
5773 | # here. | |
5774 | # | |
5775 | # $ exact exact mode exactly | |
5776 | # $ approx approximate mode approximately | |
5777 | # $ business business mode business | |
5778 | # | |
5779 | # r sephm hour/minute separator (?::) | |
5780 | # r sepms minute/second separator (?::) | |
5781 | # r sepss second/fraction separator (?:[.:]) | |
5782 | # | |
5783 | # Elements marked with an asterix (@) are returned as a set of lists. | |
5784 | # Each list contains the strings for each element. The first set is used | |
5785 | # when the 7-bit ASCII (US) character set is wanted. The 2nd set is used | |
5786 | # when an international character set is available. Both of the 1st two | |
5787 | # sets should be complete (but the 2nd list can be left empty to force the | |
5788 | # first set to be used always). The 3rd set and later can be partial sets | |
5789 | # if desired. | |
5790 | # | |
5791 | # Elements marked with a dollar ($) are returned as a simple list of words. | |
5792 | # | |
5793 | # Elements marked with a percent (%) are returned as a hash list. | |
5794 | # | |
5795 | # Elements marked with (r) are regular expression elements which must not | |
5796 | # create a back reference. | |
5797 | # | |
5798 | # ***NOTE*** Every hash element (unless otherwise noted) MUST be defined in | |
5799 | # every language. | |
5800 | ||
5801 | sub Date_Init_English { | |
5802 | print "DEBUG: Date_Init_English\n" if ($Curr{"Debug"} =~ /trace/); | |
5803 | my($d)=@_; | |
5804 | ||
5805 | $$d{"month_name"}= | |
5806 | [["January","February","March","April","May","June", | |
5807 | "July","August","September","October","November","December"]]; | |
5808 | ||
5809 | $$d{"month_abb"}= | |
5810 | [["Jan","Feb","Mar","Apr","May","Jun", | |
5811 | "Jul","Aug","Sep","Oct","Nov","Dec"], | |
5812 | [], | |
5813 | ["","","","","","","","","Sept"]]; | |
5814 | ||
5815 | $$d{"day_name"}= | |
5816 | [["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]]; | |
5817 | $$d{"day_abb"}= | |
5818 | [["Mon","Tue","Wed","Thu","Fri","Sat","Sun"], | |
5819 | ["", "Tues","", "Thur","", "", ""]]; | |
5820 | $$d{"day_char"}= | |
5821 | [["M","T","W","Th","F","Sa","S"]]; | |
5822 | ||
5823 | $$d{"num_suff"}= | |
5824 | [["1st","2nd","3rd","4th","5th","6th","7th","8th","9th","10th", | |
5825 | "11th","12th","13th","14th","15th","16th","17th","18th","19th","20th", | |
5826 | "21st","22nd","23rd","24th","25th","26th","27th","28th","29th","30th", | |
5827 | "31st"]]; | |
5828 | $$d{"num_word"}= | |
5829 | [["first","second","third","fourth","fifth","sixth","seventh","eighth", | |
5830 | "ninth","tenth","eleventh","twelfth","thirteenth","fourteenth", | |
5831 | "fifteenth","sixteenth","seventeenth","eighteenth","nineteenth", | |
5832 | "twentieth","twenty-first","twenty-second","twenty-third", | |
5833 | "twenty-fourth","twenty-fifth","twenty-sixth","twenty-seventh", | |
5834 | "twenty-eighth","twenty-ninth","thirtieth","thirty-first"]]; | |
5835 | ||
5836 | $$d{"now"} =["today","now"]; | |
5837 | $$d{"last"} =["last","final"]; | |
5838 | $$d{"each"} =["each","every"]; | |
5839 | $$d{"of"} =["in","of"]; | |
5840 | $$d{"at"} =["at"]; | |
5841 | $$d{"on"} =["on"]; | |
5842 | $$d{"future"} =["in"]; | |
5843 | $$d{"past"} =["ago"]; | |
5844 | $$d{"next"} =["next"]; | |
5845 | $$d{"prev"} =["previous","last"]; | |
5846 | $$d{"later"} =["later"]; | |
5847 | ||
5848 | $$d{"exact"} =["exactly"]; | |
5849 | $$d{"approx"} =["approximately"]; | |
5850 | $$d{"business"}=["business"]; | |
5851 | ||
5852 | $$d{"offset"} =["yesterday","-0:0:0:1:0:0:0","tomorrow","+0:0:0:1:0:0:0"]; | |
5853 | $$d{"times"} =["noon","12:00:00","midnight","00:00:00"]; | |
5854 | ||
5855 | $$d{"years"} =["y","yr","year","yrs","years"]; | |
5856 | $$d{"months"} =["mon","month","months"]; | |
5857 | $$d{"weeks"} =["w","wk","wks","week","weeks"]; | |
5858 | $$d{"days"} =["d","day","days"]; | |
5859 | $$d{"hours"} =["h","hr","hrs","hour","hours"]; | |
5860 | $$d{"minutes"} =["mn","min","minute","minutes"]; | |
5861 | $$d{"seconds"} =["s","sec","second","seconds"]; | |
5862 | $$d{"replace"} =["m","month"]; | |
5863 | ||
5864 | $$d{"sephm"} =':'; | |
5865 | $$d{"sepms"} =':'; | |
5866 | $$d{"sepss"} ='[.:]'; | |
5867 | ||
5868 | $$d{"am"} = ["AM","A.M."]; | |
5869 | $$d{"pm"} = ["PM","P.M."]; | |
5870 | } | |
5871 | ||
5872 | sub Date_Init_Italian { | |
5873 | print "DEBUG: Date_Init_Italian\n" if ($Curr{"Debug"} =~ /trace/); | |
5874 | my($d)=@_; | |
5875 | my(%h)=(); | |
5876 | &Char_8Bit(\%h); | |
5877 | my($i)=$h{"i'"}; | |
5878 | ||
5879 | $$d{"month_name"}= | |
5880 | [[qw(Gennaio Febbraio Marzo Aprile Maggio Giugno | |
5881 | Luglio Agosto Settembre Ottobre Novembre Dicembre)]]; | |
5882 | ||
5883 | $$d{"month_abb"}= | |
5884 | [[qw(Gen Feb Mar Apr Mag Giu Lug Ago Set Ott Nov Dic)]]; | |
5885 | ||
5886 | $$d{"day_name"}= | |
5887 | [[qw(Lunedi Martedi Mercoledi Giovedi Venerdi Sabato Domenica)], | |
5888 | [qw(Luned${i} Marted${i} Mercoled${i} Gioved${i} Venerd${i})]]; | |
5889 | $$d{"day_abb"}= | |
5890 | [[qw(Lun Mar Mer Gio Ven Sab Dom)]]; | |
5891 | $$d{"day_char"}= | |
5892 | [[qw(L Ma Me G V S D)]]; | |
5893 | ||
5894 | $$d{"num_suff"}= | |
5895 | [[qw(1mo 2do 3zo 4to 5to 6to 7mo 8vo 9no 10mo 11mo 12mo 13mo 14mo 15mo | |
5896 | 16mo 17mo 18mo 19mo 20mo 21mo 22mo 23mo 24mo 25mo 26mo 27mo 28mo | |
5897 | 29mo 3mo 31mo)]]; | |
5898 | $$d{"num_word"}= | |
5899 | [[qw(primo secondo terzo quarto quinto sesto settimo ottavo nono decimo | |
5900 | undicesimo dodicesimo tredicesimo quattordicesimo quindicesimo | |
5901 | sedicesimo diciassettesimo diciottesimo diciannovesimo ventesimo | |
5902 | ventunesimo ventiduesimo ventitreesimo ventiquattresimo | |
5903 | venticinquesimo ventiseiesimo ventisettesimo ventottesimo | |
5904 | ventinovesimo trentesimo trentunesimo)]]; | |
5905 | ||
5906 | $$d{"now"} =[qw(adesso oggi)]; | |
5907 | $$d{"last"} =[qw(ultimo)]; | |
5908 | $$d{"each"} =[qw(ogni)]; | |
5909 | $$d{"of"} =[qw(della del)]; | |
5910 | $$d{"at"} =[qw(alle)]; | |
5911 | $$d{"on"} =[qw(di)]; | |
5912 | $$d{"future"} =[qw(fra)]; | |
5913 | $$d{"past"} =[qw(fa)]; | |
5914 | $$d{"next"} =[qw(prossimo)]; | |
5915 | $$d{"prev"} =[qw(ultimo)]; | |
5916 | $$d{"later"} =[qw(dopo)]; | |
5917 | ||
5918 | $$d{"exact"} =[qw(esattamente)]; | |
5919 | $$d{"approx"} =[qw(circa)]; | |
5920 | $$d{"business"}=[qw(lavorativi lavorativo)]; | |
5921 | ||
5922 | $$d{"offset"} =[qw(ieri -0:0:0:1:0:0:0 domani +0:0:0:1:0:0:0)]; | |
5923 | $$d{"times"} =[qw(mezzogiorno 12:00:00 mezzanotte 00:00:00)]; | |
5924 | ||
5925 | $$d{"years"} =[qw(anni anno a)]; | |
5926 | $$d{"months"} =[qw(mesi mese mes)]; | |
5927 | $$d{"weeks"} =[qw(settimane settimana sett)]; | |
5928 | $$d{"days"} =[qw(giorni giorno g)]; | |
5929 | $$d{"hours"} =[qw(ore ora h)]; | |
5930 | $$d{"minutes"} =[qw(minuti minuto min)]; | |
5931 | $$d{"seconds"} =[qw(secondi secondo sec)]; | |
5932 | $$d{"replace"} =[qw(s sec m mes)]; | |
5933 | ||
5934 | $$d{"sephm"} =':'; | |
5935 | $$d{"sepms"} =':'; | |
5936 | $$d{"sepss"} ='[.:]'; | |
5937 | ||
5938 | $$d{"am"} = [qw(AM)]; | |
5939 | $$d{"pm"} = [qw(PM)]; | |
5940 | } | |
5941 | ||
5942 | sub Date_Init_French { | |
5943 | print "DEBUG: Date_Init_French\n" if ($Curr{"Debug"} =~ /trace/); | |
5944 | my($d)=@_; | |
5945 | my(%h)=(); | |
5946 | &Char_8Bit(\%h); | |
5947 | my($e)=$h{"e'"}; | |
5948 | my($u)=$h{"u^"}; | |
5949 | my($a)=$h{"a'"}; | |
5950 | ||
5951 | $$d{"month_name"}= | |
5952 | [["janvier","fevrier","mars","avril","mai","juin", | |
5953 | "juillet","aout","septembre","octobre","novembre","decembre"], | |
5954 | ["janvier","f${e}vrier","mars","avril","mai","juin", | |
5955 | "juillet","ao${u}t","septembre","octobre","novembre","d${e}cembre"]]; | |
5956 | $$d{"month_abb"}= | |
5957 | [["jan","fev","mar","avr","mai","juin", | |
5958 | "juil","aout","sept","oct","nov","dec"], | |
5959 | ["jan","f${e}v","mar","avr","mai","juin", | |
5960 | "juil","ao${u}t","sept","oct","nov","d${e}c"]]; | |
5961 | ||
5962 | $$d{"day_name"}= | |
5963 | [["lundi","mardi","mercredi","jeudi","vendredi","samedi","dimanche"]]; | |
5964 | $$d{"day_abb"}= | |
5965 | [["lun","mar","mer","jeu","ven","sam","dim"]]; | |
5966 | $$d{"day_char"}= | |
5967 | [["l","ma","me","j","v","s","d"]]; | |
5968 | ||
5969 | $$d{"num_suff"}= | |
5970 | [["1er","2e","3e","4e","5e","6e","7e","8e","9e","10e", | |
5971 | "11e","12e","13e","14e","15e","16e","17e","18e","19e","20e", | |
5972 | "21e","22e","23e","24e","25e","26e","27e","28e","29e","30e", | |
5973 | "31e"]]; | |
5974 | $$d{"num_word"}= | |
5975 | [["premier","deux","trois","quatre","cinq","six","sept","huit","neuf", | |
5976 | "dix","onze","douze","treize","quatorze","quinze","seize","dix-sept", | |
5977 | "dix-huit","dix-neuf","vingt","vingt et un","vingt-deux","vingt-trois", | |
5978 | "vingt-quatre","vingt-cinq","vingt-six","vingt-sept","vingt-huit", | |
5979 | "vingt-neuf","trente","trente et un"], | |
5980 | ["1re"]]; | |
5981 | ||
5982 | $$d{"now"} =["aujourd'hui","maintenant"]; | |
5983 | $$d{"last"} =["dernier"]; | |
5984 | $$d{"each"} =["chaque","tous les","toutes les"]; | |
5985 | $$d{"of"} =["en","de"]; | |
5986 | $$d{"at"} =["a","${a}0"]; | |
5987 | $$d{"on"} =["sur"]; | |
5988 | $$d{"future"} =["en"]; | |
5989 | $$d{"past"} =["il y a"]; | |
5990 | $$d{"next"} =["suivant"]; | |
5991 | $$d{"prev"} =["precedent","pr${e}c${e}dent"]; | |
5992 | $$d{"later"} =["plus tard"]; | |
5993 | ||
5994 | $$d{"exact"} =["exactement"]; | |
5995 | $$d{"approx"} =["approximativement"]; | |
5996 | $$d{"business"}=["professionel"]; | |
5997 | ||
5998 | $$d{"offset"} =["hier","-0:0:0:1:0:0:0","demain","+0:0:0:1:0:0:0"]; | |
5999 | $$d{"times"} =["midi","12:00:00","minuit","00:00:00"]; | |
6000 | ||
6001 | $$d{"years"} =["an","annee","ans","annees","ann${e}e","ann${e}es"]; | |
6002 | $$d{"months"} =["mois"]; | |
6003 | $$d{"weeks"} =["sem","semaine"]; | |
6004 | $$d{"days"} =["j","jour","jours"]; | |
6005 | $$d{"hours"} =["h","heure","heures"]; | |
6006 | $$d{"minutes"} =["mn","min","minute","minutes"]; | |
6007 | $$d{"seconds"} =["s","sec","seconde","secondes"]; | |
6008 | $$d{"replace"} =["m","mois"]; | |
6009 | ||
6010 | $$d{"sephm"} ='[h:]'; | |
6011 | $$d{"sepms"} =':'; | |
6012 | $$d{"sepss"} ='[.:,]'; | |
6013 | ||
6014 | $$d{"am"} = ["du matin"]; | |
6015 | $$d{"pm"} = ["du soir"]; | |
6016 | } | |
6017 | ||
6018 | sub Date_Init_Romanian { | |
6019 | print "DEBUG: Date_Init_Romanian\n" if ($Curr{"Debug"} =~ /trace/); | |
6020 | my($d)=@_; | |
6021 | my(%h)=(); | |
6022 | &Char_8Bit(\%h); | |
6023 | my($p)=$h{"p"}; | |
6024 | my($i)=$h{"i^"}; | |
6025 | my($a)=$h{"a~"}; | |
6026 | my($o)=$h{"-o"}; | |
6027 | ||
6028 | $$d{"month_name"}= | |
6029 | [["ianuarie","februarie","martie","aprilie","mai","iunie", | |
6030 | "iulie","august","septembrie","octombrie","noiembrie","decembrie"]]; | |
6031 | $$d{"month_abb"}= | |
6032 | [["ian","febr","mart","apr","mai","iun", | |
6033 | "iul","aug","sept","oct","nov","dec"], | |
6034 | ["","feb"]]; | |
6035 | ||
6036 | $$d{"day_name"}= | |
6037 | [["luni","marti","miercuri","joi","vineri","simbata","duminica"], | |
6038 | ["luni","mar${p}i","miercuri","joi","vineri","s${i}mb${a}t${a}", | |
6039 | "duminic${a}"]]; | |
6040 | $$d{"day_abb"}= | |
6041 | [["lun","mar","mie","joi","vin","sim","dum"], | |
6042 | ["lun","mar","mie","joi","vin","s${i}m","dum"]]; | |
6043 | $$d{"day_char"}= | |
6044 | [["L","Ma","Mi","J","V","S","D"]]; | |
6045 | ||
6046 | $$d{"num_suff"}= | |
6047 | [["prima","a doua","a 3-a","a 4-a","a 5-a","a 6-a","a 7-a","a 8-a", | |
6048 | "a 9-a","a 10-a","a 11-a","a 12-a","a 13-a","a 14-a","a 15-a", | |
6049 | "a 16-a","a 17-a","a 18-a","a 19-a","a 20-a","a 21-a","a 22-a", | |
6050 | "a 23-a","a 24-a","a 25-a","a 26-a","a 27-a","a 28-a","a 29-a", | |
6051 | "a 30-a","a 31-a"]]; | |
6052 | ||
6053 | $$d{"num_word"}= | |
6054 | [["prima","a doua","a treia","a patra","a cincea","a sasea","a saptea", | |
6055 | "a opta","a noua","a zecea","a unsprezecea","a doisprezecea", | |
6056 | "a treisprezecea","a patrusprezecea","a cincisprezecea","a saiprezecea", | |
6057 | "a saptesprezecea","a optsprezecea","a nouasprezecea","a douazecea", | |
6058 | "a douazecisiuna","a douazecisidoua","a douazecisitreia", | |
6059 | "a douazecisipatra","a douazecisicincea","a douazecisisasea", | |
6060 | "a douazecisisaptea","a douazecisiopta","a douazecisinoua","a treizecea", | |
6061 | "a treizecisiuna"], | |
6062 | ["prima","a doua","a treia","a patra","a cincea","a ${o}asea", | |
6063 | "a ${o}aptea","a opta","a noua","a zecea","a unsprezecea", | |
6064 | "a doisprezecea","a treisprezecea","a patrusprezecea","a cincisprezecea", | |
6065 | "a ${o}aiprezecea","a ${o}aptesprezecea","a optsprezecea", | |
6066 | "a nou${a}sprezecea","a dou${a}zecea","a dou${a}zeci${o}iuna", | |
6067 | "a dou${a}zeci${o}idoua","a dou${a}zeci${o}itreia", | |
6068 | "a dou${a}zeci${o}ipatra","a dou${a}zeci${o}icincea", | |
6069 | "a dou${a}zeci${o}i${o}asea","a dou${a}zeci${o}i${o}aptea", | |
6070 | "a dou${a}zeci${o}iopta","a dou${a}zeci${o}inoua","a treizecea", | |
6071 | "a treizeci${o}iuna"], | |
6072 | ["intii", "doi", "trei", "patru", "cinci", "sase", "sapte", | |
6073 | "opt","noua","zece","unsprezece","doisprezece", | |
6074 | "treisprezece","patrusprezece","cincisprezece","saiprezece", | |
6075 | "saptesprezece","optsprezece","nouasprezece","douazeci", | |
6076 | "douazecisiunu","douazecisidoi","douazecisitrei", | |
6077 | "douazecisipatru","douazecisicinci","douazecisisase","douazecisisapte", | |
6078 | "douazecisiopt","douazecisinoua","treizeci","treizecisiunu"], | |
6079 | ["${i}nt${i}i", "doi", "trei", "patru", "cinci", "${o}ase", "${o}apte", | |
6080 | "opt","nou${a}","zece","unsprezece","doisprezece", | |
6081 | "treisprezece","patrusprezece","cincisprezece","${o}aiprezece", | |
6082 | "${o}aptesprezece","optsprezece","nou${a}sprezece","dou${a}zeci", | |
6083 | "dou${a}zeci${o}iunu","dou${a}zeci${o}idoi","dou${a}zeci${o}itrei", | |
6084 | "dou${a}zecisipatru","dou${a}zeci${o}icinci","dou${a}zeci${o}i${o}ase", | |
6085 | "dou${a}zeci${o}i${o}apte","dou${a}zeci${o}iopt", | |
6086 | "dou${a}zeci${o}inou${a}","treizeci","treizeci${o}iunu"]]; | |
6087 | ||
6088 | $$d{"now"} =["acum","azi","astazi","ast${a}zi"]; | |
6089 | $$d{"last"} =["ultima"]; | |
6090 | $$d{"each"} =["fiecare"]; | |
6091 | $$d{"of"} =["din","in","n"]; | |
6092 | $$d{"at"} =["la"]; | |
6093 | $$d{"on"} =["on"]; | |
6094 | $$d{"future"} =["in","${i}n"]; | |
6095 | $$d{"past"} =["in urma", "${i}n urm${a}"]; | |
6096 | $$d{"next"} =["urmatoarea","urm${a}toarea"]; | |
6097 | $$d{"prev"} =["precedenta","ultima"]; | |
6098 | $$d{"later"} =["mai tirziu", "mai t${i}rziu"]; | |
6099 | ||
6100 | $$d{"exact"} =["exact"]; | |
6101 | $$d{"approx"} =["aproximativ"]; | |
6102 | $$d{"business"}=["de lucru","lucratoare","lucr${a}toare"]; | |
6103 | ||
6104 | $$d{"offset"} =["ieri","-0:0:0:1:0:0:0", | |
6105 | "alaltaieri", "-0:0:0:2:0:0:0", | |
6106 | "alalt${a}ieri","-0:0:0:2:0:0:0", | |
6107 | "miine","+0:0:0:1:0:0:0", | |
6108 | "m${i}ine","+0:0:0:1:0:0:0", | |
6109 | "poimiine","+0:0:0:2:0:0:0", | |
6110 | "poim${i}ine","+0:0:0:2:0:0:0"]; | |
6111 | $$d{"times"} =["amiaza","12:00:00", | |
6112 | "amiaz${a}","12:00:00", | |
6113 | "miezul noptii","00:00:00", | |
6114 | "miezul nop${p}ii","00:00:00"]; | |
6115 | ||
6116 | $$d{"years"} =["ani","an","a"]; | |
6117 | $$d{"months"} =["luni","luna","lun${a}","l"]; | |
6118 | $$d{"weeks"} =["saptamini","s${a}pt${a}m${i}ni","saptamina", | |
6119 | "s${a}pt${a}m${i}na","sapt","s${a}pt"]; | |
6120 | $$d{"days"} =["zile","zi","z"]; | |
6121 | $$d{"hours"} =["ore", "ora", "or${a}", "h"]; | |
6122 | $$d{"minutes"} =["minute","min","m"]; | |
6123 | $$d{"seconds"} =["secunde","sec",]; | |
6124 | $$d{"replace"} =["s","secunde"]; | |
6125 | ||
6126 | $$d{"sephm"} =':'; | |
6127 | $$d{"sepms"} =':'; | |
6128 | $$d{"sepss"} ='[.:,]'; | |
6129 | ||
6130 | $$d{"am"} = ["AM","A.M."]; | |
6131 | $$d{"pm"} = ["PM","P.M."]; | |
6132 | } | |
6133 | ||
6134 | sub Date_Init_Swedish { | |
6135 | print "DEBUG: Date_Init_Swedish\n" if ($Curr{"Debug"} =~ /trace/); | |
6136 | my($d)=@_; | |
6137 | my(%h)=(); | |
6138 | &Char_8Bit(\%h); | |
6139 | my($ao)=$h{"ao"}; | |
6140 | my($o) =$h{"o:"}; | |
6141 | my($a) =$h{"a:"}; | |
6142 | ||
6143 | $$d{"month_name"}= | |
6144 | [["Januari","Februari","Mars","April","Maj","Juni", | |
6145 | "Juli","Augusti","September","Oktober","November","December"]]; | |
6146 | $$d{"month_abb"}= | |
6147 | [["Jan","Feb","Mar","Apr","Maj","Jun", | |
6148 | "Jul","Aug","Sep","Okt","Nov","Dec"]]; | |
6149 | ||
6150 | $$d{"day_name"}= | |
6151 | [["Mandag","Tisdag","Onsdag","Torsdag","Fredag","Lordag","Sondag"], | |
6152 | ["M${ao}ndag","Tisdag","Onsdag","Torsdag","Fredag","L${o}rdag", | |
6153 | "S${o}ndag"]]; | |
6154 | $$d{"day_abb"}= | |
6155 | [["Man","Tis","Ons","Tor","Fre","Lor","Son"], | |
6156 | ["M${ao}n","Tis","Ons","Tor","Fre","L${o}r","S${o}n"]]; | |
6157 | $$d{"day_char"}= | |
6158 | [["M","Ti","O","To","F","L","S"]]; | |
6159 | ||
6160 | $$d{"num_suff"}= | |
6161 | [["1:a","2:a","3:e","4:e","5:e","6:e","7:e","8:e","9:e","10:e", | |
6162 | "11:e","12:e","13:e","14:e","15:e","16:e","17:e","18:e","19:e","20:e", | |
6163 | "21:a","22:a","23:e","24:e","25:e","26:e","27:e","28:e","29:e","30:e", | |
6164 | "31:a"]]; | |
6165 | $$d{"num_word"}= | |
6166 | [["forsta","andra","tredje","fjarde","femte","sjatte","sjunde", | |
6167 | "attonde","nionde","tionde","elfte","tolfte","trettonde","fjortonde", | |
6168 | "femtonde","sextonde","sjuttonde","artonde","nittonde","tjugonde", | |
6169 | "tjugoforsta","tjugoandra","tjugotredje","tjugofjarde","tjugofemte", | |
6170 | "tjugosjatte","tjugosjunde","tjugoattonde","tjugonionde", | |
6171 | "trettionde","trettioforsta"], | |
6172 | ["f${o}rsta","andra","tredje","fj${a}rde","femte","sj${a}tte","sjunde", | |
6173 | "${ao}ttonde","nionde","tionde","elfte","tolfte","trettonde","fjortonde", | |
6174 | "femtonde","sextonde","sjuttonde","artonde","nittonde","tjugonde", | |
6175 | "tjugof${o}rsta","tjugoandra","tjugotredje","tjugofj${a}rde","tjugofemte", | |
6176 | "tjugosj${a}tte","tjugosjunde","tjugo${ao}ttonde","tjugonionde", | |
6177 | "trettionde","trettiof${o}rsta"]]; | |
6178 | ||
6179 | $$d{"now"} =["idag","nu"]; | |
6180 | $$d{"last"} =["forra","f${o}rra","senaste"]; | |
6181 | $$d{"each"} =["varje"]; | |
6182 | $$d{"of"} =["om"]; | |
6183 | $$d{"at"} =["kl","kl.","klockan"]; | |
6184 | $$d{"on"} =["pa","p${ao}"]; | |
6185 | $$d{"future"} =["om"]; | |
6186 | $$d{"past"} =["sedan"]; | |
6187 | $$d{"next"} =["nasta","n${a}sta"]; | |
6188 | $$d{"prev"} =["forra","f${o}rra"]; | |
6189 | $$d{"later"} =["senare"]; | |
6190 | ||
6191 | $$d{"exact"} =["exakt"]; | |
6192 | $$d{"approx"} =["ungefar","ungef${a}r"]; | |
6193 | $$d{"business"}=["arbetsdag","arbetsdagar"]; | |
6194 | ||
6195 | $$d{"offset"} =["ig${ao}r","-0:0:0:1:0:0:0","igar","-0:0:0:1:0:0:0", | |
6196 | "imorgon","+0:0:0:1:0:0:0"]; | |
6197 | $$d{"times"} =["mitt pa dagen","12:00:00","mitt p${ao} dagen","12:00:00", | |
6198 | "midnatt","00:00:00"]; | |
6199 | ||
6200 | $$d{"years"} =["ar","${ao}r"]; | |
6201 | $$d{"months"} =["man","manad","manader","m${ao}n","m${ao}nad","m${ao}nader"]; | |
6202 | $$d{"weeks"} =["v","vecka","veckor"]; | |
6203 | $$d{"days"} =["d","dag","dagar"]; | |
6204 | $$d{"hours"} =["t","tim","timme","timmar"]; | |
6205 | $$d{"minutes"} =["min","minut","minuter"]; | |
6206 | $$d{"seconds"} =["s","sek","sekund","sekunder"]; | |
6207 | $$d{"replace"} =["m","minut"]; | |
6208 | ||
6209 | $$d{"sephm"} ='[.:]'; | |
6210 | $$d{"sepms"} =':'; | |
6211 | $$d{"sepss"} ='[.:]'; | |
6212 | ||
6213 | $$d{"am"} = ["FM"]; | |
6214 | $$d{"pm"} = ["EM"]; | |
6215 | } | |
6216 | ||
6217 | sub Date_Init_German { | |
6218 | print "DEBUG: Date_Init_German\n" if ($Curr{"Debug"} =~ /trace/); | |
6219 | my($d)=@_; | |
6220 | my(%h)=(); | |
6221 | &Char_8Bit(\%h); | |
6222 | my($a)=$h{"a:"}; | |
6223 | my($u)=$h{"u:"}; | |
6224 | my($o)=$h{"o:"}; | |
6225 | my($b)=$h{"beta"}; | |
6226 | ||
6227 | $$d{"month_name"}= | |
6228 | [["Januar","Februar","Maerz","April","Mai","Juni", | |
6229 | "Juli","August","September","Oktober","November","Dezember"], | |
6230 | ["J${a}nner","Februar","M${a}rz","April","Mai","Juni", | |
6231 | "Juli","August","September","Oktober","November","Dezember"]]; | |
6232 | $$d{"month_abb"}= | |
6233 | [["Jan","Feb","Mar","Apr","Mai","Jun", | |
6234 | "Jul","Aug","Sep","Okt","Nov","Dez"], | |
6235 | ["J${a}n","Feb","M${a}r","Apr","Mai","Jun", | |
6236 | "Jul","Aug","Sep","Okt","Nov","Dez"]]; | |
6237 | ||
6238 | $$d{"day_name"}= | |
6239 | [["Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag", | |
6240 | "Sonntag"]]; | |
6241 | $$d{"day_abb"}= | |
6242 | [["Mon","Die","Mit","Don","Fre","Sam","Son"]]; | |
6243 | $$d{"day_char"}= | |
6244 | [["M","Di","Mi","Do","F","Sa","So"]]; | |
6245 | ||
6246 | $$d{"num_suff"}= | |
6247 | [["1.","2.","3.","4.","5.","6.","7.","8.","9.","10.", | |
6248 | "11.","12.","13.","14.","15.","16.","17.","18.","19.","20.", | |
6249 | "21.","22.","23.","24.","25.","26.","27.","28.","29.","30.", | |
6250 | "31."]]; | |
6251 | $$d{"num_word"}= | |
6252 | [ | |
6253 | ["erste","zweite","dritte","vierte","funfte","sechste","siebente", | |
6254 | "achte","neunte","zehnte","elfte","zwolfte","dreizehnte","vierzehnte", | |
6255 | "funfzehnte","sechzehnte","siebzehnte","achtzehnte","neunzehnte", | |
6256 | "zwanzigste","einundzwanzigste","zweiundzwanzigste","dreiundzwanzigste", | |
6257 | "vierundzwanzigste","funfundzwanzigste","sechundzwanzigste", | |
6258 | "siebundzwanzigste","achtundzwanzigste","neunundzwanzigste", | |
6259 | "dreibigste","einunddreibigste"], | |
6260 | ["erste","zweite","dritte","vierte","f${u}nfte","sechste","siebente", | |
6261 | "achte","neunte","zehnte","elfte","zw${o}lfte","dreizehnte", | |
6262 | "vierzehnte","f${u}nfzehnte","sechzehnte","siebzehnte","achtzehnte", | |
6263 | "neunzehnte","zwanzigste","einundzwanzigste","zweiundzwanzigste", | |
6264 | "dreiundzwanzigste","vierundzwanzigste","f${u}nfundzwanzigste", | |
6265 | "sechundzwanzigste","siebundzwanzigste","achtundzwanzigste", | |
6266 | "neunundzwanzigste","drei${b}igste","einunddrei${b}igste"], | |
6267 | ["erster"]]; | |
6268 | ||
6269 | $$d{"now"} =["heute","jetzt"]; | |
6270 | $$d{"last"} =["letzte","letzten"]; | |
6271 | $$d{"each"} =["jeden"]; | |
6272 | $$d{"of"} =["der","im","des"]; | |
6273 | $$d{"at"} =["um"]; | |
6274 | $$d{"on"} =["am"]; | |
6275 | $$d{"future"} =["in"]; | |
6276 | $$d{"past"} =["vor"]; | |
6277 | $$d{"next"} =["nachste","n${a}chste","nachsten","n${a}chsten"]; | |
6278 | $$d{"prev"} =["vorherigen","vorherige","letzte","letzten"]; | |
6279 | $$d{"later"} =["spater","sp${a}ter"]; | |
6280 | ||
6281 | $$d{"exact"} =["genau"]; | |
6282 | $$d{"approx"} =["ungefahr","ungef${a}hr"]; | |
6283 | $$d{"business"}=["Arbeitstag"]; | |
6284 | ||
6285 | $$d{"offset"} =["gestern","-0:0:0:1:0:0:0","morgen","+0:0:0:1:0:0:0"]; | |
6286 | $$d{"times"} =["mittag","12:00:00","mitternacht","00:00:00"]; | |
6287 | ||
6288 | $$d{"years"} =["j","Jahr","Jahre"]; | |
6289 | $$d{"months"} =["Monat","Monate"]; | |
6290 | $$d{"weeks"} =["w","Woche","Wochen"]; | |
6291 | $$d{"days"} =["t","Tag","Tage"]; | |
6292 | $$d{"hours"} =["h","std","Stunde","Stunden"]; | |
6293 | $$d{"minutes"} =["min","Minute","Minuten"]; | |
6294 | $$d{"seconds"} =["s","sek","Sekunde","Sekunden"]; | |
6295 | $$d{"replace"} =["m","Monat"]; | |
6296 | ||
6297 | $$d{"sephm"} =':'; | |
6298 | $$d{"sepms"} ='[: ]'; | |
6299 | $$d{"sepss"} ='[.:]'; | |
6300 | ||
6301 | $$d{"am"} = ["FM"]; | |
6302 | $$d{"pm"} = ["EM"]; | |
6303 | } | |
6304 | ||
6305 | sub Date_Init_Dutch { | |
6306 | print "DEBUG: Date_Init_Dutch\n" if ($Curr{"Debug"} =~ /trace/); | |
6307 | my($d)=@_; | |
6308 | my(%h)=(); | |
6309 | &Char_8Bit(\%h); | |
6310 | ||
6311 | $$d{"month_name"}= | |
6312 | [["januari","februari","maart","april","mei","juni","juli","augustus", | |
6313 | "september","october","november","december"], | |
6314 | ["","","","","","","","","","oktober"]]; | |
6315 | ||
6316 | $$d{"month_abb"}= | |
6317 | [["jan","feb","maa","apr","mei","jun","jul", | |
6318 | "aug","sep","oct","nov","dec"], | |
6319 | ["","","mrt","","","","","","","okt"]]; | |
6320 | $$d{"day_name"}= | |
6321 | [["maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag", | |
6322 | "zondag"]]; | |
6323 | $$d{"day_abb"}= | |
6324 | [["ma","di","wo","do","vr","zat","zon"], | |
6325 | ["","","","","","za","zo"]]; | |
6326 | $$d{"day_char"}= | |
6327 | [["M","D","W","D","V","Za","Zo"]]; | |
6328 | ||
6329 | $$d{"num_suff"}= | |
6330 | [["1ste","2de","3de","4de","5de","6de","7de","8ste","9de","10de", | |
6331 | "11de","12de","13de","14de","15de","16de","17de","18de","19de","20ste", | |
6332 | "21ste","22ste","23ste","24ste","25ste","26ste","27ste","28ste","29ste", | |
6333 | "30ste","31ste"]]; | |
6334 | $$d{"num_word"}= | |
6335 | [["eerste","tweede","derde","vierde","vijfde","zesde","zevende","achtste", | |
6336 | "negende","tiende","elfde","twaalfde", | |
6337 | map {"${_}tiende";} qw (der veer vijf zes zeven acht negen), | |
6338 | "twintigste", | |
6339 | map {"${_}entwintigste";} qw (een twee drie vier vijf zes zeven acht | |
6340 | negen), | |
6341 | "dertigste","eenendertigste"], | |
6342 | ["","","","","","","","","","","","","","","","","","","","", | |
6343 | map {"${_}-en-twintigste";} qw (een twee drie vier vijf zes zeven acht | |
6344 | negen), | |
6345 | "dertigste","een-en-dertigste"], | |
6346 | ["een","twee","drie","vier","vijf","zes","zeven","acht","negen","tien", | |
6347 | "elf","twaalf", | |
6348 | map {"${_}tien"} qw (der veer vijf zes zeven acht negen), | |
6349 | "twintig", | |
6350 | map {"${_}entwintig"} qw (een twee drie vier vijf zes zeven acht negen), | |
6351 | "dertig","eenendertig"], | |
6352 | ["","","","","","","","","","","","","","","","","","","","", | |
6353 | map {"${_}-en-twintig"} qw (een twee drie vier vijf zes zeven acht | |
6354 | negen), | |
6355 | "dertig","een-en-dertig"]]; | |
6356 | ||
6357 | $$d{"now"} =["nu","nou","vandaag"]; | |
6358 | $$d{"last"} =["laatste"]; | |
6359 | $$d{"each"} =["elke","elk"]; | |
6360 | $$d{"of"} =["in","van"]; | |
6361 | $$d{"at"} =["om"]; | |
6362 | $$d{"on"} =["op"]; | |
6363 | $$d{"future"} =["over"]; | |
6364 | $$d{"past"} =["geleden","vroeger","eerder"]; | |
6365 | $$d{"next"} =["volgende","volgend"]; | |
6366 | $$d{"prev"} =["voorgaande","voorgaand"]; | |
6367 | $$d{"later"} =["later"]; | |
6368 | ||
6369 | $$d{"exact"} =["exact","precies","nauwkeurig"]; | |
6370 | $$d{"approx"} =["ongeveer","ong",'ong\.',"circa","ca",'ca\.']; | |
6371 | $$d{"business"}=["werk","zakelijke","zakelijk"]; | |
6372 | ||
6373 | $$d{"offset"} =["morgen","+0:0:0:1:0:0:0","overmorgen","+0:0:0:2:0:0:0", | |
6374 | "gisteren","-0:0:0:1:0:0:0","eergisteren","-0::00:2:0:0:0"]; | |
6375 | $$d{"times"} =["noen","12:00:00","middernacht","00:00:00"]; | |
6376 | ||
6377 | $$d{"years"} =["jaar","jaren","ja","j"]; | |
6378 | $$d{"months"} =["maand","maanden","mnd"]; | |
6379 | $$d{"weeks"} =["week","weken","w"]; | |
6380 | $$d{"days"} =["dag","dagen","d"]; | |
6381 | $$d{"hours"} =["uur","uren","u","h"]; | |
6382 | $$d{"minutes"} =["minuut","minuten","min"]; | |
6383 | $$d{"seconds"} =["seconde","seconden","sec","s"]; | |
6384 | $$d{"replace"} =["m","minuten"]; | |
6385 | ||
6386 | $$d{"sephm"} ='[:.uh]'; | |
6387 | $$d{"sepms"} ='[:.m]'; | |
6388 | $$d{"sepss"} ='[.:]'; | |
6389 | ||
6390 | $$d{"am"} = ["am","a.m.","vm","v.m.","voormiddag","'s_ochtends", | |
6391 | "ochtend","'s_nachts","nacht"]; | |
6392 | $$d{"pm"} = ["pm","p.m.","nm","n.m.","namiddag","'s_middags","middag", | |
6393 | "'s_avonds","avond"]; | |
6394 | } | |
6395 | ||
6396 | sub Date_Init_Polish { | |
6397 | print "DEBUG: Date_Init_Polish\n" if ($Curr{"Debug"} =~ /trace/); | |
6398 | my($d)=@_; | |
6399 | ||
6400 | $$d{"month_name"}= | |
6401 | [["stycznia","luty","marca","kwietnia","maja","czerwca", | |
6402 | "lipca","sierpnia","wrzesnia","pazdziernika","listopada","grudnia"], | |
6403 | ["stycznia","luty","marca","kwietnia","maja","czerwca","lipca", | |
6404 | "sierpnia","wrze\x9cnia","pa\x9fdziernika","listopada","grudnia"]]; | |
6405 | $$d{"month_abb"}= | |
6406 | [["sty.","lut.","mar.","kwi.","maj","cze.", | |
6407 | "lip.","sie.","wrz.","paz.","lis.","gru."], | |
6408 | ["sty.","lut.","mar.","kwi.","maj","cze.", | |
6409 | "lip.","sie.","wrz.","pa\x9f.","lis.","gru."]]; | |
6410 | ||
6411 | $$d{"day_name"}= | |
6412 | [["poniedzialek","wtorek","sroda","czwartek","piatek","sobota", | |
6413 | "niedziela"], | |
6414 | ["poniedzia\x81\xb3ek","wtorek","\x9croda","czwartek","pi\x81\xb9tek", | |
6415 | "sobota","niedziela"]]; | |
6416 | $$d{"day_abb"}= | |
6417 | [["po.","wt.","sr.","cz.","pi.","so.","ni."], | |
6418 | ["po.","wt.","\x9cr.","cz.","pi.","so.","ni."]]; | |
6419 | $$d{"day_char"}= | |
6420 | [["p","w","e","c","p","s","n"], | |
6421 | ["p","w","\x9c.","c","p","s","n"]]; | |
6422 | ||
6423 | $$d{"num_suff"}= | |
6424 | [["1.","2.","3.","4.","5.","6.","7.","8.","9.","10.", | |
6425 | "11.","12.","13.","14.","15.","16.","17.","18.","19.","20.", | |
6426 | "21.","22.","23.","24.","25.","26.","27.","28.","29.","30.", | |
6427 | "31."]]; | |
6428 | $$d{"num_word"}= | |
6429 | [["pierwszego","drugiego","trzeczego","czwartego","piatego","szostego", | |
6430 | "siodmego","osmego","dziewiatego","dziesiatego", | |
6431 | "jedenastego","dwunastego","trzynastego","czternastego","pietnastego", | |
6432 | "szestnastego","siedemnastego","osiemnastego","dziewietnastego", | |
6433 | "dwudziestego", | |
6434 | "dwudziestego pierwszego","dwudziestego drugiego", | |
6435 | "dwudziestego trzeczego","dwudziestego czwartego", | |
6436 | "dwudziestego piatego","dwudziestego szostego", | |
6437 | "dwudziestego siodmego","dwudziestego osmego", | |
6438 | "dwudziestego dziewiatego","trzydziestego","trzydziestego pierwszego"], | |
6439 | ["pierwszego","drugiego","trzeczego","czwartego","pi\x81\xb9tego", | |
6440 | "sz\x81\xf3stego","si\x81\xf3dmego","\x81\xf3smego","dziewi\x81\xb9tego", | |
6441 | "dziesi\x81\xb9tego","jedenastego","dwunastego","trzynastego", | |
6442 | "czternastego","pi\x81\xeatnastego","szestnastego","siedemnastego", | |
6443 | "osiemnastego","dziewietnastego","dwudziestego", | |
6444 | "dwudziestego pierwszego","dwudziestego drugiego", | |
6445 | "dwudziestego trzeczego","dwudziestego czwartego", | |
6446 | "dwudziestego pi\x81\xb9tego","dwudziestego sz\x81\xf3stego", | |
6447 | "dwudziestego si\x81\xf3dmego","dwudziestego \x81\xf3smego", | |
6448 | "dwudziestego dziewi\x81\xb9tego","trzydziestego", | |
6449 | "trzydziestego pierwszego"]]; | |
6450 | ||
6451 | $$d{"now"} =["dzisaj","teraz"]; | |
6452 | $$d{"last"} =["ostatni","ostatna"]; | |
6453 | $$d{"each"} =["kazdy","ka\x81\xbfdy", "kazdym","ka\x81\xbfdym"]; | |
6454 | $$d{"of"} =["w","z"]; | |
6455 | $$d{"at"} =["o","u"]; | |
6456 | $$d{"on"} =["na"]; | |
6457 | $$d{"future"} =["za"]; | |
6458 | $$d{"past"} =["temu"]; | |
6459 | $$d{"next"} =["nastepny","nast\x81\xeapny","nastepnym","nast\x81\xeapnym", | |
6460 | "przyszly","przysz\x81\xb3y","przyszlym", | |
6461 | "przysz\x81\xb3ym"]; | |
6462 | $$d{"prev"} =["zeszly","zesz\x81\xb3y","zeszlym","zesz\x81\xb3ym"]; | |
6463 | $$d{"later"} =["later"]; | |
6464 | ||
6465 | $$d{"exact"} =["doklandnie","dok\x81\xb3andnie"]; | |
6466 | $$d{"approx"} =["w przyblizeniu","w przybli\x81\xbfeniu","mniej wiecej", | |
6467 | "mniej wi\x81\xeacej","okolo","oko\x81\xb3o"]; | |
6468 | $$d{"business"}=["sluzbowy","s\x81\xb3u\x81\xbfbowy","sluzbowym", | |
6469 | "s\x81\xb3u\x81\xbfbowym"]; | |
6470 | ||
6471 | $$d{"times"} =["po\x81\xb3udnie","12:00:00", | |
6472 | "p\x81\xf3\x81\xb3noc","00:00:00", | |
6473 | "poludnie","12:00:00","polnoc","00:00:00"]; | |
6474 | $$d{"offset"} =["wczoraj","-0:0:1:0:0:0","jutro","+0:0:1:0:0:0"]; | |
6475 | ||
6476 | $$d{"years"} =["rok","lat","lata","latach"]; | |
6477 | $$d{"months"} =["m.","miesiac","miesi\x81\xb9c","miesiecy", | |
6478 | "miesi\x81\xeacy","miesiacu","miesi\x81\xb9cu"]; | |
6479 | $$d{"weeks"} =["ty.","tydzien","tydzie\x81\xf1","tygodniu"]; | |
6480 | $$d{"days"} =["d.","dzien","dzie\x81\xf1","dni"]; | |
6481 | $$d{"hours"} =["g.","godzina","godziny","godzinie"]; | |
6482 | $$d{"minutes"} =["mn.","min.","minut","minuty"]; | |
6483 | $$d{"seconds"} =["s.","sekund","sekundy"]; | |
6484 | $$d{"replace"} =["m.","miesiac"]; | |
6485 | ||
6486 | $$d{"sephm"} =':'; | |
6487 | $$d{"sepms"} =':'; | |
6488 | $$d{"sepss"} ='[.:]'; | |
6489 | ||
6490 | $$d{"am"} = ["AM","A.M."]; | |
6491 | $$d{"pm"} = ["PM","P.M."]; | |
6492 | } | |
6493 | ||
6494 | sub Date_Init_Spanish { | |
6495 | print "DEBUG: Date_Init_Spanish\n" if ($Curr{"Debug"} =~ /trace/); | |
6496 | my($d)=@_; | |
6497 | my(%h)=(); | |
6498 | &Char_8Bit(\%h); | |
6499 | ||
6500 | $$d{"month_name"}= | |
6501 | [["Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto", | |
6502 | "Septiembre","Octubre","Noviembre","Diciembre"]]; | |
6503 | ||
6504 | $$d{"month_abb"}= | |
6505 | [["Ene","Feb","Mar","Abr","May","Jun","Jul","Ago","Sep","Oct", | |
6506 | "Nov","Dic"]]; | |
6507 | ||
6508 | $$d{"day_name"}= | |
6509 | [["Lunes","Martes","Miercoles","Jueves","Viernes","Sabado","Domingo"]]; | |
6510 | $$d{"day_abb"}= | |
6511 | [["Lun","Mar","Mie","Jue","Vie","Sab","Dom"]]; | |
6512 | $$d{"day_char"}= | |
6513 | [["L","Ma","Mi","J","V","S","D"]]; | |
6514 | ||
6515 | $$d{"num_suff"}= | |
6516 | [["1o","2o","3o","4o","5o","6o","7o","8o","9o","10o", | |
6517 | "11o","12o","13o","14o","15o","16o","17o","18o","19o","20o", | |
6518 | "21o","22o","23o","24o","25o","26o","27o","28o","29o","30o","31o"], | |
6519 | ["1a","2a","3a","4a","5a","6a","7a","8a","9a","10a", | |
6520 | "11a","12a","13a","14a","15a","16a","17a","18a","19a","20a", | |
6521 | "21a","22a","23a","24a","25a","26a","27a","28a","29a","30a","31a"]]; | |
6522 | $$d{"num_word"}= | |
6523 | [["Primero","Segundo","Tercero","Cuarto","Quinto","Sexto","Septimo", | |
6524 | "Octavo","Noveno","Decimo","Decimo Primero","Decimo Segundo", | |
6525 | "Decimo Tercero","Decimo Cuarto","Decimo Quinto","Decimo Sexto", | |
6526 | "Decimo Septimo","Decimo Octavo","Decimo Noveno","Vigesimo", | |
6527 | "Vigesimo Primero","Vigesimo Segundo","Vigesimo Tercero", | |
6528 | "Vigesimo Cuarto","Vigesimo Quinto","Vigesimo Sexto", | |
6529 | "Vigesimo Septimo","Vigesimo Octavo","Vigesimo Noveno","Trigesimo", | |
6530 | "Trigesimo Primero"], | |
6531 | ["Primera","Segunda","Tercera","Cuarta","Quinta","Sexta","Septima", | |
6532 | "Octava","Novena","Decima","Decimo Primera","Decimo Segunda", | |
6533 | "Decimo Tercera","Decimo Cuarta","Decimo Quinta","Decimo Sexta", | |
6534 | "Decimo Septima","Decimo Octava","Decimo Novena","Vigesima", | |
6535 | "Vigesimo Primera","Vigesimo Segunda","Vigesimo Tercera", | |
6536 | "Vigesimo Cuarta","Vigesimo Quinta","Vigesimo Sexta", | |
6537 | "Vigesimo Septima","Vigesimo Octava","Vigesimo Novena","Trigesima", | |
6538 | "Trigesimo Primera"]]; | |
6539 | ||
6540 | $$d{"now"} =["Hoy","Ahora"]; | |
6541 | $$d{"last"} =["ultimo"]; | |
6542 | $$d{"each"} =["cada"]; | |
6543 | $$d{"of"} =["en","de"]; | |
6544 | $$d{"at"} =["a"]; | |
6545 | $$d{"on"} =["el"]; | |
6546 | $$d{"future"} =["en"]; | |
6547 | $$d{"past"} =["hace"]; | |
6548 | $$d{"next"} =["siguiente"]; | |
6549 | $$d{"prev"} =["anterior"]; | |
6550 | $$d{"later"} =["later"]; | |
6551 | ||
6552 | $$d{"exact"} =["exactamente"]; | |
6553 | $$d{"approx"} =["aproximadamente"]; | |
6554 | $$d{"business"}=["laborales"]; | |
6555 | ||
6556 | $$d{"offset"} =["ayer","-0:0:0:1:0:0:0","manana","+0:0:0:1:0:0:0"]; | |
6557 | $$d{"times"} =["mediodia","12:00:00","medianoche","00:00:00"]; | |
6558 | ||
6559 | $$d{"years"} =["a","ano","ano","anos","anos"]; | |
6560 | $$d{"months"} =["m","mes","mes","meses"]; | |
6561 | $$d{"weeks"} =["sem","semana","semana","semanas"]; | |
6562 | $$d{"days"} =["d","dia","dias"]; | |
6563 | $$d{"hours"} =["hr","hrs","hora","horas"]; | |
6564 | $$d{"minutes"} =["min","min","minuto","minutos"]; | |
6565 | $$d{"seconds"} =["s","seg","segundo","segundos"]; | |
6566 | $$d{"replace"} =["m","mes"]; | |
6567 | ||
6568 | $$d{"sephm"} =':'; | |
6569 | $$d{"sepms"} =':'; | |
6570 | $$d{"sepss"} ='[.:]'; | |
6571 | ||
6572 | $$d{"am"} = ["AM","A.M."]; | |
6573 | $$d{"pm"} = ["PM","P.M."]; | |
6574 | } | |
6575 | ||
6576 | sub Date_Init_Portuguese { | |
6577 | print "DEBUG: Date_Init_Portuguese\n" if ($Curr{"Debug"} =~ /trace/); | |
6578 | my($d)=@_; | |
6579 | my(%h)=(); | |
6580 | &Char_8Bit(\%h); | |
6581 | my($o) = $h{"-o"}; | |
6582 | my($c) = $h{",c"}; | |
6583 | my($a) = $h{"a'"}; | |
6584 | my($e) = $h{"e'"}; | |
6585 | my($u) = $h{"u'"}; | |
6586 | my($o2)= $h{"o'"}; | |
6587 | my($a2)= $h{"a`"}; | |
6588 | my($a3)= $h{"a~"}; | |
6589 | my($e2)= $h{"e^"}; | |
6590 | ||
6591 | $$d{"month_name"}= | |
6592 | [["Janeiro","Fevereiro","Marco","Abril","Maio","Junho", | |
6593 | "Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"], | |
6594 | ["Janeiro","Fevereiro","Mar${c}o","Abril","Maio","Junho", | |
6595 | "Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"]]; | |
6596 | ||
6597 | $$d{"month_abb"}= | |
6598 | [["Jan","Fev","Mar","Abr","Mai","Jun", | |
6599 | "Jul","Ago","Set","Out","Nov","Dez"]]; | |
6600 | ||
6601 | $$d{"day_name"}= | |
6602 | [["Segunda","Terca","Quarta","Quinta","Sexta","Sabado","Domingo"], | |
6603 | ["Segunda","Ter${c}a","Quarta","Quinta","Sexta","S${a}bado","Domingo"]]; | |
6604 | $$d{"day_abb"}= | |
6605 | [["Seg","Ter","Qua","Qui","Sex","Sab","Dom"], | |
6606 | ["Seg","Ter","Qua","Qui","Sex","S${a}b","Dom"]]; | |
6607 | $$d{"day_char"}= | |
6608 | [["Sg","T","Qa","Qi","Sx","Sb","D"]]; | |
6609 | ||
6610 | $$d{"num_suff"}= | |
6611 | [["1${o}","2${o}","3${o}","4${o}","5${o}","6${o}","7${o}","8${o}", | |
6612 | "9${o}","10${o}","11${o}","12${o}","13${o}","14${o}","15${o}", | |
6613 | "16${o}","17${o}","18${o}","19${o}","20${o}","21${o}","22${o}", | |
6614 | "23${o}","24${o}","25${o}","26${o}","27${o}","28${o}","29${o}", | |
6615 | "30${o}","31${o}"]]; | |
6616 | $$d{"num_word"}= | |
6617 | [["primeiro","segundo","terceiro","quarto","quinto","sexto","setimo", | |
6618 | "oitavo","nono","decimo","decimo primeiro","decimo segundo", | |
6619 | "decimo terceiro","decimo quarto","decimo quinto","decimo sexto", | |
6620 | "decimo setimo","decimo oitavo","decimo nono","vigesimo", | |
6621 | "vigesimo primeiro","vigesimo segundo","vigesimo terceiro", | |
6622 | "vigesimo quarto","vigesimo quinto","vigesimo sexto","vigesimo setimo", | |
6623 | "vigesimo oitavo","vigesimo nono","trigesimo","trigesimo primeiro"], | |
6624 | ["primeiro","segundo","terceiro","quarto","quinto","sexto","s${e}timo", | |
6625 | "oitavo","nono","d${e}cimo","d${e}cimo primeiro","d${e}cimo segundo", | |
6626 | "d${e}cimo terceiro","d${e}cimo quarto","d${e}cimo quinto", | |
6627 | "d${e}cimo sexto","d${e}cimo s${e}timo","d${e}cimo oitavo", | |
6628 | "d${e}cimo nono","vig${e}simo","vig${e}simo primeiro", | |
6629 | "vig${e}simo segundo","vig${e}simo terceiro","vig${e}simo quarto", | |
6630 | "vig${e}simo quinto","vig${e}simo sexto","vig${e}simo s${e}timo", | |
6631 | "vig${e}simo oitavo","vig${e}simo nono","trig${e}simo", | |
6632 | "trig${e}simo primeiro"]]; | |
6633 | ||
6634 | $$d{"now"} =["agora","hoje"]; | |
6635 | $$d{"last"} =["${u}ltimo","ultimo"]; | |
6636 | $$d{"each"} =["cada"]; | |
6637 | $$d{"of"} =["da","do"]; | |
6638 | $$d{"at"} =["as","${a2}s"]; | |
6639 | $$d{"on"} =["na","no"]; | |
6640 | $$d{"future"} =["em"]; | |
6641 | $$d{"past"} =["a","${a2}"]; | |
6642 | $$d{"next"} =["proxima","proximo","pr${o2}xima","pr${o2}ximo"]; | |
6643 | $$d{"prev"} =["ultima","ultimo","${u}ltima","${u}ltimo"]; | |
6644 | $$d{"later"} =["passadas","passados"]; | |
6645 | ||
6646 | $$d{"exact"} =["exactamente"]; | |
6647 | $$d{"approx"} =["aproximadamente"]; | |
6648 | $$d{"business"}=["util","uteis"]; | |
6649 | ||
6650 | $$d{"offset"} =["ontem","-0:0:0:1:0:0:0", | |
6651 | "amanha","+0:0:0:1:0:0:0","amanh${a3}","+0:0:0:1:0:0:0"]; | |
6652 | $$d{"times"} =["meio-dia","12:00:00","meia-noite","00:00:00"]; | |
6653 | ||
6654 | $$d{"years"} =["anos","ano","ans","an","a"]; | |
6655 | $$d{"months"} =["meses","m${e2}s","mes","m"]; | |
6656 | $$d{"weeks"} =["semanas","semana","sem","sems","s"]; | |
6657 | $$d{"days"} =["dias","dia","d"]; | |
6658 | $$d{"hours"} =["horas","hora","hr","hrs"]; | |
6659 | $$d{"minutes"} =["minutos","minuto","min","mn"]; | |
6660 | $$d{"seconds"} =["segundos","segundo","seg","sg"]; | |
6661 | $$d{"replace"} =["m","mes","s","sems"]; | |
6662 | ||
6663 | $$d{"sephm"} =':'; | |
6664 | $$d{"sepms"} =':'; | |
6665 | $$d{"sepss"} ='[,]'; | |
6666 | ||
6667 | $$d{"am"} = ["AM","A.M."]; | |
6668 | $$d{"pm"} = ["PM","P.M."]; | |
6669 | } | |
6670 | ||
6671 | sub Date_Init_Russian { | |
6672 | print "DEBUG: Date_Init_Russian\n" if ($Curr{"Debug"} =~ /trace/); | |
6673 | my($d)=@_; | |
6674 | my(%h)=(); | |
6675 | &Char_8Bit(\%h); | |
6676 | my($a) =$h{"a:"}; | |
6677 | ||
6678 | $$d{"month_name"}= | |
6679 | [ | |
6680 | ["\xd1\xce\xd7\xc1\xd2\xd1","\xc6\xc5\xd7\xd2\xc1\xcc\xd1", | |
6681 | "\xcd\xc1\xd2\xd4\xc1","\xc1\xd0\xd2\xc5\xcc\xd1","\xcd\xc1\xd1", | |
6682 | "\xc9\xc0\xce\xd1", | |
6683 | "\xc9\xc0\xcc\xd1","\xc1\xd7\xc7\xd5\xd3\xd4\xc1", | |
6684 | "\xd3\xc5\xce\xd4\xd1\xc2\xd2\xd1","\xcf\xcb\xd4\xd1\xc2\xd2\xd1", | |
6685 | "\xce\xcf\xd1\xc2\xd2\xd1","\xc4\xc5\xcb\xc1\xc2\xd2\xd1"], | |
6686 | ["\xd1\xce\xd7\xc1\xd2\xd8","\xc6\xc5\xd7\xd2\xc1\xcc\xd8", | |
6687 | "\xcd\xc1\xd2\xd4","\xc1\xd0\xd2\xc5\xcc\xd8","\xcd\xc1\xca", | |
6688 | "\xc9\xc0\xce\xd8", | |
6689 | "\xc9\xc0\xcc\xd8","\xc1\xd7\xc7\xd5\xd3\xd4", | |
6690 | "\xd3\xc5\xce\xd4\xd1\xc2\xd2\xd8","\xcf\xcb\xd4\xd1\xc2\xd2\xd8", | |
6691 | "\xce\xcf\xd1\xc2\xd2\xd8","\xc4\xc5\xcb\xc1\xc2\xd2\xd8"] | |
6692 | ]; | |
6693 | ||
6694 | $$d{"month_abb"}= | |
6695 | [["\xd1\xce\xd7","\xc6\xc5\xd7","\xcd\xd2\xd4","\xc1\xd0\xd2", | |
6696 | "\xcd\xc1\xca","\xc9\xc0\xce", | |
6697 | "\xc9\xc0\xcc","\xc1\xd7\xc7","\xd3\xce\xd4","\xcf\xcb\xd4", | |
6698 | "\xce\xcf\xd1\xc2","\xc4\xc5\xcb"], | |
6699 | ["","\xc6\xd7\xd2","","","\xcd\xc1\xd1","", | |
6700 | "","","\xd3\xc5\xce","\xcf\xcb\xd4","\xce\xcf\xd1",""]]; | |
6701 | ||
6702 | $$d{"day_name"}= | |
6703 | [["\xd0\xcf\xce\xc5\xc4\xc5\xcc\xd8\xce\xc9\xcb", | |
6704 | "\xd7\xd4\xcf\xd2\xce\xc9\xcb","\xd3\xd2\xc5\xc4\xc1", | |
6705 | "\xde\xc5\xd4\xd7\xc5\xd2\xc7","\xd0\xd1\xd4\xce\xc9\xc3\xc1", | |
6706 | "\xd3\xd5\xc2\xc2\xcf\xd4\xc1", | |
6707 | "\xd7\xcf\xd3\xcb\xd2\xc5\xd3\xc5\xce\xd8\xc5"]]; | |
6708 | $$d{"day_abb"}= | |
6709 | [["\xd0\xce\xc4","\xd7\xd4\xd2","\xd3\xd2\xc4","\xde\xd4\xd7", | |
6710 | "\xd0\xd4\xce","\xd3\xd5\xc2","\xd7\xd3\xcb"], | |
6711 | ["\xd0\xcf\xce","\xd7\xd4\xcf","\xd3\xd2e","\xde\xc5\xd4", | |
6712 | "\xd0\xd1\xd4","\xd3\xd5\xc2","\xd7\xcf\xd3\xcb"]]; | |
6713 | $$d{"day_char"}= | |
6714 | [["\xd0\xce","\xd7\xd4","\xd3\xd2","\xde\xd4","\xd0\xd4","\xd3\xc2", | |
6715 | "\xd7\xd3"]]; | |
6716 | ||
6717 | $$d{"num_suff"}= | |
6718 | [["1 ","2 ","3 ","4 ","5 ","6 ","7 ","8 ","9 ","10 ", | |
6719 | "11 ","12 ","13 ","14 ","15 ","16 ","17 ","18 ","19 ","20 ", | |
6720 | "21 ","22 ","23 ","24 ","25 ","26 ","27 ","28 ","29 ","30 ", | |
6721 | "31 "]]; | |
6722 | $$d{"num_word"}= | |
6723 | [["\xd0\xc5\xd2\xd7\xd9\xca","\xd7\xd4\xcf\xd2\xcf\xca", | |
6724 | "\xd4\xd2\xc5\xd4\xc9\xca","\xde\xc5\xd4\xd7\xc5\xd2\xd4\xd9\xca", | |
6725 | "\xd0\xd1\xd4\xd9\xca","\xdb\xc5\xd3\xd4\xcf\xca", | |
6726 | "\xd3\xc5\xc4\xd8\xcd\xcf\xca","\xd7\xcf\xd3\xd8\xcd\xcf\xca", | |
6727 | "\xc4\xc5\xd7\xd1\xd4\xd9\xca","\xc4\xc5\xd3\xd1\xd4\xd9\xca", | |
6728 | "\xcf\xc4\xc9\xce\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca", | |
6729 | "\xc4\xd7\xc5\xce\xc1\xc4\xde\xc1\xd4\xd9\xca", | |
6730 | "\xd4\xd2\xc5\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca", | |
6731 | "\xde\xc5\xd4\xd9\xd2\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca", | |
6732 | "\xd0\xd1\xd4\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca", | |
6733 | "\xdb\xc5\xd3\xd4\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca", | |
6734 | "\xd3\xc5\xcd\xd8\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca", | |
6735 | "\xd7\xcf\xd3\xc5\xcd\xd8\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca", | |
6736 | "\xc4\xc5\xd7\xd1\xd4\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca", | |
6737 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd9\xca", | |
6738 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd0\xc5\xd2\xd7\xd9\xca", | |
6739 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd7\xd4\xcf\xd2\xcf\xca", | |
6740 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd4\xd2\xc5\xd4\xc9\xca", | |
6741 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xde\xc5\xd4\xd7\xc5\xd2\xd4\xd9\xca", | |
6742 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd0\xd1\xd4\xd9\xca", | |
6743 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xdb\xc5\xd3\xd4\xcf\xca", | |
6744 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd3\xc5\xc4\xd8\xcd\xcf\xca", | |
6745 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd7\xcf\xd3\xd8\xcd\xcf\xca", | |
6746 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xc4\xc5\xd7\xd1\xd4\xd9\xca", | |
6747 | "\xd4\xd2\xc9\xc4\xc3\xc1\xd4\xd9\xca", | |
6748 | "\xd4\xd2\xc9\xc4\xc3\xc1\xd4\xd8 \xd0\xc5\xd2\xd7\xd9\xca"], | |
6749 | ||
6750 | ["\xd0\xc5\xd2\xd7\xcf\xc5","\xd7\xd4\xcf\xd2\xcf\xc5", | |
6751 | "\xd4\xd2\xc5\xd4\xd8\xc5","\xde\xc5\xd4\xd7\xc5\xd2\xd4\xcf\xc5", | |
6752 | "\xd0\xd1\xd4\xcf\xc5","\xdb\xc5\xd3\xd4\xcf\xc5", | |
6753 | "\xd3\xc5\xc4\xd8\xcd\xcf\xc5","\xd7\xcf\xd3\xd8\xcd\xcf\xc5", | |
6754 | "\xc4\xc5\xd7\xd1\xd4\xcf\xc5","\xc4\xc5\xd3\xd1\xd4\xcf\xc5", | |
6755 | "\xcf\xc4\xc9\xce\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5", | |
6756 | "\xc4\xd7\xc5\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5", | |
6757 | "\xd4\xd2\xc5\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5", | |
6758 | "\xde\xc5\xd4\xd9\xd2\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5", | |
6759 | "\xd0\xd1\xd4\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5", | |
6760 | "\xdb\xc5\xd3\xd4\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5", | |
6761 | "\xd3\xc5\xcd\xd8\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5", | |
6762 | "\xd7\xcf\xd3\xc5\xcd\xd8\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5", | |
6763 | "\xc4\xc5\xd7\xd1\xd4\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5", | |
6764 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xcf\xc5", | |
6765 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd0\xc5\xd2\xd7\xcf\xc5", | |
6766 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd7\xd4\xcf\xd2\xcf\xc5", | |
6767 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd4\xd2\xc5\xd4\xd8\xc5", | |
6768 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xde\xc5\xd4\xd7\xc5\xd2\xd4\xcf\xc5", | |
6769 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd0\xd1\xd4\xcf\xc5", | |
6770 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xdb\xc5\xd3\xd4\xcf\xc5", | |
6771 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd3\xc5\xc4\xd8\xcd\xcf\xc5", | |
6772 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd7\xcf\xd3\xd8\xcd\xcf\xc5", | |
6773 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xc4\xc5\xd7\xd1\xd4\xcf\xc5", | |
6774 | "\xd4\xd2\xc9\xc4\xc3\xc1\xd4\xcf\xc5", | |
6775 | "\xd4\xd2\xc9\xc4\xc3\xc1\xd4\xd8 \xd0\xc5\xd2\xd7\xcf\xc5"], | |
6776 | ||
6777 | ["\xd0\xc5\xd2\xd7\xcf\xc7\xcf","\xd7\xd4\xcf\xd2\xcf\xc7\xcf", | |
6778 | "\xd4\xd2\xc5\xd4\xd8\xc5\xc7\xcf", | |
6779 | "\xde\xc5\xd4\xd7\xc5\xd2\xd4\xcf\xc7\xcf","\xd0\xd1\xd4\xcf\xc7\xcf", | |
6780 | "\xdb\xc5\xd3\xd4\xcf\xc7\xcf","\xd3\xc5\xc4\xd8\xcd\xcf\xc7\xcf", | |
6781 | "\xd7\xcf\xd3\xd8\xcd\xcf\xc7\xcf", | |
6782 | "\xc4\xc5\xd7\xd1\xd4\xcf\xc7\xcf","\xc4\xc5\xd3\xd1\xd4\xcf\xc7\xcf", | |
6783 | "\xcf\xc4\xc9\xce\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf", | |
6784 | "\xc4\xd7\xc5\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf", | |
6785 | "\xd4\xd2\xc5\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf", | |
6786 | "\xde\xc5\xd4\xd9\xd2\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf", | |
6787 | "\xd0\xd1\xd4\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf", | |
6788 | "\xdb\xc5\xd3\xd4\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf", | |
6789 | "\xd3\xc5\xcd\xd8\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf", | |
6790 | "\xd7\xcf\xd3\xc5\xcd\xd8\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf", | |
6791 | "\xc4\xc5\xd7\xd1\xd4\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf", | |
6792 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf", | |
6793 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd0\xc5\xd2\xd7\xcf\xc7\xcf", | |
6794 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd7\xd4\xcf\xd2\xcf\xc5", | |
6795 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd4\xd2\xc5\xd4\xd8\xc5\xc7\xcf", | |
6796 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xde\xc5\xd4\xd7\xc5\xd2\xd4\xcf\xc7\xcf", | |
6797 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd0\xd1\xd4\xcf\xc7\xcf", | |
6798 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xdb\xc5\xd3\xd4\xcf\xc7\xcf", | |
6799 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd3\xc5\xc4\xd8\xcd\xcf\xc7\xcf", | |
6800 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd7\xcf\xd3\xd8\xcd\xcf\xc7\xcf", | |
6801 | "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xc4\xc5\xd7\xd1\xd4\xcf\xc7\xcf", | |
6802 | "\xd4\xd2\xc9\xc4\xc3\xc1\xd4\xcf\xc7\xcf", | |
6803 | "\xd4\xd2\xc9\xc4\xc3\xc1\xd4\xd8 \xd0\xc5\xd2\xd7\xcf\xc7\xcf"]]; | |
6804 | ||
6805 | $$d{"now"} =["\xd3\xc5\xc7\xcf\xc4\xce\xd1","\xd3\xc5\xca\xde\xc1\xd3"]; | |
6806 | $$d{"last"} =["\xd0\xcf\xd3\xcc\xc5\xc4\xce\xc9\xca"]; | |
6807 | $$d{"each"} =["\xcb\xc1\xd6\xc4\xd9\xca"]; | |
6808 | $$d{"of"} =[" "]; | |
6809 | $$d{"at"} =["\xd7"]; | |
6810 | $$d{"on"} =["\xd7"]; | |
6811 | $$d{"future"} =["\xd7\xd0\xc5\xd2\xc5\xc4 \xce\xc1"]; | |
6812 | $$d{"past"} =["\xce\xc1\xda\xc1\xc4 \xce\xc1 "]; | |
6813 | $$d{"next"} =["\xd3\xcc\xc5\xc4\xd5\xc0\xdd\xc9\xca"]; | |
6814 | $$d{"prev"} =["\xd0\xd2\xc5\xc4\xd9\xc4\xd5\xdd\xc9\xca"]; | |
6815 | $$d{"later"} =["\xd0\xcf\xda\xd6\xc5"]; | |
6816 | ||
6817 | $$d{"exact"} =["\xd4\xcf\xde\xce\xcf"]; | |
6818 | $$d{"approx"} =["\xd0\xd2\xc9\xcd\xc5\xd2\xce\xcf"]; | |
6819 | $$d{"business"}=["\xd2\xc1\xc2\xcf\xde\xc9\xc8"]; | |
6820 | ||
6821 | $$d{"offset"} =["\xd0\xcf\xda\xc1\xd7\xde\xc5\xd2\xc1","-0:0:0:2:0:0:0", | |
6822 | "\xd7\xde\xc5\xd2\xc1","-0:0:0:1:0:0:0", | |
6823 | "\xda\xc1\xd7\xd4\xd2\xc1","+0:0:0:1:0:0:0", | |
6824 | "\xd0\xcf\xd3\xcc\xc5\xda\xc1\xd7\xd4\xd2\xc1", | |
6825 | "+0:0:0:2:0:0:0"]; | |
6826 | $$d{"times"} =["\xd0\xcf\xcc\xc4\xc5\xce\xd8","12:00:00", | |
6827 | "\xd0\xcf\xcc\xce\xcf\xde\xd8","00:00:00"]; | |
6828 | ||
6829 | $$d{"years"} =["\xc7","\xc7\xc4","\xc7\xcf\xc4","\xcc\xc5\xd4", | |
6830 | "\xcc\xc5\xd4","\xc7\xcf\xc4\xc1"]; | |
6831 | $$d{"months"} =["\xcd\xc5\xd3","\xcd\xc5\xd3\xd1\xc3", | |
6832 | "\xcd\xc5\xd3\xd1\xc3\xc5\xd7"]; | |
6833 | $$d{"weeks"} =["\xce\xc5\xc4\xc5\xcc\xd1","\xce\xc5\xc4\xc5\xcc\xd8", | |
6834 | "\xce\xc5\xc4\xc5\xcc\xc9","\xce\xc5\xc4\xc5\xcc\xc0"]; | |
6835 | $$d{"days"} =["\xc4","\xc4\xc5\xce\xd8","\xc4\xce\xc5\xca", | |
6836 | "\xc4\xce\xd1"]; | |
6837 | $$d{"hours"} =["\xde","\xde.","\xde\xd3","\xde\xd3\xd7","\xde\xc1\xd3", | |
6838 | "\xde\xc1\xd3\xcf\xd7","\xde\xc1\xd3\xc1"]; | |
6839 | $$d{"minutes"} =["\xcd\xce","\xcd\xc9\xce","\xcd\xc9\xce\xd5\xd4\xc1", | |
6840 | "\xcd\xc9\xce\xd5\xd4"]; | |
6841 | $$d{"seconds"} =["\xd3","\xd3\xc5\xcb","\xd3\xc5\xcb\xd5\xce\xc4\xc1", | |
6842 | "\xd3\xc5\xcb\xd5\xce\xc4"]; | |
6843 | $$d{"replace"} =[]; | |
6844 | ||
6845 | $$d{"sephm"} ="[:\xde]"; | |
6846 | $$d{"sepms"} ="[:\xcd]"; | |
6847 | $$d{"sepss"} ="[:.\xd3]"; | |
6848 | ||
6849 | $$d{"am"} = ["\xc4\xd0","${a}\xf0","${a}.\xf0.","\xce\xcf\xde\xc9", | |
6850 | "\xd5\xd4\xd2\xc1", | |
6851 | "\xc4\xcf \xd0\xcf\xcc\xd5\xc4\xce\xd1"]; | |
6852 | $$d{"pm"} = ["\xd0\xd0","\xf0\xf0","\xf0.\xf0.","\xc4\xce\xd1", | |
6853 | "\xd7\xc5\xde\xc5\xd2\xc1", | |
6854 | "\xd0\xcf\xd3\xcc\xc5 \xd0\xcf\xcc\xd5\xc4\xce\xd1", | |
6855 | "\xd0\xcf \xd0\xcf\xcc\xd5\xc4\xce\xc0"]; | |
6856 | } | |
6857 | ||
6858 | sub Date_Init_Turkish { | |
6859 | print "DEBUG: Date_Init_Turkish\n" if ($Curr{"Debug"} =~ /trace/); | |
6860 | my($d)=@_; | |
6861 | ||
6862 | $$d{"month_name"}= | |
6863 | [ | |
6864 | ["ocak","subat","mart","nisan","mayis","haziran", | |
6865 | "temmuz","agustos","eylul","ekim","kasim","aralik"], | |
6866 | ["ocak","\xfeubat","mart","nisan","may\xfds","haziran", | |
6867 | "temmuz","a\xf0ustos","eyl\xfcl","ekim","kas\xfdm","aral\xfdk"] | |
6868 | ]; | |
6869 | ||
6870 | $$d{"month_abb"}= | |
6871 | [ | |
6872 | ["oca","sub","mar","nis","may","haz", | |
6873 | "tem","agu","eyl","eki","kas","ara"], | |
6874 | ["oca","\xfeub","mar","nis","may","haz", | |
6875 | "tem","a\xf0u","eyl","eki","kas","ara"] | |
6876 | ]; | |
6877 | ||
6878 | $$d{"day_name"}= | |
6879 | [ | |
6880 | ["pazartesi","sali","carsamba","persembe","cuma","cumartesi","pazar"], | |
6881 | ["pazartesi","sal\xfd","\xe7ar\xfeamba","per\xfeembe","cuma", | |
6882 | "cumartesi","pazar"], | |
6883 | ]; | |
6884 | ||
6885 | $$d{"day_abb"}= | |
6886 | [ | |
6887 | ["pzt","sal","car","per","cum","cts","paz"], | |
6888 | ["pzt","sal","\xe7ar","per","cum","cts","paz"], | |
6889 | ]; | |
6890 | ||
6891 | $$d{"day_char"}= | |
6892 | [["Pt","S","Cr","Pr","C","Ct","P"], | |
6893 | ["Pt","S","\xc7","Pr","C","Ct","P"]]; | |
6894 | ||
6895 | $$d{"num_suff"}= | |
6896 | [[ "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", | |
6897 | "11.", "12.", "13.", "14.", "15.", "16.", "17.", "18.", "19.", "20.", | |
6898 | "21.", "22.", "23.", "24.", "25.", "26.", "27.", "28.", "29.", "30.", | |
6899 | "31."]]; | |
6900 | ||
6901 | $$d{"num_word"}= | |
6902 | [ | |
6903 | ["birinci","ikinci","ucuncu","dorduncu", | |
6904 | "besinci","altinci","yedinci","sekizinci", | |
6905 | "dokuzuncu","onuncu","onbirinci","onikinci", | |
6906 | "onucuncu","ondordoncu", | |
6907 | "onbesinci","onaltinci","onyedinci","onsekizinci", | |
6908 | "ondokuzuncu","yirminci","yirmibirinci","yirmikinci", | |
6909 | "yirmiucuncu","yirmidorduncu", | |
6910 | "yirmibesinci","yirmialtinci","yirmiyedinci","yirmisekizinci", | |
6911 | "yirmidokuzuncu","otuzuncu","otuzbirinci"], | |
6912 | ["birinci","ikinci","\xfc\xe7\xfcnc\xfc","d\xf6rd\xfcnc\xfc", | |
6913 | "be\xfeinci","alt\xfdnc\xfd","yedinci","sekizinci", | |
6914 | "dokuzuncu","onuncu","onbirinci","onikinci", | |
6915 | "on\xfc\xe7\xfcnc\xfc","ond\xf6rd\xfcnc\xfc", | |
6916 | "onbe\xfeinci","onalt\xfdnc\xfd","onyedinci","onsekizinci", | |
6917 | "ondokuzuncu","yirminci","yirmibirinci","yirmikinci", | |
6918 | "yirmi\xfc\xe7\xfcnc\xfc","yirmid\xf6rd\xfcnc\xfc", | |
6919 | "yirmibe\xfeinci","yirmialt\xfdnc\xfd","yirmiyedinci","yirmisekizinci", | |
6920 | "yirmidokuzuncu","otuzuncu","otuzbirinci"] | |
6921 | ]; | |
6922 | ||
6923 | $$d{"now"} =["\xfeimdi", "simdi", "bugun","bug\xfcn"]; | |
6924 | $$d{"last"} =["son", "sonuncu"]; | |
6925 | $$d{"each"} =["her"]; | |
6926 | $$d{"of"} =["of"]; | |
6927 | $$d{"at"} =["saat"]; | |
6928 | $$d{"on"} =["on"]; | |
6929 | $$d{"future"} =["gelecek"]; | |
6930 | $$d{"past"} =["ge\xe7mi\xfe", "gecmis","gecen", "ge\xe7en"]; | |
6931 | $$d{"next"} =["gelecek","sonraki"]; | |
6932 | $$d{"prev"} =["onceki","\xf6nceki"]; | |
6933 | $$d{"later"} =["sonra"]; | |
6934 | ||
6935 | $$d{"exact"} =["tam"]; | |
6936 | $$d{"approx"} =["yakla\xfe\xfdk", "yaklasik"]; | |
6937 | $$d{"business"}=["i\xfe","\xe7al\xfd\xfema","is", "calisma"]; | |
6938 | ||
6939 | $$d{"offset"} =["d\xfcn","-0:0:0:1:0:0:0", | |
6940 | "dun", "-0:0:0:1:0:0:0", | |
6941 | "yar\xfdn","+0:0:0:1:0:0:0", | |
6942 | "yarin","+0:0:0:1:0:0:0"]; | |
6943 | ||
6944 | $$d{"times"} =["\xf6\xf0len","12:00:00", | |
6945 | "oglen","12:00:00", | |
6946 | "yarim","12:300:00", | |
6947 | "yar\xfdm","12:30:00", | |
6948 | "gece yar\xfds\xfd","00:00:00", | |
6949 | "gece yarisi","00:00:00"]; | |
6950 | ||
6951 | $$d{"years"} =["yil","y"]; | |
6952 | $$d{"months"} =["ay","a"]; | |
6953 | $$d{"weeks"} =["hafta", "h"]; | |
6954 | $$d{"days"} =["gun","g"]; | |
6955 | $$d{"hours"} =["saat"]; | |
6956 | $$d{"minutes"} =["dakika","dak","d"]; | |
6957 | $$d{"seconds"} =["saniye","sn",]; | |
6958 | $$d{"replace"} =["s","saat"]; | |
6959 | ||
6960 | $$d{"sephm"} =':'; | |
6961 | $$d{"sepms"} =':'; | |
6962 | $$d{"sepss"} ='[.:,]'; | |
6963 | ||
6964 | $$d{"am"} = ["\xf6gleden \xf6nce","ogleden once"]; | |
6965 | $$d{"pm"} = ["\xf6\xf0leden sonra","ogleden sonra"]; | |
6966 | } | |
6967 | ||
6968 | sub Date_Init_Danish { | |
6969 | print "DEBUG: Date_Init_Danish\n" if ($Curr{"Debug"} =~ /trace/); | |
6970 | my($d)=@_; | |
6971 | ||
6972 | $$d{"month_name"}= | |
6973 | [["Januar","Februar","Marts","April","Maj","Juni", | |
6974 | "Juli","August","September","Oktober","November","December"]]; | |
6975 | $$d{"month_abb"}= | |
6976 | [["Jan","Feb","Mar","Apr","Maj","Jun", | |
6977 | "Jul","Aug","Sep","Okt","Nov","Dec"]]; | |
6978 | ||
6979 | $$d{"day_name"}= | |
6980 | [["Mandag","Tirsdag","Onsdag","Torsdag","Fredag","Lordag","Sondag"], | |
6981 | ["Mandag","Tirsdag","Onsdag","Torsdag","Fredag","L\xf8rdag","S\xf8ndag"]]; | |
6982 | ||
6983 | $$d{"day_abb"}= | |
6984 | [["Man","Tis","Ons","Tor","Fre","Lor","Son"], | |
6985 | ["Man","Tis","Ons","Tor","Fre","L\xf8r","S\xf8n"]]; | |
6986 | $$d{"day_char"}= | |
6987 | [["M","Ti","O","To","F","L","S"]]; | |
6988 | ||
6989 | $$d{"num_suff"}= | |
6990 | [["1:e","2:e","3:e","4:e","5:e","6:e","7:e","8:e","9:e","10:e", | |
6991 | "11:e","12:e","13:e","14:e","15:e","16:e","17:e","18:e","19:e","20:e", | |
6992 | "21:e","22:e","23:e","24:e","25:e","26:e","27:e","28:e","29:e","30:e", | |
6993 | "31:e"]]; | |
6994 | $$d{"num_word"}= | |
6995 | [["forste","anden","tredie","fjerde","femte","sjette","syvende", | |
6996 | "ottende","niende","tiende","elfte","tolvte","trettende","fjortende", | |
6997 | "femtende","sekstende","syttende","attende","nittende","tyvende", | |
6998 | "enogtyvende","toogtyvende","treogtyvende","fireogtyvende","femogtyvende", | |
6999 | "seksogtyvende","syvogtyvende","otteogtyvende","niogtyvende", | |
7000 | "tredivte","enogtredivte"], | |
7001 | ["f\xf8rste","anden","tredie","fjerde","femte","sjette","syvende", | |
7002 | "ottende","niende","tiende","elfte","tolvte","trettende","fjortende", | |
7003 | "femtende","sekstende","syttende","attende","nittende","tyvende", | |
7004 | "enogtyvende","toogtyvende","treogtyvende","fireogtyvende","femogtyvende", | |
7005 | "seksogtyvende","syvogtyvende","otteogtyvende","niogtyvende", | |
7006 | "tredivte","enogtredivte"]]; | |
7007 | ||
7008 | $$d{"now"} =["idag","nu"]; | |
7009 | $$d{"last"} =["forrige","sidste","nyeste"]; | |
7010 | $$d{"each"} =["hver"]; | |
7011 | $$d{"of"} =["om"]; | |
7012 | $$d{"at"} =["kl","kl.","klokken"]; | |
7013 | $$d{"on"} =["pa","p\xe5"]; | |
7014 | $$d{"future"} =["om"]; | |
7015 | $$d{"past"} =["siden"]; | |
7016 | $$d{"next"} =["nasta","n\xe6ste"]; | |
7017 | $$d{"prev"} =["forrige"]; | |
7018 | $$d{"later"} =["senere"]; | |
7019 | ||
7020 | $$d{"exact"} =["pracist","pr\xe6cist"]; | |
7021 | $$d{"approx"} =["circa"]; | |
7022 | $$d{"business"}=["arbejdsdag","arbejdsdage"]; | |
7023 | ||
7024 | $$d{"offset"} =["ig\xe5r","-0:0:0:1:0:0:0","igar","-0:0:0:1:0:0:0", | |
7025 | "imorgen","+0:0:0:1:0:0:0"]; | |
7026 | $$d{"times"} =["midt pa dagen","12:00:00","midt p\xe5 dagen","12:00:00", | |
7027 | "midnat","00:00:00"]; | |
7028 | ||
7029 | $$d{"years"} =["ar","\xe5r"]; | |
7030 | $$d{"months"} =["man","maned","maneder","m\xe5n","m\xe5ned","m\xe5neder"]; | |
7031 | $$d{"weeks"} =["u","uge","uger"]; | |
7032 | $$d{"days"} =["d","dag","dage"]; | |
7033 | $$d{"hours"} =["t","tim","time","timer"]; | |
7034 | $$d{"minutes"} =["min","minut","minutter"]; | |
7035 | $$d{"seconds"} =["s","sek","sekund","sekunder"]; | |
7036 | $$d{"replace"} =["m","minut"]; | |
7037 | ||
7038 | $$d{"sephm"} ='[.:]'; | |
7039 | $$d{"sepms"} =':'; | |
7040 | $$d{"sepss"} ='[.:]'; | |
7041 | ||
7042 | $$d{"am"} = ["FM"]; | |
7043 | $$d{"pm"} = ["EM"]; | |
7044 | } | |
7045 | ||
7046 | ######################################################################## | |
7047 | # FROM MY PERSONAL LIBRARIES | |
7048 | ######################################################################## | |
7049 | ||
7050 | no integer; | |
7051 | ||
7052 | # &ModuloAddition($N,$add,\$val,\$rem); | |
7053 | # This calculates $val=$val+$add and forces $val to be in a certain range. | |
7054 | # This is useful for adding numbers for which only a certain range is | |
7055 | # allowed (for example, minutes can be between 0 and 59 or months can be | |
7056 | # between 1 and 12). The absolute value of $N determines the range and | |
7057 | # the sign of $N determines whether the range is 0 to N-1 (if N>0) or | |
7058 | # 1 to N (N<0). The remainder (as modulo N) is added to $rem. | |
7059 | # Example: | |
7060 | # To add 2 hours together (with the excess returned in days) use: | |
7061 | # &ModuloAddition(60,$s1,\$s,\$day); | |
7062 | sub ModuloAddition { | |
7063 | my($N,$add,$val,$rem)=@_; | |
7064 | return if ($N==0); | |
7065 | $$val+=$add; | |
7066 | if ($N<0) { | |
7067 | # 1 to N | |
7068 | $N = -$N; | |
7069 | if ($$val>$N) { | |
7070 | $$rem+= int(($$val-1)/$N); | |
7071 | $$val = ($$val-1)%$N +1; | |
7072 | } elsif ($$val<1) { | |
7073 | $$rem-= int(-$$val/$N)+1; | |
7074 | $$val = $N-(-$$val % $N); | |
7075 | } | |
7076 | ||
7077 | } else { | |
7078 | # 0 to N-1 | |
7079 | if ($$val>($N-1)) { | |
7080 | $$rem+= int($$val/$N); | |
7081 | $$val = $$val%$N; | |
7082 | } elsif ($$val<0) { | |
7083 | $$rem-= int(-($$val+1)/$N)+1; | |
7084 | $$val = ($N-1)-(-($$val+1)%$N); | |
7085 | } | |
7086 | } | |
7087 | } | |
7088 | ||
7089 | # $Flag=&IsInt($String [,$low, $high]); | |
7090 | # Returns 1 if $String is a valid integer, 0 otherwise. If $low is | |
7091 | # entered, $String must be >= $low. If $high is entered, $String must | |
7092 | # be <= $high. It is valid to check only one of the bounds. | |
7093 | sub IsInt { | |
7094 | my($N,$low,$high)=@_; | |
7095 | return 0 if (! defined $N or | |
7096 | $N !~ /^\s*[-+]?\d+\s*$/ or | |
7097 | defined $low && $N<$low or | |
7098 | defined $high && $N>$high); | |
7099 | return 1; | |
7100 | } | |
7101 | ||
7102 | # $Pos=&SinLindex(\@List,$Str [,$offset [,$CaseInsensitive]]); | |
7103 | # Searches for an exact string in a list. | |
7104 | # | |
7105 | # This is similar to RinLindex except that it searches for elements | |
7106 | # which are exactly equal to $Str (possibly case insensitive). | |
7107 | sub SinLindex { | |
7108 | my($listref,$Str,$offset,$Insensitive)=@_; | |
7109 | my($i,$len,$tmp)=(); | |
7110 | $len=$#$listref; | |
7111 | return -2 if ($len<0 or ! $Str); | |
7112 | return -1 if (&Index_First(\$offset,$len)); | |
7113 | $Str=uc($Str) if ($Insensitive); | |
7114 | for ($i=$offset; $i<=$len; $i++) { | |
7115 | $tmp=$$listref[$i]; | |
7116 | $tmp=uc($tmp) if ($Insensitive); | |
7117 | return $i if ($tmp eq $Str); | |
7118 | } | |
7119 | return -1; | |
7120 | } | |
7121 | ||
7122 | sub Index_First { | |
7123 | my($offsetref,$max)=@_; | |
7124 | $$offsetref=0 if (! $$offsetref); | |
7125 | if ($$offsetref < 0) { | |
7126 | $$offsetref += $max + 1; | |
7127 | $$offsetref=0 if ($$offsetref < 0); | |
7128 | } | |
7129 | return -1 if ($$offsetref > $max); | |
7130 | return 0; | |
7131 | } | |
7132 | ||
7133 | # $File=&CleanFile($file); | |
7134 | # This cleans up a path to remove the following things: | |
7135 | # double slash /a//b -> /a/b | |
7136 | # trailing dot /a/. -> /a | |
7137 | # leading dot ./a -> a | |
7138 | # trailing slash a/ -> a | |
7139 | sub CleanFile { | |
7140 | my($file)=@_; | |
7141 | $file =~ s/\s*$//; | |
7142 | $file =~ s/^\s*//; | |
7143 | $file =~ s|//+|/|g; # multiple slash | |
7144 | $file =~ s|/\.$|/|; # trailing /. (leaves trailing slash) | |
7145 | $file =~ s|^\./|| # leading ./ | |
7146 | if ($file ne "./"); | |
7147 | $file =~ s|/$|| # trailing slash | |
7148 | if ($file ne "/"); | |
7149 | return $file; | |
7150 | } | |
7151 | ||
7152 | # $File=&ExpandTilde($file); | |
7153 | # This checks to see if a "~" appears as the first character in a path. | |
7154 | # If it does, the "~" expansion is interpreted (if possible) and the full | |
7155 | # path is returned. If a "~" expansion is used but cannot be | |
7156 | # interpreted, an empty string is returned. | |
7157 | # | |
7158 | # This is Windows/Mac friendly. | |
7159 | # This is efficient. | |
7160 | sub ExpandTilde { | |
7161 | my($file)=shift; | |
7162 | my($user,$home)=(); | |
7163 | # ~aaa/bbb= ~ aaa /bbb | |
7164 | if ($file =~ s|^~([^/]*)||) { | |
7165 | $user=$1; | |
7166 | # Single user operating systems (Mac, MSWindows) don't have the getpwnam | |
7167 | # and getpwuid routines defined. Try to catch various different ways | |
7168 | # of knowing we are on one of these systems: | |
7169 | return "" if ($OS eq "Windows" or | |
7170 | $OS eq "Mac" or | |
7171 | $OS eq "Netware" or | |
7172 | $OS eq "MPE"); | |
7173 | $user="" if (! defined $user); | |
7174 | ||
7175 | if ($user) { | |
7176 | $home= (getpwnam($user))[7]; | |
7177 | } else { | |
7178 | $home= (getpwuid($<))[7]; | |
7179 | } | |
7180 | $home = VMS::Filespec::unixpath($home) if ($OS eq "VMS"); | |
7181 | return "" if (! $home); | |
7182 | $file="$home/$file"; | |
7183 | } | |
7184 | $file; | |
7185 | } | |
7186 | ||
7187 | # $File=&FullFilePath($file); | |
7188 | # Returns the full or relative path to $file (expanding "~" if necessary). | |
7189 | # Returns an empty string if a "~" expansion cannot be interpreted. The | |
7190 | # path does not need to exist. CleanFile is called. | |
7191 | sub FullFilePath { | |
7192 | my($file)=shift; | |
7193 | my($rootpat) = '^/'; #default pattern to match absolute path | |
7194 | $rootpat = '^(\\|/|([A-Za-z]:[\\/]))' if ($OS eq 'Windows'); | |
7195 | $file=&ExpandTilde($file); | |
7196 | return "" if (! $file); | |
7197 | return &CleanFile($file); | |
7198 | } | |
7199 | ||
7200 | # $Flag=&CheckFilePath($file [,$mode]); | |
7201 | # Checks to see if $file exists, to see what type it is, and whether | |
7202 | # the script can access it. If it exists and has the correct mode, 1 | |
7203 | # is returned. | |
7204 | # | |
7205 | # $mode is a string which may contain any of the valid file test operator | |
7206 | # characters except t, M, A, C. The appropriate test is run for each | |
7207 | # character. For example, if $mode is "re" the -r and -e tests are both | |
7208 | # run. | |
7209 | # | |
7210 | # An empty string is returned if the file doesn't exist. A 0 is returned | |
7211 | # if the file exists but any test fails. | |
7212 | # | |
7213 | # All characters in $mode which do not correspond to valid tests are | |
7214 | # ignored. | |
7215 | sub CheckFilePath { | |
7216 | my($file,$mode)=@_; | |
7217 | my($test)=(); | |
7218 | $file=&FullFilePath($file); | |
7219 | $mode = "" if (! defined $mode); | |
7220 | ||
7221 | # Run tests | |
7222 | return 0 if (! defined $file or ! $file); | |
7223 | return 0 if (( ! -e $file) or | |
7224 | ($mode =~ /r/ && ! -r $file) or | |
7225 | ($mode =~ /w/ && ! -w $file) or | |
7226 | ($mode =~ /x/ && ! -x $file) or | |
7227 | ($mode =~ /R/ && ! -R $file) or | |
7228 | ($mode =~ /W/ && ! -W $file) or | |
7229 | ($mode =~ /X/ && ! -X $file) or | |
7230 | ($mode =~ /o/ && ! -o $file) or | |
7231 | ($mode =~ /O/ && ! -O $file) or | |
7232 | ($mode =~ /z/ && ! -z $file) or | |
7233 | ($mode =~ /s/ && ! -s $file) or | |
7234 | ($mode =~ /f/ && ! -f $file) or | |
7235 | ($mode =~ /d/ && ! -d $file) or | |
7236 | ($mode =~ /l/ && ! -l $file) or | |
7237 | ($mode =~ /s/ && ! -s $file) or | |
7238 | ($mode =~ /p/ && ! -p $file) or | |
7239 | ($mode =~ /b/ && ! -b $file) or | |
7240 | ($mode =~ /c/ && ! -c $file) or | |
7241 | ($mode =~ /u/ && ! -u $file) or | |
7242 | ($mode =~ /g/ && ! -g $file) or | |
7243 | ($mode =~ /k/ && ! -k $file) or | |
7244 | ($mode =~ /T/ && ! -T $file) or | |
7245 | ($mode =~ /B/ && ! -B $file)); | |
7246 | return 1; | |
7247 | } | |
7248 | #&& | |
7249 | ||
7250 | # $Path=&FixPath($path [,$full] [,$mode] [,$error]); | |
7251 | # Makes sure that every directory in $path (a colon separated list of | |
7252 | # directories) appears as a full path or relative path. All "~" | |
7253 | # expansions are removed. All trailing slashes are removed also. If | |
7254 | # $full is non-nil, relative paths are expanded to full paths as well. | |
7255 | # | |
7256 | # If $mode is given, it may be either "e", "r", or "w". In this case, | |
7257 | # additional checking is done to each directory. If $mode is "e", it | |
7258 | # need ony exist to pass the check. If $mode is "r", it must have have | |
7259 | # read and execute permission. If $mode is "w", it must have read, | |
7260 | # write, and execute permission. | |
7261 | # | |
7262 | # The value of $error determines what happens if the directory does not | |
7263 | # pass the test. If it is non-nil, if any directory does not pass the | |
7264 | # test, the subroutine returns the empty string. Otherwise, it is simply | |
7265 | # removed from $path. | |
7266 | # | |
7267 | # The corrected path is returned. | |
7268 | sub FixPath { | |
7269 | my($path,$full,$mode,$err)=@_; | |
7270 | local($_)=""; | |
7271 | my(@dir)=split(/$Cnf{"PathSep"}/,$path); | |
7272 | $full=0 if (! defined $full); | |
7273 | $mode="" if (! defined $mode); | |
7274 | $err=0 if (! defined $err); | |
7275 | $path=""; | |
7276 | if ($mode eq "e") { | |
7277 | $mode="de"; | |
7278 | } elsif ($mode eq "r") { | |
7279 | $mode="derx"; | |
7280 | } elsif ($mode eq "w") { | |
7281 | $mode="derwx"; | |
7282 | } | |
7283 | ||
7284 | foreach (@dir) { | |
7285 | ||
7286 | # Expand path | |
7287 | if ($full) { | |
7288 | $_=&FullFilePath($_); | |
7289 | } else { | |
7290 | $_=&ExpandTilde($_); | |
7291 | } | |
7292 | if (! $_) { | |
7293 | return "" if ($err); | |
7294 | next; | |
7295 | } | |
7296 | ||
7297 | # Check mode | |
7298 | if (! $mode or &CheckFilePath($_,$mode)) { | |
7299 | $path .= $Cnf{"PathSep"} . $_; | |
7300 | } else { | |
7301 | return "" if ($err); | |
7302 | } | |
7303 | } | |
7304 | $path =~ s/^$Cnf{"PathSep"}//; | |
7305 | return $path; | |
7306 | } | |
7307 | #&& | |
7308 | ||
7309 | # $File=&SearchPath($file,$path [,$mode] [,@suffixes]); | |
7310 | # Searches through directories in $path for a file named $file. The | |
7311 | # full path is returned if one is found, or an empty string otherwise. | |
7312 | # The file may exist with one of the @suffixes. The mode is checked | |
7313 | # similar to &CheckFilePath. | |
7314 | # | |
7315 | # The first full path that matches the name and mode is returned. If none | |
7316 | # is found, an empty string is returned. | |
7317 | sub SearchPath { | |
7318 | my($file,$path,$mode,@suff)=@_; | |
7319 | my($f,$s,$d,@dir,$fs)=(); | |
7320 | $path=&FixPath($path,1,"r"); | |
7321 | @dir=split(/$Cnf{"PathSep"}/,$path); | |
7322 | foreach $d (@dir) { | |
7323 | $f="$d/$file"; | |
7324 | $f=~ s|//|/|g; | |
7325 | return $f if (&CheckFilePath($f,$mode)); | |
7326 | foreach $s (@suff) { | |
7327 | $fs="$f.$s"; | |
7328 | return $fs if (&CheckFilePath($fs,$mode)); | |
7329 | } | |
7330 | } | |
7331 | return ""; | |
7332 | } | |
7333 | ||
7334 | # @list=&ReturnList($str); | |
7335 | # This takes a string which should be a comma separated list of integers | |
7336 | # or ranges (5-7). It returns a sorted list of all integers referred to | |
7337 | # by the string, or () if there is an invalid element. | |
7338 | # | |
7339 | # Negative integers are also handled. "-2--1" is equivalent to "-2,-1". | |
7340 | sub ReturnList { | |
7341 | my($str)=@_; | |
7342 | my(@ret,@str,$from,$to,$tmp)=(); | |
7343 | @str=split(/,/,$str); | |
7344 | foreach $str (@str) { | |
7345 | if ($str =~ /^[-+]?\d+$/) { | |
7346 | push(@ret,$str); | |
7347 | } elsif ($str =~ /^([-+]?\d+)-([-+]?\d+)$/) { | |
7348 | ($from,$to)=($1,$2); | |
7349 | if ($from>$to) { | |
7350 | $tmp=$from; | |
7351 | $from=$to; | |
7352 | $to=$tmp; | |
7353 | } | |
7354 | push(@ret,$from..$to); | |
7355 | } else { | |
7356 | return (); | |
7357 | } | |
7358 | } | |
7359 | @ret; | |
7360 | } | |
7361 | ||
7362 | 1; |