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