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