123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- package utils
- import (
- "errors"
- "math"
- "time"
- )
- type Parameters struct {
- Latitude float64
- Longitude float64
- UtcOffset float64
- Date time.Time
- }
- func (p *Parameters) GetSunriseSunset() (time.Time, time.Time, error) {
- return GetSunriseSunset(p.Latitude, p.Longitude, p.UtcOffset, p.Date)
- }
- func rad2deg(radians float64) float64 {
- return radians * (180.0 / math.Pi)
- }
- func deg2rad(degrees float64) float64 {
- return degrees * (math.Pi / 180.0)
- }
- func createSecondsNormalized(seconds int) (vector []float64) {
- for index := 0; index < seconds; index++ {
- temp := float64(index) / float64(seconds-1)
- vector = append(vector, temp)
- }
- return
- }
- func calcJulianDay(numDays int64, secondsNorm []float64, utcOffset float64) (julianDay []float64) {
- for index := 0; index < len(secondsNorm); index++ {
- temp := float64(numDays) + 2415018.5 + secondsNorm[index] - utcOffset/24.0
- julianDay = append(julianDay, temp)
- }
- return
- }
- func calcJulianCentury(julianDay []float64) (julianCentury []float64) {
- for index := 0; index < len(julianDay); index++ {
- temp := (julianDay[index] - 2451545.0) / 36525.0
- julianCentury = append(julianCentury, temp)
- }
- return
- }
- func calcGeomMeanLongSun(julianCentury []float64) (geomMeanLongSun []float64) {
- for index := 0; index < len(julianCentury); index++ {
- a := 280.46646 + julianCentury[index]*(36000.76983+julianCentury[index]*0.0003032)
- temp := math.Mod(a, 360.0)
- geomMeanLongSun = append(geomMeanLongSun, temp)
- }
- return
- }
- func calcGeomMeanAnomSun(julianCentury []float64) (geomMeanAnomSun []float64) {
- for index := 0; index < len(julianCentury); index++ {
- temp := 357.52911 + julianCentury[index]*(35999.05029-0.0001537*julianCentury[index])
- geomMeanAnomSun = append(geomMeanAnomSun, temp)
- }
- return
- }
- func calcEccentEarthOrbit(julianCentury []float64) (eccentEarthOrbit []float64) {
- for index := 0; index < len(julianCentury); index++ {
- temp := 0.016708634 - julianCentury[index]*(0.000042037+0.0000001267*julianCentury[index])
- eccentEarthOrbit = append(eccentEarthOrbit, temp)
- }
- return
- }
- func calcSunEqCtr(julianCentury []float64, geomMeanAnomSun []float64) (sunEqCtr []float64) {
- if len(julianCentury) != len(geomMeanAnomSun) {
- return
- }
- for index := 0; index < len(julianCentury); index++ {
- temp := math.Sin(deg2rad(geomMeanAnomSun[index]))*(1.914602-julianCentury[index]*(0.004817+0.000014*julianCentury[index])) + math.Sin(deg2rad(2*geomMeanAnomSun[index]))*(0.019993-0.000101*julianCentury[index]) + math.Sin(deg2rad(3*geomMeanAnomSun[index]))*0.000289
- sunEqCtr = append(sunEqCtr, temp)
- }
- return
- }
- func calcSunTrueLong(sunEqCtr []float64, geomMeanLongSun []float64) (sunTrueLong []float64) {
- if len(sunEqCtr) != len(geomMeanLongSun) {
- return
- }
- for index := 0; index < len(sunEqCtr); index++ {
- temp := sunEqCtr[index] + geomMeanLongSun[index]
- sunTrueLong = append(sunTrueLong, temp)
- }
- return
- }
- func calcSunAppLong(sunTrueLong []float64, julianCentury []float64) (sunAppLong []float64) {
- if len(sunTrueLong) != len(julianCentury) {
- return
- }
- for index := 0; index < len(sunTrueLong); index++ {
- temp := sunTrueLong[index] - 0.00569 - 0.00478*math.Sin(deg2rad(125.04-1934.136*julianCentury[index]))
- sunAppLong = append(sunAppLong, temp)
- }
- return
- }
- func calcMeanObliqEcliptic(julianCentury []float64) (meanObliqEcliptic []float64) {
- for index := 0; index < len(julianCentury); index++ {
- temp := 23.0 + (26.0+(21.448-julianCentury[index]*(46.815+julianCentury[index]*(0.00059-julianCentury[index]*0.001813)))/60.0)/60.0
- meanObliqEcliptic = append(meanObliqEcliptic, temp)
- }
- return
- }
- func calcObliqCorr(meanObliqEcliptic []float64, julianCentury []float64) (obliqCorr []float64) {
- if len(meanObliqEcliptic) != len(julianCentury) {
- return
- }
- for index := 0; index < len(julianCentury); index++ {
- temp := meanObliqEcliptic[index] + 0.00256*math.Cos(deg2rad(125.04-1934.136*julianCentury[index]))
- obliqCorr = append(obliqCorr, temp)
- }
- return
- }
- func calcSunDeclination(obliqCorr []float64, sunAppLong []float64) (sunDeclination []float64) {
- if len(obliqCorr) != len(sunAppLong) {
- return
- }
- for index := 0; index < len(obliqCorr); index++ {
- temp := rad2deg(math.Asin(math.Sin(deg2rad(obliqCorr[index])) * math.Sin(deg2rad(sunAppLong[index]))))
- sunDeclination = append(sunDeclination, temp)
- }
- return
- }
- func calcEquationOfTime(multiFactor []float64, geomMeanLongSun []float64, eccentEarthOrbit []float64, geomMeanAnomSun []float64) (equationOfTime []float64) {
- if len(multiFactor) != len(geomMeanLongSun) ||
- len(multiFactor) != len(eccentEarthOrbit) ||
- len(multiFactor) != len(geomMeanAnomSun) {
- return
- }
- for index := 0; index < len(multiFactor); index++ {
- a := multiFactor[index] * math.Sin(2.0*deg2rad(geomMeanLongSun[index]))
- b := 2.0 * eccentEarthOrbit[index] * math.Sin(deg2rad(geomMeanAnomSun[index]))
- c := 4.0 * eccentEarthOrbit[index] * multiFactor[index] * math.Sin(deg2rad(geomMeanAnomSun[index]))
- d := math.Cos(2.0 * deg2rad(geomMeanLongSun[index]))
- e := 0.5 * multiFactor[index] * multiFactor[index] * math.Sin(4.0*deg2rad(geomMeanLongSun[index]))
- f := 1.25 * eccentEarthOrbit[index] * eccentEarthOrbit[index] * math.Sin(2.0*deg2rad(geomMeanAnomSun[index]))
- temp := 4.0 * rad2deg(a-b+c*d-e-f)
- equationOfTime = append(equationOfTime, temp)
- }
- return
- }
- func calcHaSunrise(latitude float64, sunDeclination []float64) (haSunrise []float64) {
- for index := 0; index < len(sunDeclination); index++ {
- temp := rad2deg(math.Acos(math.Cos(deg2rad(90.833))/(math.Cos(deg2rad(latitude))*math.Cos(deg2rad(sunDeclination[index]))) - math.Tan(deg2rad(latitude))*math.Tan(deg2rad(sunDeclination[index]))))
- haSunrise = append(haSunrise, temp)
- }
- return
- }
- func calcSolarNoon(longitude float64, equationOfTime []float64, utcOffset float64) (solarNoon []float64) {
- for index := 0; index < len(equationOfTime); index++ {
- temp := (720.0 - 4.0*longitude - equationOfTime[index] + utcOffset*60.0) * 60.0
- solarNoon = append(solarNoon, temp)
- }
- return
- }
- func checkLatitude(latitude float64) bool {
- if latitude < -90.0 || latitude > 90.0 {
- return false
- }
- return true
- }
- func checkLongitude(longitude float64) bool {
- if longitude < -180.0 || longitude > 180.0 {
- return false
- }
- return true
- }
- func checkUtcOffset(utcOffset float64) bool {
- if utcOffset < -12.0 || utcOffset > 14.0 {
- return false
- }
- return true
- }
- func checkDate(date time.Time) bool {
- minDate := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)
- maxDate := time.Date(2200, 1, 1, 0, 0, 0, 0, time.UTC)
- if date.Before(minDate) || date.After(maxDate) {
- return false
- }
- return true
- }
- func diffDays(date1, date2 time.Time) int64 {
- return int64(date2.Sub(date1) / (24 * time.Hour))
- }
- func minIndex(slice []float64) int {
- if len(slice) == 0 {
- return -1
- }
- min := slice[0]
- minIndex := 0
- for index := 0; index < len(slice); index++ {
- if slice[index] < min {
- min = slice[index]
- minIndex = index
- }
- }
- return minIndex
- }
- func abs(slice []float64) []float64 {
- var newSlice []float64
- for _, value := range slice {
- if value < 0.0 {
- value = math.Abs(value)
- }
- newSlice = append(newSlice, value)
- }
- return newSlice
- }
- func round(value float64) int {
- if value < 0 {
- return int(value - 0.5)
- }
- return int(value + 0.5)
- }
- func GetSunriseSunset(latitude float64, longitude float64, utcOffset float64, date time.Time) (sunrise time.Time, sunset time.Time, err error) {
-
- if !checkLatitude(latitude) {
- err = errors.New("Invalid latitude")
- return
- }
-
- if !checkLongitude(longitude) {
- err = errors.New("Invalid longitude")
- return
- }
-
- if !checkUtcOffset(utcOffset) {
- err = errors.New("Invalid UTC offset")
- return
- }
-
- if !checkDate(date) {
- err = errors.New("Invalid date")
- return
- }
-
- since := time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)
- numDays := diffDays(since, date)
-
- seconds := 24 * 60 * 60
-
- secondsNorm := createSecondsNormalized(seconds)
-
- julianDay := calcJulianDay(numDays, secondsNorm, utcOffset)
-
- julianCentury := calcJulianCentury(julianDay)
-
- geomMeanLongSun := calcGeomMeanLongSun(julianCentury)
-
- geomMeanAnomSun := calcGeomMeanAnomSun(julianCentury)
-
- eccentEarthOrbit := calcEccentEarthOrbit(julianCentury)
-
- sunEqCtr := calcSunEqCtr(julianCentury, geomMeanAnomSun)
-
- sunTrueLong := calcSunTrueLong(sunEqCtr, geomMeanLongSun)
-
- sunAppLong := calcSunAppLong(sunTrueLong, julianCentury)
-
- meanObliqEcliptic := calcMeanObliqEcliptic(julianCentury)
-
- obliqCorr := calcObliqCorr(meanObliqEcliptic, julianCentury)
-
- sunDeclination := calcSunDeclination(obliqCorr, sunAppLong)
-
- var multiFactor []float64
- for index := 0; index < len(obliqCorr); index++ {
- temp := math.Tan(deg2rad(obliqCorr[index]/2.0)) * math.Tan(deg2rad(obliqCorr[index]/2.0))
- multiFactor = append(multiFactor, temp)
- }
-
- equationOfTime := calcEquationOfTime(multiFactor, geomMeanLongSun, eccentEarthOrbit, geomMeanAnomSun)
-
- haSunrise := calcHaSunrise(latitude, sunDeclination)
-
- solarNoon := calcSolarNoon(longitude, equationOfTime, utcOffset)
-
- var tempSunrise []float64
- var tempSunset []float64
- for index := 0; index < len(solarNoon); index++ {
- tempSunrise = append(tempSunrise, (solarNoon[index] - float64(round(haSunrise[index]*4.0*60.0)) - float64(seconds)*secondsNorm[index]))
- tempSunset = append(tempSunset, (solarNoon[index] + float64(round(haSunrise[index]*4.0*60.0)) - float64(seconds)*secondsNorm[index]))
- }
-
- sunriseSeconds := minIndex(abs(tempSunrise))
- sunsetSeconds := minIndex(abs(tempSunset))
-
- defaultTime := new(time.Time)
- sunrise = defaultTime.Add(time.Duration(sunriseSeconds) * time.Second)
- sunset = defaultTime.Add(time.Duration(sunsetSeconds) * time.Second)
- return
- }
- func SunriseSunsetForChina(latitude, longitude float64) (string, string, error) {
- p := Parameters{
- Latitude: latitude,
- Longitude: longitude,
- UtcOffset: 8.0,
- Date: New(MlNow()).BeginningOfDay(),
- }
-
- sunrise, sunset, err := p.GetSunriseSunset()
- if err != nil {
- return "", "", err
- }
- if sunrise.Second() >= 30 {
- sunrise = sunrise.Add(time.Minute)
- }
- if sunset.Second() >= 30 {
- sunset = sunset.Add(time.Minute)
- }
-
- return sunrise.Format("15:04"), sunset.Format("15:04"), nil
- }
|