<?php

/*
   ###########################################
   Inverse Parallel JD Number Table Calculator
   For Both the Julian and Gregorian Calendars

   Range:From BC 9999-Jan-01 to AD 9999-Dec-31

   -----------------------------
   Gregorian Calendar Mode Span:

   BC 9999-Jan-01-Tue       JD Number -1930634
   to
   AD 9999-Dec-31-Fri       JD Number  5373484


   --------------------------
   Julian Calendar Mode Span:

   BC 9999-Jan-01-Tue       JD Number -1930711
   to
   AD 9999-Dec-31-Mon       JD Number  5373557


   AUTHOR   : Jay Tanner - 2025
   LANGUAGE : PHP v8.2.12
   LICENSE  : Public Domain

   ###########################################
*/

   
ob_start();

   
$cYear date('Y');

   
$MinJDNum = -1930711;
   
$MaxJDNum =  5373557;

// ---------------------------------------------------------------
// Define the program cookie name and set it to expire in 30 days.

   
$CookieName 'Parallel-Greg-Julian-JD-Number-Table-Calculator';
   
$SetToExpireIn30Days time() + 30*86400;

// ---------------------------------
// Define PHP program and HTML info.

   
$_AUTHOR_           "Jay Tanner - $cYear";
   
$_PROGRAM_VERSION_  'v2.0 - '$at "&#97;&#116;&#32;&#76;&#111;&#99;&#97;&#108;&#32;&#84;&#105;&#109;&#101;&#32;"$LTC "&#85;&#84;&#67;";
   
$_SCRIPT_FILE_PATH_ Filter_Input(INPUT_SERVER'SCRIPT_FILENAME');
   
$_REVISION_DATE_    $_PROGRAM_VERSION_ .'Revised: 'date("Y-M-d-D $at h:i:s A   ($LTC"FileMTime($_SCRIPT_FILE_PATH_))."&minus;05:00)";
   
$_BROWSER_TAB_TEXT_ "Parallel Gregorian/Julian JD Number Table Calculator";
   
$_INTERFACE_TITLE_  "<span style='font-size:15pt;'>Parallel Gregorian/Julian JD Number Table Calculator</span><br>
                          <span style='font-size:11pt; line-height:175%;'>For the JD Number / Date Span From</span><br>
                          <span style='font-size:11pt;'>BC 9999-Jan-01 (&minus;1930711) &nbsp; to &nbsp; AD 9999-Dec-31 (5373557)</span><br>
                          <span style='font-size:9pt; line-height:175%;'>PHP Program by Jay Tanner - 
$cYear</span>";

// -------------------------------------
// Define main TextArea text and background
// colors and HTML table row span. If an
// error is reported, then these colors
// will change internally to red/white.

   
$TxColor 'black';
   
$BgColor 'white';

