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