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