<?php
/*
##########################################################################
This program demonstrates a function to generate a table of geocentric
lunar phases at any given interval for any given time zone.
THIS VERSION IS REVISED FOR THE CURRENT MONTH UTC ONLY AND TO DISPLAY THE
GEOCENTRIC PHASE ANGLES AT 00:00 UT ON EACH DATE.
AUTHOR : Jay Tanner - Built around the NASA/JPL Horizons API
LANGUAGE : PHP v8.2.12
LICENSE : Public Domain
##########################################################################
*/
$cYear = date('Y');
// -------------------------------------------------
// Define parameters for function test/demo example.
$TimeZone = '+00:00'; // Time zone offset from UT (+Positive = East)
$DaySumYN = 'No'; // 'Yes|No'
$HeaderYN = 'Yes'; // 'Yes|No'
// --------------------------------------------------
// Set up for current month at 00:00 UT on each date.
$Y = GMDate('Y');
$m = GMDate('m');
$M = GMDate('M');
$mDays = Cal_Days_In_Month (CAL_GREGORIAN, $m, $Y);
$StartDateTimeStr = GMDate("Y-M-01 00:00:00");
$StopDateTimeStr = GMDate("$Y-") . $M . "-$mDays 00:00:00";
$StepSize = '1 day';
// ------------------------------------------------
// Compute Time Zone equivalent as fraction of day.
list($TZHH, $TZmm) = PReg_Split("[\:]", $TimeZone);
$TZFracDay = (trim($TZHH) . '.' . StrRChr(trim($TZmm)/60, '.'))/24;
$TZFracDay = SPrintF("%+1.10f", $TZFracDay);
// ------------------------------------------------------
// Define standard/Daylight Saving|Summer Time mode text.
$DaySumModeStr = (StrToUpper(substr(trim($DaySumYN),0,1)) == 'Y')?
'Day/Summ' : 'Standard';
/* --------------------------------------------------------------------
Compute simple geocentric ecliptical lunar phase angle table for the
current month at 00:00:00 UTC on each date.
*/
$PhaseTable = Lunar_Phase_Table ($StartDateTimeStr,$StopDateTimeStr,
$StepSize,$TimeZone,$DaySumYN,$HeaderYN);
// -----------------------------------------------
// Generate client HTML page to display the table.
print <<< END_OF_HTML_WEB_PAGE
<!DOCTYPE HTML>
<body style='color:black; background:white; font-family:Verdana;'>
<!-- Top yellow source code view link. --->
<br>
<table width="800" align="center" cellspacing="1" cellpadding="3">
<tr>
<td colspan="1" style="font-size:10pt; color:transparent; background:transparent;
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 PHP Source Code </a></b>
</td></tr>
<tr><td>
<pre style='font-size:11pt; font-weight:bold; padding:8px; text-align:left;'>
******************************************************************************
SIMPLE LUNAR PHASE ANGLE TABLE FUNCTION DEMO
Built around the NASA/JPL Horizons API
PHP Program by Jay Tanner - $cYear
This program is based on a custom function to generate a simple lunar phase
table over a given range from a single date to multiple dates spanning any
general interval at any given time step size.
This demo program generates a table of the simple geocentric lunar phase
angles for each date of the current month at 00:00:00 UTC on each date.
It is called the 'simple' lunar phase because it is geocentric and based on
the simple difference between the ecliptical longitudes of the moon and sun
at the same moment and excludes the tiny effects of librations, but still
results in a good enough lunar phase approximation for most practical pur-
poses and general small-scale graphical simulations.
-----------------
CALLING TEMPLATE:
PhaseTable = Lunar_Phase_Table (StartDateTimeStr, StopDateTimeStr, StepSize,
TimeZone, DaySumYN, HeaderYN)
*********************************************************
Geocentric Lunar Phase Table
Time Zone = UT$TimeZone (dJDate = $TZFracDay)
Day/Summ Time = $DaySumYN
Table Header = $HeaderYN
START Date/Time = $StartDateTimeStr ($DaySumModeStr Time)
STOP Date/Time = $StopDateTimeStr
Step Size = $StepSize
$PhaseTable
*********************************************************
Table to help visualize the lunar phase angles:
PhaseAng Description
-------- -----------------
0° New Moon
45 Waxing Crescent
90 First Quarter
135 Waxing Gibbous
180 Full Moon
225 Waning Gibbous
270 Last Quarter
315 Waning Crescent
360/0 New Moon
******************************************************************************
To compute the simple geocentric lunar phase angle (0 to 360 deg) based on
the ecliptical longitudes of the moon and sun at the same moment also in the
the range from 0 to 360 degrees:
Let:
PhaseAng = Simple lunar phase angle (0 to 360 deg) based on the
difference between the ecliptical longitudes.
Given:
Lm = Geocentric ecliptical longitude of the moon (0 to 360 deg).
Ls = Geocentric ecliptical longitude of the sun (0 to 360 deg).
Then, the simple phase angle may be found
by one of the following simple algorithms:
----------------------------------------
w = 360 - Lm + Ls
if (w > 360) then w = w - 360
PhaseAng = 360 - w
----------------------------------------
Or, the alternate equivalent:
w = 360 - Lm + Ls
PhaseAng = 360 − (w −= (w > 360)? 360:0)
******************************************************************************
</pre>
</td></tr>
</table>
<br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br>
</body>
END_OF_HTML_WEB_PAGE;
/*
###########################################################################
This function generates a table of geocentric lunar phases starting on any
given date and spanning a given interval at regular time steps.
It can also be used for a single computation for any given date and time.
It takes into account the Time Zone and Daylight Saving/Summer Time.
The table text header is optional.
DEPENDENCIES: The NASA/JPL Horizons API
###########################################################################
*/
function Lunar_Phase_Table ($StartDateTime, $StopDateTime, $StepSize,
$TimeZone='+00:00', $DaySumYN='No',
$HeaderYN='No')
{
$StartDateTime = trim($StartDateTime);
$StopDateTime = trim($StopDateTime);
$HeaderYN = substr(StrToUpper(trim($HeaderYN)),0,1);
/* -----------------------------------------------------------
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);
$DSSTAdj = ($DaySumYN == 'N')? 0:1;
list($TZHH, $TZmm) = PReg_Split("[\:]", $TimeZone);
$TZSign = substr($TZHH,0,1);
$TZHours = (($TZSign == '-')? -1:1)*(abs($TZHH) + $TZmm/60) + $DSSTAdj;
$i = StrPos($TZHours, '.'); if ($i == FALSE) {$TZHours .= '.00';}
$i = StrPos($TZHours, '.');
$TZHH = $TZSign.SPrintF("%02d", abs(substr($TZHours,0,$i)));
$TimeZone = URLEncode("$TZHH:$TZmm");
// **********************************************************
// MOON - GEOCENTRIC ECLIPTICAL LONGITUDE AND LATITUDE (GELL)
$From_Horizons_API =
"https://ssd.jpl.nasa.gov/api/horizons.api?format=text" .
"&COMMAND='301'" .
"&OBJ_DATA='NO'" .
"&MAKE_EPHEM='YES'" .
"&EPHEM_TYPE='OBSERVER'" .
"&CAL_FORMAT='BOTH'" .
"&CAL_TYPE='MIXED'" .
"&REF_SYSTEM='ICRF'" .
"&APPARENT='AIRLESS'" .
"&RANGE_UNITS='AU'" .
"&CENTER='500@399'" .
"&TIME_DIGITS='SECONDS'" .
"&TIME_ZONE='$TimeZone'" .
"&START_TIME='$StartDateTime UT'" .
"&STOP_TIME='$StopDateTime'" .
"&STEP_SIZE='$StepSize'" .
"&EXTRA_PREC='YES'" .
"&CSV_FORMAT='YES'" .
"&QUANTITIES='31,29" ;
// -----------------------------------------------------------------
// Get the geocentric ecliptical longitude and latitude of the moon.
$MoonGELL = Str_Replace(",\n", " \n", trim(File_Get_Contents($From_Horizons_API)));
/* ----------------------------------------------------
Set pointers to start and end of ephemeris table and
extract ONLY the required ephemeris CSV data lines
from between the Start/End pointers.
*/
$i = StrPos($MoonGELL, '$$SOE');
$j = StrPos($MoonGELL, '$$EOE');
$MoonTable = trim(substr($MoonGELL, $i+5, $j-$i-5));
$MoonTable = (substr($MoonTable,0,1) <> 'b')?
" $MoonTable" : $MoonTable;
// *********************************************************
// SUN - GEOCENTRIC ECLIPTICAL LONGITUDE AND LATITUDE (GELL)
$From_Horizons_API =
"https://ssd.jpl.nasa.gov/api/horizons.api?format=text" .
"&COMMAND='10'" .
"&OBJ_DATA='NO'" .
"&MAKE_EPHEM='YES'" .
"&EPHEM_TYPE='OBSERVER'" .
"&CAL_FORMAT='BOTH'" .
"&CAL_TYPE='MIXED'" .
"&REF_SYSTEM='ICRF'" .
"&APPARENT='AIRLESS'" .
"&RANGE_UNITS='AU'" .
"&CENTER='500@399'" .
"&TIME_DIGITS='SECONDS'" .
"&TIME_ZONE='$TimeZone'" .
"&START_TIME='$StartDateTime UT'" .
"&STOP_TIME='$StopDateTime'" .
"&STEP_SIZE='$StepSize'" .
"&EXTRA_PREC='YES'" .
"&CSV_FORMAT='YES'" .
"&QUANTITIES='31,29" ;
// ----------------------------------------------------------------
// Get the geocentric ecliptical longitude and latitude of the sun.
$SunGELL = Str_Replace(",\n", " \n", trim(File_Get_Contents($From_Horizons_API)));
/* ----------------------------------------------------
Set pointers to start and end of ephemeris table and
extract ONLY the required ephemeris CSV data lines
from between the Start/End pointers.
*/
$i = StrPos($SunGELL, '$$SOE');
$j = StrPos($SunGELL, '$$EOE');
$SunTable = trim(substr($SunGELL, $i+5, $j-$i-5));
$SunTable = (substr($SunTable,0,1) <> 'b')? " $SunTable" : $SunTable;
/* ------------------------------------------
PARSE THE TABLES AND CONSTRUCT A SINGLE
CUSTOMIZED GEOCENTRIC LUNAR PHASE TABLE.
=========================================================
Loc_Date Loc_Time Cnst Julian_Date_UT Phase_Ang
============ ======== ==== ================= =========
2025-Feb-01 00:00:00 Aqr 2460707.708333333 35.36319
...
*/
$LunarPhaseAngleTable = '';
/* --------------------------------------------
Store lunar and solar ecliptical coordinates
in their respective work arrays.
*/
$MoonLonArray = PReg_Split("[\n]", $MoonTable);
$MoonLonCount = count($MoonLonArray);
$SunLonArray = PReg_Split("[\n]", $SunTable);
$SunLonCount = count($SunLonArray);
/* -----------------------------------
Fatal error if unequal array count.
*/
if ($MoonLonCount <> $SunLonCount)
{exit ("FATAL ERROR: Unequal array count.");}
/* -------------------------------------------
Construct geocentric ecliptical coordinates
and lunar phase table.
*/
for ($i=0; $i < $MoonLonCount; $i++)
{
$CurrMoonLine = $MoonLonArray[$i];
$CurrSunLine = $SunLonArray[$i];
list ($DateTimeStr,$JDate,$w,$w,$CurrMoonLon,$w, $MoonCnst) = PReg_Split("[,]", $CurrMoonLine);
list ($w,$JDate,$w,$w,$CurrSunLon) = PReg_Split("[,]", $CurrSunLine);
$DateTimeStr = Str_Replace(' ', ' ', trim($DateTimeStr));
$DateTimeStr = (substr($DateTimeStr,0,1) <> 'b')? " $DateTimeStr" : $DateTimeStr;
// ----------------------------------------------------------
// Get IAU symbol for constellation in which moon is located.
$MoonCnst = trim($MoonCnst);
// -------------------------------
// Get longitudes of moon and sun.
$Lm = trim($CurrMoonLon);
$Ls = trim($CurrSunLon);
// -------------------------------
// Compute the simple phase angle.
$w = 360 - $Lm + $Ls;
$PhaseAng = SPrintF("% 9.5f", 360 - ($w -= ($w > 360)? 360:0));
// -----------------------------------------
// Construct current output table text line.
$LunarPhaseAngleTable .= "$DateTimeStr $MoonCnst $JDate $PhaseAng\n";
}
$LunarPhaseAngleTable = RTrim($LunarPhaseAngleTable);
// --------------------------------------------
// Return table with header text, if indicated.
if ($HeaderYN == 'Y')
{
return
"=========================================================
Loc_Date Loc_Time Cnst Julian_Date_UT Phase_Ang
============ ======== ==== ================= =========
$LunarPhaseAngleTable";
}
// --------------------------------------------
// Otherwise, return table without header test.
return $LunarPhaseAngleTable;
} // End of Lunar_Phase_Table (...)
?>