0001806: Date problems fixed and new date formats MmmDDYYYY, DDMmmYYYY and YYYYMmmDD...
[fa-stable.git] / includes / date_functions.inc
1 <?php
2 /**********************************************************************
3     Copyright (C) FrontAccounting, LLC.
4         Released under the terms of the GNU General Public License, GPL, 
5         as published by the Free Software Foundation, either version 3 
6         of the License, or (at your option) any later version.
7     This program is distributed in the hope that it will be useful,
8     but WITHOUT ANY WARRANTY; without even the implied warranty of
9     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
10     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
11 ***********************************************************************/
12 /*
13 date validation and parsing functions
14
15 These functions refer to the global variable defining the date format
16 The date format is defined in config.php called dateformats
17 this can be a string either "d/m/Y" for UK/Australia/New Zealand dates or
18 "m/d/Y" for US/Canada format dates depending on setting in preferences.
19
20 */
21
22 function __date($year, $month, $day)
23 {
24         global $dateseps, $tmonths;
25         
26         $how = user_date_format();
27         $sep = $dateseps[user_date_sep()];
28         $day = (int)$day;
29         $month = (int)$month;
30         if ($how < 3)
31         {
32                 if ($day < 10)
33                         $day = "0".$day;
34                 if ($month < 10)
35                         $month = "0".$month;
36         }               
37         if ($how == 0)
38                 return $month.$sep.$day.$sep.$year;
39         elseif ($how == 1)
40                 return $day.$sep.$month.$sep.$year;
41         elseif ($how == 2)
42                 return $year.$sep.$month.$sep.$day;
43         elseif ($how == 3)
44                 return $tmonths[$month].$sep.$day.$sep.$year;
45         elseif ($how == 4)
46                 return $day.$sep.$tmonths[$month].$sep.$year;
47         else
48                 return $year.$sep.$tmonths[$month].$sep.$day;
49 }
50
51 function is_date($date_) 
52 {
53         global $dateseps;
54
55         if ($date_ == null || $date_ == "")
56                 return 0;
57         $how = user_date_format();
58         $sep = $dateseps[user_date_sep()];
59
60         $date_ = trim($date_);
61         $date = str_replace($sep, "", $date_);
62         if (strlen($date_) == 6)
63         {
64                 if ($how == 0)
65                 {
66                         $day = substr($date,2,2);
67                         $month = substr($date,0,2);
68                         $year = substr($date,4,2);
69                 } 
70                 elseif ($how == 1)
71                 {
72                         $day = substr($date,0,2);
73                         $month = substr($date,2,2);
74                         $year = substr($date,4,2);
75                 } 
76                 else
77                 {
78                         $day = substr($date,4,2);
79                         $month = substr($date,2,2);
80                         $year = substr($date,0,2);
81                 }
82         }
83         elseif (strlen($date_) == 8)
84         {
85                 if ($how == 0)
86                 {
87                         $day = substr($date,2,2);
88                         $month = substr($date,0,2);
89                         $year = substr($date,4,4);
90                 } 
91                 elseif ($how == 1)
92                 {
93                         $day = substr($date,0,2);
94                         $month = substr($date,2,2);
95                         $year = substr($date,4,4);
96                 } 
97                 else
98                 {
99                         $day = substr($date,6,2);
100                         $month = substr($date,4,2);
101                         $year = substr($date,0,4);
102                 }
103         }
104         elseif ($how > 2)
105         {
106                 global $tmonths;
107                 $dd = explode($sep, $date_);
108                 if ($how == 3)
109                 {
110                         $day = $dd[1];
111                         $month = array_search($dd[0], $tmonths);
112                         $year = $dd[2];
113                 } 
114                 elseif ($how == 4)
115                 {
116                         $day = $dd[0];
117                         $month = array_search($dd[1], $tmonths);
118                         $year = $dd[2];
119                 } 
120                 else
121                 {
122                         $day = $dd[2];
123                         $month = array_search($dd[1], $tmonths);
124                         $year = $dd[0];
125                 }
126                 if ($year < 1000)
127                         return 0;
128         }
129         if (!isset($year)|| (int)$year > 9999) 
130         {
131                 return 0;
132         }
133
134         if (is_long((int)$day) && is_long((int)$month) && is_long((int)$year))
135         {
136                 global $date_system;
137                 if ($date_system == 1)
138                         list($year, $month, $day) = jalali_to_gregorian($year, $month, $day);  
139                 elseif ($date_system == 2)      
140                         list($year, $month, $day) = islamic_to_gregorian($year, $month, $day);  
141                 if (checkdate((int)$month, (int)$day, (int)$year))
142                 {
143                         return 1;
144                 }
145                 else
146                 {
147                         return 0;
148                 }
149         }
150         else
151         { /*Can't be in an appropriate DefaultDateFormat */
152                 return 0;
153         }
154 } //end of is_date function
155
156 function Today() 
157 {
158         global $date_system;
159
160         $year = date("Y");
161         $month = date("n");
162         $day = date("j");
163         if ($date_system == 1)
164                 list($year, $month, $day) = gregorian_to_jalali($year, $month, $day);
165         elseif ($date_system == 2)      
166                 list($year, $month, $day) = gregorian_to_islamic($year, $month, $day);
167         return __date($year, $month, $day);     
168 }
169
170 function Now() 
171 {
172         if (user_date_format() == 0)
173                 return date("h:i a");
174         else
175                 return date("H:i");
176 }
177 //
178 //      Retrieve and optionaly set default date for new document.
179 //
180 function new_doc_date($date=null)
181 {
182         if (isset($date) && $date != '')
183                 $_SESSION['_default_date'] = $date;
184
185         if (!isset($_SESSION['_default_date']) || !sticky_doc_date())
186                 $_SESSION['_default_date'] = Today();
187
188         return $_SESSION['_default_date'];
189 }
190
191 function is_date_in_fiscalyear($date, $convert=false)
192 {
193         global $path_to_root;
194         include_once($path_to_root . "/admin/db/fiscalyears_db.inc");
195
196     //Chaitanya
197     if ($convert)
198         $date2 = sql2date($date);
199     else
200         $date2 = $date;
201
202     if ($_SESSION["wa_current_user"]->can_access('SA_MULTIFISCALYEARS')) // allow all open years for this one
203         return is_date_in_fiscalyears($date2, false); 
204
205     $myrow = get_current_fiscalyear();
206     if ($myrow['closed'] == 1)
207         return 0;
208     
209     $begin = sql2date($myrow['begin']);
210     $end = sql2date($myrow['end']);
211     if (date1_greater_date2($begin, $date2) || date1_greater_date2($date2, $end))
212     {
213         return 0;
214     }
215     return 1;
216 }
217
218 function begin_fiscalyear()
219 {
220         global $path_to_root;
221         include_once($path_to_root . "/admin/db/fiscalyears_db.inc");
222
223         $myrow = get_current_fiscalyear();
224         return sql2date($myrow['begin']);
225 }
226
227 function end_fiscalyear()
228 {
229         global $path_to_root;
230         include_once($path_to_root . "/admin/db/fiscalyears_db.inc");
231
232         $myrow = get_current_fiscalyear();
233         return sql2date($myrow['end']);
234 }
235
236 function begin_month($date)
237 {
238         global $date_system;
239     list($day, $month, $year) = explode_date_to_dmy($date);
240     if ($date_system == 1)
241         list($year, $month, $day) = gregorian_to_jalali($year, $month, $day);
242     elseif ($date_system == 2)  
243         list($year, $month, $day) = gregorian_to_islamic($year, $month, $day);
244         return __date($year, $month, 1);
245 }
246
247 function days_in_month($month, $year)
248 {
249         global $date_system;
250
251         if ($date_system == 1)
252         {
253                 $days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, ((((((($year - (($year > 0) ? 474 : 473)) % 2820) + 474) + 38) * 682) % 2816) < 682 ? 30 : 29));
254         }
255         elseif ($date_system == 2)
256         {
257                 $days_in_month = array(30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, (((((11 * $year) + 14) % 30) < 11) ? 30 : 29));
258         }
259         else // gregorian date
260                 $days_in_month = array(31, ((!($year % 4 ) && (($year % 100) || !($year % 400)))?29:28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
261
262         return $days_in_month[$month - 1];
263 }
264
265 function end_month($date)
266 {
267         global $date_system;
268
269     list($day, $month, $year) = explode_date_to_dmy($date);
270         if ($date_system == 1)
271         {
272                 list($year, $month, $day) = gregorian_to_jalali($year, $month, $day);
273         }
274         elseif ($date_system == 2)
275         {
276                 list($year, $month, $day) = gregorian_to_islamic($year, $month, $day);
277         }
278
279         return __date($year, $month, days_in_month($month, $year));
280 }
281
282 function add_days($date, $days) // accepts negative values as well
283 {
284         global $date_system;
285     list($day, $month, $year) = explode_date_to_dmy($date);
286         $timet = mktime(0,0,0, $month, $day + $days, $year);
287     if ($date_system == 1 || $date_system == 2)
288     {
289         if ($date_system == 1)
290                 list($year, $month, $day) = gregorian_to_jalali(date("Y", $timet), date("n", $timet), date("j", $timet));
291         elseif ($date_system == 2)      
292                 list($year, $month, $day) = gregorian_to_islamic(date("Y", $timet), date("n", $timet), date("j", $timet));
293         return __date($year, $month, $day);
294     }
295     return date(user_date_display(), $timet);
296 }
297
298 function add_months($date, $months) // accepts negative values as well
299 {
300         global $date_system;
301     list($day, $month, $year) = explode_date_to_dmy($date);
302
303         $months += $year*12+$month;
304         $month = ($months-1)%12+1;
305         $year = ($months-$month)/12;
306
307         $timet = mktime(0,0,0, $month, min($day, days_in_month($month, $year)), $year);
308
309     if ($date_system == 1 || $date_system == 2)
310     {
311         if ($date_system == 1)
312                 list($year, $month, $day) = gregorian_to_jalali(date("Y", $timet), date("n", $timet), date("j", $timet));
313         elseif ($date_system == 2)      
314                 list($year, $month, $day) = gregorian_to_islamic(date("Y", $timet), date("n", $timet), date("j", $timet));
315         return __date($year, $month, $day);
316     }
317     return date(user_date_display(), $timet);
318 }
319
320 function add_years($date, $years) // accepts negative values as well
321 {
322         global $date_system;
323     list($day, $month, $year) = explode_date_to_dmy($date);
324         $timet = Mktime(0,0,0, $month, $day, $year + $years);
325     if ($date_system == 1 || $date_system == 2)
326     {
327         if ($date_system == 1)
328                 list($year, $month, $day) = gregorian_to_jalali(date("Y", $timet), date("n", $timet), date("j", $timet));
329         elseif ($date_system == 2)      
330                 list($year, $month, $day) = gregorian_to_islamic(date("Y", $timet), date("n", $timet), date("j", $timet));
331         return __date($year, $month, $day);
332     }
333     return date(user_date_display(), $timet);
334 }
335
336 //_______________________________________________________________
337
338 function sql2date($date_) 
339 {
340         global $date_system;
341
342         //for MySQL dates are in the format YYYY-mm-dd
343         if ($date_ == null || strlen($date_) == 0)
344                 return "";
345
346         if (strpos($date_, "/")) 
347         { // In MySQL it could be either / or -
348                 list($year, $month, $day) = explode("/", $date_);
349         } 
350         elseif (strpos ($date_, "-")) 
351         {
352                 list($year, $month, $day) = explode("-", $date_);
353         }
354
355         if (strlen($day) > 4) 
356         {  /*chop off the time stuff */
357                 $day = substr($day, 0, 2);
358         }
359         if ($date_system == 1)
360                 list($year, $month, $day) = gregorian_to_jalali($year, $month, $day);
361         elseif ($date_system == 2)
362                 list($year, $month, $day) = gregorian_to_islamic($year, $month, $day);
363         return __date($year, $month, $day);     
364 } // end function sql2date
365
366
367 function date2sql($date_)
368 {
369         global $dateseps, $date_system, $tmonths;
370 /* takes a date in a the format specified in $DefaultDateFormat
371 and converts to a yyyy/mm/dd format */
372
373         $how = user_date_format();
374         $sep = $dateseps[user_date_sep()];
375
376         if ($date_ == null || strlen($date_) == 0)
377                 return "";
378
379         $date_ = trim($date_);
380     $year = $month = $day = 0;
381     // Split up the date by the separator based on "how" to split it
382     if ($how == 0 || $how == 3) // MMDDYYYY or MmmDDYYYY
383         list($month, $day, $year) = explode($sep, $date_);
384     elseif ($how == 1 || $how == 4) // DDMMYYYY or DDMmYYYY
385         list($day, $month, $year) = explode($sep, $date_);
386     else // $how == 2 || $how == 5, YYYYMMDD or YYYYMmmDD
387         list($year, $month, $day) = explode($sep, $date_);
388         if ($how > 2)
389         {
390                 global $tmonths;
391                 $month = array_search($month, $tmonths);
392         }       
393 //to modify assumption in 2030
394         if ($date_system == 0 || $date_system == 3)
395         {
396                 if ((int)$year < 60)
397                 {
398                         $year = "20".$year;
399                 } 
400                 elseif ((int)$year > 59 && (int)$year < 100)
401                 {
402                         $year = "19".$year;
403                 }
404         }       
405         if ((int)$year > 9999)
406         {
407                 return 0;
408         }
409         if ($date_system == 1)
410                 list($year, $month, $day) = jalali_to_gregorian($year, $month, $day); 
411         elseif ($date_system == 2)
412                 list($year, $month, $day) = islamic_to_gregorian($year, $month, $day); 
413
414         return sprintf("%04d-%02d-%02d", $year, $month, $day);
415 }// end of function
416
417 function date1_greater_date2 ($date1, $date2) 
418 {
419
420 /* returns 1 true if date1 is greater than date_ 2 */
421
422         $date1 = date2sql($date1);
423         $date2 = date2sql($date2);
424
425         @list($year1, $month1, $day1) = explode("-", $date1);
426         @list($year2, $month2, $day2) = explode("-", $date2);
427
428         if ($year1 > $year2)
429         {
430                 return 1;
431         }
432         elseif ($year1 == $year2)
433         {
434                 if ($month1 > $month2)
435                 {
436                         return 1;
437                 }
438                 elseif ($month1 == $month2)
439                 {
440                         if ($day1 > $day2)
441                         {
442                                 return 1;
443                         }
444                 }
445         }
446         return 0;
447 }
448
449
450 function date_diff2 ($date1, $date2, $period) 
451 {
452
453 /* expects dates in the format specified in $DefaultDateFormat - period can be one of 'd','w','y','m'
454 months are assumed to be 30 days and years 365.25 days This only works
455 provided that both dates are after 1970. Also only works for dates up to the year 2035 ish */
456
457         $date1 = date2sql($date1);
458         $date2 = date2sql($date2);
459         list($year1, $month1, $day1) = explode("-", $date1);
460         list($year2, $month2, $day2) = explode("-", $date2);
461
462         $stamp1 = mktime(0,0,0, (int)$month1, (int)$day1, (int)$year1);
463         $stamp2 = mktime(0,0,0, (int)$month2, (int)$day2, (int)$year2);
464         $difference = $stamp1 - $stamp2;
465
466 /* difference is the number of seconds between each date negative if date_ 2 > date_ 1 */
467
468         switch ($period) 
469         {
470                 case "d":
471                         return (int)($difference / (24 * 60 * 60));
472                 case "w":
473                         return (int)($difference / (24 * 60 * 60 * 7));
474                 case "m":
475                         return (int)($difference / (24 * 60 * 60 * 30));
476                 case "s":
477                         return $difference;
478                 case "y":
479                         return (int)($difference / (24 * 60 * 60 * 365.25));
480                 default:
481                         Return 0;
482         }
483 }
484
485 function explode_date_to_dmy($date_)
486 {
487         $date = date2sql($date_);
488         if ($date == "") 
489         {
490                 return array(0,0,0);
491         }
492         list($year, $month, $day) = explode("-", $date);
493         return array($day, $month, $year);
494 }
495
496 function div($a, $b) 
497 {
498     return (int) ($a / $b);
499 }
500 /* Based on convertor to and from Gregorian and Jalali calendars.
501    Copyright (C) 2000  Roozbeh Pournader and Mohammad Toossi 
502    Released under GNU General Public License */
503
504 function gregorian_to_jalali ($g_y, $g_m, $g_d)
505 {
506     $g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
507     $j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
508
509         $gy = $g_y - 1600;
510         $gm = $g_m - 1;
511         $gd = $g_d - 1;
512
513         $g_day_no = 365 * $gy + div($gy + 3, 4) - div($gy + 99, 100) + div($gy + 399, 400);
514
515         for ($i = 0; $i < $gm; ++$i)
516         $g_day_no += $g_days_in_month[$i];
517         if ($gm > 1 && (($gy % 4 == 0 && $gy % 100 != 0) || ($gy % 400 == 0)))
518         /* leap and after Feb */
519         $g_day_no++;
520         $g_day_no += $gd;
521         $j_day_no = $g_day_no - 79;
522
523         $j_np = div($j_day_no, 12053); /* 12053 = 365*33 + 32/4 */
524         $j_day_no %= 12053;
525
526         $jy = 979 + 33 * $j_np + 4 * div($j_day_no, 1461); /* 1461 = 365*4 + 4/4 */
527
528         $j_day_no %= 1461;
529
530         if ($j_day_no >= 366) 
531         {
532         $jy += div($j_day_no - 1, 365);
533         $j_day_no = ($j_day_no - 1) % 365;
534         }
535
536         for ($i = 0; $i < 11 && $j_day_no >= $j_days_in_month[$i]; ++$i)
537         $j_day_no -= $j_days_in_month[$i];
538         $jm = $i + 1;
539         $jd = $j_day_no + 1;
540
541         return array($jy, $jm, $jd);
542 }
543
544 function jalali_to_gregorian($j_y, $j_m, $j_d)
545 {
546     $g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
547     $j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
548
549         $jy = $j_y - 979;
550         $jm = $j_m - 1;
551         $jd = $j_d - 1;
552
553         $j_day_no = 365 * $jy + div($jy, 33) * 8 + div($jy % 33 + 3, 4);
554         for ($i = 0; $i < $jm; ++$i)
555         $j_day_no += $j_days_in_month[$i];
556
557         $j_day_no += $jd;
558
559         $g_day_no = $j_day_no + 79;
560
561         $gy = 1600 + 400 * div($g_day_no, 146097); /* 146097 = 365*400 + 400/4 - 400/100 + 400/400 */
562         $g_day_no %= 146097;
563
564         $leap = true;
565         if ($g_day_no >= 36525) /* 36525 = 365*100 + 100/4 */
566         {
567         $g_day_no--;
568         $gy += 100 * div($g_day_no,  36524); /* 36524 = 365*100 + 100/4 - 100/100 */
569         $g_day_no %= 36524;
570
571         if ($g_day_no >= 365)
572                 $g_day_no++;
573         else
574                 $leap = false;
575         }
576
577         $gy += 4 * div($g_day_no, 1461); /* 1461 = 365*4 + 4/4 */
578         $g_day_no %= 1461;
579
580         if ($g_day_no >= 366) 
581         {
582         $leap = false;
583
584         $g_day_no--;
585         $gy += div($g_day_no, 365);
586         $g_day_no %= 365;
587         }
588
589         for ($i = 0; $g_day_no >= $g_days_in_month[$i] + ($i == 1 && $leap); $i++)
590         $g_day_no -= $g_days_in_month[$i] + ($i == 1 && $leap);
591         $gm = $i + 1;
592         $gd = $g_day_no + 1;
593
594         return array($gy, $gm, $gd);
595 }
596 /* Based on Hidri Date Script 
597    Released under GNU General Public License */
598 function gregorian_to_islamic($g_y, $g_m, $g_d)
599 {
600         $y = $g_y;   
601         $m = $g_m;
602         $d = $g_d;
603         if (($y > 1582) || (($y == 1582) && ($m > 10)) || (($y == 1582) && 
604                 ($m == 10) && ($d > 14))) 
605         {
606                 $jd = (int)((1461 * ($y + 4800 + (int)(($m - 14) / 12)))/ 4) + 
607                         (int)((367 * ($m - 2 - 12 * ((int)(($m - 14) / 12)))) / 12) - 
608                         (int)((3 * ((int)(($y + 4900 + (int)(($m - 14) / 12)) / 100))) / 4) + $d - 32075;
609         } 
610         else 
611         {
612                 $jd = 367 * $y - (int)((7 * ($y + 5001 + (int)(($m - 9) / 7))) / 4) + 
613                         (int)((275 * $m) / 9) + $d + 1729777;
614         }
615         $l = $jd - 1948440 + 10632;
616         $n = (int)(($l - 1) / 10631);
617         $l = $l - 10631 * $n + 354;
618         $j = ((int)((10985 - $l) / 5316)) * ((int)((50 * $l) / 17719)) + 
619                 ((int)($l / 5670)) * ((int)((43 * $l) / 15238));
620         $l = $l - ((int)((30 - $j) / 15)) * ((int)((17719 * $j) / 50)) - 
621                 ((int)($j / 16)) * ((int)((15238 * $j) / 43)) + 29;
622         $m = (int)((24 * $l) / 709);
623         $d = $l - (int)((709 * $m) / 24);
624         $y = 30 * $n + $j - 30;
625         return array($y, $m, $d);
626 }
627
628 function islamic_to_gregorian($i_y, $i_m, $i_d)
629 {
630         $y = $i_y;   
631         $m = $i_m;
632         $d = $i_d;
633
634         $jd = (int)((11 * $y + 3) / 30) + 354 * $y + 30 * $m - (int)(($m - 1) / 2) + $d + 1948440 - 385;
635         if ($jd > 2299160)
636         {
637                 $l = $jd + 68569;
638                 $n = (int)((4 * $l) / 146097);
639                 $l = $l - (int)((146097 * $n + 3) / 4);
640                 $i = (int)((4000 * ($l + 1)) / 1461001);
641                 $l = $l - (int)((1461 * $i) / 4) + 31;
642                 $j = (int)((80 * $l) / 2447);
643                 $d = $l - (int)((2447 * $j) / 80);
644                 $l= (int)($j / 11);
645                 $m = $j + 2 - 12 * $l;
646                 $y = 100 * ($n - 49) + $i + $l;
647         } 
648         else 
649         {
650                 $j = $jd + 1402;
651                 $k = (int)(($j - 1) / 1461);
652                 $l = $j - 1461 * $k;
653                 $n = (int)(($l - 1) / 365) - (int)($l / 1461);
654                 $i = $l - 365 * $n + 30;
655                 $j = (int)((80 * $i) / 2447);
656                 $d = $i - (int)((2447 * $j) / 80);
657                 $i = (int)($j / 11);
658                 $m = $j + 2 - 12 * $i;
659                 $y = 4 * $k + $n + $i - 4716;
660         }
661         return array($y, $m, $d);
662 }
663 ?>