DurinsDay.frink

View or download DurinsDay.frink in plain text format


// Calculate Durin's Day, from The Hobbit.
//
// "The first day of the dwarves' New Year, said Thorin, is as all should
//  know the first day of the last moon of Autumn on the threshold of Winter.
//  We still call it Durin's Day when the last moon of Autumn and the sun are
//  in the sky together. But this will not help us much, I fear, for it passes
//  our skill in these days to guess when such a time will come again."
//
// Many of these definitions are vague, and we use some conventions to put
// the dates earlier than a strict astronomical reading might yield.  The
// astronomical figures are rigorous, but the clarity of Thorin's definition
// is in some question.

use sun.frink

// How many years should be checked?
years = 25
// How chatty should we be?
verbose[] :=
{
   // true:  report everything
   // false:  report New Year's Days and Durin's Days
   return true
}

y = parseInt[input["Enter year: ",2000]]
limit = y + years

// GPS-surveyed position for east side of MIT's Infinite corridor, Cambridge,
// Massachusetts.
lat = 42.36002 degrees North
long = 71.09332 degrees West

// NWS for Denver, CO
//lat = 39.78 degrees North
//long = 104.88 degrees West

// Greenwich, England
//lat = DMS[51,28,38] North
//long = 0 degrees West


// Loop until we find a New Year's Day with:
// a sunrise or sunset when the moon is entirely above the horizon
// AND the separation between sun and moon is at least 7.5 degrees,
// which has been proven to be minimal for seeing a crescent.
// See http://www.skyandtelescope.com/observing/objects/projects/3308686.html
// and http://www.earthsky.org/faq/young-moon-visibility
do
{
   found = false
   dawn = false
   nyd = NewYearsDay[y]

   print["  New Year's Day occurs on "]
   if (verbose[])
      println["$nyd."]
   else
      println[(nyd -> ###yyyy-MM-dd###) + "."]

   if (verbose[])
      printSunMoonPos[nyd, lat, long]  
      
   sunrise = sunrise[nyd, lat, long]
   sunset = sunset[nyd, lat, long]

   if (verbose[])
      println["   Sunrise is at $sunrise"]
   [moonalt, sep] = printSunMoonPos[sunrise, lat, long]
   if (moonalt > moonRadiusAngle[sunrise]) and (sep > 7.5 degrees)
   {
      found = true
      dawn = true
   }

   if (verbose[])
      println["   Sunset is at $sunset"]
   [moonalt, sep] = printSunMoonPos[sunset, lat, long]
   if (moonalt > moonRadiusAngle[sunset]) and (sep > 7.5 degrees)
   {
      found = true
      dawn = false
   }

   if (! found) and (verbose[])
   {
      println["   This is not Durin's Day."]
      println[]
   }

   if (found)
   {
      print["Durin's day occurs at "]
      if (dawn)
         print["dawn"]
      else
         print["dusk"]
      println[" on " + (nyd -> ### MMMM d, yyyy ###) + "."]
      if (verbose[])
         println[]
   }
      
   y = y + 1
      
} while (y < limit)


// Print the position of sun and moon at a specified time.
printSunMoonPos[nyd, lat, long] :=
{
   [sunaz, sunalt] = refractedSunAzimuthAltitude[nyd, lat, long]
   [moonaz, moonalt] = refractedMoonAzimuthAltitude[nyd, lat, long]
   sep = sunMoonAngularSeparation[nyd, lat, long]

   if (verbose[])
   {
      illum = moonIlluminatedFraction[nyd]
      illum1 = moonIlluminatedFraction[nyd + 1 minute]
      if (illum1 > illum)
         indicator = "waxing"
      else
         indicator = "waning"
      println["     At this time, the altitude of the moon is: " +
      format[moonalt, "degrees" , 5]]
      println["       Angular separation: " + format[sep,"degrees",3]]
      println["       Moon illuminated fraction: " +
      format[illum, percent, 3] + "% ($indicator)"]
      println[]
   }
   return [moonalt, sep]
}


// Find New Year's Day, the first day of the last month before the
// cross-quarter day between the autumn equinox and winter solstice.
NewYearsDay[y] :=
{
   autumn = autumnEquinox[y]
   winter = winterSolstice[y]
   endautumn = autumn + (winter-autumn)/2

   // Find the last new moon of "autumn."
   nextmoon = endautumn
   do
   {
      newmoon = newMoon[nextmoon]
      nextmoon = newmoon - lunarmonth
   } while newmoon > endautumn

   // Return the new moon
   return newmoon
}


View or download DurinsDay.frink in plain text format


This is a program written in the programming language Frink.
For more information, view the Frink Documentation or see More Sample Frink Programs.

Alan Eliasen was born 17651 days, 5 hours, 19 minutes ago.