Skip to content

Instantly share code, notes, and snippets.

@derickr
Last active September 16, 2024 16:15
Show Gist options
  • Save derickr/f32dd7a05d5c0a099db4e449111f5ccd to your computer and use it in GitHub Desktop.
Save derickr/f32dd7a05d5c0a099db4e449111f5ccd to your computer and use it in GitHub Desktop.
PHP script to calculate the times of solstices and equinoxes
<?php
/* Algorithms taken from Meeus Astronomical Algorithms, 2nd edition */
/* Run the php script on the command line:
* php equinox.php <year> <what>
* with <what> being MAR, JUN, SEP, or DEC
*
* For the the Summer Solstice of 2020:
* php equinox.php 2020 JUN
*/
/* Constants */
define('MAR', 0);
define('JUN', 1);
define('SEP', 2);
define('DEC', 3);
/* Read arguments from the command line */
$year = $argv[1];
$which = constant($argv[2]);
/* Tables from Meeus, page 178 */
/* Table 27.A, for the years -1000 to 1000 */
$yearTable0 = [
MAR => [ 1721139.29189, 365242.13740, 0.06134, 0.00111, 0.00071 ],
JUN => [ 1721233.25401, 365241.72562, 0.05323, 0.00907, 0.00025 ],
SEP => [ 1721325.70455, 365242.49558, 0.11677, 0.00297, 0.00074 ],
DEC => [ 1721414.39987, 365242.88257, 0.00769, 0.00933, 0.00006 ],
];
/* Table 27.B, for the years 1000 to 3000 */
$yearTable2000 = [
MAR => [ 2451623.80984, 365242.37404, 0.05169, 0.00411, 0.00057 ],
JUN => [ 2451716.56767, 365241.62603, 0.00325, 0.00888, 0.00030 ],
SEP => [ 2451810.21715, 365242.01767, 0.11575, 0.00337, 0.00078 ],
DEC => [ 2451900.05952, 365242.74049, 0.06223, 0.00823, 0.00032 ],
];
/* Meeus, page 177 */
function calculateJDE0($year, $which)
{
global $yearTable0, $yearTable2000;
$table = $year < 1000 ? $yearTable0 : $yearTable2000;
$Y = $year < 1000 ? ($year / 1000) : (($year - 2000) / 1000);
$terms = $table[$which];
$JDE0 = $terms[0] +
($terms[1] * $Y) +
($terms[2] * $Y * $Y) +
($terms[3] * $Y * $Y * $Y) +
($terms[4] * $Y * $Y * $Y * $Y);
return $JDE0;
}
/* Meeus, Table 27.C, page 179 */
function calculateS($T)
{
$table = [
[ 485, 324.96, 1934.136 ],
[ 203, 337.23, 32964.467 ],
[ 199, 342.08, 20.186 ],
[ 182, 27.85, 445267.112 ],
[ 156, 73.14, 45036.886 ],
[ 136, 171.52, 22518.443 ],
[ 77, 222.54, 65928.934 ],
[ 74, 296.72, 3034.906 ],
[ 70, 243.58, 9037.513 ],
[ 58, 119.81, 33718.147 ],
[ 52, 297.17, 150.678 ],
[ 50, 21.02, 2281.226 ],
[ 45, 247.54, 29929.562 ],
[ 44, 325.15, 31555.956 ],
[ 29, 60.93, 4443.417 ],
[ 18, 155.12, 67555.328 ],
[ 17, 288.79, 4562.452 ],
[ 16, 198.04, 62894.029 ],
[ 14, 199.76, 31436.921 ],
[ 12, 95.39, 14577.848 ],
[ 12, 287.11, 31931.756 ],
[ 12, 320.81, 34777.259 ],
[ 9, 227.73, 1222.114 ],
[ 8, 15.45, 16859.074 ],
];
$sum = 0;
foreach( $table as $term ) {
$c = $term[0] * cos(deg2rad( $term[1] + ($term[2] * $T) ));
$sum += $c;
}
var_dump($term);
return $sum;
}
function deltaDTtoUTFromTable($year)
{
/* Meeus, page 79 */
$deltaTtab = [
121, 112, 103, 95, 88, 82, 77, 72, 68, 63, 60, 56, 53, 51, 48, 46, 44, 42, 40, 38,
35, 33, 31, 29, 26, 24, 22, 20, 18, 16, 14, 12, 11, 10, 9, 8, 7, 7, 7, 7,
7, 7, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11,
11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16,
16, 16, 16, 16, 16, 16, 15, 15, 14, 13, 13.1, 12.5, 12.2, 12, 12, 12, 12, 12, 12, 11.9,
11.6, 11, 10.2, 9.2, 8.2, 7.1, 6.2, 5.6, 5.4, 5.3, 5.4, 5.6, 5.9, 6.2, 6.5, 6.8, 7.1, 7.3, 7.5, 7.6,
7.7, 7.3, 6.2, 5.2, 2.7, 1.4, -1.2, -2.8, -3.8, -4.8, -5.5, -5.3, -5.6, -5.7, -5.9, -6, -6.3, -6.5, -6.2, -4.7,
-2.8, -0.1, 2.6, 5.3, 7.7, 10.4, 13.3, 16, 18.2, 20.2, 21.1, 22.4, 23.5, 23.8, 24.3, 24, 23.9, 23.9, 23.7, 24.0,
24.3, 25.3, 26.2, 27.3, 28.2, 29.1, 30, 30.7, 31.4, 32.2, 33.1, 34, 35, 36.5, 38.3, 40.2, 42.2, 44.5, 46.5, 48.5,
50.5, 52.2, 53.8, 54.9, 55.8, 56.9, 58.3, 60, 61.6, 63, 65, 66.6,
];
$i = floor(($year - 1620) / 2);
$f = (($year - 1620) / 2) - $i; /* Fractional part of year */
$dT = $deltaTtab[$i] + (($deltaTtab[$i + 1] - $deltaTtab[$i]) * $f);
return $dT;
}
/* Meeus, chapter 10 */
function deltaDTtoUT($year)
{
if (($year >= 1620) && ($year <= 2000)) {
return deltaDTtoUTFromTable($year);
}
$t = ($year - 2000) / 100;
if ($year < 948) {
return 2177 + (497 * $t) + (44.1 * $t * $t);
}
if (($year >= 948 && $year < 1620) || $year >= 2000) {
$dT = 102 + (102 * $t) + (25.3 * $t * $t);
}
if ($year >= 2000 && $year < 2100) {
$dT += 0.37 * ($year - 2100);
}
return $dT;
}
function JDEtoTimestamp($JDE)
{
$tmp = $JDE;
$tmp -= 2440587.5;
$tmp *= 86400;
return $tmp;
}
/* Meeus, page 177 */
$JDE0 = calculateJDE0($year, $which);
$T = ($JDE0 - 2451545.0) / 36525;
$W = (35999.373 * $T) - 2.47;
$L = 1 + 0.0334 * cos(deg2rad($W)) + 0.0007 * cos(2 * deg2rad($W));
$S = calculateS($T);
/* Meeus, page 178 */
$JDE = $JDE0 + ((0.00001 * $S) / $L);
/* Convert TD to PHP Date */
$date = JDEtoTimestamp($JDE);
$TD = new \DateTimeImmutable('@' . round($date));
/* Correct DT to UT, and convert DT to PHP Date */
$date += deltaDTtoUT($year);
$UT = new \DateTimeImmutable('@' . round($date));
/* Output */
echo "Dynamical Time: ", $TD->format(DateTimeImmutable::ISO8601), "\n";
echo "UT: ", $UT->format(DateTimeImmutable::ISO8601), "\n";
@timovn
Copy link

