Sunrise/Sunset Calculations

The Sunrise application provides the ability to programatically calculate the times of Sunrise, Solar Noon and Sunset accurately to within one minute of the NOAA Sunrise/Sunset Calculator.

Sunrise.h

/*********************************************************************************************
* Copyright (c) 2008 - 2010 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
*********************************************************************************************/

#ifndef _SUNRISE_H
#define _SUNRISE_H

#ifdef  __cplusplus
extern "C" {
#endif   /* __cplusplus */

extern double TimeOfSunrise   ( double dblLatitude,   double dblLongitude, int nMonth, int nDay, int nYear );
extern double TimeOfSolarNoon (                       double dblLongitude, int nMonth, int nDay, int nYear );
extern double TimeOfSunset    ( double dblLatitude,   double dblLongitude, int nMonth, int nDay, int nYear );

#ifdef  __cplusplus
}
#endif   /* __cplusplus */

#endif   /* _SUNRISE_H */

DateTime.h

/*********************************************************************************************
* Copyright (c) 2008 - 2010 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
*********************************************************************************************/

/*
 * DateTime.h - Header File for the Date/Time Functions
 */

#if !defined(DATETIME_H__4915DDA3_D454_4C36_AD25_4F2DF5E21C9B__INCLUDED_)
#define DATETIME_H__4915DDA3_D454_4C36_AD25_4F2DF5E21C9B__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif /* _MSC_VER > 1000 */

#ifdef TRACE_HEADERS
#pragma message ( "NOTE:  Included header file:  \"" __FILE__ "\"" )
#endif   /* TRACE_HEADERS */

#ifndef _INC_STDIO
#include <STDIO.H>
#endif   /* _INC_STDIO */

#ifndef _INC_TIME
#include <TIME.H>
#endif   /* _INC_TIME */

/**********************************
* Windows-NT Compatiblity Defines *
**********************************/

#ifndef BOOL
typedef int BOOL;
#endif   /* BOOL */

#ifndef VOID
typedef void VOID;
#endif   /* VOID */

#ifndef _SIZE_T_DEFINED
typedef unsigned int size_t;
#define _SIZE_T_DEFINED
#endif   /* _SIZE_T_DEFINED */

#ifndef  __SQLDATE

typedef short           SQLSMALLINT;
typedef unsigned short  SQLUSMALLINT;
typedef unsigned long   SQLUINTEGER;

typedef struct tagTIMESTAMP_STRUCT {

   SQLSMALLINT    year;
   SQLUSMALLINT   month;
   SQLUSMALLINT   day;
   SQLUSMALLINT   hour;
   SQLUSMALLINT   minute;
   SQLUSMALLINT   second;
   SQLUINTEGER    fraction;

} TIMESTAMP_STRUCT;

#endif   /* __SQLDATE */

#ifdef  __cplusplus
extern "C" {
#endif

long int          MDY2GD            ( int nMonth, int nDay, int nYear );
void              GD2MDY            ( long int lnDate, int * pnMonth, int * pnDay, int * pnYear );

double            CAL2JD            ( int nMo, int nDy, int nYear, int nHr, int nMn, int nSc, int nMs );
void              JD2CAL            ( double jdDateTime, int * lpnMo, int * lpnDy, int * lpnYear, int * lpnHr, int * lpnMn, int * lpnSc, int * lpnMs );

void              GetTzInfo         ( int * pnTimeZoneOffsetInHours, int * pfUseDaylightSavingsTime );

BOOL              Year2DST          ( int nYear, int nTimeZoneOffsetInHours, double * putcBeg, double * putcEnd );

double            UTC2Civil         ( double utcDateTime, BOOL * pfDaylightSavingsInEffect,  int nTimeZoneOffsetInHours, BOOL fUseDaylightSavingsTime );
double            Civil2UTC         ( double civDateTime, BOOL * pfDaylightSavingsAmbiguity, int nTimeZoneOffsetInHours, BOOL fUseDaylightSavingsTime );

double            CurrentTime       ( void );

TIMESTAMP_STRUCT  GetCivilTimeStamp ( double utcDateTime );

void              DumpJD2UTC        ( FILE * hFile, char * szLegend, double dblTimeUTC );
void              DumpJD2Civ        ( FILE * hFile, char * szLegend, double dblTimeUTC );

char *            myctime           ( const time_t * plnTime );

void              TimeStamp         ( long * plnUTCDate, long * plnUTCMilliseconds );

#ifdef   __cplusplus
}
#endif

#endif   /* !defined(DATETIME_H__4915DDA3_D454_4C36_AD25_4F2DF5E21C9B__INCLUDED_) */

Sunrise.c

/************************************************************************************************
*                                                                                               *
*  Copyright (c) 2008 - 2011 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342   *
*                                                                                               *
*  Much of this code is a rework of the Sunrise/Sunset calculations by By Brian Heilman,        *
*  14 Dec 2000 published at http://www.codeproject.com/KB/datetime/srss.aspx.  Parts are also   *
*  a port from the Java code in http://www.srrb.noaa.gov/highlights/sunrise/sunrise.html.       *
*                                                                                               *
*  The NOAA Sunrise/Sunset Calculator referenced above was used to verify the accuracy of these *
*  calculations.  So far, they are in agreement to less than one minute for sunrise, solar noon *
*  and sunset.                                                                                  *
*                                                                                               *
************************************************************************************************/


