春、秋分时,世界各地昼夜时长相等,都为 12h。由于黄赤交角的存在,太阳直射点在一年中在南北回归线之间移动。地轴可以被理解为地心与北极星的连线,垂直于赤道平面。而地球围绕太阳旋转的黄道平面与赤道平面呈约 23°26'的角。因此每年的夏至日,太阳直射点落在北回归线(23°26'N),冬至日则在南回归线(23°26'S)。

图片来自网络,侵删

根据日期或历法计算太阳直射点所在纬度不在本文的讨论范围内。假设我们已知太阳直射点所在纬度,那么可以计算地球上任意一点的昼长。在讨论这个话题时,不妨将地球看作不透光的理想球体,那么,地球上已知纬度的任意一点所在沿纬线的截面圆半径 rrcosθ\cos \thetaθθ 为当地纬度值,则该截面圆圆心到地心的连线 llsinθ\sin \theta

好,现在你应该已经有一个理想地球的建模了。现在再来考虑太阳直射点所在纬度,即太阳光线与地心连线交地表所在点的纬度,设为 ψψ。由于地球是不透光的,所以地球的一半为白昼,另一半为黑夜,交线称作“晨昏线”。仍然是黄赤交角,使其切面圆直径与地轴夹角始终为 ψψ

进行简单的几何运算

d=l×tanψd=l\times \tan ψ

即可确定关键的角 αα

cosα=dr\cos \alpha=\frac{d}{r}

理想地球和纬度为 θ 的截面圆

arcsindr\arcsin \frac{d}{r} 可解出 αααα 的作用是确定黑夜占一天的比重。白昼则占:

παπ\frac{\pi - \alpha}{\pi}

则当地白昼时长就迎刃而解了:

T=T×παπT_昼=T\times\frac{\pi - \alpha}{\pi}

这是由于:

T=2πωT昼 =2(πα)ω\begin{aligned} T & =\frac{2 \pi}{\omega} \\ T_{\text {昼 }} & =\frac{2(\pi-\alpha)}{\omega} \end{aligned}

TT 为一个恒星日,ω\omega 为地球自转的角速度。

我将其写为程序,以下。当纬度在南半球时,输入负值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from math import *  

input_1 = eval(input("输入太阳直射点纬度:"))
input_2 = eval(input("输入当地纬度:"))

x, y = radians(input_1), radians(input_2)
print("x={}, y={}".format(x, y))
a = 2 * cos(y)
b = sin(y)
c = b * tan(x)
cos_alpha = c / (a / 2)
"""
错误算法:
cos_alpha = (
(input_2 / 90) # 纬度不具有长度比例意义
* tan(x)) / a
"""
alpha = acos(cos_alpha)
print(
"cos(alpha)={}, alpha={}, degrees(alpha)={}"
.format(cos_alpha, alpha, degrees(alpha))
)
h = 24 * (1 - (alpha / pi))
sunrise = 12 - h / 2
sunset = 12 + h / 2
print(
"h={},sunrise={},sunset={}"
.format(h, sunrise, sunset)
)
  • input_1input_2 为角度值
  • xy 为弧度值,对应上文的 ψψθθ
  • a:当地纬度截面圆直径,相当于上文的 2r2r
  • b:当地纬度截面圆心与地心的连线,对应 ll
  • c:晨昏线与当地纬度截面圆直径的交点到当地纬度截面圆心与地心的连线的距离,对应 dd
  • alpha:黑夜(劣弧)所对圆心角一半弧度,对应 α\alpha
  • h:当地白昼时长,对应 TT_昼

上述代码中我给出了错误示例。在建模过程中,不能将纬度的变化看作线性的函数曲线,否则就会犯昼长随纬度平均变化的错误。这导致在开始研究这个灵感时我计算出太阳直射北回归线时北回归线的白昼时长比十五小时还多,与真实情况相差一个半小时之久,好可怕。

这是上述代码开源在 Github 的项目,你若有更多运用地理知识的想法,那就快去贡献吧。比如根据日期和历法计算太阳直射点,达到计算当天昼长的效果。根据对称法则,日出日落时间也就不难得到了。

Cystee/calcDay

今天(3 月 18 日)的昼长十分接近 12h ,这是为什么呢?