Various code cleanups
[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         return sprintf("%04d-%02d-%02d", $year, $month, $day);
355 }// end of function
356
357 function date1_greater_date2 ($date1, $date2) 
358 {
359
360 /* returns 1 true if date1 is greater than date_ 2 */
361
362         $date1 = date2sql($date1);
363         $date2 = date2sql($date2);
364
365         @list($year1, $month1, $day1) = explode("-", $date1);
366         @list($year2, $month2, $day2) = explode("-", $date2);
367
368         if ($year1 > $year2)
369         {
370                 return 1;
371         }
372         elseif ($year1 == $year2)
373         {
374                 if ($month1 > $month2)
375                 {
376                         return 1;
377                 }
378                 elseif ($month1 == $month2)
379                 {
380                         if ($day1 > $day2)
381                         {
382                                 return 1;
383                         }
384                 }
385         }
386         return 0;
387 }
388
389
390 function date_diff2 ($date1, $date2, $period) 
391 {
392
393 /* expects dates in the format specified in $DefaultDateFormat - period can be one of 'd','w','y','m'
394 months are assumed to be 30 days and years 365.25 days This only works
395 provided that both dates are after 1970. Also only works for dates up to the year 2035 ish */
396
397         $date1 = date2sql($date1);
398         $date2 = date2sql($date2);
399         list($year1, $month1, $day1) = explode("-", $date1);
400         list($year2, $month2, $day2) = explode("-", $date2);
401
402         $stamp1 = mktime(0,0,0, (int)$month1, (int)$day1, (int)$year1);
403         $stamp2 = mktime(0,0,0, (int)$month2, (int)$day2, (int)$year2);
404         $difference = $stamp1 - $stamp2;
405
406 /* difference is the number of seconds between each date negative if date_ 2 > date_ 1 */
407
408         switch ($period) 
409         {
410                 case "d":
411                         return (int)($difference / (24 * 60 * 60));
412                 case "w":
413                         return (int)($difference / (24 * 60 * 60 * 7));
414                 case "m":
415                         return (int)($difference / (24 * 60 * 60 * 30));
416                 case "s":
417                         return $difference;
418                 case "y":
419                         return (int)($difference / (24 * 60 * 60 * 365.25));
420                 default:
421                         Return 0;
422         }
423 }
424
425 function explode_date_to_dmy($date_)
426 {
427         $date = date2sql($date_);
428         if ($date == "") 
429         {
430                 return array(0,0,0);
431         }
432         list($year, $month, $day) = explode("-", $date);
433         return array($day, $month, $year);
434 }
435
436 function div($a, $b) 
437 {
438     return (int) ($a / $b);
439 }
440 /* Based on convertor to and from Gregorian and Jalali calendars.
441    Copyright (C) 2000  Roozbeh Pournader and Mohammad Toossi 
442    Released under GNU General Public License */
443
444 function gregorian_to_jalali ($g_y, $g_m, $g_d)
445 {
446     $g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
447     $j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
448
449         $gy = $g_y - 1600;
450         $gm = $g_m - 1;
451         $gd = $g_d - 1;
452
453         $g_day_no = 365 * $gy + div($gy + 3, 4) - div($gy + 99, 100) + div($gy + 399, 400);
454
455         for ($i = 0; $i < $gm; ++$i)
456         $g_day_no += $g_days_in_month[$i];
457         if ($gm > 1 && (($gy % 4 == 0 && $gy % 100 != 0) || ($gy % 400 == 0)))
458         /* leap and after Feb */
459         $g_day_no++;
460         $g_day_no += $gd;
461         $j_day_no = $g_day_no - 79;
462
463         $j_np = div($j_day_no, 12053); /* 12053 = 365*33 + 32/4 */
464         $j_day_no %= 12053;
465
466         $jy = 979 + 33 * $j_np + 4 * div($j_day_no, 1461); /* 1461 = 365*4 + 4/4 */
467
468         $j_day_no %= 1461;
469
470         if ($j_day_no >= 366) 
471         {
472         $jy += div($j_day_no - 1, 365);
473         $j_day_no = ($j_day_no - 1) % 365;
474         }
475
476         for ($i = 0; $i < 11 && $j_day_no >= $j_days_in_month[$i]; ++$i)
477         $j_day_no -= $j_days_in_month[$i];
478         $jm = $i + 1;
479         $jd = $j_day_no + 1;
480
481         return array($jy, $jm, $jd);
482 }
483
484 function jalali_to_gregorian($j_y, $j_m, $j_d)
485 {
486     $g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
487     $j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
488
489         $jy = $j_y - 979;
490         $jm = $j_m - 1;
491         $jd = $j_d - 1;
492
493         $j_day_no = 365 * $jy + div($jy, 33) * 8 + div($jy % 33 + 3, 4);
494         for ($i = 0; $i < $jm; ++$i)
495         $j_day_no += $j_days_in_month[$i];
496
497         $j_day_no += $jd;
498
499         $g_day_no = $j_day_no + 79;
500
501         $gy = 1600 + 400 * div($g_day_no, 146097); /* 146097 = 365*400 + 400/4 - 400/100 + 400/400 */
502         $g_day_no %= 146097;
503
504         $leap = true;
505         if ($g_day_no >= 36525) /* 36525 = 365*100 + 100/4 */
506         {
507         $g_day_no--;
508         $gy += 100 * div($g_day_no,  36524); /* 36524 = 365*100 + 100/4 - 100/100 */
509         $g_day_no %= 36524;
510
511         if ($g_day_no >= 365)
512                 $g_day_no++;
513         else
514                 $leap = false;
515         }
516
517         $gy += 4 * div($g_day_no, 1461); /* 1461 = 365*4 + 4/4 */
518         $g_day_no %= 1461;
519
520         if ($g_day_no >= 366) 
521         {
522         $leap = false;
523
524         $g_day_no--;
525         $gy += div($g_day_no, 365);
526         $g_day_no %= 365;
527         }
528
529         for ($i = 0; $g_day_no >= $g_days_in_month[$i] + ($i == 1 && $leap); $i++)
530         $g_day_no -= $g_days_in_month[$i] + ($i == 1 && $leap);
531         $gm = $i + 1;
532         $gd = $g_day_no + 1;
533
534         return array($gy, $gm, $gd);
535 }
536 /* Based on Hidri Date Script 
537    Released under GNU General Public License */
538 function gregorian_to_islamic($g_y, $g_m, $g_d)
539 {
540         $y = $g_y;   
541         $m = $g_m;
542         $d = $g_d;
543         if (($y > 1582) || (($y == 1582) && ($m > 10)) || (($y == 1582) && 
544                 ($m == 10) && ($d > 14))) 
545         {
546                 $jd = (int)((1461 * ($y + 4800 + (int)(($m - 14) / 12)))/ 4) + 
547                         (int)((367 * ($m - 2 - 12 * ((int)(($m - 14) / 12)))) / 12) - 
548                         (int)((3 * ((int)(($y + 4900 + (int)(($m - 14) / 12)) / 100))) / 4) + $d - 32075;
549         } 
550         else 
551         {
552                 $jd = 367 * $y - (int)((7 * ($y + 5001 + (int)(($m - 9) / 7))) / 4) + 
553                         (int)((275 * $m) / 9) + $d + 1729777;
554         }
555         $l = $jd - 1948440 + 10632;
556         $n = (int)(($l - 1) / 10631);
557         $l = $l - 10631 * $n + 354;
558         $j = ((int)((10985 - $l) / 5316)) * ((int)((50 * $l) / 17719)) + 
559                 ((int)($l / 5670)) * ((int)((43 * $l) / 15238));
560         $l = $l - ((int)((30 - $j) / 15)) * ((int)((17719 * $j) / 50)) - 
561                 ((int)($j / 16)) * ((int)((15238 * $j) / 43)) + 29;
562         $m = (int)((24 * $l) / 709);
563         $d = $l - (int)((709 * $m) / 24);
564         $y = 30 * $n + $j - 30;
565         return array($y, $m, $d);
566 }
567
568 function islamic_to_gregorian($i_y, $i_m, $i_d)
569 {
570         $y = $i_y;   
571         $m = $i_m;
572         $d = $i_d;
573
574         $jd = (int)((11 * $y + 3) / 30) + 354 * $y + 30 * $m - (int)(($m - 1) / 2) + $d + 1948440 - 385;
575         if ($jd > 2299160)
576         {
577                 $l = $jd + 68569;
578                 $n = (int)((4 * $l) / 146097);
579                 $l = $l - (int)((146097 * $n + 3) / 4);
580                 $i = (int)((4000 * ($l + 1)) / 1461001);
581                 $l = $l - (int)((1461 * $i) / 4) + 31;
582                 $j = (int)((80 * $l) / 2447);
583                 $d = $l - (int)((2447 * $j) / 80);
584                 $l= (int)($j / 11);
585                 $m = $j + 2 - 12 * $l;
586                 $y = 100 * ($n - 49) + $i + $l;
587         } 
588         else 
589         {
590                 $j = $jd + 1402;
591                 $k = (int)(($j - 1) / 1461);
592                 $l = $j - 1461 * $k;
593                 $n = (int)(($l - 1) / 365) - (int)($l / 1461);
594                 $i = $l - 365 * $n + 30;
595                 $j = (int)((80 * $i) / 2447);
596                 $d = $i - (int)((2447 * $j) / 80);
597                 $i = (int)($j / 11);
598                 $m = $j + 2 - 12 * $i;
599                 $y = 4 * $k + $n + $i - 4716;
600         }
601         return array($y, $m, $d);
602 }
603 ?>