#include <math.h>
#include <stdio.h>

#include "DateTime.h"

#include "Sunrise.h"

#define PI 3.14159265358979323846

static double  RadiansToDegrees           ( double dblAngleInRadians );
static double  DegreesToRadians           ( double dblAngleInDegrees );

static int     DayOfYear                  ( int nMonth,int nDay, int nYear );

static double  Gamma                      ( int nDayOfYear );
static double  Gamma2                     ( int nDayOfYear, int nHour );

static double  EquationOfTime             ( double dblGamma );
static double  SolarDeclination           ( double dblGamma );
static double  HourAngle                  ( double dblLatitude, double dblDeclination );

static double  TimeOfSunriseInMinutes     ( int nDayOfYear, double dblLatitude, double dblLongitude );
static double  TimeOfSolarNoonInMinutes   ( int nDayOfYear,                   double dblLongitude );
static double  TimeOfSunsetInMinutes      ( int nDayOfYear, double dblLatitude, double dblLongitude );

/*
 * Convert Radians to Degrees
 */

static double RadiansToDegrees ( double dblAngleInRadians )

   {

   return ( 180.0 * dblAngleInRadians / PI );

   }  /* double RadiansToDegrees ( double dblAngleInRadians ) */

/*
 * Convert Degrees to Radians
 */

static double DegreesToRadians ( double dblAngleInDegrees )

   {

   return ( PI * dblAngleInDegrees / 180.0 );

   }  /* double DegreesToRadians ( double dblAngleInDegrees ) */

/*
 * Compute the Day of the Year - January 1 is Day 1
 */

static int DayOfYear ( int nMonth,int nDay, int nYear )

   {

   return MDY2GD ( nMonth, nDay, nYear ) - MDY2GD ( 1, 1, nYear ) + 1;

   }

/*
 * Compute Gamma
 */

static double Gamma ( int nDayOfYear )

   {

   return ( 2.0 * PI / 365) * ( nDayOfYear - 1 );

   }  /* double Gamma ( int nDayOfYear ) */

/*
 * Compute Gamma for the Fractional Day
 */

static double Gamma2 ( int nDayOfYear, int nHour )

   {

   return ( 2.0 * PI / 365.0 ) * ( nDayOfYear - 1 + ( nHour / 24 ) );

   }  /* double Gamma2 ( int nDayOfYear, int nHour ) */

/*
 * Calculate the Equation of Time
 */

static double EquationOfTime ( double dblGamma )

   {

   return ( 229.18 * ( 0.000075 + 0.001868 * cos ( dblGamma ) - 0.032077 * sin ( dblGamma ) - 0.014615 * cos (2.0 * dblGamma ) - 0.040849 *  sin ( 2.0 * dblGamma ) ) );

   }  /* double EquationOfTime ( double dblGamma ) */

/*
 * Calculate the Solar Declination
 */

static double SolarDeclination ( double dblGamma )

   {

   return ( 0.006918 - 0.399912 * cos ( dblGamma ) + 0.070257 * sin ( dblGamma ) - 0.006758 * cos ( 2.0 * dblGamma ) + 0.000907 *  sin ( 2.0 * dblGamma ) );

   }  /* double SolarDeclination ( double dblGamma ) */

/*
 * The hour angle returned below is only for sunrise/sunset, i.e. when the solar zenith angle is 90.8 degrees.
 * The reason why it's not 90 degrees is because we need to account for atmoshperic refraction.
 */

static double HourAngle ( double dblLatitude, double dblDeclination )

   {
   double dblLatitudeInRadians   = DegreesToRadians ( dblLatitude );
   double dblHourAngle           = acos ( cos ( DegreesToRadians ( 90.833 ) ) / ( cos ( dblLatitudeInRadians ) * cos ( dblDeclination ) ) - tan ( dblLatitudeInRadians ) * tan ( dblDeclination ) );

   return dblHourAngle;

   }  /* double HourAngle ( double dblLatitude, double dblDeclination, BOOL fPositiveHourAngle ) */

/*
 * Calculate the Time of Sunrise in Minutes Since Midnight
 */

static double TimeOfSunriseInMinutes ( int nDayOfYear, double dblLatitude, double dblLongitude )

   {

/*
 * The First Pass Approximates Sunrise
 */
   double dblGamma               = Gamma ( nDayOfYear );
   double dblEquationOfTime      = EquationOfTime ( dblGamma );
   double dblSolarDeclination    = SolarDeclination ( dblGamma );
   double dblHourAngle           = HourAngle ( dblLatitude, dblSolarDeclination );
   double dblAngle               = dblLongitude - RadiansToDegrees ( +dblHourAngle );
   double dblTimeDifference      = 4.0 * dblAngle;
   double dblTimeInMinutes       = 720.0 + dblTimeDifference - dblEquationOfTime;

/*
 * The Second Pass Includes the Fractional Julian Day in the Gamma Calculation
 */
   double dblGammaOfSunrise      = Gamma2 ( nDayOfYear, ( int ) ( dblTimeInMinutes / 60.0 + 0.5 ) );

   dblEquationOfTime             = EquationOfTime ( dblGammaOfSunrise );
   dblSolarDeclination           = SolarDeclination ( dblGammaOfSunrise );
   dblHourAngle                  = HourAngle ( dblLatitude, dblSolarDeclination );
   dblAngle                      = dblLongitude - RadiansToDegrees ( +dblHourAngle );
   dblTimeDifference             = 4.0 * dblAngle;
   dblTimeInMinutes              = 720.0 + dblTimeDifference - dblEquationOfTime;

   return dblTimeInMinutes;

   }  /* static double TimeOfSunriseInMinutes ( int nDayOfYear, double dblLatitude, double dblLongitude ) */

/*
 * Calculate the Time of Solar Noon in Minutes Since Midnight
 */

static double  TimeOfSolarNoonInMinutes ( int nDayOfYear, double dblLongitude )

   {

/*
 * Add the Approximate Fractional Day to Day of Year Before Calculating Gamma
 */
   double dblGamaOfSolarNoon     = Gamma2 ( nDayOfYear, ( int ) ( 12.0 + ( dblLongitude / 15.0 ) ) );
   double dblEquationOfTime      = EquationOfTime ( dblGamaOfSolarNoon );
   double dblTimeInMinutes       = 720.0 + ( dblLongitude * 4.0 ) - dblEquationOfTime;

   return dblTimeInMinutes;

   }  /* static double  TimeOfSolarNoonInMinutes ( int nDayOfYear, double dblLongitude ) */

/*
 * Calculate the Time of Sunset in Minutes Since Midnight
 */

static double TimeOfSunsetInMinutes ( int nDayOfYear, double dblLatitude, double dblLongitude )

   {

/*
 * The First Pass Approximates Sunset
 */
   double dblGamma               = Gamma ( nDayOfYear + 1 );
   double dblEquationOfTime      = EquationOfTime ( dblGamma );
   double dblSolarDeclination    = SolarDeclination ( dblGamma );
   double dblHourAngle           = HourAngle ( dblLatitude, dblSolarDeclination );
   double dblAngle               = dblLongitude - RadiansToDegrees ( -dblHourAngle );
   double dblTimeDifference      = 4.0 * dblAngle;
   double dblTimeInMinutes       = 720.0 + dblTimeDifference - dblEquationOfTime;

/*
 * The Second Pass Includes the Fractional Julian Day in the Gamma Calculation
 */
   double dblGammaOfSunset       = Gamma2 ( nDayOfYear, ( int ) ( dblTimeInMinutes / 60.0 + 0.5 ) );

   dblEquationOfTime             = EquationOfTime ( dblGammaOfSunset );
   dblSolarDeclination           = SolarDeclination ( dblGammaOfSunset );
   dblHourAngle                  = HourAngle ( dblLatitude, dblSolarDeclination );
   dblAngle                      = dblLongitude - RadiansToDegrees ( -dblHourAngle );
   dblTimeDifference             = 4.0 * dblAngle;
   dblTimeInMinutes              = 720.0 + dblTimeDifference - dblEquationOfTime;

   return dblTimeInMinutes;

   }  /* static double TimeOfSunsetInMinutes ( int nDayOfYear, double dblLatitude, double dblLongitude ) */

extern double TimeOfSunrise ( double dblLatitude, double dLon, int nMonth, int nDay, int nYear )

   {
   double   dblMinutes  = TimeOfSunriseInMinutes ( DayOfYear ( nMonth, nDay, nYear ), dblLatitude, dLon );

   long     lnSeconds   = ( long ) ( dblMinutes * 60.0 + 0.5 );

   int      nHour       = ( int ) ( ( lnSeconds / 3600L ) % 24L );
   int      nMinute     = ( int ) ( ( lnSeconds /   60L ) % 60L );
   int      nSecond     = ( int ) ( ( lnSeconds /    1L ) % 60L );

   double   dblUTC      = CAL2JD ( nMonth, nDay, nYear, nHour, nMinute, nSecond, 0 );

/* DumpJD2Civ ( stdout, "SR ", dblUTC ); */

   return dblUTC;

   }  /* extern double TimeOfSunrise ( double dblLatitude, double dLon, int nMonth, int nDay, int nYear ) */

extern double TimeOfSolarNoon ( double dLon, int nMonth, int nDay, int nYear )

   {
   double   dblMinutes  = TimeOfSolarNoonInMinutes ( DayOfYear ( nMonth, nDay, nYear ), dLon );

   long     lnSeconds   = ( long ) ( dblMinutes * 60.0 + 0.5 );

   int      nHour       = ( int ) ( ( lnSeconds / 3600L ) % 24L );
   int      nMinute     = ( int ) ( ( lnSeconds /   60L ) % 60L );
   int      nSecond     = ( int ) ( ( lnSeconds /    1L ) % 60L );

   double   dblUTC      = CAL2JD ( nMonth, nDay, nYear, nHour, nMinute, nSecond, 0 );

/* DumpJD2Civ ( stdout, "SN ", dblUTC ); */

   return dblUTC;

   }  /* extern double TimeOfSolarNoon ( double dLon, int nMonth, int nDay, int nYear ) */

extern double TimeOfSunset ( double dblLatitude, double dLon, int nMonth, int nDay, int nYear )

   {
   double   dblMinutes  = TimeOfSunsetInMinutes ( DayOfYear ( nMonth, nDay, nYear ), dblLatitude, dLon );

   long     lnSeconds   = ( long ) ( dblMinutes * 60.0 + 0.5 );

   int      nHour       = ( int ) ( ( lnSeconds / 3600L ) % 24L );
   int      nMinute     = ( int ) ( ( lnSeconds /   60L ) % 60L );
   int      nSecond     = ( int ) ( ( lnSeconds /    1L ) % 60L );

   double   dblUTC      = CAL2JD ( nMonth, nDay, nYear, nHour, nMinute, nSecond, 0 ) + 1.0;

/* DumpJD2Civ ( stdout, "SS ", dblUTC ); */

   return dblUTC;

   }  /* extern double TimeOfSunset ( double dblLatitude, double dLon, int nMonth, int nDay, int nYear ) */

DateTime.c

/*********************************************************************************************
* Copyright (c) 2008 - 2010 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
*********************************************************************************************/

#include <TIME.H>

#include "DateTime.h"

#pragma warning ( disable : 4996 )

#define FALSE 0
#define TRUE ( ~FALSE )

typedef unsigned short int WORD;

typedef struct _SYSTEMTIME {

   WORD wYear;
   WORD wMonth;
   WORD wDayOfWeek;
   WORD wDay;
   WORD wHour;
   WORD wMinute;
   WORD wSecond;
   WORD wMilliseconds;

} SYSTEMTIME, * PSYSTEMTIME, * LPSYSTEMTIME;

extern __declspec ( dllimport ) void __stdcall GetSystemTime ( LPSYSTEMTIME lpSystemTime );

static BOOL g_fTzSet = FALSE;

/*********************************************************************************************************************
*                                                                                                                    *
*  MDY2GD and GD2MDY Derived from Algorithm 199 of the Collected Algorithms of the ACM                               *
*  see http://portal.acm.org/citation.cfm?doid=366707.390020                                                         *
*                                                                                                                    *
*  The functions MDY2GD() and GD2MDY() convert integer Gregorian Day Number back and forth between calendar dates.   *
*  The Gregorian Calendar was established in 1582 by Pope Gregory XIII and is the calendar that we currently use.    *
*  The Gregorian Day Number, modulo 7, returns a day of the week index where Sunday = 0.                             *
*                                                                                                                    *
*  The functions CAL2JD() and CALUTC() convert double precision floating point astronomical Julian Day number        *
*  back and forth between calendar dates.  Because of its astronomical origins, the Julian Day number changes        *
*  at noon so that it remains the same during a night of observations.                                               *
*                                                                                                                    *
*  "A full discussion of 'Julian Date' is likewise beyond the scope of this manual. It is                            *
*  interesting to note, however, that 'Julian Date' 0,0 was Greenwich Mean Time at noon                              *
*  on January 1, 4713 BC. It is a time scale widely used by astronomers because it is                                *
*  unambiguous, employs no leap-years, and because a single number represents both date                              *
*  and time. For convenience, Gemini's display of 'Julian Date' also includes the day of the                         *
*  week for the longitude of Greenwich, England."                                                                    *
*                                                                                                                    *
*  http://www.losmandy.com/losmandygoto/gemini_manual.pdf                                                            *
*                                                                                                                    *
*  Convert from Month/Day/Year to the Gregorian Day Index                                                            *
*                                                                                                                    *
*  month = 1 to 12                                                                                                   *
*  day   = ? to ?                                                                                                    *
*  year  = 1 to < 32768                                                                                              *
*********************************************************************************************************************/

long int MDY2GD ( int nMonth, int nDay, int nYear )

   {  /*                                     Jan   Feb   Mar   Apr   May   Jun   Jly   Aug   Sep   Oct   Nov   Dec   */
   static const int  nDays [ 13 ] = {    0,    0,  -31,  306,  275,  245,  214,  184,  153,  122,   92,   61,   31 };
   static const int  nBias [ 13 ] = {    0,    1,    1,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0 };

   long  nYears, nDate;

   nYears = nYear - nBias [ nMonth ];

   nDate = ( ( nYears / 100 ) * 146097l ) / 4
         + ( ( nYears % 100 ) *    1461 ) / 4
         - nDays [ nMonth ]
         + nDay;

   return nDate;

   }  /* long MDY2GD ( int nMonth, int nDay, int nYear ) */

/* Convert from Gregorian Day Index to Month/Day/Year */

void GD2MDY ( long int lnDate, int * pnMonth, int * pnDay, int * pnYear )

   {     /*                            Jan   Feb   Mar   Apr   May   Jun   Jly   Aug   Sep   Oct   Nov   Dec   */
   static const int  nBias [ 12 ] = {    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,  -10,  -10 };
   long              lnLD, lnYr, lnMo, lnDy;

   lnLD = 4 * ( lnDate + 306 ) - 1;

   lnYr = ( lnLD / 146097l ) * 100;
   lnDy = ( lnLD % 146097l ) /   4;

   lnLD = 4 * lnDy + 3;

   lnYr = ( lnLD / 1461 )     + lnYr;
   lnDy = ( lnLD % 1461 ) / 4 + 1;

   lnLD = 5 * lnDy - 3;

   lnMo = ( lnLD / 153 )     + 1;
   lnDy = ( lnLD % 153 ) / 5 + 1;

   * pnMonth   = ( int ) ( lnMo + nBias [ lnMo - 1 ] );
   * pnDay     = ( int ) ( lnDy );
   * pnYear    = ( int ) ( lnYr + lnMo/11 );

   }  /* void GD2MDY ( long lnDate, int * pnMonth, int * pnDay, int * pnYear ) */

/* Convert From Mo/Dy/Year hh:mm:ss.ms to the Julian Day Number */

double CAL2JD ( int nMo, int nDy, int nYear, int nHr, int nMn, int nSc, int nMs )

   {

   return   ( ( double ) MDY2GD ( nMo, nDy, nYear )   /* Gregorian Day Index        */

            + ( double ) nHr /       24.0             /* Hours Fraction             */
            + ( double ) nMn /     1440.0             /* Minutes Fraction           */
            + ( double ) nSc /    86400.0             /* Seconds Fraction           */
            + ( double ) nMs / 86400000.0             /* Milliseconds Fraction      */

            + 1721424.5 );                            /* Julian Day Number Offset   */

   }  /* double CAL2JD ( int nMo, int nDy, int nYear, int nHr, int nMn, int nSc, int nMs ) */

/* Convert From Julian Day Number To Mo/Dy/Year hh:mm:ss.ms */

void JD2CAL ( double jdDateTime, int * lpnMo, int * lpnDy, int * lpnYear, int * lpnHr, int * lpnMn, int * lpnSc, int * lpnMs )

   {
   long     lnTime;
   double   gdDate;

   /* Convert the Julian Day Number to the Gregorian Day Number                           */

   gdDate = jdDateTime - 1721424.5;                   /* Julian Day Number Offset         */

   /* Convert the Gregorian Day to the Gregorian Calendar Month, Day and lpnYear          */

   GD2MDY ( ( long ) gdDate, lpnMo, lpnDy, lpnYear ); /* Gregorian Day Index              */

   /* Extract the Gregorian Day Fraction ( 0.0 <= fraction < 1.0 ) and convert            */
   /* it into Milliseconds per Day:                                                       */

   /* Milliseconds per Day = Milliseconds per Second                                      */
   /*                      * Seconds      per Minute                                      */
   /*                      * Minutes      per Hour                                        */
   /*                      * Hours        per Day                                         */

   /* 1000 * 60 * 60 * 24 = 86400000                                                      */

   /* ( 0 <= lnTime < 86400000 )                                                          */

   lnTime = ( long ) ( ( gdDate - ( double ) ( ( long ) gdDate ) ) * 86400000.0 + 0.5 );

   /* Convert the Milliseconds to Hours, Minutes, Seconds and Milliseconds:               */
   /*                                                                                     */
   /* Unit = mod ( Milliseconds / Milliseconds per Unit, Units )                          */

   if ( lpnHr ) * lpnHr = ( int ) ( ( lnTime /  3600000L ) %   24L );   /* Hours          */
   if ( lpnMn ) * lpnMn = ( int ) ( ( lnTime /    60000L ) %   60L );   /* Minutes        */
   if ( lpnSc ) * lpnSc = ( int ) ( ( lnTime /     1000L ) %   60L );   /* Seconds        */

   if ( lpnMs ) * lpnMs = ( int ) ( ( lnTime /        1L ) % 1000L );   /* Milliseconds   */

   }  /* void JD2CAL ( double jdDateTime, int * lpnMo, int * lpnDy, int * lpnYear, int * lpnHr, int * lpnMn, int * lpnSc, int * lpnMs ) */

void GetTzInfo ( int * pnTimeZoneOffsetInHours, int * pfUseDaylightSavingsTime )

   {

   _tzset();

   * pnTimeZoneOffsetInHours  = -( _timezone / 3600L );
   * pfUseDaylightSavingsTime = _daylight;

   }  /* void GetTzInfo ( int * pnTimeZoneOffsetInHours, int * pfUseDaylightSavingsTime ) */

/* Compute the Starting and Ending Daylight Savings Times, for this Timezone, Adjusted to UTC Julian Day Numbers (NOT Civil) */