// ---------------------------------------------
// Do this only if [COMPUTE] button was clicked.

   
$w Filter_Input(INPUT_POST'ComputeButton');

   if (!IsSet(
$w))
  {

// ----------------------------------------------------------------------
// If this program is being called externally, rather than being executed
// by clicking the [COMPUTE] button, and an active cookie also exists,
// then restore the previously saved interface settings from it. If
// the user leaves and comes back later, all the interface settings
// will be remembered and restored if the cookie was not deleted.

   
$w Filter_Input(INPUT_COOKIE$CookieName);

   if (IsSet(
$w))
      {
       
$CookieDataString Filter_Input(INPUT_COOKIE$CookieName);
       list(
$JDNumArg,$NumDaysArg) = Preg_Split("[\|]"$CookieDataString);
      }

   else

// -----------------------------------------------------------
// If there is no previous cookie with the interface settings,
// then set the initial default interface startup values and
// store them in a new cookie.

 
{
       
$Y IntVal(date('Y'));
       
$m IntVal(date('m'));
       
$d IntVal(date('d'));
       
$JDNumArg GregorianToJD($m$d$Y);
       
$NumDaysArg 31;

// -------------------------------------------
// Store current interface settings in cookie.

   
$CookieDataString "$JDNumArg|$NumDaysArg";
   
SetCookie ($CookieName$CookieDataString$SetToExpireIn30Days);
  } 
// End of  else {...}

  
// End of  if (!isset(_POST['ComputeButton']))


// ------------------------------------------
// Read values of all interface arguments and
// set all empty arguments to default values.

   
$w Filter_Input(INPUT_POST'ComputeButton');

   if (isset(
$w))
{
   
$JDNumArg trim(Filter_Input(INPUT_POST'JDNumArg'));

// --------------------------------------
// Filter any commas from input argument.

   
$JDNumArg Str_Replace(','''$JDNumArg);

// ----------------------------------------
// Set default JD number argument to today.

   
if ($JDNumArg == '')
      {
       
$Y IntVal(date('Y'));
       
$m IntVal(date('m'));
       
$d IntVal(date('d'));
       
$JDNumArg GregorianToJD($m$d$Y);
      }

/* -----------------------------------------------------------------------
   If the argument is NOT numeric, assume it is a calendar date string and
   try to compute the corresponding Julian Day Number and then use this
   value as the starting JD Number value. If argument is numeric, then
   assume it is already a JD Number value within the valid calendar span
   and proceed with it. (An error could still be possible.)
*/
   
if (!Is_Numeric($JDNumArg))
  {
   
$JDNumArg trim(JD_Num($JDNumArg'G'));
  }


   
$MaxDays 10000;
   
$MinDays = -$MaxDays;

   
$NumDaysArg trim(Filter_Input(INPUT_POST'NumDaysArg'));
                 if (!
Is_Numeric($NumDaysArg)) {$NumDaysArg 0;}
                 if (
$NumDaysArg $MaxDays)   {$NumDaysArg $MaxDays;}
                 if (
$NumDaysArg $MinDays)   {$NumDaysArg $MinDays;}

// ------------------------------------
// Store interface argument in cookie.

   
$CookieDataString "$JDNumArg|$NumDaysArg";
   
SetCookie ($CookieName$CookieDataString$SetToExpireIn30Days);
}




// *******************************************************************
// *******************************************************************
// ERROR FILTER CODE CAN GO HERE.
// If error detected, then set ErrFlag = TRUE
// and define error message to be displayed.

   
$ErrFlag FALSE;


// Check if JD Number is within valid range.
   
if ($JDNumArg $MinJDNum or $JDNumArg $MaxJDNum)
      {
       
$ErrFlag TRUE;
       
$ErrMssg "ERROR:\nThe Starting JD Number is outside of the valid range.\n\nValid JD Number/Date Range:\nMinimum JD Number &minus;1930711 (BC 9999-Jan-01) \nto\nMaximum JD Number  5373557 (AD 9999-Dec-31)";
      }


// -------------------------
// Check (NumDaysArg) value.

   
if (!Is_Numeric($NumDaysArg))
      {
       
$ErrFlag TRUE;
       
$ErrMssg "Invalid argument:\nThe number of days must be an integer value.";
      }
   else
      {
       
$JDNumArg   $JDNumArg;
       
$NumDaysArg SPrintF("%+1d"$NumDaysArg);
      }





// ******************************************
// ******************************************
// If error was reported (TRUE), then display
// the error message on a red background.

   
if ($ErrFlag === TRUE)
  {
   
$TxColor 'white';
   
$BgColor '#CC0000';
   
$TextArea2Text '';

   
$TextArea1Text =
"$ErrMssg\n\n";
  }

else


  {
// *********************************************************
// BEGIN MAIN COMPUTATIONS HERE IF NO ERRORS DETECTED ABOVE.
// *********************************************************





// Computation or function call code.
   
$JDNumberTable Inv_JD_Number_Table($JDNumArg$NumDaysArg);



// Correct interactive English.
   
$TableSpanDays abs($NumDaysArg) + 1;
   
$s = ($TableSpanDays <> 1)? 's':'';

// *******************************************
// DROP THROUGH HERE AFTER COMPUTATIONS ABOVE.
// *******************************************

   
$TextArea1Text =
"       PARALLEL GREGORIAN/JULIAN  JD NUMBER TABLE

Starting JD Number =  
$JDNumArg
Table Span         =  
$TableSpanDays day$s

$JDNumberTable
"
;
  }


// ****************************
// Define TextArea2 text block.

   
$TextArea2Text =
"
This program also handles negative JD Numbers.

Entering a blank JD Number argument defaults to the
current date JD Number (UT).

A starting calendar date can also be used, such as:
'BC 1949-5-20'  or  '2025-Feb-24'  or  'AD 170-Nov-03'

The number of days represents the number of days
leading up to or following the starting point.

If the number of days is positive, the listing will
begin on the starting JD number and span that many
days after.

If the number of days is negative, the listing will
begin that many days prior to and span from there
up to the starting point.

If a calendar column has dots ...... in it, it means
that the given JD number is outside the valid range
on that calendar.  It may sometimes be a valid JD
number on one calendar but not on the other. As
a general rule, this only happens near the ends
of the calendar system, which should not really
pose any serious problem for general use."
;



// **************************************************************************
// Determine number of text columns and rows to use in the output text areas.
// These values vary randomly according to the text block width and length.
// The idea is to eliminate the need for scroll-bars within the text areas
// or worry as much about the variable dimensions of a text display area.

// -----------
// Text Area 1
   
$Text1Cols Max(Array_Map('StrLen'PReg_Split("[\n]"trim($TextArea1Text))));
   if (
$Text1Cols 80) {$Text1Cols 54;}  // Default
   
$Text1Rows Substr_Count($TextArea1Text"\n");

// -----------
// Text Area 2
// Match width of TextArea1.

   
$Text2Cols Max(Array_Map('StrLen'PReg_Split("[\n]"trim($TextArea1Text))));
   if (
$Text2Cols 80) {$Text2Cols 54;} // Default
   
$Text2Rows Substr_Count($TextArea2Text"\n");

// ---------------------------------
// Set initial uniform tables width.

   
$TableWidth '666'// Width in pixels


// ******************************************
// ******************************************
// GENERATE CLIENT WEB PAGE TO DISPLAY OUTPUT

   
print <<< _HTML

<!DOCTYPE HTML>
<HTML>

<head>
<title>
$_BROWSER_TAB_TEXT_</title>

<meta name='viewport' content='width=device-width, initial-scale=0.90'>

<meta http-equiv='content-type' content='text/html; charset=UTF-8'>
<meta http-equiv='pragma'  content='no-cache'>
<meta http-equiv='expires' content='-1'>
<meta name='description' content='Parallel Gregorian/Julian Day Number Calculator'>
<meta name='keywords' content='Julian Day Number Calculator,PHPScienceLabs.com'>
<meta name='author' content='Jay Tanner - https://www.PHPScienceLabs.com'>
<meta name='robots' content='index,follow'>
<meta name='googlebot' content='index,follow'>

<style>
 BODY
{
 background:black; color:white; font-family:Verdana; font-size:11pt;
 line-height:125%;
}



 TABLE
{font-family:Verdana;}



 TD
{
 color:black; background:white; line-height:150%; font-size:10pt;
 padding:6px; text-align:center;
}



 OL,UL
{font-family:Verdana; font-size:11pt; line-height:150%; text-align:justify;}

 LI
{font-family:Verdana; line-height:150%;}



 PRE
{
 background:white; color:black; font-family:monospace; font-size:11pt;
 font-weight:bold; text-align:left; line-height:125%; padding:6px;
 border:2px solid black; border-radius:8px;
 page-break-before:page;
}



 DIV
{
 background:white; color:black; font-family:Verdana; font-size:11pt;
 font-weight:normal; line-height:125%; padding:6px;
}



 TEXTAREA
{
 background:white; color:black; font-family:monospace; font-size:11pt;
 font-weight:bold; padding:4pt; white-space:pre; border-radius:8px;
 line-height:125%;
}



 INPUT[type='text']::-ms-clear {width:0; height:0;}

 INPUT[type='text']
{
 background:white; color:black; font-family:monospace; font-size:13pt;
 font-weight:bold; text-align:center; box-shadow:2px 2px 3px #666666;
 border:2px solid black; border-radius:4px;
}

 INPUT[type='text']:focus
{
 font-family:monospace; background:white; box-shadow:2px 2px 3px #666666;
 font-size:13pt; border:2px solid blue; text-align:center; font-weight:bold;
 border-radius:4px;
}



 INPUT[type='submit']
{
 background:black; color:cyan; font-family:Verdana; font-size:10pt;
 font-weight:bold; border-radius:4px; border:4px solid #777777;
 padding:3pt;
}
 INPUT[type='submit']:hover
{
 background:black; color:white; font-family:Verdana; font-size:10pt;
 font-weight:bold; border-radius:4px; border:4px solid red;
 padding:3pt;
}




/* -------------------------------------------
   Link states below MUST be defined in CSS in
   the following sequence to work correctly:

   :link,  :visited,  :hover,  :active
*/

 A:link
{
 font-size:10pt; background:transparent; color:#8080FF; border-radius:4px;
 font-family:Verdana; font-weight:bold; text-decoration:none;
 line-height:175%; padding:3px; border:1px solid transparent;
}

 A:visited
{
 font-size:10pt; background:transparent; color:DodgerBlue; border-radius:4px;
}

 A:hover
{
 font-size:10pt; background:yellow; color:black; border:1px solid black;
 box-shadow:1px 1px 3px #222222; border-radius:4px;
}

 A:active
{
 font-size:10pt; background:yellow; color:black; border-radius:4px;
}



 HR {background:red; height:4px; border:0px;}




::selection{background-color:yellow !important; color:black !important;}
::-moz-selection{background-color:yellow !important; color:black !important;}
</style>

</head>

<body>

<form name='form1' method='post' action=''>

<!-- Define main page title/header. --->
<table width="
$TableWidth" align='center' border='0' cellspacing='1' cellpadding='3'>

<tr><td colspan="99" style='color:white; background-color:#000066; border:2px solid white; border-radius:8px 8px 0px 0px;'>
$_INTERFACE_TITLE_</td></tr>


<!-- Define input argument text boxes  --->
<tr><td style='line-height:200%;' title=' STARTING POINT: \n\n BLANK = Current Date/Time \n\n JD Number like: 2433057 \n\n Gregorian Date String Like:\n BC 8817-7-15 \n AD 1949-May-20 \n 2109-Nov-03 '>
<span style='font-size:10pt;'>Starting Gregorian JD Number &nbsp;or&nbsp; Gregorian Date String</span><br>
<input name='JDNumArg'  type='text' value="
$JDNumArg"  size='16' maxlength='14'></td>

<td style='line-height:200%;' title=' Days to span before or after starting point. \n\n Span: 0  to  &plusmn; 10000 days'><span style='font-size:10pt;'>Number of Days </span><br>
<input name='NumDaysArg'  type='text' value="
$NumDaysArg"  size='7' maxlength='6'>
</td></tr>


<!-- Define [COMPUTE] button --->
<tr>
<td colspan="99" style='background-color:black;'><input name='ComputeButton' type='submit' value=' C O M P U T E '></td>
</tr>

<tr>
<td colspan="2" style='font-size:10pt; color:black; background:black;
                       text-align:center;' title=' Tries to Open in a New Tab. '>
<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;
            border-radius:4px; font-weight:normal;'>
&nbsp;View/Copy Source Code&nbsp;</a></b>
</td>
</tr>


<tr>
<td colspan="99" style='text-align:center; color:GreenYellow; background-color:black;'>Double-Click Within Text Area to Select ALL Text<br>
<textarea ID='TextArea1' name='TextArea1' style='color:
$TxColor; background:$BgColor; padding:6px; border:2px solid white;' cols="$Text1Cols" rows="$Text1Rows" ReadOnly OnDblClick='this.select();' OnMouseUp='return true;'>
$TextArea1Text
</textarea>
</td>
</tr>

<!-- Define TextArea2 --->

<tr>
<td colspan="99" style='text-align:center; color:GreenYellow; background:black;'><br>
<textarea ID='TextArea2' name='TextArea2' style='color:black; background:LightYellow; padding:6px;' cols="
$Text2Cols" rows="$Text2Rows" ReadOnly OnDblClick='this.select();' OnMouseUp='return true;'>
$TextArea2Text
</textarea>
</tr>

<tr>
<td colspan="99" style='color:GreenYellow; background:black;'>PHP Program by 
$_AUTHOR_<br><span style='color:silver; background:black;'>$_REVISION_DATE_</span></td>
</tr>

</table>
</form>

<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>
</HTML>



_HTML;

// END OF PROGRAM




/*
   ***************************************************************************
   API NAME :  Custom-API.php
   CREATED   : 2024-Aug-08-Thu 07:54:46 UTC
   FILE SIZE : 4,225 bytes

   This custom API contains the following
   2 functions:

   JD_Num()
   Inv_JD_Num()
   Inv_JD_Number_Table()

   ***************************************************************************
*/



/*
   ###########################################################################
   This function is the inverse of the JD number function. Given any
   signed JD Number, it will return the corresponding calendar date
   string in 'BC|AD Yyyy-Mmm-dd-DoW' format.

   CALENDAR YEAR RANGE:
   BC 9999  to  AD 9999
   There is no calendar year 0 (zero).

   Mathematical origins of the calendar systems:
   BC 4713-Jan-01-Mon   JDNum = 0   On old Julian calendar
   BC 4714-Nov-24-Mon   JDNum = 0   On modern Gregorian calendar

   ARGUMENT:
   JDNumber = Julian Day number for the calendar date to be computed.

   JGAMode = Calendar mode
             'G' = Gregorian
             'J' = Julian
             'A' = Auto-select mode = Default

   RETURNS:
   Calendar date string in  'BC|AD Yyyy-Mmm-dd-DoW'  format
   according to the selected calendar mode.

   ERRORS:
   FALSE is returned if JD number argument is non-numeric.

   NO DEPENDENCIES
   ###########################################################################
*/

   
function Inv_JD_Num ($JDNumber$JGAMode='A')
 {
   GLOBAL 
$DD// Used for separating days in the listing.

   
$JDNum trim($JDNumber);

// -------------------------------------------
// Define Month and Day-Of-Week abbreviations.

   
$MONTHS   'JanFebMarAprMayJunJulAugSepOctNovDec';
   
$WEEKDAYS 'SunMonTueWedThuFriSat';

// ----------------------------
// Read calendar mode argument.
// 'G' = Gregorian = Default
// 'J' = Julian
// 'A' = Auto-select

   
$JGAMode substr(StrToUpper(trim($JGAMode)),0,1);
   if (
$JGAMode == '') {$JGAMode 'A';}

// ----------------------------------------------
// If calendar mode = 'A' = Auto-select, then the
// calendar mode is automatically determined by
// the given JD Number argument.

   
if ($JGAMode == 'A')
      {
       
$CMode  = ($JDNum 2299161)? 0:1;
       
$JGAMode = ($CMode == 0)? 'J':'G';
      }
   else
      {
       
$CMode = ($JGAMode == 'J')? 0:1;
      }

// -----------------------------------------
// Compute numerical date elements (y, m, d)
// according to the calendar mode selection.

  
$A floor($JDNum 0.5);
  
$B $CMode*floor(($A 1867216.25) / 36524.25);
  
$C $A $CMode*($B floor($B/4) + 1);
  
$D $C 1524;
  
$E floor(($D 122.1) / 365.25);
  
$F floor(365.25 $E);
  
$G floor(($D $F) / 30.6001);
  
$d $D $F floor(30.6001 $G);     // Day num   (1 to 31)
  
$m $G 12*floor($G/14) - 1;          // Month num (1 to 12)
  
$y $E 4716 floor((14 $m) / 12); // Mathematical year
  
$Y = ($y 0)? $y $y-1;               // Calendar year (Negative = BC)

// ------------------------------------------------------------
// At this point we have the numerical date elements (y, m, d).
// The next step is to construct the full calendar date text
// string for output. EXAMPLE OUTPUT: 'BC 9998-May-20-Tue'

   
$i     = (+ ($JDNum 1) % 7) % 7;
   
$DoW   substr($WEEKDAYS3*$i3);
   
$Y     Str_Replace('-''BC 'SPrintF("%+05d"$Y));
   
$Y     Str_Replace('+''AD '$Y);
   
$Mmm   substr($MONTHS3*($m-1), 3);
   
$dd    SPrintf("%02d"$d);
   
$JDNum SPrintF("% +8d"$JDNum);

   
$DD $d;

// DONE.
   
return "$Y-$Mmm-$dd-$DoW";

 } 
// End of  Inv_JD_Num(...)




/*
   ###########################################################################

   Given any JD number and any number of days span within the calendar range,
   this function will retuen the corresponding calendar date on both the old
   Julian calendar and our modern Gregorian calendar, side-by-side.

   This way we can view the same JD numbers on both calendars in parallel.

   Input is assumed to be according to the Gregorian calendar.

   ARGUMENTS:
   StartJDNum   = Starting Julian Day number for the table.

   NumDays      = Number of days to span before (-) or after (+) starting JD.
                  For a single JD number, simply set NumDays = 0

   StopJDNum    = JD number at which to stop before or after starting JD.
                  Current limit = -/+ 10000 days
                                = 1428 weeks and 4 days
                                = 27.3785 years

   NOTE:
   If the starting JD number is greater than the stopping JD number, then the
   start/stop JD values are swapped internally. This way the table is always
   numbered forward from the earlier date.

   DEPENDENCIES:
   Inv_JD_Number()

   ###########################################################################
*/

   
function Inv_JD_Number_Table ($StartJDNum$NumDays)
{
   GLOBAL 
$DD// Used for separating days in the listing.

   
$StartJDNum trim($StartJDNum);


/* --------------------------------------
   Read number of days argument and limit
   it to -+ 10000 days either way.   This
   can be changed to any convenient value.
*/
   
$MaxDays 10000;
   
$NumDays trim($NumDays);   $ns = ($NumDays 0)? -1:1;
   if (
abs($NumDays) > $MaxDays) {$NumDays $ns $MaxDays;}

   
$StopJDNum  $StartJDNum $NumDays;


   
$header "JD Number   Gregorian Calendar    Julian Calendar
========= |====================|===================\n"
;

   
$w '';

   if (
$StartJDNum $StopJDNum)
      {
$u $StartJDNum;  $StartJDNum $StopJDNum;  $StopJDNum $u;}

   for (
$JDNum $StartJDNum;    $JDNum <= $StopJDNum;    $JDNum += 1)
       {
        
$J Inv_JD_Num($JDNum'J');
        
$G Inv_JD_Num($JDNum'G');

        
$JDNum SPrintF("% 8d"$JDNum);


// Blank out any BC 10000 lines and AD 10000 lines.
   
if (substr($J,0,8) == 'BC 10000')
      {
$J '      ......      ';}
// Blankout any BC 10000 lines and AD 10000 lines.
   
if (substr($J,0,8) == 'AD 10000')
      {
$J '      ......      ';}

// Blank out any BC 10000 lines and AD 10000 lines.
   
if (substr($G,0,8) == 'BC 10000')
      {
$G '      ......      ';}
// Blankout any BC 10000 lines and AD 10000 lines.
   
if (substr($G,0,8) == 'AD 10000')
      {
$G '      ......      ';}

// ---------------------------------------------------
// Separate the Gregorian months with a column header.

    
if ($DD == and $JDNum $StartJDNum) {$w .= "\n$header";}

        
$w .= "$JDNum  | $G | $J\n";
}
    return 
$header.$w;

// End of  Inv_JD_Number_Table (...)





/*
   ###########################################################################
   This function returns the Julian Day Number for any given calendar date
   in the range from BC 9999 to AD 9999 on the old Julian calendar or on the
   modern Gregorian calendar system.

   CALENDAR YEAR RANGE:
   BC 9999  to  AD 9999
   There is no calendar year 0 (zero).

   Mathematical origins of the calendar systems:
   BC 4713-Jan-01-Mon   JDNum = 0   Old Julian Calendar
   BC 4714-Nov-24-Mon   JDNum = 0   Modern Gregorian Calendar

   NOTE:
   If a year is given as a negative number, it refers to a BC year
   and will be converted to BC|AD format internally.

   Month = 1 to 12 or as 3-letter abbreviation string ('Jan' to 'Dec').
   Date strings are NOT case-sensitive.

   The returned signed JD Number is left-space-padded to 8 characters
   to facilitate easy columnar alignment if used for tabulation.

   ARGUMENTS:
   $BCADDateStr = Date string in BC|AD format.
                  VALID EXAMPLES:
                  'BC 9949-May-20'
                  'AD 1949-5-20'
                  '1959-1-29'
                  '-1023-Nov-15'

   JGAMode = Calendar mode
             'G' = Gregorian
             'J' = Julian
             'A' = Auto-select mode = Default

   ERRORS:
   FALSE is returned if an invalid argument is detected.

   NO DEPENDENCIES

   ###########################################################################
*/

   
function JD_Num ($BCADDateStr$JGAMode='A')
{
// --------------------------------------------------
// Read and adjust input date string argument format.
   
$BCADDateStr PReg_Replace("/\s+/"" "trim($BCADDateStr));

// -----------------------------------------------------
// If a weekday abbreviation is identified, then remove
// it and use the remaining string as the date argument.
// This allows the output to be used as the input to the
// Inv_JD_Number() function by ignoring the weekday. The
// weekday given to the inverse function may be wrong.

//   if (substr(substr($BCADDateStr, -4),0,1) == '-')
//      {$BCADDateStr = substr($BCADDateStr,0, StrLen($BCADDateStr)-4);}

// ---------------------------------------------------
// If first character is a minus sign (negative year),
// then convert it into a BC year string.

   
if (substr($BCADDateStr,0,1) == '-')
      {
$BCADDateStr 'BC ' substr($BCADDateStr1StrLen($BCADDateStr));}

// -----------------------------------------------------------
// If no BC|AD prefix at all, then attach a default AD prefix.
   
$ww StrToUpper(substr($BCADDateStr,0,2));
   if (
$ww <> 'BC' and $ww <> 'AD') {$BCADDateStr "AD $BCADDateStr";}

/* ------------------------------------
   Error if instant bad argument format.
   Valid formats:
   BC|AD Yyyy-Mmm-dd     1949-May-02     1908-12-25
*/
//   if (Substr_Count($BCADDateStr, '-') <> 2) {return FALSE;}

// ------------------------------
// Read and parse date arguments.
   
list($BCADYear,$Month,$Day) = PReg_Split("[-]"$BCADDateStr);

//exit("85: $BCADYear|$Month|$Day");

// ------------------
// A few adjustments.
   
$BCADYear trim($BCADYear);
   
$Month    trim($Month);
   
$Day      trim($Day);

// -----------------------------------
// Get BC|AD prefix and calendar year.
   
$BCAD StrToUpper(substr($BCADYear0,2));
   
$Y trim(substr($BCADYear2StrLen($BCADYear)));

// ---------------------------------
// Adjust for BC year, if necessary.
   
if ($BCAD == 'BC') {$Y = -$Y;}

// ------------------------------------------------------------
// Read calendar year argument value and return FALSE on error.
   
$w abs($Y);  if ($w == or $w 9999)  {return FALSE;}

// ---------------------------------------------------
// Read month argument. Could be a string or a number.
   
$m UCFirst(substr(StrToLower(trim($Month)),0,3));
// Read day argument value.
   
$d trim($Day);

// ----------------------------
// Read calendar mode argument.
// 'G' = Gregorian | 'J' = Julian
// 'A' = Auto-select = Default
   
$JGAMode substr(StrToUpper(trim($JGAMode)),0,1);
   if (
$JGAMode == '') {$JGAMode 'A';}

// -------------------------------------------------
// Define abbreviations for month and weekday names.
   
$MONTHS   'JanFebMarAprMayJunJulAugSepOctNovDec';
   
$WEEKDAYS 'SunMonTueWedThuFriSat';
   
$JGDiff   0;

// -----------------------------------------------------
// If month is a 3-letter abbreviation ('Jan' to 'Dec'),
// then replace it with the month number 1 to 12, if
// possible.  Otherwise, return FALSE if it cannot
// resolve the abbreviation text.

   
if (!Is_Numeric($m))
      {
       
$i StrPos($MONTHS$m);
       if (
$i === FALSE) {return $i;}
       
$m $i/3;
      }

// ---------------------------------------
// Error if invalid month number.

   
if ($m or $m 12) {return FALSE;}

// -------------------------------------------------
// Proceed to compute the Julian calendar JD Number.
// This is the base JD Number value. If the Gregorian
// calendar is selected, then the difference between
// the calendars is applied to obtain the Gregorian
// calendar JD Number.

   
$A floor((14-$m) / 12);
   
$B = (($Y 0)? $Y+$Y) - $A;
   
$C floor($B/100);

   
$JDNum floor(30.6001*(12*$A $m 1))
          + 
floor(365.25*($B 4716)) - 1524 $d;

// ----------------------------------------------
// Handle automatic calendar mode selection.
// If calendar mode = 'A' = Auto-select, then the
// calendar mode is automatically determined by
// the computed JD Number value.

   
if ($JGAMode == 'A')
      {
       
$JGAMode = ($JDNum 2299161)? 'J':'G';
      }

// ---------------------------------------------
// Handle Gregorian (= default) calendar mode by
// by ADDING the difference  in days between the
// Julian and Gregorian JD Numbers, if indicated
// by the JGAMode setting.  This value could be
// negative or positive, depending on the given
// date.  Default Logic: If not 'J', then 'G'.
//
// GregorianJDNum = JulianJDNum + (+-JGDiff)

   
if ($JGAMode <> 'J')
      {
       
$A = ($Y 0)? $Y+$Y;
       
$B trim($m);
       
$C $A floor((14-$B) / 12);
       
$D floor($C/100);
       
$JGDiff = (floor($D/4) - $D 2);
      }
       
$JDNum += $JGDiff;

// -------------------------------------------
// Left-pad signed JD number digits field with
// spaces to span exactly 8 characters width,
// just in case the values are used in a table.
// This helps to arrange the columns neatly.

   
$JDNum SPrintF("% 8d"$JDNum);

// DONE:
   
return $JDNum;

// End of  JD_Num(...)
























?>