timovn commented Sep 15, 2024

Sorry to dig this up, but this yelds an error if the year is between 1600 and 2000: no $dT in the deltaDTtoUT.
When you say you didn’t bother include that one table page 79, maybe you should have for those years.

You can do something like this:

function deltaDTtoUT($year) {

	/* Meeus, page 79 */
	$deltaTtab = [
		121,    112,   103,    95,    88,    82,    77,    72,    68,   63,    60,  56,  53,  51,  48, 46,
		44,      42,    40,    38,    35,    33,    31,    29,    26,   24,    22,  20,  18,  16,  14, 12,
		11,      10,     9,     8,     7,     7,     7,     7,     7,    7,     8,   8,   9,   9,   9,  9, 9, 10, 10, 10,
		10,      10,    10,    10,    10,    11,    11,    11,    11,   11,    12,  12,  12,  12,  13, 13,
		13,      14,    14,    14,    14,    15,    15,    15,    15,   15,    16,  16,  16,  16,  16, 16,
		16,      16,    15,    15,    14,    13,  13.1,  12.5,  12.2,   12,    12,  12,  12,  12,  12,
		11.9,  11.6,    11,  10.2,   9.2,   8.2,   7.1,   6.2,   5.6,  5.4,   5.3, 5.4, 5.6,
		5.9,    6.2,   6.5,   6.8,   7.1,   7.3,   7.5,   7.6,   7.7,  7.3,   6.2, 5.2, 2.7,
		1.4,   -1.2,  -2.8,  -3.8,  -4.8,  -5.5,  -5.3,  -5.6,  -5.7, -5.9,    -6,
		-6.3,  -6.5,  -6.2,  -4.7,  -2.8,  -0.1,   2.6,   5.3,   7.7, 10.4,  13.3,  16,
		18.2,  20.2,  21.1,  22.4,  23.5,  23.8,  24.3,    24,  23.9, 23.9,  23.7,
		24,    24.3,  25.3,  26.2,  27.3,  28.2,  29.1,    30,  30.7, 31.4,  32.2,
		33.1,    34,    35,  36.5,  38.3,  40.2,  42.2,  44.5,  46.5, 48.5,  50.5,
		52.2,  53.8,  54.9,  55.8,  56.9,  58.3,    60,  61.6,    63,   65,  66.6
	];

	if (($year >= 1620) && ($year <= 2000)) {
		$i = floor(($year - 1620) / 2);
		$f = (($year - 1620) / 2) - $i;  /* Fractional part of year */
		$dT = $deltaTtab[$i] + (($deltaTtab[$i + 1] - $deltaTtab[$i]) * $f);
	} else {
		$t = ($year - 2000) / 100;
		if ($year < 948) {
			$dT = 2177 + (497 * $t) + (44.1 * $t * $t);
		} else {
			$dT = 102 + (102 * $t) + (25.3 * $t * $t);
			if (($year > 2000) && ($year < 2100)) {
				$dT += 0.37 * ($year - 2100);
			}
		}
	}

	return $dT;
}

This way there won’t be any undefined variable dT error, and it will cover all the years.

Anyway, thanks for this script! It will be useful for me :)

@derickr
Copy link
Author

derickr commented Sep 16, 2024

I think I've found a better function, but it's in JavaScript: https://github.com/commenthol/astronomia/blob/master/src/deltat.js

In any case, I've updated the function with something similar as @timovn suggested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment