Wschód i zachód słońca

12

Jestem trochę romantyczny, uwielbiam zabierać moją żonę, aby zobaczyć wschody i zachody słońca w miejscu, w którym się znajdujemy. Na potrzeby tego ćwiczenia powiedzmy, że nie mam kodu, który mógłby mi wskazać godzinę zachodu lub wschodu słońca dla dowolnej daty, szerokości i długości geograficznej, w której się znajdę.

Twoim zadaniem, programistom, jest wygenerowanie możliwie najmniejszego kodu, który przyjmuje szerokość dziesiętną i długość geograficzną (przyjmowane w stopniach N i W, więc stopnie S i E będą przyjmowane jako negatywy) i datę w formacie RRRR-MM-DD ( od 1 stycznia 2000 roku) i wypluje dwa razy w formacie 24-godzinnym dla wschodu i zachodu słońca.

np. na dzisiaj w Sydney w Australii

riseset -33.87 -151.2 2013-12-27

05:45 20:09

Bonusy: -100, jeśli można uwzględnić wzniesienie -100, jeśli można uwzględnić oszczędności w świetle dziennym

Kod MUSI wypluć czasy w odpowiedniej strefie czasowej określonej na wejściu w oparciu o szerokość i długość geograficzną LUB we własnej strefie czasowej komputera klienta.

WallyWest
źródło
3
Zaraz, musimy zrobić wyszukiwanie [szerokość x długość] => [strefa czasowa]? Czy otrzymujemy do tego plik danych? Lub serwer, do którego mamy dostęp? A może jest język, który ma takie rzeczy wbudowane? Czy możesz nam powiedzieć, który? Czy musimy zapamiętać granice strefy czasowej? Do jakiej precyzji? Skąd mamy te dane? Czy zdajesz sobie sprawę, że te dane zajmą większość długości kodu? Co ze współrzędnymi, które mieszczą się dokładnie na granicy strefy czasowej? Powiedzmy, że bieguny geograficzne? Jakie zachowanie jest dozwolone, gdy wejście jest regionem polarnym podczas polarnej nocy / dnia? Co ze współrzędnymi poza zakresem?
John Dvorak,
Ja kocham wyzwanie, aby obliczyć horyzont w oparciu o punkt wyżej wyidealizowanej kuli, ale ja nienawidzę ten powiązany wyzwanie, aby znaleźć ręcznie kompres, programowo decopmress a następnie wyszukać w, strefę czasową Lookup map. O ile oczywiście nie możemy użyć wyidealizowanych stref czasowych (przesunięcie jest wybierane tak, aby słońce było najwyższe w południe, a następnie jest zaokrąglane do najbliższej godziny).
John Dvorak,
1
@JanDvorak Zastosowanie co można, jeśli język użyć można wykorzystać strefę czasową klienta wówczas za wszelką cenę zrobić więc ...
WallyWest
1
Jakie jest pożądane zachowanie w regionach polarnych, gdy jest to polarny dzień / noc?
John Dvorak
1
Oto narzędzie, które robi dokładnie to samo: weatherimages.org/latlonsun.html
Eisa Adil

Odpowiedzi:

4

Spędziłem sporo czasu pisząc to:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from math import *


