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