BOOL Year2DST ( int nYear, int nTimeZoneOffsetInHours, double * putcBeg, double * putcEnd )

   {
   int      nMo = 0, nDy = 0;
   double   dblTimeZoneOffset = nTimeZoneOffsetInHours / 24.0;

   /***************************************************************************************************
   *  "Starting in 2007, daylight time begins in the United States on the second Sunday in March      *
   *  and ends on the first Sunday in November. On the second Sunday in March, clocks are set ahead   *
   *  one hour at 2:00 a.m. local standard time, which becomes 3:00 a.m. local daylight time. On      *
   *  the first Sunday in November, clocks are set back one hour at 2:00 a.m. local daylight time,    *
   *  which becomes 1:00 a.m. local standard time. These dates were established by the                *
   *  Energy Policy Act of 2005, Pub. L. no. 109-58, 119 Stat 594 (2005)."                            *
   *                                                                                                  *
   *  see http://aa.usno.navy.mil/faq/docs/daylight_time.php                                          *
   *                                                                                                  *
   *  Compute the First Day of Daylight Savings Time for the Specified Year                           *
   *                                                                                                  *
   *  Note: Remember that the gd() of the last day of the prior month is the                          *
   *        same as the gd() of day zero of the current month.  The expression                        *
   *        Lo = gd ( 5, 0, nYear ), or day zero of May, returns the Gregorian                        *
   *        Day Index of April 30 of the specified year.  By taking advantage                         *
   *        of the fact that the Gregorian Day Index, modulo 7, returns a value                       *
   *        of 0 - 6 where 0 = Sunday, the expression "Lo = gd(5,0,nYear)/7*7;"                       *
   *        effectively truncates the date to the last sunday of the prior                            *
   *        month (April).                                                                            *
   *                                                                                                  *
   *        The expression "Lo = gd(4,0,nYear)/7*7 + 7;" takes advantage of the                       *
   *        fact that the second Sunday of the current month occurs 14 days after                     *
   *        the last Sunday of the prior month and the first Sunday of the current                    *
   *        month occurs 7 days after the last Sunday of the prior month.                             *
   *                                                                                                  *
   *        It starts at 2:00 a.m. (3:00 a.m. DST)                                                    *
   *        It ends   at 1:00 a.m. (2:00 a.m. DST)                                                    *
   *                                                                                                  *
   *  Only Handle Years After 2007                                                                    *
   *                                                                                                  *
   ***************************************************************************************************/

   if ( nYear < 2007 )
      return FALSE;

   /* Compute the First Day of Daylight Savings Time for the Specified Year   */

   GD2MDY ( MDY2GD ( 3, 0, nYear ) / 7 * 7 + 14, &nMo, &nDy, &nYear );
   * putcBeg = CAL2JD ( nMo, nDy, nYear, 2, 0, 0, 0 ) - dblTimeZoneOffset;

   /* Compute the Last Day of Daylight Savings Time for the Specified Year    */

   GD2MDY ( MDY2GD ( 11, 0, nYear ) / 7 * 7 + 7, &nMo, &nDy, &nYear );
   * putcEnd = CAL2JD ( nMo, nDy, nYear, 1, 0, 0, 0 ) - dblTimeZoneOffset;

   /* Return Success!   */

   return TRUE;

   }  /* BOOL Year2DST ( int nYear, int nTimeZoneOffsetInHours, double * putcBeg, double * putcEnd ) */

/* Convert from a UTC Date/Time Index to a Civil Date/Time Index and Tell Me if Daylight Savings Time is In Effect */

double UTC2Civil ( double utcDateTime, BOOL * pfDaylightSavingsInEffect, int nTimeZoneOffsetInHours, BOOL fUseDaylightSavingsTime )

   {
   double   civDateTime    = 0.0;

   double   utcBegDST      = 0.0;
   double   utcEndDST      = 0.0;

   int      nMonth         = 0;
   int      nDay           = 0;
   int      nYear          = 0;

   int      nHour          = 0;
   int      nMinute        = 0;
   int      nSecond        = 0;

   int      nMillisecond   = 0;

   /* Default to NOT Using Daylight Savings Time               */

   if ( pfDaylightSavingsInEffect )
      * pfDaylightSavingsInEffect = FALSE;

   /* Convert from UTC to Civil Time                           */

   civDateTime = utcDateTime + nTimeZoneOffsetInHours / 24.0;

   /* Adjust for Daylight Savings Time if Required             */

   if ( fUseDaylightSavingsTime )
      {

      /* Determine the UTC Year                                */

      JD2CAL ( utcDateTime, &nMonth, &nDay, &nYear, &nHour, &nMinute, &nSecond, &nMillisecond );

      /* Only Handle Years After 2007                          */

      if ( nYear < 2007 )
         return 0.0;

      /* Find Out When Daylight Savings Time Starts and Stops  */

      Year2DST ( nYear, nTimeZoneOffsetInHours, &utcBegDST, &utcEndDST );

      /* Handle the Daylight Savings Time Adjustment           */

      if ( utcDateTime >= utcBegDST && utcDateTime < utcEndDST )
         {
         if ( pfDaylightSavingsInEffect )
            * pfDaylightSavingsInEffect = TRUE;

         civDateTime += 1.0 / 24.0;
         }

      }  /* End - Adjust for Daylight Savings Time if Required */

   /* Return the Adjusted Time                                 */

   return civDateTime;

   }  /* double UTC2Civil ( double utcDateTime, BOOL * pfDaylightSavingsInEffect, int nTimeZoneOffsetInHours, BOOL fUseDaylightSavingsTime ) */

/* Convert from a Civil Date/Time Index to a UTC Date/Time Index and Tell Me if Daylight Savings Time Ambiguity */

