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