问题
I'm wondering if there is a python function/module that calculates the local time after midnight (or local solar time) given the UTC time and longitude? It doesn't need to take into account daylight saving time.
Thanks in advance.
回答1:
Or if you want to go even shorter, you could use NOAA's low-accuracy equations:
#!/usr/local/bin/python
import sys
from datetime import datetime, time, timedelta
from math import pi, cos, sin
def solar_time(dt, longit):
return ha
def main():
if len(sys.argv) != 4:
print 'Usage: hour_angle.py [YYYY/MM/DD] [HH:MM:SS] [longitude]'
sys.exit()
else:
dt = datetime.strptime(sys.argv[1] + ' ' + sys.argv[2], '%Y/%m/%d %H:%M:%S')
longit = float(sys.argv[3])
gamma = 2 * pi / 365 * (dt.timetuple().tm_yday - 1 + float(dt.hour - 12) / 24)
eqtime = 229.18 * (0.000075 + 0.001868 * cos(gamma) - 0.032077 * sin(gamma) \
- 0.014615 * cos(2 * gamma) - 0.040849 * sin(2 * gamma))
decl = 0.006918 - 0.399912 * cos(gamma) + 0.070257 * sin(gamma) \
- 0.006758 * cos(2 * gamma) + 0.000907 * sin(2 * gamma) \
- 0.002697 * cos(3 * gamma) + 0.00148 * sin(3 * gamma)
time_offset = eqtime + 4 * longit
tst = dt.hour * 60 + dt.minute + dt.second / 60 + time_offset
solar_time = datetime.combine(dt.date(), time(0)) + timedelta(minutes=tst)
print solar_time
if __name__ == '__main__':
main()
回答2:
Using ephem
's sidereal_time()
method:
import ephem # pip install pyephem (on Python 2)
# pip install ephem (on Python 3)
def solartime(observer, sun=ephem.Sun()):
sun.compute(observer)
# sidereal time == ra (right ascension) is the highest point (noon)
hour_angle = observer.sidereal_time() - sun.ra
return ephem.hours(hour_angle + ephem.hours('12:00')).norm # norm for 24h
Note: ephem.hours
is a float number that represents an angle in radians and converts to/from a string as "hh:mm:ss.ff".
For comparison, here's the "utc + longitude" formula:
import math
from datetime import timedelta
def ul_time(observer):
utc_dt = observer.date.datetime()
longitude = observer.long
return utc_dt + timedelta(hours=longitude / math.pi * 12)
Example
from datetime import datetime
# "solar time" for some other cities
for name in ['Los Angeles', 'New York', 'London',
'Paris', 'Moscow', 'Beijing', 'Tokyo']:
city = ephem.city(name)
print("%-11s %11s %s" % (name, solartime(city),
ul_time(city).strftime('%T')))
# set date, longitude manually
o = ephem.Observer()
o.date = datetime(2012, 4, 15, 1, 0, 2) # some utc time
o.long = '00:00:00.0' # longitude (you could also use a float (radians) here)
print("%s %s" % (solartime(o), ul_time(o).strftime('%T')))
Output
Los Angeles 14:59:34.11 14:44:30
New York 17:56:31.27 17:41:27
London 22:52:02.04 22:36:58
Paris 23:01:56.56 22:46:53
Moscow 1:23:00.33 01:07:57
Beijing 6:38:09.53 06:23:06
Tokyo 8:11:17.81 07:56:15
1:00:00.10 01:00:01
回答3:
I took a look at Jean Meeus' Astronomical Algorithms. I think you might be asking for local hour angle, which can be expressed in time (0-24hr), degrees (0-360) or radians (0-2pi).
I'm guessing you can do this with ephem. But just for the heck of it, here's some python:
#!/usr/local/bin/python
import sys
from datetime import datetime, time, timedelta
from math import pi, sin, cos, atan2, asin
# helpful constant
DEG_TO_RAD = pi / 180
# hardcode difference between Dynamical Time and Universal Time
# delta_T = TD - UT
# This comes from IERS Bulletin A
# ftp://maia.usno.navy.mil/ser7/ser7.dat
DELTA = 35.0
def coords(yr, mon, day):
# @input year (int)
# @input month (int)
# @input day (float)
# @output right ascention, in radians (float)
# @output declination, in radians (float)
# get julian day (AA ch7)
day += DELTA / 60 / 60 / 24 # use dynamical time
if mon <= 2:
yr -= 1
mon += 12
a = yr / 100
b = 2 - a + a / 4
jd = int(365.25 * (yr + 4716)) + int(30.6 * (mon + 1)) + day + b - 1524.5
# get sidereal time at greenwich (AA ch12)
t = (jd - 2451545.0) / 36525
# Calculate mean equinox of date (degrees)
l = 280.46646 + 36000.76983 * t + 0.0003032 * t**2
while (l > 360):
l -= 360
while (l < 0):
l += 360
# Calculate mean anomoly of sun (degrees)
m = 357.52911 + 35999.05029 * t - 0.0001537 * t**2
# Calculate eccentricity of Earth's orbit
e = 0.016708634 - 0.000042037 * t - 0.0000001267 * t**2
# Calculate sun's equation of center (degrees)
c = (1.914602 - 0.004817 * t - .000014 * t**2) * sin(m * DEG_TO_RAD) \
+ (0.019993 - .000101 * t) * sin(2 * m * DEG_TO_RAD) \
+ 0.000289 * sin(3 * m * DEG_TO_RAD)
# Calculate the sun's radius vector (AU)
o = l + c # sun's true longitude (degrees)
v = m + c # sun's true anomoly (degrees)
r = (1.000001018 * (1 - e**2)) / (1 + e * cos(v * DEG_TO_RAD))
# Calculate right ascension & declination
seconds = 21.448 - t * (46.8150 + t * (0.00059 - t * 0.001813))
e0 = 23 + (26 + (seconds / 60)) / 60
ra = atan2(cos(e0 * DEG_TO_RAD) * sin(o * DEG_TO_RAD), cos(o * DEG_TO_RAD)) # (radians)
decl = asin(sin(e0 * DEG_TO_RAD) * sin(o * DEG_TO_RAD)) # (radians)
return ra, decl
def hour_angle(dt, longit):
# @input UTC time (datetime)
# @input longitude (float, negative west of Greenwich)
# @output hour angle, in degrees (float)
# get gregorian time including fractional day
y = dt.year
m = dt.month
d = dt.day + ((dt.second / 60.0 + dt.minute) / 60 + dt.hour) / 24.0
# get right ascention
ra, _ = coords(y, m, d)
# get julian day (AA ch7)
if m <= 2:
y -= 1
m += 12
a = y / 100
b = 2 - a + a / 4
jd = int(365.25 * (y + 4716)) + int(30.6 * (m + 1)) + d + b - 1524.5
# get sidereal time at greenwich (AA ch12)
t = (jd - 2451545.0) / 36525
theta = 280.46061837 + 360.98564736629 * (jd - 2451545) \
+ .000387933 * t**2 - t**3 / 38710000
# hour angle (AA ch13)
ha = (theta + longit - ra / DEG_TO_RAD) % 360
return ha
def main():
if len(sys.argv) != 4:
print 'Usage: hour_angle.py [YYYY/MM/DD] [HH:MM:SS] [longitude]'
sys.exit()
else:
dt = datetime.strptime(sys.argv[1] + ' ' + sys.argv[2], '%Y/%m/%d %H:%M:%S')
longit = float(sys.argv[3])
ha = hour_angle(dt, longit)
# convert hour angle to timedelta from noon
days = ha / 360
if days > 0.5:
days -= 0.5
td = timedelta(days=days)
# make solar time
solar_time = datetime.combine(dt.date(), time(12)) + td
print solar_time
if __name__ == '__main__':
main()
回答4:
Trying again, with ephem. I included latitude and elevation as arguments, but they are not needed of course. You can just call them 0
for your purposes.
#!/usr/local/bin/python
import sys
from datetime import datetime, time, timedelta
import ephem
def hour_angle(dt, longit, latit, elev):
obs = ephem.Observer()
obs.date = dt.strftime('%Y/%m/%d %H:%M:%S')
obs.lon = longit
obs.lat = latit
obs.elevation = elev
sun = ephem.Sun()
sun.compute(obs)
# get right ascention
ra = ephem.degrees(sun.g_ra) - 2 * ephem.pi
# get sidereal time at greenwich (AA ch12)
jd = ephem.julian_date(dt)
t = (jd - 2451545.0) / 36525
theta = 280.46061837 + 360.98564736629 * (jd - 2451545) \
+ .000387933 * t**2 - t**3 / 38710000
# hour angle (AA ch13)
ha = (theta + longit - ra * 180 / ephem.pi) % 360
return ha
def main():
if len(sys.argv) != 6:
print 'Usage: hour_angle.py [YYYY/MM/DD] [HH:MM:SS] [longitude] [latitude] [elev]'
sys.exit()
else:
dt = datetime.strptime(sys.argv[1] + ' ' + sys.argv[2], '%Y/%m/%d %H:%M:%S')
longit = float(sys.argv[3])
latit = float(sys.argv[4])
elev = float(sys.argv[5])
# get hour angle
ha = hour_angle(dt, longit, latit, elev)
# convert hour angle to timedelta from noon
days = ha / 360
if days > 0.5:
days -= 0.5
td = timedelta(days=days)
# make solar time
solar_time = datetime.combine(dt.date(), time(12)) + td
print solar_time
if __name__ == '__main__':
main()
回答5:
For a very simple function & very very approximated local time: Time variation goes from -12h to +12h and longitude goes from -180 to 180. Then:
import datetime as dt
def localTimeApprox(myDateTime, longitude):
"""Returns local hour approximation"""
return myDateTime+dt.timedelta(hours=(longitude*12/180))
Sample calling: localTimeApprox(dt.datetime(2014, 7, 9, 20, 00, 00), -75)
Returns: datetime.datetime(2014, 7, 9, 15, 0)
来源:https://stackoverflow.com/questions/13314626/local-solar-time-function-from-utc-and-longitude