이 페이지는 코딩도장 데이터의 읽기 전용 정적 보관본입니다.

일출,일몰 시각 계산하기.완-3)경도를 입력하고 대기 굴절보정하여 일출일몰 계산하기

2회차 까지는 시간-시점의 간격을 다룬 것이고
마지막 회차인 이번엔 시각(예:현재 오후 한시 정각)을 다루게 됩니다.

과거에는 태양 남중 시간이 정오-즉 낮 12시 였습니다.
이런경우 경도가 다르면 시각도 다르게 됩니다.

통신도 불가능하고, 이동도 걸어서 다니거나 마차 타고 다닐 때야 문제 없겠지만
요즘 그런 제도를 쓰면 강릉과 서울도 시간이 달라져 불편함이 끝도 없겠죠.
따라서 현대는 시간 기준선으로 시간을 정 합니다.
지구경도는 360도 이고 하루는 24시간 임으로

360/24 = 15

15도 차이가 나면 1시간 차이가 납니다.
1도는 4분 차이.

따라서 15도 마다 1시간 단위로 기준시각 경도가 설정되어 있고
우리나라와 일본은 도오쿄오 주변을 지나는 동경 135도를
중국은 북경 지방을 지나는 동경 120도를 기준으로 합니다.

그 중간쯤에 있는 서울중구는 127도로 살짝 120도에 가깝지만 일본 지배 때문인지 동경135도가 기준입니다.

얼마전에 북한은 30분을 느추어 (지금은 원위치 되었나?) 세계의 지탄을 받았었습다. 15도 간격의 시간 기준선을 안지켰기 때문이죠.

그럼 본론으로 들어가서 127도인 서울에서 정오 12시에 태양 위치를 확인하면
태양은 동경 135도에 있기 때문에 8도 동쪽에 있게 됩니다.
따라서 남중시간은 8*4=32분이 느추어져 12:32분에 남중이 일어납니다.
일몰 일출도 경도에 따라 시간을 조정 해 주어야 합니다.

세계에서 다 통하는 일출 일몰 계산기를 만들려면
시간 기준선과 위치 경도를 입력하고 계산하면 됩니다.
외부 서비스를 하려면 DB 에 지역명과 그지역의 경도위도를 자료로 넣어두고 불러다 쓰면 될 겁니다.
여기서는 우리나라에서만 사용하는 것으로 하고, 135도를 시준 선으로 정합니다.

태양광의 굴절 9분(낮길이를 9분 늘림)과, 경도차이를 보정하여 일출 일몰 시간을 출력 합니다.
9분보정은 비율은 1이 1일 이기 때문에
9/60/24=0.00625를 밤 비율에서 빼주면 됩니다.
앞서 회차까지 모두 정리하면


밤길이의 비율은 2×Acos(tan(태양방향지구기울기)×tan(위도)) / 360 태양방향지구기울기 : 하지 23.5, 춘분,추분 0, 동지 -23.5, 변화는 sin 곡선을 그림
경도에 따른 차이 : 135를 기준으로 1도 작으면 4분 시간 지연
굴절에 따른 오차 조정 : 밤길이를 약9분 줄인다.(낮길이는 9분 늘어 난다)

https://blog.naver.com/i_jeju/221509242068

지구과학

2019/04/10 09:42

이이충학

- 신동준, 2019/06/09 15:24

2개의 풀이가 있습니다.

C#

using System;
using System.Text;

namespace CD223
{
    class Program
    {
        static void Main()
        {
            Console.Write("월(month): ");
            int month = int.Parse(Console.ReadLine());
            Console.Write("일(day): ");
            int day = int.Parse(Console.ReadLine());
            Console.Write("위도(degree): ");
            double latitude = double.Parse(Console.ReadLine());
            Console.Write("경도(degree): ");
            double longitude = double.Parse(Console.ReadLine());

            DayNightRatio testCase = new DayNightRatio(month, day, latitude, longitude);
            Console.WriteLine(testCase.DisplayResult());
        }
    }

    public class DayNightRatio
    {
        private readonly double AxialTilt;
        private readonly double Latitude;
        private readonly double Longitude;

        public DayNightRatio(int month, int day, double latitude, double longitude)
        {
            AxialTilt = DateToAxialTilt(month, day);
            Latitude = latitude;
            Longitude = longitude;
        }

        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 - 0.00625; // 굴절 9분 보정
        }

        public string DisplayResult()
        {
            StringBuilder sb = new StringBuilder();
            double ratio = NightRatio();
            if (ratio <= 0)
            {
                sb.AppendLine("계속 낮입니다.");
            }
            else if (ratio >= 1)
            {
                sb.AppendLine("계속 밤입니다.");
            }
            else
            {
                TimeSpan sunrise =
                    TimeSpan.FromSeconds(60 * 60 * 24 * ratio / 2);
                sunrise += TimeSpan.FromMinutes((135 - Longitude) * 4);
                TimeSpan sunset =
                    TimeSpan.FromSeconds(60 * 60 * 12 + 60 * 60 * 24 * (1 - ratio) / 2);
                sunset += TimeSpan.FromMinutes((135 - Longitude) * 4);
                sb.AppendLine($"일출 시간 {sunrise.ToString()}");
                sb.AppendLine($"일몰 시간 {sunset.ToString()}");
            }
            return sb.ToString();
        }

        // 월, 일 => 자전축 기울기 계산
        private static double DateToAxialTilt(int month, int day)
        {
            // 평년(2019년, 365일) 기준으로 일차 계산
            DateTime VernalEquinox = new DateTime(2019, 3, 21); // 춘분을 기준으로
            DateTime checkDate = new DateTime(2019, month, day);
            int timeSpan = (checkDate - VernalEquinox).Days;
            timeSpan = timeSpan < 0 ? 365 + timeSpan : timeSpan;
            // Sin 함수 적용
            double axialTilt = 23.5 * Math.Sin(ToRad(360 * (double)timeSpan / 365));
            return axialTilt;
        }

        private static double ToRad(double degree) => 2 * Math.PI / 360 * degree;

        private static double ToDeg(double rad) => 360 / (2 * Math.PI) * rad;
    }
}

2019/05/03 09:02

mohenjo

#일출, 일몰시간 계산
import math

def NightR(Q1,Q2): #밤 비율 계산
    if  abs(Q2) > abs(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

def ptime(tit,stim): #비율을 시간으로 계산 및 출력
    nti=int(stim*24)
    ims=stim*24 - nti
    nmi=int(ims*60)
    ims=ims*60 - nmi
    nse=int(ims*60+0.5)
    if nse==60 :     #반올림처리
        nse=0
        nmi=nmi+1
        if nmi==60 :
            nmi=0
            nti=nti+1
    print(tit,nti,':',nmi,':',nse)

# 월    1   2  3  4  5  6   7   8   9  10  11  12
lmsd=[285,316,344,10,40,71,101,132,163,193,214,254] #춘분(3.21)부터 전월까지 누적일
mm=int(input('월입력 :'))
dd=int(input('일입력 :'))

se2=float(input('위도 입력 :')) #북위 +, 남위 -
se3=float(input('경도 입력 :'))

pd=lmsd[mm-1]+dd #경과 날자
if pd >= 365 :   #3월 21~31일 처리
    pd=pd-365

se1=23.5*math.sin(math.radians(pd*360/365)) #각도 계산 sin90
nrat=NightR(se1,se2)
nrat=nrat-0.00625 #9분보정

if  nrat <= 0:
    print('계속 낮 입니다')
else:
    if nrat >= 1:
        print('계속 밤 입니다')
    else :
        ptime('일출시간',nrat/2+(135-se3)/360)
        ptime('일몰시간',1-nrat/2+(135-se3)/360)

수행결과
월입력 :4
일입력 :15
위도 입력 :37.5
경도 입력 :127
일출시간 5 : 57 : 1
일몰시간 19 : 6 : 59

네이버에 올라온 4월 15일 일출일몰 시간(서울) 일출 05:58 일몰 19:07

2019/04/11 09:07

이이충학

목록으로