Merged changes from stable branch up to 2.3.23.
[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 $SysPrefs, $tmonths;
25         
26         $how = user_date_format();
27         $sep = $SysPrefs->dateseps[user_date_sep()];
28         $day = (int)$day;
29         $month = (int)$month;
30         if ($how < 3)
31         {
32                 if ($day < 10)
33                         $day = "0".$day;
34                 if ($month < 10)
35                         $month = "0".$month;
36         }               
37         if ($how == 0)
38                 return $month.$sep.$day.$sep.$year;
39         elseif ($how == 1)
40                 return $day.$sep.$month.$sep.$year;
41         elseif ($how == 2)
42                 return $year.$sep.$month.$sep.$day;
43         elseif ($how == 3)
44                 return $tmonths[$month].$sep.$day.$sep.$year;
45         elseif ($how == 4)
46                 return $day.$sep.$tmonths[$month].$sep.$year;
47         else
48                 return $year.$sep.$tmonths[$month].$sep.$day;
49 }
50
51 function is_date($date_) 
52 {
53         global $SysPrefs;
54
55         if ($date_ == null || $date_ == "")
56                 return 0;
57         $how = user_date_format();
58         $sep = $SysPrefs->dateseps[user_date_sep()];
59
60         $date_ = trim($date_);
61         $date = str_replace($sep, "", $date_);
62         
63         if ($how > 2)
64         {
65                 global $tmonths;
66                 $dd = explode($sep, $date_);
67                 if ($how == 3)
68                 {
69                         $day = $dd[1];
70                         $month = array_search($dd[0], $tmonths);
71                         $year = $dd[2];
72                 } 
73                 elseif ($how == 4)
74                 {
75                         $day = $dd[0];
76                         $month = array_search($dd[1], $tmonths);
77                         $year = $dd[2];
78                 } 
79                 else
80                 {
81                         $day = $dd[2];
82                         $month = array_search($dd[1], $tmonths);
83                         $year = $dd[0];
84                 }
85                 if ($year < 1000)
86                         return 0;
87         }
88         elseif (strlen($date) == 6)
89         {
90                 if ($how == 0)
91                 {
92                         $day = substr($date,2,2);
93                         $month = substr($date,0,2);
94                         $year = substr($date,4,2);
95                 } 
96                 elseif ($how == 1)
97                 {
98                         $day = substr($date,0,2);
99                         $month = substr($date,2,2);
100                         $year = substr($date,4,2);
101                 } 
102                 else
103                 {
104                         $day = substr($date,4,2);
105                         $month = substr($date,2,2);
106                         $year = substr($date,0,2);
107                 }
108         }
109         elseif (strlen($date) == 8)
110         {
111                 if ($how == 0)
112                 {
113                         $day = substr($date,2,2);
114                         $month = substr($date,0,2);
115                         $year = substr($date,4,4);
116                 } 
117                 elseif ($how == 1)
118                 {
119                         $day = substr($date,0,2);
120                         $month = substr($date,2,2);
121                         $year = substr($date,4,4);
122                 } 
123                 else
124                 {
125                         $day = substr($date,6,2);
126                         $month = substr($date,4,2);
127                         $year = substr($date,0,4);
128                 }
129         }
130         if (!isset($year)|| (int)$year > 9999) 
131         {
132                 return 0;
133         }
134
135         if (is_long((int)$day) && is_long((int)$month) && is_long((int)$year))
136         {
137                 global $SysPrefs;
138                 if ($SysPrefs->date_system == 1)
139                         list($year, $month, $day) = jalali_to_gregorian($year, $month, $day);  
140                 elseif ($SysPrefs->date_system == 2)    
141                         list($year, $month, $day) = islamic_to_gregorian($year, $month, $day);  
142                 if (checkdate((int)$month, (int)$day, (int)$year))
143                 {
144                         return 1;
145                 }
146                 else
147                 {
148                         return 0;
149                 }
150         }
151         else
152         { /*Can't be in an appropriate DefaultDateFormat */
153                 return 0;
154         }
155 } //end of is_date function
156
157 function Today() 
158 {
159         global $SysPrefs;
160
161         $year = date("Y");
162         $month = date("n");
163         $day = date("j");
164         if ($SysPrefs->date_system == 1)
165                 list($year, $month, $day) = gregorian_to_jalali($year, $month, $day);
166         elseif ($SysPrefs->date_system == 2)    
167                 list($year, $month, $day) = gregorian_to_islamic($year, $month, $day);
168         return __date($year, $month, $day);     
169 }
170
171 function Now() 
172 {
173         if (user_date_format() == 0)
174                 return date("h:i a");
175         else
176                 return date("H:i");
177 }
178 //
179 //      Retrieve and optionaly set default date for new document.
180 //
181 function new_doc_date($date=null)
182 {
183         if (isset($date) && $date != '')
184                 $_SESSION['_default_date'] = $date;
185
186         if (!isset($_SESSION['_default_date']) || !sticky_doc_date())
187                 $_SESSION['_default_date'] = Today();
188
189         return $_SESSION['_default_date'];
190 }
191
192 function is_date_in_fiscalyear($date, $convert=false)
193 {
194         global $path_to_root;
195         include_once($path_to_root . "/admin/db/fiscalyears_db.inc");
196
197         if ($convert)
198                 $date2 = sql2date($date);
199         else
200                 $date2 = $date;
201
202         if (user_check_access('SA_MULTIFISCALYEARS')) // allow all open years for this one
203                 return is_date_in_fiscalyears($date2, false);
204
205         if (is_date_closed($date2))
206                 return 0;
207         $myrow = get_current_fiscalyear();
208         $begin = sql2date($myrow['begin']);
209         $end = sql2date($myrow['end']);
210         if (date1_greater_date2($begin, $date2) || date1_greater_date2($date2, $end))
211         {
212                 return 0;
213         }
214         return 1;
215 }
216
217 function is_date_closed($date)
218 {
219         return !date1_greater_date2($date, sql2date(get_company_pref('gl_closing_date')));
220 }
221
222 function begin_fiscalyear()
223 {
224         global $path_to_root;
225         include_once($path_to_root . "/admin/db/fiscalyears_db.inc");
226
227         $myrow = get_current_fiscalyear();
228         return sql2date($myrow['begin']);
229 }
230
231 function end_fiscalyear()
232 {
233         global $path_to_root;
234         include_once($path_to_root . "/admin/db/fiscalyears_db.inc");
235
236         $myrow = get_current_fiscalyear();
237         return sql2date($myrow['end']);
238 }
239
240 function begin_month($date)
241 {
242         global $SysPrefs;
243     list($day, $month, $year) = explode_date_to_dmy($date);
244     if ($SysPrefs->date_system == 1)
245         list($year, $month, $day) = gregorian_to_jalali($year, $month, $day);
246     elseif ($SysPrefs->date_system == 2)        
247         list($year, $month, $day) = gregorian_to_islamic($year, $month, $day);
248         return __date($year, $month, 1);
249 }
250
251 function days_in_month($month, $year)
252 {
253         global $SysPrefs;
254
255         if ($SysPrefs->date_system == 1)
256         {
257                 $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));
258         }
259         elseif ($SysPrefs->date_system == 2)
260         {
261                 $days_in_month = array(30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, (((((11 * $year) + 14) % 30) < 11) ? 30 : 29));
262         }
263         else // gregorian date
264                 $days_in_month = array(31, ((!($year % 4 ) && (($year % 100) || !($year % 400)))?29:28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
265
266         return $days_in_month[$month - 1];
267 }
268
269 function end_month($date)
270 {
271         global $SysPrefs;
272
273     list($day, $month, $year) = explode_date_to_dmy($date);
274         if ($SysPrefs->date_system == 1)
275         {
276                 list($year, $month, $day) = gregorian_to_jalali($year, $month, $day);
277         }
278         elseif ($SysPrefs->date_system == 2)
279         {
280                 list($year, $month, $day) = gregorian_to_islamic($year, $month, $day);
281         }
282
283         return __date($year, $month, days_in_month($month, $year));
284 }
285
286 function add_days($date, $days) // accepts negative values as well
287 {
288         global $SysPrefs;
289     list($day, $month, $year) = explode_date_to_dmy($date);
290         $timet = mktime(0,0,0, $month, $day + $days, $year);
291     if ($SysPrefs->date_system == 1 || $SysPrefs->date_system == 2)
292     {
293         if ($SysPrefs->date_system == 1)
294                 list($year, $month, $day) = gregorian_to_jalali(date("Y", $timet), date("n", $timet), date("j", $timet));
295         elseif ($SysPrefs->date_system == 2)    
296                 list($year, $month, $day) = gregorian_to_islamic(date("Y", $timet), date("n", $timet), date("j", $timet));
297         return __date($year, $month, $day);
298     }
299     list($year, $month, $day) = explode("-", date("Y-m-d", $timet));
300         return __date($year, $month, $day);
301 }
302
303 function add_months($date, $months) // accepts negative values as well
304 {
305         global $SysPrefs;
306
307     list($day, $month, $year) = explode_date_to_dmy($date);
308
309         $months += $year*12+$month;
310         $month = ($months-1)%12+1;
311         $year = ($months-$month)/12;
312
313         $timet = mktime(0,0,0, $month, min($day, days_in_month($month, $year)), $year);
314
315     if ($SysPrefs->date_system == 1 || $SysPrefs->date_system == 2)
316     {
317         if ($SysPrefs->date_system == 1)
318                 list($year, $month, $day) = gregorian_to_jalali(date("Y", $timet), date("n", $timet), date("j", $timet));
319         elseif ($SysPrefs->date_system == 2)    
320                 list($year, $month, $day) = gregorian_to_islamic(date("Y", $timet), date("n", $timet), date("j", $timet));
321         return __date($year, $month, $day);
322     }
323     list($year, $month, $day) = explode("-", date("Y-m-d", $timet));
324         return __date($year, $month, $day);
325 }
326
327 function add_years($date, $years) // accepts negative values as well
328 {
329         global $SysPrefs;
330
331     list($day, $month, $year) = explode_date_to_dmy($date);
332         $timet = Mktime(0,0,0, $month, $day, $year + $years);
333     if ($SysPrefs->date_system == 1 || $SysPrefs->date_system == 2)
334     {
335         if ($SysPrefs->date_system == 1)
336                 list($year, $month, $day) = gregorian_to_jalali(date("Y", $timet), date("n", $timet), date("j", $timet));
337         elseif ($SysPrefs->date_system == 2)    
338                 list($year, $month, $day) = gregorian_to_islamic(date("Y", $timet), date("n", $timet), date("j", $timet));
339         return __date($year, $month, $day);
340     }
341     list($year, $month, $day) = explode("-", date("Y-m-d", $timet));
342         return __date($year, $month, $day);
343 }
344
345 //_______________________________________________________________
346
347 function sql2date($date_) 
348 {
349         global $SysPrefs;
350
351         //for MySQL dates are in the format YYYY-mm-dd
352
353         if (strpos($date_, "/")) 
354         { // In MySQL it could be either / or -
355                 list($year, $month, $day) = explode("/", $date_);
356         } 
357         elseif (strpos ($date_, "-")) 
358         {
359                 list($year, $month, $day) = explode("-", $date_);
360         }
361         if (!isset($day)) // data format error
362                 return "";
363
364         if (strlen($day) > 4) 
365         {  /*chop off the time stuff */
366                 $day = substr($day, 0, 2);
367         }
368         if ($SysPrefs->date_system == 1)
369                 list($year, $month, $day) = gregorian_to_jalali($year, $month, $day);
370         elseif ($SysPrefs->date_system == 2)
371                 list($year, $month, $day) = gregorian_to_islamic($year, $month, $day);
372         return __date($year, $month, $day);     
373 } // end function sql2date
374
375
376 function date2sql($date_)
377 {
378         global $SysPrefs, $tmonths;
379 /* takes a date in a the format specified in $DefaultDateFormat
380 and converts to a yyyy/mm/dd format */
381
382         $how = user_date_format();
383         $sep = $SysPrefs->dateseps[user_date_sep()];
384
385         if ($date_ == null || strlen($date_) == 0)
386                 return "";
387
388         $date_ = trim($date_);
389     $year = $month = $day = 0;
390     // Split up the date by the separator based on "how" to split it
391     if ($how == 0 || $how == 3) // MMDDYYYY or MmmDDYYYY
392         list($month, $day, $year) = explode($sep, $date_);
393     elseif ($how == 1 || $how == 4) // DDMMYYYY or DDMmYYYY
394         list($day, $month, $year) = explode($sep, $date_);
395     else // $how == 2 || $how == 5, YYYYMMDD or YYYYMmmDD
396         list($year, $month, $day) = explode($sep, $date_);
397         if ($how > 2)
398         {
399                 global $tmonths;
400                 $month = array_search($month, $tmonths);
401         }       
402 //to modify assumption in 2030
403         if ($SysPrefs->date_system == 0 || $SysPrefs->date_system == 3)
404         {
405                 if ((int)$year < 60)
406                 {
407                         $year = "20".$year;
408                 } 
409                 elseif ((int)$year > 59 && (int)$year < 100)
410                 {
411                         $year = "19".$year;
412                 }
413         }       
414         if ((int)$year > 9999)
415         {
416                 return 0;
417         }
418         if ($SysPrefs->date_system == 1)
419                 list($year, $month, $day) = jalali_to_gregorian($year, $month, $day); 
420         elseif ($SysPrefs->date_system == 2)
421                 list($year, $month, $day) = islamic_to_gregorian($year, $month, $day); 
422
423         return sprintf("%04d-%02d-%02d", $year, $month, $day);
424 }// end of function
425
426 /**
427  *      Compare dates in sql format.
428  *      Return +1 if sql date1>date2, -1 if date1<date2,
429  *  or 0 if dates are equal.
430  */
431 function sql_date_comp($date1, $date2)
432 {
433         @list($year1, $month1, $day1) = explode("-", $date1);
434         @list($year2, $month2, $day2) = explode("-", $date2);
435
436         if ($year1 != $year2) {
437                 return $year1 < $year2 ? -1 : +1;
438     }
439     elseif ($month1 != $month2) {
440                 return $month1 < $month2 ? -1 : +1;
441         }
442         elseif ($day1 != $day2) {
443                 return $day1 < $day2 ? -1 : +1;
444         }
445         return 0;
446 }
447 /*
448         Compare dates in user format.
449 */
450 function date_comp($date1, $date2)
451 {
452         $date1 = date2sql($date1);
453         $date2 = date2sql($date2);
454
455         return sql_date_comp($date1, $date2);
456 }
457
458 function date1_greater_date2 ($date1, $date2) 
459 {
460
461 /* returns 1 true if date1 is greater than date_ 2 */
462
463         $date1 = date2sql($date1);
464         $date2 = date2sql($date2);
465
466         @list($year1, $month1, $day1) = explode("-", $date1);
467         @list($year2, $month2, $day2) = explode("-", $date2);
468
469         if ($year1 > $year2)
470         {
471                 return 1;
472         }
473         elseif ($year1 == $year2)
474         {
475                 if ($month1 > $month2)
476                 {
477                         return 1;
478                 }
479                 elseif ($month1 == $month2)
480                 {
481                         if ($day1 > $day2)
482                         {
483                                 return 1;
484                         }
485                 }
486         }
487         return 0;
488 }
489
490 function date_diff2 ($date1, $date2, $period) 
491 {
492
493 /* expects dates in the format specified in $DefaultDateFormat - period can be one of 'd','w','y','m'
494 months are assumed to be 30 days and years 365.25 days This only works
495 provided that both dates are after 1970. Also only works for dates up to the year 2035 ish */
496
497         $date1 = date2sql($date1);
498         $date2 = date2sql($date2);
499         list($year1, $month1, $day1) = explode("-", $date1);
500         list($year2, $month2, $day2) = explode("-", $date2);
501
502         $stamp1 = mktime(0,0,0, (int)$month1, (int)$day1, (int)$year1);
503         $stamp2 = mktime(0,0,0, (int)$month2, (int)$day2, (int)$year2);
504         $difference = $stamp1 - $stamp2;
505
506 /* difference is the number of seconds between each date negative if date_ 2 > date_ 1 */
507
508         switch ($period) 
509         {
510                 case "d":
511                         return (int)($difference / (24 * 60 * 60));
512                 case "w":
513                         return (int)($difference / (24 * 60 * 60 * 7));
514                 case "m":
515                         return (int)($difference / (24 * 60 * 60 * 30));
516                 case "s":
517                         return $difference;
518                 case "y":
519                         return (int)($difference / (24 * 60 * 60 * 365.25));
520                 default:
521                         Return 0;
522         }
523 }
524
525 function explode_date_to_dmy($date_)
526 {
527         $date = date2sql($date_);
528         if ($date == "") 
529         {
530                 return array(0,0,0);
531         }
532         list($year, $month, $day) = explode("-", $date);
533         return array($day, $month, $year);
534 }
535
536 function div($a, $b) 
537 {
538     return (int) ($a / $b);
539 }
540 /* Based on convertor to and from Gregorian and Jalali calendars.
541    Copyright (C) 2000  Roozbeh Pournader and Mohammad Toossi 
542    Released under GNU General Public License */
543
544 function gregorian_to_jalali ($g_y, $g_m, $g_d)
545 {
546     $g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
547     $j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
548
549         $gy = $g_y - 1600;
550         $gm = $g_m - 1;
551         $gd = $g_d - 1;
552
553         $g_day_no = 365 * $gy + div($gy + 3, 4) - div($gy + 99, 100) + div($gy + 399, 400);
554
555         for ($i = 0; $i < $gm; ++$i)
556         $g_day_no += $g_days_in_month[$i];
557         if ($gm > 1 && (($gy % 4 == 0 && $gy % 100 != 0) || ($gy % 400 == 0)))
558         /* leap and after Feb */
559         $g_day_no++;
560         $g_day_no += $gd;
561         $j_day_no = $g_day_no - 79;
562
563         $j_np = div($j_day_no, 12053); /* 12053 = 365*33 + 32/4 */
564         $j_day_no %= 12053;
565
566         $jy = 979 + 33 * $j_np + 4 * div($j_day_no, 1461); /* 1461 = 365*4 + 4/4 */
567
568         $j_day_no %= 1461;
569
570         if ($j_day_no >= 366) 
571         {
572         $jy += div($j_day_no - 1, 365);
573         $j_day_no = ($j_day_no - 1) % 365;
574         }
575
576         for ($i = 0; $i < 11 && $j_day_no >= $j_days_in_month[$i]; ++$i)
577         $j_day_no -= $j_days_in_month[$i];
578         $jm = $i + 1;
579         $jd = $j_day_no + 1;
580
581         return array($jy, $jm, $jd);
582 }
583
584 function jalali_to_gregorian($j_y, $j_m, $j_d)
585 {
586     $g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
587     $j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
588
589         $jy = $j_y - 979;
590         $jm = $j_m - 1;
591         $jd = $j_d - 1;
592
593         $j_day_no = 365 * $jy + div($jy, 33) * 8 + div($jy % 33 + 3, 4);
594         for ($i = 0; $i < $jm; ++$i)
595         $j_day_no += $j_days_in_month[$i];
596
597         $j_day_no += $jd;
598
599         $g_day_no = $j_day_no + 79;
600
601         $gy = 1600 + 400 * div($g_day_no, 146097); /* 146097 = 365*400 + 400/4 - 400/100 + 400/400 */
602         $g_day_no %= 146097;
603
604         $leap = true;
605         if ($g_day_no >= 36525) /* 36525 = 365*100 + 100/4 */
606         {
607         $g_day_no--;
608         $gy += 100 * div($g_day_no,  36524); /* 36524 = 365*100 + 100/4 - 100/100 */
609         $g_day_no %= 36524;
610
611         if ($g_day_no >= 365)
612                 $g_day_no++;
613         else
614                 $leap = false;
615         }
616
617         $gy += 4 * div($g_day_no, 1461); /* 1461 = 365*4 + 4/4 */
618         $g_day_no %= 1461;
619
620         if ($g_day_no >= 366) 
621         {
622         $leap = false;
623
624         $g_day_no--;
625         $gy += div($g_day_no, 365);
626         $g_day_no %= 365;
627         }
628
629         for ($i = 0; $g_day_no >= $g_days_in_month[$i] + ($i == 1 && $leap); $i++)
630         $g_day_no -= $g_days_in_month[$i] + ($i == 1 && $leap);
631         $gm = $i + 1;
632         $gd = $g_day_no + 1;
633
634         return array($gy, $gm, $gd);
635 }
636 /* Based on Hidri Date Script 
637    Released under GNU General Public License */
638 function gregorian_to_islamic($g_y, $g_m, $g_d)
639 {
640         $y = $g_y;   
641         $m = $g_m;
642         $d = $g_d;
643         if (($y > 1582) || (($y == 1582) && ($m > 10)) || (($y == 1582) && 
644                 ($m == 10) && ($d > 14))) 
645         {
646                 $jd = (int)((1461 * ($y + 4800 + (int)(($m - 14) / 12)))/ 4) + 
647                         (int)((367 * ($m - 2 - 12 * ((int)(($m - 14) / 12)))) / 12) - 
648                         (int)((3 * ((int)(($y + 4900 + (int)(($m - 14) / 12)) / 100))) / 4) + $d - 32075;
649         } 
650         else 
651         {
652                 $jd = 367 * $y - (int)((7 * ($y + 5001 + (int)(($m - 9) / 7))) / 4) + 
653                         (int)((275 * $m) / 9) + $d + 1729777;
654         }
655         $l = $jd - 1948440 + 10632;
656         $n = (int)(($l - 1) / 10631);
657         $l = $l - 10631 * $n + 354;
658         $j = ((int)((10985 - $l) / 5316)) * ((int)((50 * $l) / 17719)) + 
659                 ((int)($l / 5670)) * ((int)((43 * $l) / 15238));
660         $l = $l - ((int)((30 - $j) / 15)) * ((int)((17719 * $j) / 50)) - 
661                 ((int)($j / 16)) * ((int)((15238 * $j) / 43)) + 29;
662         $m = (int)((24 * $l) / 709);
663         $d = $l - (int)((709 * $m) / 24);
664         $y = 30 * $n + $j - 30;
665         return array($y, $m, $d);
666 }
667
668 function islamic_to_gregorian($i_y, $i_m, $i_d)
669 {
670         $y = $i_y;   
671         $m = $i_m;
672         $d = $i_d;
673
674         $jd = (int)((11 * $y + 3) / 30) + 354 * $y + 30 * $m - (int)(($m - 1) / 2) + $d + 1948440 - 385;
675         if ($jd > 2299160)
676         {
677                 $l = $jd + 68569;
678                 $n = (int)((4 * $l) / 146097);
679                 $l = $l - (int)((146097 * $n + 3) / 4);
680                 $i = (int)((4000 * ($l + 1)) / 1461001);
681                 $l = $l - (int)((1461 * $i) / 4) + 31;
682                 $j = (int)((80 * $l) / 2447);
683                 $d = $l - (int)((2447 * $j) / 80);
684                 $l= (int)($j / 11);
685                 $m = $j + 2 - 12 * $l;
686                 $y = 100 * ($n - 49) + $i + $l;
687         } 
688         else 
689         {
690                 $j = $jd + 1402;
691                 $k = (int)(($j - 1) / 1461);
692                 $l = $j - 1461 * $k;
693                 $n = (int)(($l - 1) / 365) - (int)($l / 1461);
694                 $i = $l - 365 * $n + 30;
695                 $j = (int)((80 * $i) / 2447);
696                 $d = $i - (int)((2447 * $j) / 80);
697                 $i = (int)($j / 11);
698                 $m = $j + 2 - 12 * $i;
699                 $y = 4 * $k + $n + $i - 4716;
700         }
701         return array($y, $m, $d);
702 }