double Civil2UTC ( double civDateTime, BOOL * pfDaylightSavingsAmbiguity, int nTimeZoneOffsetInHours, BOOL fUseDaylightSavingsTime )

   {
   double   utcDateTime = 0.0;
   int      nMonth = 0, nDay = 0, nYear = 0, nHour = 0, nMinute = 0, nSecond = 0, nMillisecond = 0;
   double   utcBegDST = 0.0, utcEndDST = 0.0;

   /* Default to No Ambiguity                                  */

   if ( pfDaylightSavingsAmbiguity )
      * pfDaylightSavingsAmbiguity = FALSE;

   /* Convert from Civil Time to UTC                           */

   utcDateTime = civDateTime - nTimeZoneOffsetInHours / 24.0;

   /* Adjust for Daylight Savings Time if Required             */

   if ( fUseDaylightSavingsTime )
      {

      /* Determine the UTC Year                                */

      JD2CAL ( civDateTime, &nMonth, &nDay, &nYear, &nHour, &nMinute, &nSecond, &nMillisecond );

      /* Only Handle Years After 2007                          */

      if ( nYear < 2007 )
         return 0.0;

      /* Find Out When Daylight Savings Time Starts and Stops  */

      Year2DST ( nYear, nTimeZoneOffsetInHours, &utcBegDST, &utcEndDST );

      /* Handle the Daylight Savings Time Adjustment           */

      if ( utcDateTime >= utcBegDST && utcDateTime < utcEndDST )
         {
         utcDateTime -= 1.0 / 24.0;

         if ( pfDaylightSavingsAmbiguity )
            {
            * pfDaylightSavingsAmbiguity = utcDateTime < ( utcBegDST + 1.0 / 24.0 ) || utcDateTime > ( utcEndDST - 1.0 / 24.0 );
            }
         }

      }  /* End - Adjust for Daylight Savings Time if Required */

   /* Return the Adjusted Time                                 */

   return utcDateTime;

   }  /* double Civil2UTC ( double civDateTime, BOOL * pfDaylightSavingsAmbiguity, int nTimeZoneOffsetInHours, BOOL fUseDaylightSavingsTime ) */

double CurrentTime ( void )

   {
   SYSTEMTIME stSystemTime = { 0 };

   GetSystemTime ( &stSystemTime );

   return CAL2JD ( stSystemTime.wMonth, stSystemTime.wDay, stSystemTime.wYear, stSystemTime.wHour, stSystemTime.wMinute, stSystemTime.wSecond, stSystemTime.wMilliseconds );

   }  /* double CurrentTime ( void ) */

/*
 * GetCivilTimeStamp takes a UTC Julian Day Number and Converts it into a TIMESTAMP_STRUCT for ODBC and SQL Server
 */

TIMESTAMP_STRUCT GetCivilTimeStamp ( double utcDateTime )

   {
   TIMESTAMP_STRUCT  stCivilTime    = { 0 };

   double            civDateTime    = 0.0;

   int               nMonth         = 0;
   int               nDay           = 0;
   int               nYear          = 0;
   int               nHour          = 0;
   int               nMinute        = 0;
   int               nSecond        = 0;
   int               nMillisecond   = 0;

   /* Convert the UTC Julian Day Number to a Civil Time Julian Day Number */

   civDateTime = UTC2Civil ( utcDateTime, NULL, -( _timezone / 3600L ), _daylight );

   /* Convert the Civil Time Julian Day Number into Months, Days, Years, Hours, Minutes, Seconds and Milliseconds */

   JD2CAL ( civDateTime, &nMonth, &nDay, &nYear, &nHour, &nMinute, &nSecond, &nMillisecond );

   /* Store the Date and Time into the TIMESTAMP_STRUCT */

   stCivilTime.month    = ( SQLUSMALLINT  ) nMonth;
   stCivilTime.day      = ( SQLUSMALLINT  ) nDay;
   stCivilTime.year     = ( SQLSMALLINT   ) nYear;
   stCivilTime.hour     = ( SQLUSMALLINT  ) nHour;
   stCivilTime.minute   = ( SQLUSMALLINT  ) nMinute;
   stCivilTime.second   = ( SQLUSMALLINT  ) nSecond;
   stCivilTime.fraction = ( SQLUINTEGER   ) ( nMillisecond * 1000000LU );

   /* Return the TIMESTAMP_STRUCT Representing the Date and Time as Civil Time */

   return stCivilTime;

   }  /* TIMESTAMP_STRUCT GetCivilTimeStamp ( STDISHSIGNALS & stDishSignals ) */

void DumpJD2UTC ( FILE * hFile, char * szLegend, double dblTimeUTC )

   {
   int nMo     = 0;
   int nDy     = 0;
   int nYear   = 0;
   int nHr     = 0;
   int nMn     = 0;
   int nSc     = 0;
   int nMs     = 0;

   JD2CAL ( dblTimeUTC, &nMo, &nDy, &nYear, &nHr, &nMn, &nSc, &nMs );

   fprintf ( hFile, "%s%2.2d/%2.2d/%4.4d %2.2d:%2.2d:%2.2d.%3.3d GMT\n", szLegend, nMo, nDy, nYear, nHr, nMn, nSc, nMs ); 

   }  /* void DumpJD2UTC ( FILE * hFile, char * szLegend, double dblTime ) */

void DumpJD2Civ ( FILE * hFile, char * szLegend, double dblTimeUTC )

   {
   int   nMo   = 0;
   int   nDy   = 0;
   int   nYear = 0;
   int   nHr   = 0;
   int   nMn   = 0;
   int   nSc   = 0;
   int   nMs   = 0;

   BOOL fDST   = FALSE;

   /* Convert to Civil Time */

   if ( ! g_fTzSet )
      {
      _tzset();
      g_fTzSet = TRUE;
      }

   JD2CAL ( UTC2Civil ( dblTimeUTC, &fDST, -( _timezone / 3600L ), _daylight ), &nMo, &nDy, &nYear, &nHr, &nMn, &nSc, &nMs );

   fprintf ( hFile, "%s%2.2d/%2.2d/%4.4d %2.2d:%2.2d:%2.2d.%3.3d %s\n", szLegend, nMo, nDy, nYear, nHr, nMn, nSc, nMs, fDST ? "MDT" : "MST" ); 

   }  /* void DumpJD2Civ ( FILE * hFile, char * szLegend, double dblTime ) */

