<?php
/*
This is a function to compute the local moonrise, transit
and moonset times for a single date or a range of dates.
This example is for New York City, USA and spans the month
of February 2026.
It calls the NASA/JPL Horizons API.
AUTHOR : Jay Tanner - 2025
LANGUAGE : PHP v8.2.12
*/
// -----------------------------------------------
// Define test/demo values for New York City, USA.
$LatDeg = '+40.7127281';
$LonDeg = '-74.0060152';
$AltMet = '+0.0';
$StartDate = '2026-Feb-01';
$StopDate = '2026-Feb-28';
$TimeZone = '-05:00';
$DaySumYN = 'No'; // Yes = Daylight Time / No = Standard Time
// ---------------------------------------------------------------
// Compute table of rising, transit and setting times of the moon.
$RTSTimes = R_T_S_Times ('301', $StartDate,$StopDate, $TimeZone,
$DaySumYN, $LatDeg,$LonDeg, $AltMet);
print <<< _END_of_HTML_PAGE
<!DOCTYPE HTML>
<head>
<title>Moonrise, Transit, Moonset Demo</title>
<!-- Top yellow source code view link. --->
<br>
<table width="420" align="bottom" cellspacing="1" cellpadding="3">
<tr>
<td colspan="1" style="font-size:10pt; color:black; background:white;
text-align:left;">
<b>
<a href='View-Source-Code.php' target='_blank'
style='font-family:Verdana; color:black; background:yellow;
text-decoration:none; border:1px solid black; padding:4px;'>
View Source Code </a>
</b>
</td>
</tr>
</table>
<pre style='font-family:monospace; font-size:10.5pt; font-weight:bold;'>
#############################################################
TABLE OF LOCAL RISING, TRANSIT AND SETTING TIMES OF THE MOON
FOR NEW YORK CITY, USA VIA THE NASA/JPL HORIZONS API
GPS Longitude Deg = $LonDeg °
GPS Latitude Deg = $LatDeg °
Altitude in Meters = $AltMet m
Start Date = $StartDate
Stop Date = $StopDate
Time Zone = $TimeZone
Day/Sum Time = $DaySumYN
This example shows what a raw Rising, Transit and Setting
times table looks like, as computed by the Horizons API.
You can take the raw table and parse it and reformat it to
your own custom specifications for neat display or printing.
See:
https://www.neoprogrammics.com/archive/RTS-Calculators/Sun-Moon-RTS.php
############################################################
$RTSTimes
</pre>
<br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br>
_END_of_HTML_PAGE;
/*
###########################################################################
This function returns a topocentric ephemeris of rise/transit/set times
from the NASA/JPL Horizons API. A topocentric ephemeris takes the location
and altitude of the observer into account. Standard Earth refraction model
is applied.
DaySumYN = Means Daylght Saving/Summer Time 'Yes|No'
'N|No' = Use Standard Clock Time (Default)
'Y|Yes' = Use Daylight Saving/Summer Clock Time
COLUMN CONTENT
====== =======================================================================
1 Date and Time String (UT or ZONE)
2 Sp (Solar Presence Symbol = Indicates if Sun is in the Sky.
3 Lp (Lunar Presence Symbol = Indicates if Moon is in the Sky.
See explanatory footer following the demo RTS table for a description
of the (Sp, Lp) symbols.
4 Azimuth Angle (Compass Direction Reckoned Clockwise From North = 0)
5 Elevation Angle (Relative to Horizon = 0 degrees)
6 Apparent Visual Magnitude or Brightness Level
7 S-brt (Brightness of 1 Square Arcsecond of Visible Disc)
NO DEPENDENCIES
###########################################################################
*/
function R_T_S_Times ($BodyID, $StartDate,$StopDate, $TimeZone, $DaySumYN,
$LatDeg,$LonDeg, $AltMet)
{
// ===========================================================================
// Construct query URL for the NASA/JPL Horizons API.
$BodyID = trim($BodyID);
$Command = URLEncode($BodyID);
$AltKm = trim($AltMet) / 1000;
/* -----------------------------------------------------------
Adjust for Daylight/Summer Time, if indicated. This assumes
that the Time Zone string is given in the standard +-HH:mm
format or an error may occur.
*/
$DaySumYN = substr(StrToUpper(trim($DaySumYN)),0,1);
$DaySumAdj = ($DaySumYN == 'N')? 0:1;
list($TZHH, $TZmm) = PReg_Split("[\:]", $TimeZone);
$TZSign = substr($TZHH,0,1);
$TZHours = (($TZSign == '-')? -1:1)*(abs($TZHH) + $TZmm/60) + $DaySumAdj;
$i = StrPos($TZHours, '.'); if ($i == FALSE) {$TZHours .= '.00';}
$i = StrPos($TZHours, '.');
$TZHH = $TZSign.SPrintF("%02d", abs(substr($TZHours,0,$i)));
$TimeZone = "$TZHH:$TZmm";
/* ----------------------------------------------------------
Account for special case of the moon. Set distance (range)
units = 'KM' and add SOT angle (Quantity #23) for finding
the simple lunar phase angle.
*/
$AUorKM = 'AU'; $SOT = ''; // Initialize.
if ($BodyID == '301') {$AUorKM = 'KM';}
// -------------------------------------
// Construct URL for Horizons API query.
$From_Horizons_API =
"https://ssd.jpl.nasa.gov/api/horizons.api?format=text" .
"&COMMAND='$Command'" .
"&OBJ_DATA='NO'" .
"&MAKE_EPHEM='YES'" .
"&EPHEM_TYPE='OBSERVER'" .
"&CAL_FORMAT='CAL'" .
"&REF_SYSTEM='ICRF'" .
"&APPARENT='REFRACTED'" .
"&CENTER='COORD@399'" .
"&COORD_TYPE='GEODETIC'" .
"&SITE_COORD='$LonDeg,$LatDeg,$AltKm'" .
"&TIME_DIGITS='MINUTES'" .
"&TIME_ZONE='$TimeZone'" .
"&START_TIME='$StartDate%2000:00:00%20UT'" .
"&STOP_TIME='$StopDate%2023:59:59'" .
"&STEP_SIZE='1 MINUTE'" .
"&EXTRA_PREC='YES'" .
"&R_T_S_ONLY='TVH'" .
"&CSV_FORMAT='YES'" .
"&QUANTITIES='4,9'" ;
// ============================================
/* -----------------------------------------------------------------------
Send query to Horizons API to obtain the apparent topocentric ephemeris
R-T-S times for the given body ID.
*/
$RTS = Str_Replace(",\n", " \n", File_Get_Contents($From_Horizons_API));
/* ----------------------------------------------------------------------
If no ephemeris data is found, then return an empty string as an error
state indicator.
*/
if (StrPos($RTS, '$$SOE') === FALSE) {return $RTS;}
/* -------------------------------------------------------------------------
DO NOT TRIM HERE BECAUSE INITIAL CHARACTER MAY BE A SPACE INDICATING AN
'AD' YEAR. 'BC' YEARS BEGIN WITH A SINGLE 'b' AS THE INITIAL CHARACTER.
BASICALLY, IF A DATE DOES NOT START WITH A 'b', THEN IT IS AN 'AD' YEAR.
*/
return $RTS;
} // End of R_T_S_Times(...)
?>