PHP 儒略日期转换器算法

PHP Julian date converter algorithms

以下算法:

京东1099114.5

PHP:3 月 -1704 12:00:00(PHP 内部转换器)

echo jdtogregorian($int_jd);

FLN:0 Mar -1703 12:00:00(Fliegel-Van Flandern)

function jd_to_gd_fln ($J) {
   $p = $J + 68569;
   $q = floor(4*$p/146097);
   $r = floor($p - (146097*$q + 3)/4);
   $s = floor(4000*($r+1)/1461001);
   $t = floor($r - (1461*$s/4) + 31);
   $u = floor(80*$t/2447);
   $v = floor($u/11);

     $Y = floor(100*($q-49)+$s+$v);
     $M = floor($u + 2 - 12*$v);
     $D = floor($t - 2447*$u/80);

return "$M/$D/$Y";

}

MEU:3 月 18 日 -1703 12:00:00(Jean Meeus“天文算法,第 2 版,更正)

function jd_to_greg_meeus($julian) { 
    $Z = intval($J+0.5); 
 $F = ($J+0.5)-$Z;



  if ($Z < 2299161) {$A = $Z;}
   if ($Z >= 2299161) {
        $alpha = floor(($Z-1867216.25)/36524.25);
         $A = $Z + 1 + $alpha - floor($alpha/4);
         }


         $B = $A + 1524;
         $C = floor( ($B-122.1)/365.25);
         $D = floor( 365.25*$C );
         $E = floor( ($B-$D)/30.6001 );


     $day = floor($B - $D - floor(30.6001*$E)); 

if ($E < 13.5) {   $month = $E - 1;}
if ($E > 13.5) {   $month = $E - 13;}
if ($month > 2.5) {  $year = $C - 4716; }
if ($month < 2.5) {  $year = $C - 4715; }



    return "$month/$day/$year";
} 

RICH:4 Mar -1703 12:00:00(Richards in Explanatory Supplement 3rd Ed.)

function jd_to_gd_rchrds ($J) {
$y=4716;    
$v=3;
$j=1401;    
$u=5;
$m=2;   
$s=153;
$n=12;  
$w=2;
$r=4;   
$B=274277;
$p=1461;    
$C=-38;

$f = $J + $j + (((4 * $J + $B) / 146097) * 3) / 4 + $C;


$e = $r * $f + $v;
$g = ($e % $p) / $r;
$h = $u * $g + $w;
$D = floor((($h%$s)) / $u + 1);
$M = floor((($h / $s + $m) % $n) + 1);
$Y = floor(($e / $p) - $y + ($n + $m - $M) / $n);

return "$M/$D/$Y"; 
}

每种算法都有其问题。

我的代码哪里做错了?

供参考的测试数据应包括:

Meeus 假设有公历 0 年,即使这在天文学上是正确的,但从日历的角度来看却毫无意义。从技术上讲,所有转换为公历日期的结果都是错误的?从日历上讲,如果没有 0,但从天文学上讲,有一个 0,那如何转化为同一日期?

我没有看 Fliegel-Van Flandern 算法。我针对 Danny F 要求的测试用例测试了剩余的算法,并添加了罗马儒略历的最后一个中午 (JD 2299160) 和罗马公历的第一个中午 (JD 2299161)。对于非整数儒略日,我只使用了 Meeus 算法,因为这是唯一一个说它支持非整数的算法。

内部算法是正确的,当您考虑到 0 年不存在时,它总是转换为公历。 Meeus 算法是正确的,当你允许它假设存在 0 年,并在 1582 年 10 月 4 日及更早的时候转换为 Julian,并在之后的日期转换为 Gregorian。

Richards 算法需要更正。我没有在某些点使用 floor 函数,而是使用 intdiv 函数代替每个“/”运算符,这更接近于 Richard 对算法的描述。在这些更正之后,测试用例是成功的。 (Richards 认为 0 年存在并且总是转换为 Gregorian。)

function jd_to_gd_rchrds ($J) {
$y=4716;    
$v=3;
$j=1401;    
$u=5;
$m=2;   
$s=153;
$n=12;  
$w=2;
$r=4;   
$B=274277;
$p=1461;    
$C=-38;

$f = $J + $j + intdiv(intdiv(4 * $J + $B,146097) * 3,4) + $C;

$e = $r * $f + $v;
$g = intdiv(($e % $p) , $r);

$h = $u * $g + $w;
$D = intdiv((($h%$s)) , $u) + 1;
$M = ((intdiv($h , $s) + $m) % $n) + 1;
$Y = intdiv($e , $p) - $y + intdiv($n + $m - $M,$n);

return "$M/$D/$Y"; 
}

测试用例结果:

Julian day PHP internal Meeus      Richards
0          0/0/0        1/1/-4712  11/24/-4713
1          11/25/-4714  1/2/-4712  11/25/-4713
1507231.5  bad input    7/30/-586  bad input
1721420    12/26/-1     12/28/0    12/26/0
1721425    12/31/-1     1/2/1      12/31/0
1741426    10/5/55      10/7/55    10/5/55
2222444    9/28/1372    9/20/1372  9/28/1372
2299160    10/14/1582   10/4/1582  10/14/1582
2299161    10/15/1582   10/15/1582 10/15/1582
2399301.5  bad input    12/18/1856 bad input
2422444    4/29/1920    4/29/1920  4/29/1920

不,没有公历 0 年这样的东西,因为公历直到 1582 年才开始。天文算法在公历改革之前使用儒略历。是天文算法 return 零年。 Meeus 是绝对正确的。 -years 与 BC years 不同。查一下。任何使用 BC-AD 的算法都在使用天文学家未使用的完全虚构的公历。查一下。

void JDToDateMeeus(double jDNum, int *month, double *day, int *year) //converts a Julian day to a calendar Date
{
int alpha, A, B, C, D, E, Z;
double F;

jDNum += 0.5;
Z = jDNum;  //Z == int so I = int part
F = jDNum - Z;  //F =  fractional part
if(Z < 2299161)  //Julian?
    A = Z;
else{  //Gregorian
    alpha = (int)floor((Z - 1867216.25) / 36524.25);
    A = Z + 1 + alpha - (int)floor(alpha / 4.0);
    }
B = A + 1524;
C = (int)floor((B - 122.1) /365.25);
D = (int)floor(365.25 * C);
E = (int)floor((B - D) /30.6001);
*day = B - D - (int)floor(30.6001 * E) + F;
if( E < 14)
    *month = E - 1;
else
    *month = E - 13;
if(*month > 2)
    *year = C - 4716;
else
    *year = C - 4715;
}

double DateToJulianDayNumber(int month, double day, int year) //after Meeus
{
int  M, Y, A, B;
double JD;

if(month > 2){
    Y = year;
    M = month;
    }
else{
    Y = year - 1;
    M = month + 12;
    }
if((year > 1582) || ((year == 1582) && ((month == 10 && day >= 5.0) || (month > 10)))){ //Gregorian
    A = (int)floor(Y / 100.0);
    B = 2 - A + (int)floor(A / 4.0);
    }
else
    B = 0;
JD = (int)floor(365.25 * (Y + 4716)) + (int)floor(30.6001 * (M + 1)) + day + B - 1524.5;
return JD;
}

这些函数不使用虚构的公历。根据教皇格雷戈里的历法改革,10 月 4 日之后是 1582 年的 15 日。 1582年以后使用公历闰年,有0年,之前的年写负号。

我使用下面的 php 代码将儒略日期转换为公历格式。

$ts=mktime(0, 0, 0, 1, 136, "20" . 20);

$mydate=date ('m-d-Y', $ts);

echo $mydate;

也可以参考https://www.juliandate.net进行日期转换