amanecer y el atardecer

12

Soy un poco romántico, me encanta llevar a mi esposa a ver los amaneceres y atardeceres en el lugar donde estamos ubicados. Por el bien de este ejercicio, digamos que no tengo un código que pueda decirme la hora del atardecer o el amanecer para cualquier fecha, latitud y longitud en la que esté.

Su tarea, codificadores, es generar el código más pequeño posible que tome una latitud y longitud decimal (tomada en grados N y W, por lo que los grados S y E se tomarán como negativos) y una fecha en el formato AAAA-MM-DD ( desde el 1 de enero de 2000 en adelante) y escupirá dos veces en formato de 24 horas para el amanecer y el atardecer.

Por ejemplo, para hoy en Sydney, Australia

riseset -33.87 -151.2 2013-12-27

05:45 20:09

Bonificaciones: -100 si puede factorizar la elevación -100 si puede factorizar el horario de verano

El código DEBE escupir tiempos en la zona horaria relevante especificada en la entrada basada en la latitud y longitud O en la zona horaria de la máquina del cliente.

WallyWest
fuente
3
Espera, ¿qué, tenemos que hacer una búsqueda [latitud x longitud] => [zona horaria]? ¿Obtenemos un archivo de datos para eso? ¿O un servidor al que podamos acceder? ¿O hay un lenguaje que tiene esas cosas incorporadas? ¿Puedes decirnos cuál? ¿O tenemos que memorizar los límites de la zona horaria? ¿Con qué precisión? ¿Dónde obtenemos estos datos? ¿Te das cuenta de que estos datos ocuparán la mayor parte de la longitud del código? ¿Qué pasa con las coordenadas que caen exactamente en el límite de la zona horaria? Digamos, los polos geográficos? Además, ¿qué comportamiento se permite cuando la entrada es una región polar durante una noche / día polar? ¿Qué pasa con las coordenadas fuera de rango?
John Dvorak
Me encantaría el desafío de calcular el horizonte en función de un punto por encima de una esfera idealizada, pero odio el desafío asociado de encontrar, comprimir a mano, decochress programáticamente y luego buscar en un mapa de búsqueda de zona horaria. A menos, por supuesto, que podamos usar zonas horarias idealizadas (el desplazamiento se elige de modo que el sol sea el más alto durante el mediodía, luego se redondea a la hora más cercana) también.
John Dvorak
1
@JanDvorak Utilice lo que se puede, si el idioma que usa puede explotar la zona horaria del cliente y luego por todos los medios hacerlo ...
Wally West
1
¿Cuál es el comportamiento deseado para las regiones polares cuando es un día / noche polar?
John Dvorak
1
Aquí hay una herramienta que hace exactamente lo mismo: weatherimages.org/latlonsun.html
Eisa Adil

Respuestas:

4

He pasado bastante tiempo escribiendo esto:

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

Ahora todavía no es funcional (arruiné algunos cálculos). Volveré a ello más tarde (si todavía tengo el coraje) para completarlo / comentarlo .

Además, algunos recursos interesantes que encontré mientras investigaba el tema:

Deneb
fuente
3
Acabo de ver su comentario de # It's late, I'm tired, and OP is a prick for asking me to do this. No había obligación de hacer esta tarea ... Por favor, no ponga comentarios como este en su código ... No se siente favorablemente con otros codificadores ... incluyéndome a mí. Admiro el hecho de que lo hayas probado y los otros enlaces que has proporcionado, pero no
vuelvas a
@ Eliseod'Annunzio Tienes mis disculpas.
Deneb
@ Eliseod'Annunzio No tenía la intención de ofenderte. También me gustaría agradecerle por darme una idea absolutamente fantástica para investigar y codificar. Ahora quiero convertir esto en un módulo de Python autónomo (con argumentos sys, etc.). Resulta ser un poco más complicado de lo que pensaba anteriormente, pero tengo la intención de lograrlo. Gracias de nuevo.
Deneb
@Alex, ¿te das cuenta de que este desafío tiene un año? Estoy bastante seguro de que ganó.
mbomb007
@ mbomb007: No me di cuenta.
Alex A.