사무실에 가로등 타이머가 고장나업체를 불러 수리 하였습니다. 그때 문득 일몰일출 시간계산 알고리즘이 궁굼해 지더군요. 그래서 일차적으로 만든 밤 길이 비율 수식은
(acos(tanθ₁×tanθ₂)×2)/360
θ₁:지구 자전축의 북쪽이 태양쪽으로 기울어진 각도
θ₂:위도(북위, 남위는 -)
acos:코싸인의 역함수
제 블로그에 자세한 유도 과정이 있습니다.
https://blog.naver.com/i_jeju/221506869006
지구 기울기와 위도를 입력하여 낮시간, 밤시간 길이를 출력해 보도록 합니다.
지구가 기울어진 각도 :23.5
위도 입력 :38
밤길이 9 : 21 : 8
낮길이 14 : 38 : 52
지구가 기울어진 각도 :23.5
위도 입력 :80
계속 낮 입니다
지구가 기울어진 각도 :-23.5
위도 입력 :80
계속 밤 입니다
기울어진 각도가 23.5 ->하지 기울어진 각도가 -23.5 ->동지
6개의 풀이가 있습니다.
#지구 기울기와 위도 입력으로 밤시간과 낮시간 계산
import math
def NightR(Q1,Q2):
if abs(Q2) > 90-abs(Q1):
if Q1*Q2 > 0:
return 0
if Q1*Q2 < 0:
return 1
#밤 비율 계산
rat1=math.acos(math.tan(math.radians(Q1))*math.tan(math.radians(Q2)))
rat2=2*math.degrees(rat1)
return rat2/360
se1=float(input('지구가 기울어진 각도 :')) #북극이 태양쪽으로 기울어진 것이 +
se2=float(input('위도 입력 :')) #북위 +, 남위 -
nrat=NightR(se1,se2)
if nrat == 0:
print('계속 낮 입니다')
else:
if nrat == 1:
print('계속 밤 입니다')
else :
#밤 길이 비율을 시간으로 계산
nti=int(nrat*24)
ims=nrat*24 - nti
nmi=int(ims*60)
ims=ims*60 - nmi
nse=int(ims*60+0.5)
#낮 길이 비율을 시간으로 계산
ati=int((1-nrat)*24)
ims=(1-nrat)*24 - ati
ami=int(ims*60)
ims=ims*60 - ami
ase=int(ims*60+0.5)
#인쇄
print('밤길이',nti,':',nmi,':',nse)
print('낮길이',ati,':',ami,':',ase)
밤 비율이기 대문에 1은 하루-24시간 입니다.
시스템에서는 레디안을 사용하고 경도 위도 등은 디그리를 사용 하기 때문에 변환이 필요 합니다.
math.degrees() 는 레디안을 디그리로 바꾸는 함수 입니다.
math.radians()는 디그리를 레디안으로 바꾸는 함수구요.
C#
using System;
using System.Text;
namespace CD220
{
internal class Program
{
private static void Main()
{
Console.Write("지구가 기울어진 각도(degree): ");
double axialTile = double.Parse(Console.ReadLine());
Console.Write("위도(degree): ");
double latitude = double.Parse(Console.ReadLine());
DayNightRatio testCase = new DayNightRatio(axialTile, latitude);
Console.WriteLine(testCase.ToString());
}
}
public class DayNightRatio
{
private readonly double AxialTilt;
private readonly double Latitude;
public DayNightRatio(double axialTilt, double latitude) // 각도(Degree) 단위 입력
{
AxialTilt = axialTilt;
Latitude = latitude;
}
private double NightRatio()
{
if (Math.Abs(AxialTilt) > 90 - Math.Abs(Latitude))
{
return AxialTilt * Latitude >= 0 ? 0 : 1;
}
double theta3Rad =
Math.Acos(Math.Tan(ToRad(AxialTilt)) * Math.Tan(ToRad(Latitude)));
return 2 * ToDeg(theta3Rad) / 360;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
double ratio = NightRatio();
if (ratio == 0)
{
sb.AppendLine("계속 낮입니다.");
}
else if (ratio == 1)
{
sb.AppendLine("계속 밤입니다.");
}
else
{
TimeSpan nightTime = TimeSpan.FromSeconds(60 * 60 * 24 * ratio);
TimeSpan dayTime = TimeSpan.FromSeconds(60 * 60 * 24 * (1 - ratio));
sb.AppendLine($"낮의 길이 {dayTime.ToString()}");
sb.AppendLine($"밤의 길이 {nightTime.ToString()}");
}
return sb.ToString();
}
private static double ToRad(double degree) => 2 * Math.PI / 360 * degree;
private static double ToDeg(double rad) => 360 / (2 * Math.PI) * rad;
}
}
import math
import time
def nightT(ax, lat):
th1 = math.radians(ax)
th2 = math.radians(lat)
nt = math.acos(math.tan(th1)*math.tan(th2))
ntR = (2*math.degrees(nt))/360
print('밤길이: {}'.format(time.strftime('%H:%M:%S', time.gmtime(ntR * 24 * 3600 + 0.5))))
print('낮길이: {}'.format(time.strftime('%H:%M:%S', time.gmtime((1-ntR) * 24 * 3600 + 0.5))))
if __name__ == '__main__':
ax = 23.5
lat = 38
nightT(ax, lat)
Go 1.14.4
package main
import (
"fmt"
"math"
)
func deg(rad float64) (y float64) {
y = rad * 180 / math.Pi
return
}
func rad(deg float64) (y float64) {
y = deg * math.Pi / 180
return
}
func night(theta1, theta2 float64) {
if math.Abs(theta2) > 90-math.Abs(theta1) {
if theta1*theta2 > 0 {
fmt.Println("계속 낮입니다.")
} else {
fmt.Println("계속 밤입니다.")
}
} else {
rat1 := deg(math.Acos(math.Tan(rad(theta1))*math.Tan(rad(theta2)))) / 180
nti := int(rat1 * 24)
ims := rat1*24 - float64(nti)
nmi := int(ims * 60)
ims = ims*60 - float64(nmi)
nse := int(ims*60 + 0.5)
ati := int((1 - rat1) * 24)
ims = (1-rat1)*24 - float64(ati)
ami := int(ims * 60)
ims = ims*60 - float64(ami)
ase := int(ims*60 + 0.5)
fmt.Printf("밤길이 %d:%d:%d\n낮길이 %d:%d:%d\n", nti, nmi, nse, ati, ami, ase)
}
}
func main() {
var theta1, theta2 float64
var n1, n2 int
fmt.Printf("지구가 기울어진 각도: ")
n1, _ = fmt.Scanf("%f\n", &theta1)
fmt.Printf("위도 입력: ")
n2, _ = fmt.Scanf("%f\n", &theta2)
if n1 != 1 && n2 != 1 {
fmt.Println("잘못된 값이 입력되었습니다.")
} else {
night(theta1, theta2)
}
}
import math
def sunRiseNSet(a, l):
nightRatio = math.degrees(math.acos(math.tan(math.radians(a)) * math.tan(math.radians(l)))) * 2 / 360
nh = str(round(nightRatio * 86400 / (60 * 60))).zfill(2)
nm = str(round(nightRatio * 86400 % (60 * 60) / 60)).zfill(2)
ns = str(round(nightRatio * 86400 % (60 * 60) % 60)).zfill(2)
dh = str(23 - int(nh)).zfill(2)
dm = str(59 - int(nm)).zfill(2)
ds = str(60 - int(ns)).zfill(2)
print("낮시간 - " + dh + ":" + dm + ":" + ds)
print("밤시간 - " + nh + ":" + nm + ":" + ns)
sunRiseNSet(23.5, 38)
from math import *
ang = float(input("지구와의 기울기 입력"))
lat = float(input("위도를 입력 하시오"))
def ratio (a,l):
if abs(l) > 90-abs(a):
if a*l >0:
print("계속 밤입니다")
elif a*l < 0 :
print("계속 낮입니다")
else:
a = radians(ang)
l = radians(lat)
night_ratio = degrees(acos(tan(a)*tan(l)))*2/360
day = 60*60*24 #하루 초
n=int(day*night_ratio)
d=int(day*(1-night_ratio))
print("밤길이 {0}:{1}:{2}".format(n//3600,n%3600//60,n%3600%60))
print("낮길이 {0}:{1}:{2}".format(d//3600,d%3600//60,d%3600%60))
ratio(ang,lat)