class RiseSet(object):

    __ZENITH = {'official': 90.833,
                'civil': '96',
                'nautical': '102',
                'astronomical': '108'}

    def __init__(self, day, month, year, latitude, longitude, daylight=False,
                 elevation=840, zenith='official'):
        ''' elevation is set to 840 (m) because that is the mean height of land above the sea level '''

        if abs(latitude) > 63.572375290155:
            raise ValueError('Invalid latitude: {0}.'.format(latitude))

        if zenith not in self.__ZENITH:
            raise ValueError('Invalid zenith value, must be one of {0}.'.format
                            (self.__ZENITH.keys()))

        self.day = day
        self.month = month
        self.year = year
        self.latitude = latitude
        self.longitude = longitude
        self.daylight = daylight
        self.elevation = elevation
        self.zenith = zenith

    def getZenith(self):
        return cos(radians(self.__ZENITH[self.zenith]))

    def dayOfTheYear(self):
        n0 = floor(275*self.month/9)
        n1 = floor((self.month + 9) / 12)
        n2 = (1 + floor((self.year - 4*floor(self.year/4) + 2) / 3))
        return n0 - (n1*n2) + self.day - 30

    def approxTime(self):
        sunrise = self.dayOfTheYear() + ((6 - (self.longitude/15.0)) / 24)
        sunset = self.dayOfTheYear() + ((18 - (self.longitude/15.0)) / 24)
        return (sunrise, sunset)

    def sunMeanAnomaly(self):
        sunrise = (0.9856 * self.approxTime()[0]) - 3.289
        sunset = (0.9856 * self.approxTime()[1]) - 3.289
        return (sunrise, sunset)

    def sunTrueLongitude(self):
        sma = self.sunMeanAnomaly()
        sunrise = sma[0] + (1.916*sin(radians(sma[0]))) + \
                  (0.020*sin(radians(2*sma[0]))) + 282.634

        if sunrise < 0:
            sunrise += 360
        if sunrise > 360:
            sunrise -= 360

        sunset = sma[1] + (1.916*sin(radians(sma[1]))) + \
                 (0.020*sin(radians(2*sma[1]))) + 282.634

        if sunset <= 0:
            sunset += 360
        if sunset > 360:
            sunset -= 360

        return (sunrise, sunset)

    def sunRightAscension(self):
        stl = self.sunTrueLongitude()
        sunrise = atan(radians(0.91764*tan(radians(stl[0]))))

        if sunrise <= 0:
            sunrise += 360
        if sunrise > 360:
            sunrise -= 360

        sunset = atan(radians(0.91764*tan(radians(stl[1]))))

        if sunset <= 0:
            sunset += 360
        if sunset > 360:
            sunset -= 360

        sunrise_stl_q = (floor(stl[0]/90)) * 90
        sunrise_ra_q = (floor(sunrise/90)) * 90
        sunrise = sunrise + (sunrise_stl_q - sunrise_ra_q)
        sunrise = sunrise/15.0

        sunset_stl_q = (floor(stl[1]/90)) * 90
        sunset_ra_q = (floor(sunset/90)) * 90
        sunset = sunrise + (sunset_stl_q - sunset_ra_q)
        sunset /= 15.0

        return (sunrise, sunset)

    def sunDeclination(self):
        sunrise_sin_dec = 0.39782 * sin(radians(self.sunTrueLongitude()[0]))
        sunrise_cos_dec = cos(radians(asin(radians(sunrise_sin_dec))))

        sunset_sin_dec = 0.39782 * sin(radians(self.sunTrueLongitude()[1]))
        sunset_cos_dec = cos(radians(asin(radians(sunrise_sin_dec))))

        return (sunrise_sin_dec, sunrise_cos_dec,
                sunset_sin_dec, sunset_cos_dec)

    def sunHourAngle(self):
        sd = self.sunDeclination()
        sunrise_cos_h = (cos(radians(self.getZenith())) - (sd[0]* \
                         sin(radians(self.latitude))) / (sd[1]* \
                         cos(radians(self.latitude))))
        if sunrise_cos_h > 1:
            raise Exception('The sun never rises on this location.')

        sunset_cos_h = (cos(radians(self.getZenith())) - (sd[2]* \
                         sin(radians(self.latitude))) / (sd[3]* \
                         cos(radians(self.latitude))))
        if sunset_cos_h < -1:
            raise Exception('The sun never sets on this location.')

        sunrise = 360 - acos(radians(sunrise_cos_h))
        sunrise /= 15.0

        sunset = acos(radians(sunrise_cos_h))
        sunset /= 15.0

        return (sunrise, sunset)

    def localMeanTime(self):
        sunrise = self.sunHourAngle()[0] + self.sunRightAscension()[0] - \
                 (0.06571*self.approxTime()[0]) - 6.622
        sunset = self.sunHourAngle()[1] + self.sunRightAscension()[1] - \
                 (0.06571*self.approxTime()[1]) - 6.622
        return (sunrise, sunset)

    def convertToUTC(self):
        sunrise = self.localMeanTime()[0] - (self.longitude/15.0)

        if sunrise <= 0:
            sunrise += 24
        if sunrise > 24:
            sunrise -= 24

        sunset = self.localMeanTime()[1] - (self.longitude/15.0)

        if sunset <= 0:
            sunset += 24
        if sunset > 24:
            sunset -= 24

        return (sunrise, sunset)

    def __str__(self):
        return None

Teraz nie jest jeszcze funkcjonalny (zepsułem kilka obliczeń) - wrócę do niego później (jeśli nadal będę miał odwagę), aby go ukończyć / skomentować .

Kilka ciekawych zasobów, które znalazłem podczas badania tematu:

Deneb
źródło
3
Właśnie zobaczyłem twój komentarz do # It's late, I'm tired, and OP is a prick for asking me to do this. Nie było obowiązku wykonania tego zadania ... Proszę nie umieszczać takich komentarzy w swoim kodzie ... To nie pasuje do innych programistów ... w tym do mnie. Podziwiam fakt, że dałeś mu czerwoną
gorączkę
@ Eliseod'Annunzio Masz moje przeprosiny.
Deneb
@ Eliseod'Annunzio Nie zamierzałem cię obrazić. Chciałbym również podziękować za przekazanie mi absolutnie fantastycznego pomysłu na badania i kodowanie. Teraz chcę przekształcić to w samodzielny moduł python (z argumentami sys i tak dalej). Okazuje się, że jest to trochę bardziej skomplikowane, niż wcześniej myślałem, ale zamierzam to zrobić. Jeszcze raz dziękuję.
Deneb
@Alex, czy zdajesz sobie sprawę, że to wyzwanie ma rok? Jestem prawie pewien, że wygrał.
mbomb007
@ mbomb007: Nie zdawałem sobie sprawy.
Alex A.