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