Восход и закат


12

Я немного романтик, я люблю брать мою жену, чтобы увидеть восходы и закаты в том месте, где мы находимся. Ради этого упражнения, скажем, у меня нет кода, который мог бы сообщить мне время заката или восхода солнца для любой даты, широты и долготы, в которой я бы оказался.

Ваша задача, кодеры, - сгенерировать наименьший возможный код, который принимает десятичную широту и долготу (взятые в градусах N и W, поэтому градусы S и E будут считаться отрицательными) и дату в формате YYYY-MM-DD ( с 1 января 2000 года), и он будет выплевывать два раза в 24-часовом формате для восхода и захода солнца.

например, на сегодня в Сиднее, Австралия

riseset -33.87 -151.2 2013-12-27

05:45 20:09

Бонусы: -100, если вы можете учесть высоту -100, если вы можете учесть летнее время

Код ДОЛЖЕН выплевывать время в соответствующем часовом поясе, указанном во входных данных, исходя из широты и долготы ИЛИ в собственном часовом поясе клиентского компьютера.


3
Подождите, что, мы должны сделать поиск [широта х долгота] => [часовой пояс]? Получим ли мы файл данных для этого? Или сервер, к которому мы можем получить доступ? Или есть язык, в который встроены такие вещи? Можете ли вы сказать нам, какой? Или мы должны запомнить границы часового пояса? С какой точностью? Где мы получаем эти данные? Вы понимаете, что эти данные будут занимать большую часть длины кода? Как насчет координат, которые попадают именно на границу часового пояса? Скажите, географические полюса? Кроме того, какое поведение допускается, когда вход является полярной областью в течение полярной ночи / дня? А как насчет координат вне диапазона?
Джон Дворжак

Мне бы очень хотелось, чтобы задача вычисляла горизонт на основе точки над идеализированной сферой, но я ненавижу связанную задачу: найти, сжать вручную, программно декомпрессировать и затем посмотреть в карте поиска часового пояса. Если, конечно, мы не можем использовать идеализированные часовые пояса (смещение выбирается так, чтобы солнце было самым высоким в полдень, затем оно округлялось до ближайшего часа).
Джон Дворжак

1
@JanDvorak Используйте все, что вы можете, если язык, который вы используете, может использовать часовой пояс клиента, тогда непременно сделайте это ...
WallyWest

1
Каково желаемое поведение для полярных регионов, когда это полярный день / ночь?
Джон Дворжак

1
Вот инструмент, который делает то же самое: weatherimages.org/latlonsun.html
Эйса Адиль

Ответы:


4

Я потратил довольно много времени на написание этого:

#!/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

Теперь он еще не функционален (я облажался с некоторыми вычислениями) - я вернусь к нему позже (если у меня еще хватит смелости), чтобы завершить его / прокомментировать .

Кроме того, некоторые интересные ресурсы, которые я нашел, исследуя предмет:


3
Я только что увидел ваш комментарий. # It's late, I'm tired, and OP is a prick for asking me to do this. Не было никаких обязательств по выполнению этой задачи ... Пожалуйста, не помещайте подобные комментарии в ваш код ... Это не устраивает других кодировщиков ... включая меня. Я восхищаюсь тем фактом, что вы дали ему горячий отклик, и другим ссылкам, которые вы предоставили, но, пожалуйста, больше никогда не используйте подобные комментарии ...
WallyWest

@ Eliseod'Annunzio Приношу свои извинения.
Денеб

@ Eliseod'Annunzio Я не собирался тебя обидеть. Я также хотел бы поблагодарить вас за то, что вы дали мне совершенно фантастическую идею для исследования и написания кода. Теперь я хочу превратить это в автономный модуль Python (с аргументами sys и так далее). Оказывается, все немного сложнее, чем я думал ранее, но я собираюсь это осуществить. Еще раз спасибо.
Денеб

@ Алекс, ты понимаешь, что этому вызову год? Я уверен, что он победил.
mbomb007

@ mbomb007: не понял.
Алекс А.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.