[net.sources] sunrise and sunset

rgb@nsc-pdc.UUCP (Robert Bond) (05/10/85)

I finally got around to a manual page for the sunrise sunset program I posted
a while ago.  Since I don't think the program got wide distribution, and
it's small, I threw it in too.

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	sun.c
#	sun.1
#	makefile
# This archive created: Fri May 10 11:35:00 1985
# By:	Robert Bond (NSC Portland, Orygun)
echo shar: extracting sun.c '(10571 characters)'
sed 's/^XX//' << \SHAR_EOF > sun.c
XX/* sun.c
XX* 
XX*        sun <options>
XX*
XX*        options:        -t hh:mm:ss	time (default is current system time)
XX*			 -d mm/dd/yy	date (default is current system date)
XX*                        -a lat		decimal latitude (default = 45.5333)
XX*                        -o lon		decimal longitude (default = 122.8333) 
XX*			 -z tz		timezone (default = 8, pst)
XX*			 -p		show position of sun (azimuth)
XX*        
XX*        All output is to standard io.  
XX*
XX*	 Compile with cc -O  -o sun -lm
XX*	 Non 4.2 systems may have to change <sys/time.h> to <time.h> below.
XX*
XX*	 Note that the latitude, longitude, time zone correction and
XX*	 time zone string are all defaulted in the global variable section.
XX*
XX*	 Most of the code in this program is adapted from algorithms
XX*	 presented in "Practical Astronomy With Your Calculator" by
XX*	 Peter Duffet-Smith.
XX*
XX*	 The GST and ALT-AZIMUTH algorithms are from Sky and Telescope,
XX*	 June, 1984 by Roger W. Sinnott
XX*
XX*	 Author Robert Bond - Beaverton Oregon.
XX*	
XX*/
XX
XX#include <stdio.h>
XX#include <math.h>
XX#include <sys/types.h>
XX#include <sys/time.h>
XX
XX#define PI       3.141592654
XX#define EPOCH	 1980
XX#define JDE	 2444238.5	/* Julian date of EPOCH */
XX
XXdouble dtor();
XXdouble adj360();
XXdouble adj24();
XXdouble julian_date();
XXdouble hms_to_dh();
XXdouble solar_lon();
XXdouble acos_deg();
XXdouble asin_deg();
XXdouble atan_q_deg();
XXdouble atan_deg();
XXdouble sin_deg();
XXdouble cos_deg();
XXdouble tan_deg();
XXdouble gmst();
XX
XXint th;
XXint tm;
XXint ts;
XXint mo;
XXint day;
XXint yr;
XXint tz=8;			/* Default time zone */
XXchar *tzs = "(PST)";		/* Default time zone string */
XXchar *dtzs = "(PDT)";		/* Default daylight savings time string */
XXint popt = 0;
XX
XXdouble lat = 45.5333;		/* Default latitude (Beaverton Ore.) */
XXdouble lon = 122.8333;		/* Default Longitude (Degrees west) */ 
XX
XXmain(argc,argv)
XXint argc;
XXchar *argv[];
XX{
XX    double ed, jd;
XX    double alpha1, delta1, alpha2, delta2, st1r, st1s, st2r, st2s;
XX    double a1r, a1s, a2r, a2s, dt, dh, x, y;
XX    double trise, tset, ar, as, alpha, delta, tri, da;
XX    double lambda1, lambda2;
XX    double alt, az, gst, m1;
XX    double hsm, ratio;
XX    time_t sec_1970;
XX    int h, m;
XX    struct tm *pt;
XX
XX    sec_1970 = time((time_t *)0);  
XX    pt = localtime(&sec_1970);  
XX
XX    th = pt->tm_hour;
XX    tm = pt->tm_min;
XX    ts = pt->tm_sec;
XX    yr = pt->tm_year + 1900;
XX    mo = pt->tm_mon + 1;
XX    day = pt->tm_mday;
XX    if (pt->tm_isdst) {		/* convert tz to daylight savings time */
XX	tz--;
XX	tzs = dtzs;	
XX    }
XX
XX    initopts(argc,argv);
XX
XX    jd = julian_date(mo,day,yr);
XX    ed = jd - JDE;
XX
XX    lambda1 = solar_lon(ed);
XX    lambda2 = solar_lon(ed + 1.0);
XX
XX    lon_to_eq(lambda1, &alpha1, &delta1);
XX    lon_to_eq(lambda2, &alpha2, &delta2);
XX
XX    rise_set(alpha1, delta1, &st1r, &st1s, &a1r, &a1s);
XX    rise_set(alpha2, delta2, &st2r, &st2s, &a2r, &a2s);
XX
XX    m1 = adj24(gmst(jd - 0.5, 0.5 + tz / 24.0) - lon / 15); /* lst midnight */
XX    hsm = adj24(st1r - m1);
XX    ratio = hsm / 24.07;
XX
XX    if (fabs(st2r - st1r) > 1.0) {
XX	st2r += 24.0;
XX    }
XX
XX    trise = adj24((1.0 - ratio) * st1r + ratio * st2r);
XX
XX    hsm = adj24(st1s - m1);
XX    ratio = hsm / 24.07;
XX
XX    if (fabs(st2s - st1s) > 1.0) {
XX	st2s += 24.0;
XX    }
XX
XX    tset = adj24((1.0 - ratio) * st1s + ratio * st2s);
XX
XX    ar = a1r * 360.0 / (360.0 + a1r - a2r);
XX    as = a1s * 360.0 / (360.0 + a1s - a2s);
XX
XX    delta = (delta1 + delta2) / 2.0;
XX    tri = acos_deg(sin_deg(lat)/cos_deg(delta));
XX
XX    x = 0.835608;	/* correction for refraction, parallax, size of sun */
XX    y = asin_deg(sin_deg(x)/sin_deg(tri));
XX    da = asin_deg(tan_deg(x)/tan_deg(tri));
XX    dt = 240.0 * y / cos_deg(delta) / 3600;
XX
XX    lst_to_hm(trise - dt, jd, &h, &m);
XX    printf("Sunrise: %2d:%02d    ", h, m);
XX
XX    if (popt) {
XX        dh_to_hm(ar - da, &h, &m);
XX        printf("Azimuth: %2d deg %02d min \n", h, m);
XX    }
XX
XX    lst_to_hm(tset + dt, jd, &h, &m);
XX    printf("Sunset:  %2d:%02d    ", h, m);
XX
XX    if (popt) {
XX        dh_to_hm(as + da, &h, &m);
XX        printf("Azimuth: %2d deg %02d min \n", h, m);
XX    } else 
XX        printf("%s \n",tzs);
XX
XX    if (popt) {
XX
XX	if (alpha1 < alpha2)
XX	    alpha = (alpha1 + alpha2) / 2.0;
XX	else
XX	    alpha = (alpha1 + 24.0 + alpha2) / 2.0;
XX	
XX	if (alpha > 24.0)
XX	    alpha -= 24.0;
XX
XX	dh = (hms_to_dh(th, tm, ts) + tz) / 24.0;
XX	if (dh > 0.5) {
XX	    dh -= 0.5;
XX	    jd += 0.5;
XX	} else {
XX	    dh += 0.5;
XX	    jd -= 0.5;
XX	}
XX
XX	gst = gmst(jd, dh);
XX
XX	eq_to_altaz(alpha, delta, gst, &alt, &az);
XX
XX	printf("The sun is at ");
XX	dh_to_hm(alt, &h, &m);
XX	printf(" altitude: %2d deg %02d min", h, m);
XX	dh_to_hm(az, &h, &m);
XX	printf("   azimuth:  %2d deg %02d min. \n", h, m);
XX    }
XX}
XX
XXdouble
XXdtor(deg)
XXdouble deg;
XX{
XXreturn (deg * PI / 180.0);
XX}
XX
XXdouble
XXrtod(deg)
XXdouble deg;
XX{
XX    return (deg * 180.0 / PI);
XX}
XX
XX
XXdouble 
XXadj360(deg)
XXdouble deg;
XX{
XX    while (deg < 0.0) 
XX	deg += 360.0;
XX    while (deg > 360.0)
XX	deg -= 360.0;
XX    return(deg);
XX}
XX
XXdouble 
XXadj24(hrs)
XXdouble hrs;
XX{
XX    while (hrs < 0.0) 
XX	hrs += 24.0;
XX    while (hrs > 24.0)
XX	hrs -= 24.0;
XX    return(hrs);
XX}
XX
XXinitopts(argc,argv)
XXint argc;
XXchar *argv[];
XX{
XX    int ai;
XX    char *ca;
XX    char *str;
XX
XX    while (--argc) {
XX        if ((*++argv)[0] == '-') {
XX	    ca = *argv;
XX	    for(ai = 1; ca[ai] != '\0'; ai++)
XX                switch (ca[ai]) {
XX		case 'p':
XX		    popt++;
XX		    break;
XX                case 'a':
XX                    str = *++argv;
XX		    if (sscanf(str, "%lf", &lat) != 1)
XX			usage();
XX                    argc--;
XX                    break;
XX                case 'o':
XX                    str = *++argv;
XX		    if (sscanf(str, "%lf", &lon) != 1)
XX			usage();
XX                    argc--;
XX                    break;
XX                case 'z':
XX                    str = *++argv;
XX		    if (sscanf(str, "%d", &tz) != 1)
XX			usage();
XX		    tzs = "   ";
XX                    argc--;
XX                    break;
XX                case 't':
XX                    str = *++argv;
XX		    if (sscanf(str, "%d:%d:%d", &th, &tm, &ts) != 3)
XX			usage();
XX                    argc--;
XX                    break;
XX                case 'd':
XX                    str = *++argv;
XX		    if (sscanf(str, "%d/%d/%d", &mo, &day, &yr) != 3)
XX			usage();
XX                    argc--;
XX                    break;
XX                default: usage();
XX                }
XX        } else usage();
XX    }
XX}
XX
XXusage()
XX{
XX    printf("Usage: sun [-p] [-t h:m:s] [-d m/d/y] [-a lat] [-o lon] [-z tz]\n");
XX    exit(1);
XX}
XX
XXdouble 
XXjulian_date(m, d, y)
XX{
XX    int a, b;
XX    double jd;
XX
XX    if (m == 1 || m == 2) {
XX	--y;
XX	m += 12;
XX    }
XX    if (y < 1583) {
XX	printf("Can't handle dates before 1583 \n");
XX	exit(1);
XX    }
XX    a = y/100;
XX    b = 2 - a + a/4;
XX    b += (int)((double)y * 365.25);
XX    b += (int)(30.6001 * ((double)m + 1.0));
XX    jd = (double)d + (double)b + 1720994.5;
XX    return(jd);
XX}
XX
XXdouble 
XXhms_to_dh(h, m, s)
XX{
XX    double rv;
XX
XX    rv = h + m / 60.0 + s / 3600.0;
XX    return rv;
XX}
XX
XXdouble 
XXsolar_lon(ed)
XXdouble ed;
XX{
XX    double n, m, e, ect, errt, v;
XX
XX    n = 360.0 * ed / 365.2422;
XX    n = adj360(n);
XX    m = n + 278.83354 - 282.596403;
XX    m = adj360(m);
XX    m = dtor(m);
XX    e = m; ect = 0.016718;
XX    while ((errt = e - ect * sin(e) - m) > 0.0000001) 
XX        e = e - errt / (1 - ect * cos(e));
XX    v = 2 * atan(1.0168601 * tan(e/2));
XX    v = adj360(v * 180.0 / PI + 282.596403);
XX    return(v);
XX}
XX
XXdouble 
XXacos_deg(x)
XXdouble x;
XX{
XX    return rtod(acos(x));
XX}
XX
XXdouble 
XXasin_deg(x)
XXdouble x;
XX{
XX    return rtod(asin(x));
XX}
XX
XXdouble 
XXatan_q_deg(y,x)
XXdouble y,x;
XX{
XX    double rv;
XX
XX    if (y == 0)
XX        rv = 0;
XX    else if (x == 0)
XX        rv = y>0 ? 90.0 : -90.0;
XX    else rv = atan_deg(y/x);
XX
XX    if (x<0) return rv+180.0;
XX    if (y<0) return rv+360.0;
XX    return(rv);
XX}
XX
XXdouble
XXatan_deg(x)
XXdouble x;
XX{
XX    return rtod(atan(x));
XX}
XX
XXdouble 
XXsin_deg(x)
XXdouble x;
XX{
XX    return sin(dtor(x));
XX}
XX
XXdouble 
XXcos_deg(x)
XXdouble x;
XX{
XX    return cos(dtor(x));
XX}
XX
XXdouble 
XXtan_deg(x)
XXdouble x;
XX{
XX    return tan(dtor(x));
XX}
XX
XXlon_to_eq(lambda, alpha, delta)
XXdouble lambda;
XXdouble *alpha;
XXdouble *delta;
XX{
XX    double tlam,epsilon;
XX
XX    tlam = dtor(lambda);
XX    epsilon = dtor((double)23.441884);
XX    *alpha = atan_q_deg((sin(tlam))*cos(epsilon),cos(tlam)) / 15.0;
XX    *delta = asin_deg(sin(epsilon)*sin(tlam));
XX}
XX
XXrise_set(alpha, delta, lstr, lsts, ar, as)
XXdouble alpha, delta, *lstr, *lsts, *ar, *as;
XX{
XX    double tar;
XX    double h;
XX
XX    tar = sin_deg(delta)/cos_deg(lat);
XX    if (tar < -1.0 || tar > 1.0) {
XX	printf("The object is circumpolar \n");
XX	exit (1);
XX    }
XX    *ar = acos_deg(tar);
XX    *as = 360.0 - *ar;
XX
XX    h = acos_deg(-tan_deg(lat) * tan_deg(delta)) / 15.0;
XX    *lstr = 24.0 + alpha - h;
XX    if (*lstr > 24.0)
XX	*lstr -= 24.0;
XX    *lsts = alpha + h;
XX    if (*lsts > 24.0)
XX	*lsts -= 24.0;
XX}
XX
XXlst_to_hm(lst, jd, h, m)
XXdouble lst, jd;
XXint *h, *m;
XX{
XX    double ed, gst, jzjd, t, r, b, t0, gmt;
XX
XX    gst = lst + lon / 15.0;
XX    if (gst > 24.0)
XX	gst -= 24.0;
XX    jzjd = julian_date(1,0,yr);
XX    ed = jd-jzjd;
XX    t = (jzjd -2415020.0)/36525.0;
XX    r = 6.6460656+2400.05126*t+2.58E-05*t*t;
XX    b = 24-(r-24*(yr-1900));
XX    t0 = ed * 0.0657098 - b;
XX    if (t0 < 0.0)
XX	t0 += 24;
XX    gmt = gst-t0;
XX    if (gmt<0) 
XX	gmt += 24.0;
XX    gmt = gmt * 0.99727 - tz;;
XX    if (gmt < 0)
XX	gmt +=24.0;
XX    dh_to_hm(gmt, h, m);
XX}
XX
XXdh_to_hm(dh, h, m)
XXdouble dh;
XXint *h, *m;
XX{
XX    double tempsec;
XX
XX    *h = dh;
XX    *m = (dh - *h) * 60;
XX    tempsec = (dh - *h) * 60 - *m;
XX    tempsec = tempsec * 60 + 0.5;
XX    if (tempsec > 30)
XX	(*m)++;
XX    if (*m == 60) {
XX	*m = 0;
XX	(*h)++;
XX    }
XX}
XX
XXeq_to_altaz(r, d, t, alt, az)
XXdouble r, d, t;
XXdouble *alt, *az;
XX{
XX    double p = 3.14159265;
XX    double r1 = p / 180.0;
XX    double b = lat * r1;
XX    double l = (360 - lon) * r1;
XX    double t5, s1, c1, c2, s2, a, h;
XX
XX    r = r * 15.0 * r1;
XX    d = d * r1;
XX    t = t * 15.0 * r1;
XX    t5 = t - r + l;
XX    s1 = sin(b) * sin(d) + cos(b) * cos(d) * cos(t5);
XX    c1 = 1 - s1 * s1;
XX    if (c1 > 0) {
XX	c1 = sqrt(c1);
XX	h = atan(s1 / c1);
XX    } else {
XX	h = (s1 / fabs(s1)) * (p / 2.0);
XX    }
XX    c2 = cos(b) * sin(d) - sin(b) * cos(d) * cos(t5);
XX    s2 = -cos(d) * sin(t5);
XX    if (c2 == 0) 
XX	a = (s2/fabs(s2)) * (p/2);
XX    else {
XX	a = atan(s2/c2);
XX	if (c2 < 0)
XX	    a=a+p;
XX    }
XX    if (a<0)
XX        a=a+2*p;
XX    *alt = h / r1;
XX    *az = a / r1;
XX}
XX
XXdouble
XXgmst(j, f)
XXdouble j,f;
XX{
XX    double d, j0, t, t1, t2, s;
XX
XX    d = j - 2451545.0;
XX    t = d / 36525.0;
XX    t1 = floor(t);
XX    j0 = t1 * 36525.0 + 2451545.0;
XX    t2 = (j - j0 + 0.5)/36525.0;
XX    s = 24110.54841 + 184.812866 * t1; 
XX    s += 8640184.812866 * t2;
XX    s += 0.093104 * t * t;
XX    s -= 0.0000062 * t * t * t;
XX    s /= 86400.0;
XX    s -= floor(s);
XX    s = 24 * (s + (f - 0.5) * 1.002737909);
XX    if (s < 0)
XX	s += 24.0;
XX    if (s > 24.0)
XX	s -= 24.0;
XX    return(s);
XX}
XX	
XX    
SHAR_EOF
if test 10571 -ne "`wc -c sun.c`"
then
echo shar: error transmitting sun.c '(should have been 10571 characters)'
fi
echo shar: extracting sun.1 '(1625 characters)'
sed 's/^XX//' << \SHAR_EOF > sun.1
XX.TH SUN 1 "9 May 1985"
XX.UC 4
XX.SH NAME
XXsun \- calculate sunrise and sunset times
XX.SH SYNOPSIS
XX.B sun
XX[
XX.B \-p 
XX]
XX[
XX.B -t \fIh:m:s\fP 
XX]
XX[
XX.B -d \fIm/d/y\fP 
XX]
XX[
XX.B -a \fIlat\fP 
XX]
XX[
XX.B -o \fIlon\fP 
XX]
XX [
XX.B -z \fItz\fP 
XX]
XX.LP
XX.SH DESCRIPTION
XX.I  Sun
XXCalculates the times of sunrise and sunset for the current system date.
XXOptionally,
XX.I sun
XXcalculates the current position of the sun and its position at sunrise and
XXsunset for other dates, times and places.
XX.PP
XXThe command line options are:
XX.TP
XX.B \-p 
XXShow current altitude and azimuth for the sun and its azimuth 
XXat sunrise and sunset.
XX.TP
XX.B -t \fIh:m:s\fP 
XXUse \fIh:m:s\fP as local hours (24 hour clock), minutes and  seconds as
XXthe time instead of the current system time.
XX.TP
XX.B -d \fIm/d/y\fP 
XXUse \fIm/d/y\fP as the month, day and year instead of the current system date.
XX.TP
XX.B -a \fIlat\fP 
XXUse \fIlat\fP as the latitude of the observer, instead of the system latitude.
XXThe latitude is specified in decimal degrees north.  For example, use 
XX45.5333 for Beaverton, Oregon.
XX.TP
XX.B -o \fIlon\fP 
XXUse \fIlon\fP as the longitude of the observer, instead of the system longitude.
XXThe longitude is specified in decimal degrees west.  For example, use 
XX122.8333 for Beaverton, Oregon.
XX.TP
XX.B -z \fItz\fP 
XXUse \fItz\fP as the time zone of the observer, instead of the current system
XXtimezone.  Timezone is specified as a positive number for locations west of
XXGreenwich.  For example, use 8 for Pacific Standard Time.
XX.SH AUTHOR
XXRobert Bond
XX.SH BUGS
XXShould figure out timezone and guess at longitude from the system time.  
XXTimezone, latitude and longitude are compiled in.
SHAR_EOF
if test 1625 -ne "`wc -c sun.1`"
then
echo shar: error transmitting sun.1 '(should have been 1625 characters)'
fi
echo shar: extracting makefile '(82 characters)'
sed 's/^XX//' << \SHAR_EOF > makefile
XX
XXsun:	sun.c
XX	cc -O -o sun sun.c -lm
XX    
XXmanual:	sun.1
XX	nroff -man sun.1 >sun.doc
SHAR_EOF
if test 82 -ne "`wc -c makefile`"
then
echo shar: error transmitting makefile '(should have been 82 characters)'
fi
#	End of shell archive
exit 0
-- 
    Robert Bond 			nsc!nsc-pdc!rgb
    National Semiconductor		tektronix!reed!nsc-pdc!rgb