-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
217
-
218
-
219
-
220
-
221
-
222
-
223
-
224
-
225
-
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
-
237
-
238
-
239
-
240
-
241
-
242
-
243
-
244
-
245
-
246
-
247
-
248
-
249
-
250
-
251
-
252
-
253
-
254
-
255
-
256
-
257
-
258
-
259
-
260
-
261
-
262
-
263
-
264
-
265
-
266
/*
** print.c (of sunwait)
**
** Who Ver When What
** IFC 0.5 04-12-2014 Fix my 1st release of sunwait for windows and port to linux
** IFC 0.6 08-12-2014 Add timezone for output of timings
** IFC 0.7 30-04-2015 Fix timexone and DST trouble - and problems near dateline
** IFC 0.8 2015-05-27 Resolve 'dodgy day' and cleanup
** DRR 0.91 2022-09-16 Accept change to C from mstilkerich Michael Stilkerich
**
*/
#include <stdio.h>
#include <math.h>
#include <time.h>
#include "sunwait.h"
#include "sunriset.h"
#include "print.h"
static const char* cTo = " to ";
static const char* cComma = ", ";
#define NO_OFFSET 0.0
// The user-specified offset reduces the diurnal arc, at sunrise AND sunset.
// But make sure dawn aways is before dusk. The offset can mess that up.
static double diurnalArcWithOffset1 (const double pDiurnalArc, const double pOffset)
{ double arcWithOffset = pDiurnalArc - pOffset - pOffset;
if (arcWithOffset >= 24.0) return 24.0;
if (arcWithOffset <= 0.0) return 0.0;
return arcWithOffset;
}
// Simpler to use form
double diurnalArcWithOffset (const runStruct *pRun, const targetStruct *pTarget)
{ return diurnalArcWithOffset1 (pTarget->diurnalArc, pRun->offsetHour);
}
// What time, in hours UTC, is the offset sunrise?
static double getOffsetRiseHourUTC1 (const double pSouthHourUTC, const double pDiurnalArc, const double pOffsetHour)
{ return pSouthHourUTC - diurnalArcWithOffset1 (pDiurnalArc, pOffsetHour)/2.0;
}
// Simpler to use form
double getOffsetRiseHourUTC (const runStruct *pRun, const targetStruct *pTarget)
{ return getOffsetRiseHourUTC1 (pTarget->southHourUTC, pTarget->diurnalArc, pRun->offsetHour);
}
// What time, in hours UTC, is the offset sunset?
static double getOffsetSetHourUTC1 (const double pSouthHourUTC, const double pDiurnalArc, const double pOffsetHour)
{ return pSouthHourUTC + diurnalArcWithOffset1 (pDiurnalArc, pOffsetHour)/2.0;
}
// Simpler to use form
double getOffsetSetHourUTC (const runStruct *pRun, const targetStruct *pTarget)
{ return getOffsetSetHourUTC1 (pTarget->southHourUTC, pTarget->diurnalArc, pRun->offsetHour);
}
static void print_a_time
( const OnOff pGmt_OnOff
, const time_t *pMidnightTimet
, const double pEventHour
)
{ struct tm tmpTm;
char tmpBuffer [80];
// Convert current time to struct tm for UTC or local timezone
if (pGmt_OnOff == ONOFF_ON)
{ myUtcTime (pMidnightTimet, &tmpTm);
tmpTm.tm_min += (int) (pEventHour * 60.0);
time_t x = mktime (&tmpTm);
myUtcTime (&x, &tmpTm);
}
else
{ myLocalTime (pMidnightTimet, &tmpTm);
tmpTm.tm_min += (int) (pEventHour * 60.0);
mktime (&tmpTm);
}
strftime (tmpBuffer, 80, "%H:%M", &tmpTm);
printf ("%s", tmpBuffer);
}
static void print_a_sun_time
( const OnOff pGmt_OnOff
, const time_t *pMidnightTimet
, const double pEventHour
, const double pOffsetDiurnalArc
)
{ // A positive offset reduces the diurnal arc
if (pOffsetDiurnalArc <= 0.0 || pOffsetDiurnalArc >= 24.0)
printf ("--:--");
else
print_a_time (pGmt_OnOff, pMidnightTimet, pEventHour);
}
static void print_times
( const runStruct *pRun
, const targetStruct *pTarget
, const double pOffsetHour
, const char *pSeparator
)
{ double offsetDiurnalArc = diurnalArcWithOffset1 (pTarget->diurnalArc, pOffsetHour);
double riseHour = getOffsetRiseHourUTC1 (pTarget->southHourUTC, pTarget->diurnalArc, pOffsetHour);
double setHour = getOffsetSetHourUTC1 (pTarget->southHourUTC, pTarget->diurnalArc, pOffsetHour);
if (pRun->reportSunrise == ONOFF_ON)
print_a_sun_time (pRun->utc, &pRun->targetTimet, riseHour, offsetDiurnalArc);
if (pRun->reportSunrise == ONOFF_ON && pRun->reportSunset == ONOFF_ON)
printf ("%s", pSeparator);
if (pRun->reportSunset == ONOFF_ON)
print_a_sun_time (pRun->utc, &pRun->targetTimet, setHour, offsetDiurnalArc);
if (offsetDiurnalArc >= 24.0) printf (" (Midnight sun)");
else if (offsetDiurnalArc <= 0.0) printf (" (Polar night)");
printf ("\n");
}
inline void print_twilight
( const double pDayLength
, const double pTwilightLength
)
{ printf
( "%2.2d:%2.2d hours (twilight: %2.2d:%2.2d hours)\n"
, hours (pDayLength), minutes (pDayLength)
, hours (pTwilightLength), minutes (pTwilightLength)
);
}
void generate_report (const runStruct *pRun)
{
/*
** Generate and save sunrise and sunset times for target
*/
targetStruct tmpTarget;
tmpTarget.twilightAngle = pRun->twilightAngle;
tmpTarget.daysSince2000 = pRun->target2000;
sunriset (pRun, &tmpTarget);
double twilightAngleTarget = tmpTarget.twilightAngle;
/*
** Now generate the report
*/
struct tm nowTm;
struct tm targetTm;
char buffer [80];
if (pRun->utc == ONOFF_ON)
{ myUtcTime (&pRun->nowTimet, &nowTm);
myUtcTime (&pRun->targetTimet, &targetTm);
}
else
{ myLocalTime (&pRun->nowTimet, &nowTm);
myLocalTime (&pRun->targetTimet, &targetTm);
}
printf ("\n");
strftime (buffer, 80, "%d-%b-%Y %H:%M %Z", &nowTm);
printf
(" Current Date and Time: %s\n", buffer);
printf ("\n\nTarget Information ...\n\n");
printf
(" Location: %10.6fN, %10.6fE\n"
, pRun->latitude
, pRun->longitude
);
strftime (buffer, 80, "%d-%b-%Y", &targetTm);
printf
(" Date: %s\n", buffer);
strftime (buffer, 80, "%Z", &targetTm);
printf
(" Timezone: %s\n", buffer);
printf
(" Sun directly north/south: ");
print_a_time (pRun->utc, &pRun->targetTimet, tmpTarget.southHourUTC);
printf ("\n");
if (pRun->offsetHour != NO_OFFSET)
{ printf
( " Offset: %2.2d:%2.2d hours\n"
, hours (pRun->offsetHour)
, minutes (pRun->offsetHour)
);
}
if (tmpTarget.twilightAngle == TWILIGHT_ANGLE_DAYLIGHT) printf(" Twilight angle: %5.2f degrees (daylight)\n", twilightAngleTarget);
else if (tmpTarget.twilightAngle == TWILIGHT_ANGLE_CIVIL) printf(" Twilight angle: %5.2f degrees (civil)\n", twilightAngleTarget);
else if (tmpTarget.twilightAngle == TWILIGHT_ANGLE_NAUTICAL) printf(" Twilight angle: %5.2f degrees (nautical)\n", twilightAngleTarget);
else if (tmpTarget.twilightAngle == TWILIGHT_ANGLE_ASTRONOMICAL) printf(" Twilight angle: %5.2f degrees (astronomical)\n", twilightAngleTarget);
else printf(" Twilight angle: %5.2f degrees (custom angle)\n", twilightAngleTarget);
printf (" Day with twilight: "); print_times (pRun, &tmpTarget, NO_OFFSET, cTo);
if (pRun->offsetHour != NO_OFFSET)
{ printf (" Day with twilight & offset: "); print_times (pRun, &tmpTarget, pRun->offsetHour, cTo); }
printf (" It is: %s\n", isDay (pRun) == ONOFF_ON ? "Day (or twilight)" : "Night");
/*
** Generate times for different types of twilight
*/
targetStruct daylightTarget;
daylightTarget.twilightAngle = TWILIGHT_ANGLE_DAYLIGHT;
daylightTarget.daysSince2000 = tmpTarget.daysSince2000;
sunriset (pRun, &daylightTarget);
targetStruct civilTarget;
civilTarget.twilightAngle = TWILIGHT_ANGLE_CIVIL;
civilTarget.daysSince2000 = tmpTarget.daysSince2000;
sunriset (pRun, &civilTarget);
targetStruct nauticalTarget;
nauticalTarget.twilightAngle = TWILIGHT_ANGLE_NAUTICAL;
nauticalTarget.daysSince2000 = tmpTarget.daysSince2000;
sunriset (pRun, &nauticalTarget);
targetStruct astronomicalTarget;
astronomicalTarget.twilightAngle = TWILIGHT_ANGLE_ASTRONOMICAL;
astronomicalTarget.daysSince2000 = tmpTarget.daysSince2000;
sunriset (pRun, &astronomicalTarget);
printf ("\nGeneral Information (no offset) ...\n\n");
printf (" Times ... Daylight: "); print_times (pRun, &tmpTarget, NO_OFFSET, cTo);
printf (" with Civil twilight: "); print_times (pRun, &civilTarget, NO_OFFSET, cTo);
printf (" with Nautical twilight: "); print_times (pRun, &nauticalTarget, NO_OFFSET, cTo);
printf (" with Astronomical twilight: "); print_times (pRun, &astronomicalTarget, NO_OFFSET, cTo);
printf ("\n");
printf (" Duration ... Day length: %2.2d:%2.2d hours\n", hours ( daylightTarget.diurnalArc), minutes ( daylightTarget.diurnalArc));
printf (" with civil twilight: %2.2d:%2.2d hours\n", hours ( civilTarget.diurnalArc), minutes ( civilTarget.diurnalArc));
printf (" with nautical twilight: %2.2d:%2.2d hours\n", hours ( nauticalTarget.diurnalArc), minutes ( nauticalTarget.diurnalArc));
printf (" with astronomical twilight: %2.2d:%2.2d hours\n", hours (astronomicalTarget.diurnalArc), minutes (astronomicalTarget.diurnalArc));
printf ("\n");
}
void print_list (const runStruct *pRun)
{
targetStruct tmpTarget;
tmpTarget.daysSince2000 = pRun->target2000;
tmpTarget.twilightAngle = pRun->twilightAngle;
for (unsigned int day=0; day < pRun->listDays; day++)
{
sunriset (pRun, &tmpTarget);
print_times
( pRun
, &tmpTarget
, pRun->offsetHour
, cComma
);
tmpTarget.daysSince2000++;
}
}