31QPair<QDateTime, QDateTime>
calculateSunTimings(
const QDateTime &dateTime,
double latitude,
double longitude,
bool morning)
37 const double rad = M_PI / 180.;
38 const double earthObliquity = 23.4397;
40 const double lat = latitude;
41 const double lng = -longitude;
44 const QDateTime utcDateTime = dateTime.toUTC();
45 const double juPrompt = utcDateTime.date().toJulianDay();
46 const double ju2000 = 2451545.;
49 auto mod360 = [](
double number) ->
double {
50 return std::fmod(number, 360.);
53 auto sin = [&rad](
double angle) ->
double {
54 return std::sin(angle * rad);
56 auto cos = [&rad](
double angle) ->
double {
57 return std::cos(angle * rad);
59 auto asin = [&rad](
double val) ->
double {
60 return std::asin(val) / rad;
62 auto acos = [&rad](
double val) ->
double {
63 return std::acos(val) / rad;
66 auto anomaly = [&](
const double date) ->
double {
67 return mod360(357.5291 + 0.98560028 * (date - ju2000));
70 auto center = [&sin](
double anomaly) ->
double {
71 return 1.9148 * sin(anomaly) + 0.02 * sin(2 * anomaly) + 0.0003 * sin(3 * anomaly);
74 auto ecliptLngMean = [](
double anom) ->
double {
75 return anom + 282.9372;
78 auto ecliptLng = [&](
double anom) ->
double {
79 return ecliptLngMean(anom) + center(anom);
82 auto declination = [&](
const double date) ->
double {
83 const double anom = anomaly(date);
84 const double eclLng = ecliptLng(anom);
86 return mod360(asin(sin(earthObliquity) * sin(eclLng)));
90 auto hourAngle = [&](
const double date,
double angle) ->
double {
91 const double decl = declination(date);
92 const double ret0 = (sin(angle) - sin(lat) * sin(decl)) / (cos(lat) * cos(decl));
94 double ret = mod360(acos(ret0));
106 auto getTransit = [&](
const double date) ->
double {
107 const double juMeanSolTime = juPrompt - ju2000 - 0.0009 - lng / 360.;
108 const double juTrEstimate = date + qRound64(juMeanSolTime) - juMeanSolTime;
109 const double anom = anomaly(juTrEstimate);
110 const double eclLngM = ecliptLngMean(anom);
112 return juTrEstimate + 0.0053 * sin(anom) - 0.0068 * sin(2 * eclLngM);
115 auto getSunMorning = [&hourAngle](
const double angle,
const double transit) ->
double {
116 return transit - hourAngle(transit, angle) / 360.;
119 auto getSunEvening = [&hourAngle](
const double angle,
const double transit) ->
double {
120 return transit + hourAngle(transit, angle) / 360.;
128 const double juNoon = getTransit(juPrompt);
133 end = getSunMorning(
SUN_HIGH, juNoon);
135 begin = getSunEvening(
SUN_HIGH, juNoon);
142 QDateTime dateTimeBegin;
143 QDateTime dateTimeEnd;
145 if (!std::isnan(begin)) {
146 const double dayFraction = begin - int(begin);
147 const QTime utcTime = QTime::fromMSecsSinceStartOfDay(dayFraction * MSC_DAY);
148 const QTime localTime = convertToLocalTime(dateTime, utcTime);
149 dateTimeBegin = QDateTime(dateTime.date(), localTime);
152 if (!std::isnan(end)) {
153 const double dayFraction = end - int(end);
154 const QTime utcTime = QTime::fromMSecsSinceStartOfDay(dayFraction * MSC_DAY);
155 const QTime localTime = convertToLocalTime(dateTime, utcTime);
156 dateTimeEnd = QDateTime(dateTime.date(), localTime);
159 return {dateTimeBegin, dateTimeEnd};