home *** CD-ROM | disk | FTP | other *** search
- Subject: Sun and Moon rise/set program
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- Mod.sources: Volume 5, Issue 10
- Submitted by: Marc Kaufman <talcott!su-shasta.arpa:kaufman>
-
- Enclosed is a -C- program to compute sun and moon rise and set times.
- Have fun. The version below is the running source for a VAX.
- Send bugs (if any) to <kaufman@SU-Shasta> at Stanford.
-
- ---------------------CUT HERE---------------------CUT HERE------------
- /* <sdate.c>
- * Compute various useful times
- *
- * Written by Marc T. Kaufman
- * 14100 Donelson Place
- * Los Altos Hills, CA 94022
- * (415) 948-3777
- *
- * Based on : "Explanatory Supplement to the Astronomical Ephemeris
- * and the American Ephemeris and Nautical Almanac",
- * H.M. Nautical Almanac Office, London. Updated from
- * equations in the 1985 Astronomical Almanac.
- *
- * Copyright 1986 by Marc Kaufman
- *
- * Permission to use this program is granted, provided it is not sold.
- *
- * This program was originally written on a VAX, under 4.2bsd.
- * it was then ported to a 68000 system under REGULUS (Alcyon's version
- * of UNIX system III). Major differences included: no 'double' and
- * a default integer length of 'short'. Having been through all that,
- * porting to your machine should be easy. Watch out for 'time' related
- * functions and make sure your 'atan2' program works right.
- *
- * 850210 revised to 1985 Ephemeris - mtk
- */
-
- #include <time.h>
- #include <sys/types.h>
- #include <sys/timeb.h>
- #include <stdio.h>
- #include <math.h>
-
- long UTC, TDT, tim, tim2, localdst;
- double Julian_Day, MJD, Tu, Ru, T70, Local, GMST, LST;
- double Eqt, Tua, L, G, e, eps, g, alpha, delta, sd, cd, lha, lhr, sh, ch;
- double la, lf, S, C, sp, cp, tp, Az, alt;
- double Lm, lm, px, SD, am, dm;
- double zs, x;
- double fabs(), fmod(), asin(), acos();
- struct tm *t, *Rlocaltime(), *gmtime();
- char *tdate, *gmctime(), *localctime();
- int ftime();
- struct timeb tb;
-
- #define Pi 3.1415926535
- #define Degree_to_Radian ((2.0 * Pi)/ 360.)
- #define Asec_Radian ((2.0 * Pi)/(360. * 60. * 60.))
- #define Tsec_to_Radian ((2.0 * Pi)/( 24. * 60.* 60.))
- #define Asec_to_Tsec (24./360.)
- #define Sec_per_day (24 * 60 * 60)
- #define Round 0.5 /* for rounding to integer */
-
- #define J1900 /* 24 */15020.0 /* Julian Day number at Epoch 1900.0 */
- #define J1970 /* 24 */40587.5 /* VAX clock Epoch 1970 Jan 1 (0h UT) */
- #define J1985 /* 24 */46065.5 /* Epoch 1985 Jan 1 (0h UT) */
- #define J2000 /* 24 */51545.0 /* Epoch 2000 Jan 1 (12h UT) */
- #define Delta_T (54.6 + 0.9*(Julian_Day - J1985)/365.) /* TDT - UT */
- /* (This is the position of my house ) */
- #define Longitude (((122.)*60. + 8.)*60. + 3.) /* Arc-seconds West */
- #define Latitude ((( 37.)*60. + 22.)*60. + 58.) /* Arc-seconds North */
- #define f1 (1. - (1./298.25)) /* 1 - flattening of Earth */
- /* the following alternate values are useful when debugging */
- /*#define Longitude (((000.)*60. + 0.)*60. + 0.) /* Arc-seconds West */
- /*#define Latitude ((( 35.)*60. + 0.)*60. + 0.) /* Arc-seconds North */
- /*#define f1 1. /* 1 - flattening of Earth */
-
- main() {
-
- /* at this point we digress to discuss UNIX differences.
- * In UCB UNIX we dont have ctime(), but do instead have asctime(),
- * which works from the structures created by gmtime() and localtime().
- * However, system time is kept in UTC (Greenwich), and the localtime
- * routine correctly handles daylight savings time.
- * Since the Regulus system only knows local time, a few direct
- * fiddles are needed.
- */
-
- /* correct apparent latitude for shape of Earth */
-
- lf= atan(f1*f1 * tan(Latitude * Asec_Radian));
- sp= sin(lf);
- cp= cos(lf);
- tp= sp/cp;
-
- time(&UTC); /* get time */
- Local= - Longitude/15.; /* Local apparent time correction */
-
- { int h, m, s; /* manual entry mode */
- /* time(&tim);
- t= gmtime(&tim);
- tim= tim - (60 * (60 * t->tm_hour + t->tm_min) + t->tm_se);
- scanf("%d %d %d", &h, &m, &s);
- {UTC = tim + 60 * (60 * h + m) + s;
- */ }
-
- /* ! t= gmtime(&UTC); /* this is Regulus time */
- t= localtime(&UTC); /* VAX version */
-
- /* Compute delta to real UTC from time zone time */
-
- /* do this by hand since Regulus wont */
-
- switch (t->tm_mon + 1) /* months are numbered from 0 */
- {
- case 1:
- case 2:
- case 3:
- case 11:
- case 12:
- t->tm_isdst = 0;
- break;
-
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- t->tm_isdst = 1;
- break;
-
- case 4:
- if ((t->tm_mday < 24) || (t->tm_mday - t->tm_wday <= 24))
- t->tm_isdst = 0;
- else
- t->tm_isdst = 1;
- break;
-
- case 10:
- if ((t->tm_mday < 25) || (t->tm_mday - t->tm_wday <= 25))
- t->tm_isdst = 1;
- else
- t->tm_isdst = 0;
- break;
- }
- ftime(&tb); /* gets time-zone information */
- if (tb.dstflag == 0)
- t->tm_isdst = 0; /* dst never used here */
- localdst = (-tb.timezone + t->tm_isdst*60) * 60L; /* local time correction */
-
- /* ! UTC -= localdst; /* this is real UTC, not what the OS gave us! */
- printf("%.24s GMT\n", gmctime(&UTC));
-
- stuff(UTC); /* start with local time info */
-
- /* Compute Terrestrial Dynamical Time (this used to be called Ephemeris Time) */
-
- TDT = UTC + (long)(Delta_T + Round);
- tdate= gmctime(&TDT);
- printf(" %.8s Terrestrial Dynamical Time\n", tdate+11);
-
- printf("%.24s Local Civil Time\n", localctime(&UTC));
-
- tim2 = UTC + (long)(Local + Round); /* Compute Local Solar Time */
- tdate= gmctime(&tim2);
- printf(" %.8s Local Mean Time\n", tdate+11);
-
- /* compute phase of moon */
-
- moondata(UTC);
- Lm = fmod(Lm-L, 360.); /* phase is Lm - L (longitude of Sun) */
- lm = fmod(Lm, 90.); /* excess over phase boundary */
- printf("The Moon is%4.1f days past ", lm*36525./481267.883);
- if (Lm < 90.) printf("New\n");
- else if (Lm < 180.) printf("First Quarter\n");
- else if (Lm < 270.) printf("Full\n");
- else printf("Last Quarter\n");
-
- printf("Julian Day 24%9.3f\n", Julian_Day);
-
- tim2 = GMST + Round;
- tdate= gmctime(&tim2);
- printf(" %.8s Greenwich Mean Sidereal Time\n", tdate+11);
-
- tim2 = LST + Round;
- tdate= gmctime(&tim2);
- printf(" %.8s Local Sidereal Time\n", tdate+11);
-
- tim2= lha + Round;
- tdate= gmctime(&tim2);
- printf(" %.8s L.H.A. of Sun\n", tdate+11);
- printf(" %11.3f Degrees Declnation\n",delta/3600.);
- printf("Azimuth %11.3f Degrees\n",Az/3600.);
- printf("Elevation %11.3f Degrees\n",alt/3600.);
-
- /* compute sunrise and sunset */
- t= Rlocaltime(&UTC); /* compute start of day */
- tim = UTC - (3600L * t->tm_hour + 60L * t->tm_min + t->tm_sec)
- + Sec_per_day/2; /* about noon */
-
- zs = 90. + 50./60.; /* zenith angle of rise/set */
- sunrise(tim, -1.0, zs, "Sunrise ");
- printf(" ");
- sunrise((long)(tim+Sec_per_day), -1.0, zs, "Tomorrow");
- printf("\n");
- sunrise(tim, 1.0, zs, "Sunset ");
- printf(" ");
- sunrise((long)(tim+Sec_per_day), 1.0, zs, "Tomorrow");
- printf("\n");
-
- /* compute moonrise and moonset */
- tim = tim - Sec_per_day/2 - 31; /* about start of day */
-
- zs = 90. + 34./60.; /* zenith angle of rise/set */
- moonrise(tim, -1.0, zs, "Moonrise");
- printf(" ");
- moonrise((long)(tim+Sec_per_day), -1.0, zs, "Tomorrow");
- printf("\n");
- moonrise(tim, 1.0, zs, "Moonset ");
- printf(" ");
- moonrise((long)(tim+Sec_per_day), 1.0, zs, "Tomorrow");
- printf("\n");
- }
-
- sunrise(t0, rs, z, s)
- long t0;
- double rs, z;
- char *s;
- {
- double cz, dh;
- long dt;
-
- cz = cos(z * Degree_to_Radian); /* zenith distance of phenomonon */
-
- do { /* iterate */
- stuff(t0); /* compute declination and current hour angle */
- dh= -tp*sd/cd + cz/(cp*cd);
- if ((dh < -1.0) || (dh > 1.0)) {
- printf("%.8s none ", s);
- return;
- }
- dh=acos(dh)*rs;
- dt= (dh - lhr) / Tsec_to_Radian;
- t0 += dt;
- } while (dt);
-
- t0 += 30 /* seconds, rounding to nearest minute */;
- tdate= localctime(&t0);
- printf("%.8s %.5s ", s, tdate+11);
- }
-
- moonrise(t0, rs, z, s)
- long t0;
- double rs, z;
- char *s;
- {
- #define SRATE 1.033863192 /* ratio of Moon's motion to Sun's motion */
- double cz, dh, sd, cd;
- long t1, dt;
-
- moondata(t0); /* get starting declination of Moon */
-
- /* compute zenith distance of phenomonon */
- cz = cos(z * Degree_to_Radian + SD /* -px */);
-
- /* first iteraton is forward only (to approx. phenom time) */
- sd = sin(dm);
- cd = cos(dm);
- dh= -tp*sd/cd + cz/(cp*cd);
- if ((dh < -1.0) || (dh > 1.0)) {
- printf("%.8s none ", s);
- return;
- }
- dh= acos(dh)*rs;
- dt= fmod((dh - am), 2.0*Pi) * SRATE / Tsec_to_Radian;
- t1 = t0 + dt;
-
- do { /* iterate */
- moondata(t1); /* compute declination and current hour angle */
- cz = cos(z * Degree_to_Radian + SD /* -px */);
- sd = sin(dm);
- cd = cos(dm);
-
- dh= -tp*sd/cd + cz/(cp*cd);
- if ((dh < -1.0) || (dh > 1.0)) {
- printf("%.8s none ", s);
- return;
- }
- dh= acos(dh)*rs;
- dt= (dh - am) * SRATE / Tsec_to_Radian;
- t1 += dt;
- } while (dt);
-
- if ((t1 - t0) >= Sec_per_day) {
- printf("%.8s none ", s);
- return;
- }
- t1 += 30 /* seconds, rounding to nearest minute */;
- tdate= localctime(&t1);
- printf("%.8s %.5s ", s, tdate+11);
- }
-
- stuff(tim)
- long tim;
- { /* main computation loop */
-
- timedata(tim);
-
- /* where is the Sun (angles are in seconds of arc) */
- /* Low precision elements from 1985 Almanac */
-
- L= 280.460 + 0.9856474 * MJD; /* Mean Longitde */
- L = fmod(L, 360.); /* corrected for aberration */
-
- g= 357.528 + 0.9856003 * MJD; /* Mean Anomaly */
- g = fmod(g, 360.);
-
- eps= 23.439 - 0.0000004 * MJD; /* Mean Obiquity of Ecliptic */
-
- { /* convert to R.A. and DEC */
- double Lr, gr, epsr, lr, ca, sa, R;
- double sA, cA, gphi;
-
- Lr = L * Degree_to_Radian;
- gr = g * Degree_to_Radian;
- epsr = eps * Degree_to_Radian;
-
- lr = (L + 1.915*sin(gr) + 0.020*sin(2.0*gr)) * Degree_to_Radian;
-
- sd = sin(lr) * sin(epsr);
- cd = sqrt(1.0 - sd*sd);
- sa = sin(lr) * cos(epsr);
- ca = cos(lr);
-
- delta = asin(sd);
- alpha = atan2(sa, ca);
-
- /* equation of time */
- Eqt= (Lr - alpha) / Tsec_to_Radian;
-
- delta = delta / Asec_Radian;
- alpha = alpha / Tsec_to_Radian;
-
- lhr = (LST - alpha) * Tsec_to_Radian;
- sh = sin(lhr);
- ch = cos(lhr);
- lhr= atan2(sh, ch); /* normalized -pi to pi */
- lha= lhr / Tsec_to_Radian + Sec_per_day/2;
-
- /* convert to Azimuth and altitude */
-
- alt = asin(sd*sp + cd*ch*cp);
- ca = cos(alt);
- sA = -cd * sh / ca;
- cA = (sd*cp - cd*ch*sp) / ca;
- Az = atan2(sA, cA) / Asec_Radian;
- Az = fmod(Az, 1296000. /* 360.*3600. */);
- alt = alt / Asec_Radian;
- }
- }
-
- moondata(tim)
- long tim;
- {
- double lst, beta, rm, sa, ca, sl, cl, sb, cb, x, y, z, l, m, n;
-
- /* compute location of the moon */
- /* Ephemeris elements from 1985 Almanac */
-
- timedata(tim);
-
- Lm= 218.32 + 481267.883*Tu
- + 6.29 * sin((134.9 + 477198.85*Tu)*Degree_to_Radian)
- - 1.27 * sin((259.2 - 413335.38*Tu)*Degree_to_Radian)
- + 0.66 * sin((235.7 + 890534.23*Tu)*Degree_to_Radian)
- + 0.21 * sin((269.9 + 954397.70*Tu)*Degree_to_Radian)
- - 0.19 * sin((357.5 + 35999.05*Tu)*Degree_to_Radian)
- - 0.11 * sin((186.6 + 966404.05*Tu)*Degree_to_Radian);
-
- beta= 5.13 * sin(( 93.3 + 483202.03*Tu)*Degree_to_Radian)
- + 0.28 * sin((228.2 + 960400.87*Tu)*Degree_to_Radian)
- - 0.28 * sin((318.3 + 6003.18*Tu)*Degree_to_Radian)
- - 0.17 * sin((217.6 - 407332.20*Tu)*Degree_to_Radian);
-
- px= 0.9508
- + 0.0518 * cos((134.9 + 477198.85*Tu)*Degree_to_Radian)
- + 0.0095 * cos((259.2 - 413335.38*Tu)*Degree_to_Radian)
- + 0.0078 * cos((235.7 + 890534.23*Tu)*Degree_to_Radian)
- + 0.0028 * cos((269.9 + 954397.70*Tu)*Degree_to_Radian);
-
- /* SD= 0.2725 * px; */
-
- rm= 1.0 / sin(px * Degree_to_Radian);
-
- lst= (100.46 + 36000.77*Tu) * Degree_to_Radian
- + ((tim % Sec_per_day) + Local) * Tsec_to_Radian;
-
- /* form geocentric direction cosines */
-
- sl= sin(Lm * Degree_to_Radian);
- cl= cos(Lm * Degree_to_Radian);
- sb= sin(beta* Degree_to_Radian);
- cb= cos(beta * Degree_to_Radian);
-
- l= cb * cl;
- m= 0.9175 * cb * sl - 0.3978 * sb;
- n= 0.3978 * cb * sl + 0.9175 * sb;
-
- /* R.A. and Dec of Moon, geocentric*/
-
- am= atan2(m, l);
- dm= asin(n);
-
- /* topocentric rectangular coordinates */
-
- cd= cos(dm);
- sd= n;
- ca= cos(am);
- sa= sin(am);
- sl= sin(lst);
- cl= cos(lst);
-
- x= rm * cd *ca - cp * cl;
- y= rm * cd * sa - cp * sl;
- z= rm * sd - sp;
-
- /* finally, topocentric Hour-Angle and Dec */
-
- am = lst - atan2(y, x);
- ca = cos(am);
- sa = sin(am);
- am = atan2(sa,ca);
- rm = sqrt(x*x + y*y + z*z);
- dm = asin(z/rm);
- px = asin(1.0 / rm);
- SD = 0.2725 * px;
- }
-
- timedata(tim)
- long tim;
- {
-
- /* compute seconds from 2000 Jan 1.5 UT (Ephemeris Epoch) */
- /* the VAX Epoch is 1970 Jan 1.0 UT (Midnight on Jan 1) */
-
- Julian_Day = (tim/Sec_per_day) +
- (double)(tim % Sec_per_day)/Sec_per_day + J1970;
- MJD= Julian_Day -J2000; /* Julian Days past Epoch */
- Tu = MJD/36525.; /* Julian Centuries past Epoch */
-
- /* compute Sidereal time */
-
- Ru= 24110.54841 + Tu * (8640184.812866
- + Tu * (0.09304 - Tu * 6.2e-6)); /* seconds */
- GMST = (tim % Sec_per_day) + Sec_per_day + fmod(Ru, (double)Sec_per_day);
- LST = GMST + Local;
- }
-
- /* time functions, for Regulus */
- char *gmctime(t) /* re-hack for VAX, since ctime gives local */
- long *t;
- {
- long t1;
-
- t1 = *t - localdst; /* convert to local time */
- return(ctime(&t1));
- }
-
- char *localctime(t)
- long *t;
- {
- long t1;
-
- t1 = *t + localdst; /* convert to local time */
- return(gmctime(&t1));
- }
-
- struct tm *Rlocaltime(t)
- long *t;
- {
- long t1;
-
- t1 = *t + localdst; /* convert to local time */
- return(gmtime(&t1));
- }
-
- /* double precision modulus, put in range 0 <= result < m */
- double fmod(x, m)
- double x, m;
- {
- long i;
-
- i = fabs(x)/m; /* compute integer part of x/m */
- if (x < 0) return( x + (i+1)*m);
- else return( x - i*m);
- }
- %%
-
-
-