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