char * myctime ( const time_t * plnTime )

   {
   static const char * pszMonth     []       = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly", "Aug", "Sep", "Oct", "Nov", "Dec" };
   static const char * pszDayOfWeek []       = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
   static char       szTime         [ 26 ]   = { 0 };

   long              lnTime                  = ( long ) ( * plnTime );
   long              gdNow                   = ( lnTime / 86400L ) + 719163L;
   double            dblTime                 = ( lnTime % 86400L ) / 86400.0;
   double            dblTimeUTC              = gdNow + dblTime + 1721424.5;

   int               nMo                     = 0;
   int               nDy                     = 0;
   int               nYear                   = 0;
   int               nHr                     = 0;
   int               nMn                     = 0;
   int               nSc                     = 0;
   int               nMs                     = 0;

   BOOL              fDST                    = FALSE;

   unsigned          uDayOfWeek              = 0U;

   /* Convert from UTC to Local Time */

   if ( ! g_fTzSet )
      {
      _tzset();
      g_fTzSet = TRUE;
      }

   JD2CAL ( UTC2Civil ( dblTimeUTC, &fDST, -( _timezone / 3600L ), _daylight ), &nMo, &nDy, &nYear, &nHr, &nMn, &nSc, &nMs );

   uDayOfWeek = MDY2GD ( nMo, nDy, nYear ) % 7L;

   /* Returned as "Mon Dec 15 19:41:22 2008\n\0" */

   _snprintf ( szTime, sizeof szTime, "%s %s %2d %2.2d:%2.2d:%2.2d %4.4d\n", pszDayOfWeek [ uDayOfWeek ], pszMonth [ nMo ], nDy, nHr, nMn, nSc, nYear );

   return szTime;

   }  /* char * myctime ( const time_t * plnTime ) */

void TimeStamp ( long * plnDate, long * plnMilliseconds )

   {
   SYSTEMTIME stSystemTime = { 0 };

   GetSystemTime ( &stSystemTime );

   * plnDate         = MDY2GD ( stSystemTime.wMonth, stSystemTime.wDay, stSystemTime.wYear );
   * plnMilliseconds = ( ( stSystemTime.wHour * 60L + stSystemTime.wMinute ) * 60L + stSystemTime.wSecond ) * 1000L + stSystemTime.wMilliseconds;

   }  /* void TimeStamp ( long * plnDate, long * plnMilliseconds ) */

Try.cpp

/************************************************************************************************
*                                                                                               *
*  Copyright (c) 2008 - 2010 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342   *
*                                                                                               *
*  This program computes the sunrise, solar noon and sunset for the current date.  Use the      *
*  Sunrise/Sunset Calculator at http://www.srrb.noaa.gov/highlights/sunrise/sunrise.html as a   *
*  check for accuracy.  So far, agreement is to within less than one minute.                    *
*                                                                                               *
*  To compile from the command line:  "CL Try.cpp DateTime.c Sunrise.c"                         *
*                                                                                               *
************************************************************************************************/

#define WIN32_LEAN_AND_MEAN            // Exclude Rarely-Used Stuff from Windows Headers

#include <WINDOWS.H>                   // Windows OS Prototypes and Defines

#include <STDIO.H>

#include "Sunrise.h"
#include "DateTime.h"

int main ( int /* argc */, char * /* argv */ [], char * /* envp */ [] )

   {

   // Get the Current Date and Time

   SYSTEMTIME stSystemTime = { 0U };

   GetSystemTime ( &stSystemTime );

   // Configure Latitude and Longitude to match the Albuquerque coordinates given by the NOAA
   // Sunrise Sunset Calculator.  Those values are given in Degrees, Minutes and Seconds.

   double   m_dblLatitude  =  35.0 +  5.0/60.0 + 0.0/3600.0;
   double   m_dblLongitude = 106.0 + 39.0/60.0 + 0.0/3600.0;

   // Compute the Times

   double m_dblJDSunrise   = TimeOfSunrise   ( m_dblLatitude,  m_dblLongitude, stSystemTime.wMonth, stSystemTime.wDay, stSystemTime.wYear );
   double m_dblJDSolarNoon = TimeOfSolarNoon (                 m_dblLongitude, stSystemTime.wMonth, stSystemTime.wDay, stSystemTime.wYear );
   double m_dblJDSunset    = TimeOfSunset    ( m_dblLatitude,  m_dblLongitude, stSystemTime.wMonth, stSystemTime.wDay, stSystemTime.wYear );

   // Display the Times

   DumpJD2Civ ( stdout, "SR ", m_dblJDSunrise   );
   DumpJD2Civ ( stdout, "SN ", m_dblJDSolarNoon );
   DumpJD2Civ ( stdout, "SS ", m_dblJDSunset    );

// DumpJD2UTC ( stdout, "SR ", m_dblJDSunrise   );
// DumpJD2UTC ( stdout, "SN ", m_dblJDSolarNoon );
// DumpJD2UTC ( stdout, "SS ", m_dblJDSunset    );

   return 0;

   }  // int main ( int argc, char * argv [], char * envp [] )