<?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;'>
&nbsp;View Source Code&nbsp;</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 &deg;
GPS Latitude  Deg  =  
$LatDeg &deg;
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(...)



?>