Skip to content

Commit

Permalink
Merge pull request #242 from vsimakhin/fix/night-time-polar-circle
Browse files Browse the repository at this point in the history
fix night time calculation inside polar circle
  • Loading branch information
vsimakhin authored Jul 3, 2024
2 parents e15f9a2 + 541251d commit 84d97c2
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 25 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [Unreleased]

- Fix: Incorrect night time calculation when flying inside the polar circle

## [2.38.0] - 25.06.2024

- Fix: Bug with columns for the extended PDF format, both A4 and A5.
Expand Down
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ You also can easily export all flight records into EASA style pdf format, print

# Changelog

## [Unreleased]

- Fix: Incorrect night time calculation when flying inside the polar circle

## [2.38.0] - 25.06.2024

- Fix: Bug with columns for the extended PDF format, both A4 and A5.
Expand All @@ -39,12 +43,6 @@ You also can easily export all flight records into EASA style pdf format, print
- Fix: Add dynamic resizing for the charts on Stats pages
- Fix: Instructor's hours for the Total Stats table were mixed up for the last 90 days and the last 12 months

## [2.35.1] - 20.05.2024

- Fix: Correct using styles and classes for the sidebar when switching between the pages
- Update: Code cleanup, removing code for synchronization with mobile client (will not continue working on it)
- Update: Update golang version (1.21.10) and go packages.

The full changelog is [here](https://github.com/vsimakhin/web-logbook/blob/main/CHANGELOG.md)

# Usage
Expand Down
63 changes: 44 additions & 19 deletions internal/nighttime/nighttime.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,25 +77,40 @@ func (route *Route) FlightSpeed() float64 {
return route.RouteDistance() / route.FlightTime().Hours()
}

// SunriseSunset returns sunrise and sunset times
func (place *Place) SunriseSunset() (time.Time, time.Time) {
sunrise, sunset := sunrise.SunriseSunset(place.Lat, place.Lon, place.Time.UTC().Year(), place.Time.UTC().Month(), place.Time.UTC().Day())
// SunriseSunset returns sunrise and sunset times or time.Time{} if there is no night
func (place *Place) SunriseSunset() (time.Time, time.Time, float64) {
sunElevation := sunrise.Elevation(place.Lat, place.Lon, place.Time)
sunRise, sunSet := sunrise.SunriseSunset(place.Lat, place.Lon, place.Time.UTC().Year(), place.Time.UTC().Month(), place.Time.UTC().Day())

noNight := time.Time{}
if sunRise == noNight || sunSet == noNight {
return noNight, noNight, sunElevation
}

aviationSunRise := sunRise.Add(time.Duration(-30) * time.Minute)
aviationSunSet := sunSet.Add(time.Duration(30) * time.Minute)

return sunrise.UTC().Add(time.Duration(-30) * time.Minute), sunset.UTC().Add(time.Duration(30) * time.Minute)
return aviationSunRise, aviationSunSet, sunElevation
}

// Sunrise returns aviation sunrise time
func (place *Place) Sunrise() time.Time {
s, _ := place.SunriseSunset()
s, _, _ := place.SunriseSunset()
return s
}

// Sunset returns aviation sunset time (+30 minutes from apparent sunset)
func (place *Place) Sunset() time.Time {
_, s := place.SunriseSunset()
_, s, _ := place.SunriseSunset()
return s
}

// Elevation returns sun elevation at the place
func (place *Place) Elevation() float64 {
_, _, e := place.SunriseSunset()
return e
}

func (route *Route) NightTime() time.Duration {
speed := route.FlightSpeed()
speedPerMinute := speed / 60
Expand All @@ -107,29 +122,39 @@ func (route *Route) NightTime() time.Duration {
}

func nightSegment(start Place, end Place, maxDistance float64, speedPerMinute float64) time.Duration {
d := time.Duration(0)

distance := distance(start, end)

if distance > maxDistance {
// too long, let's split it again
mid := midpoint(start, end)
// calculate time at the mid point
flightTime := distance / 2 / speedPerMinute
mid.Time = start.Time.Add(time.Duration(flightTime) * time.Minute)

d = nightSegment(start, mid, maxDistance, speedPerMinute) + nightSegment(mid, end, maxDistance, speedPerMinute)
} else {
// get sunrise and sunset for the end point
// it could be calculated for the middle point again to be more precise,
// but it will add few more calculations and the error is not so high
sr, ss := end.SunriseSunset()

if end.Time.After(sr) && end.Time.Before(ss) {
d = time.Duration(0)
} else {
d = time.Duration(distance / speedPerMinute * float64(time.Minute))
return nightSegment(start, mid, maxDistance, speedPerMinute) + nightSegment(mid, end, maxDistance, speedPerMinute)
}

// get sunrise and sunset for the end point
// it could be calculated for the middle point again to be more precise,
// but it will add few more calculations and the error is not so high
sr, ss, elevation := end.SunriseSunset()

nightTime := time.Duration(distance / speedPerMinute * float64(time.Minute))

if sr.Year() == 1 && ss.Year() == 1 {
if elevation > 0 {
// Polar day, no night time
return 0
}
// Polar night, all time is night
return nightTime
}

// day time
if end.Time.After(sr) && end.Time.Before(ss) {
return 0
}

return d
return nightTime
}

0 comments on commit 84d97c2

Please sign in to comment.