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