﻿#include <Array.au3>
#include <Date.au3>

Global $iYear = 2017 ; <- das Jahr, dessen Jahreszeiten berechnet werden soll
Global $UTC, $LocalTime, $aSeasons[4][3] = [['Frühling', '', ''], ['Sommer', '', ''], ['Herbst', '', ''], ['Winter', '', '']]
For $iSeason = 0 To 3 ; die 4 Jahreszeiten durchgehen
	$UTC = _calcEquiSol($iSeason, $iYear) ; die Jahreszeit berechnen (UTC)
	$LocalTime = _UTCtoLocalTime($UTC, False) ; ohne Formatierung in die Lokalzeit umwandeln
	$aSeasons[$iSeason][1] = $LocalTime
;~ 	ConsoleWrite('>> ' & $LocalTime & @CR)
	$LocalTime = _UTCtoLocalTime($UTC, True) ; mit Formatierung in die Lokalzeit umwandeln
	$aSeasons[$iSeason][2] = $LocalTime
;~ 	ConsoleWrite('-> ' & $LocalTime & @CR)
Next
_ArrayDisplay($aSeasons, 'Jahreszeiten ' & $iYear, '', 16 + 64, Default, ' |ohne Format|mit Format')

; Author: Oscar (www.autoit.de)
Func _UTCtoLocalTime($UTC, $fFormat = False)
	Local $aDate, $aTime
	_DateTimeSplit($UTC, $aDate, $aTime) ; UTC aufsplitten
	Local $tSystem = _Date_Time_EncodeSystemTime($aDate[2], $aDate[3], $aDate[1], $aTime[1], $aTime[2], $aTime[3]) ; in Systemzeit umwandeln
	Local $tLocal = _Date_Time_SystemTimeToTzSpecificLocalTime($tSystem) ; Zeitzone + Sommerzeit beruecksichtigen
	Local $sLocalTime = _Date_Time_SystemTimeToDateTimeStr($tLocal, 1) ; ins Format "yyyy/mm/dd hh:mm:ss"
	If Not $fFormat Then Return $sLocalTime ; wenn keine formatierte Ausgabe gewuenscht, dann so zurueckgeben
	_DateTimeSplit($sLocalTime, $aDate, $aTime) ; ansonsten Lokalzeit aufsplitten
	Local $iWeekday = _DateToDayOfWeek($aDate[1], $aDate[2], $aDate[3]) ; Wochentag berechnen
	Return _DateDayOfWeek($iWeekday, 3) & '. ' & _DateTimeFormat($sLocalTime, 0) ; und formatiert zurueckgeben
EndFunc   ;==>_UTCtoLocalTime


; die folgenden Funktionen habe ich von Javascript nach AutoIt uebersetzt
; die Javascript-Funktionen stammen von "http://stellafane.org/misc/equinox.html"
;
; -----Calculate a single event for a single year (Either a Equiniox or Solstice)--------
; Meeus Astronmical Algorithms Chapter 27
Func _calcEquiSol($season, $year)
	Local Const $PI = 3.14159265358979, $fDegToRad = $PI / 180
	Local $JDE0 = _calcInitial($season, $year) ; Initial estimate of date of event
	Local $T = ($JDE0 - 2451545) / 36525
	Local $W = 35999.373 * $T - 2.47
	Local $dL = 1 + 0.0334 * Cos($W * $fDegToRad) + 0.0007 * Cos((2 * $W) * $fDegToRad)
	Local $S = _periodic24($T)
	Local $JDE = $JDE0 + ((0.00001 * $S) / $dL) ; This is the answer in Julian Emphemeris Days
	Local $TDT = _fromJDtoTDT($JDE) ; Convert Julian Days to TDT at this format "yyyy/mm/dd hh:mm:ss"
	Local $UTC = _fromTDTtoUTC($TDT) ; Convert TDT to UTC at this format "yyyy/mm/dd hh:mm:ss"
	Return $UTC
EndFunc   ;==>_calcEquiSol

; -----Calculate an initial guess as the JD of the Equinox or Solstice of a Given Year
; Meeus Astronmical Algorithms Chapter 27
Func _calcInitial($season, $year) ; Valid for years 1000 to 3000
	Local Enum $Spring, $Summer, $Autumn, $Winter
	Local $JDE = 0, $Y = ($year - 2000) / 1000
	Switch $season
		Case $Spring
			$JDE = 2451623.80984 + 365242.37404 * $Y + 0.05169 * $Y ^ 2 - 0.00411 * $Y ^ 3 - 0.00057 * $Y ^ 4
		Case $Summer
			$JDE = 2451716.56767 + 365241.62603 * $Y + 0.00325 * $Y ^ 2 + 0.00888 * $Y ^ 3 - 0.00030 * $Y ^ 4
		Case $Autumn
			$JDE = 2451810.21715 + 365242.01767 * $Y - 0.11575 * $Y ^ 2 + 0.00337 * $Y ^ 3 + 0.00078 * $Y ^ 4
		Case $Winter
			$JDE = 2451900.05952 + 365242.74049 * $Y - 0.06223 * $Y ^ 2 - 0.00823 * $Y ^ 3 + 0.00032 * $Y ^ 4
	EndSwitch
	Return $JDE
EndFunc   ;==>_calcInitial

; -----Calculate 24 Periodic Terms----------------------------------------------------
; Meeus Astronmical Algorithms Chapter 27
Func _periodic24($T)
	Local Const $PI = 3.14159265358979, $fDegToRad = $PI / 180
	Local $A[] = [485, 203, 199, 182, 156, 136, 77, 74, 70, 58, 52, 50, 45, 44, 29, 18, 17, 16, 14, 12, 12, 12, 9, 8]
	Local $B[] = [324.96, 337.23, 342.08, 27.85, 73.14, 171.52, 222.54, 296.72, 243.58, 119.81, 297.17, 21.02, 247.54, 325.15, 60.93, 155.12, 288.79, 198.04, 199.76, 95.39, 287.11, 320.81, 227.73, 15.45]
	Local $C[] = [1934.136, 32964.467, 20.186, 445267.112, 45036.886, 22518.443, 65928.934, 3034.906, 9037.513, 33718.147, 150.678, 2281.226, 29929.562, 31555.956, 4443.417, 67555.328, 4562.452, 62894.029, 31436.921, 14577.848, 31931.756, 34777.259, 1222.114, 16859.074]
	Local $S = 0
	For $i = 0 To 23
		$S += $A[$i] * Cos(($B[$i] + ($C[$i] * $T)) * $fDegToRad)
	Next
	Return $S
EndFunc   ;==>_periodic24

; -----Julian Date to TDT----------------------------------------------------------------
; Meeus Astronmical Algorithms Chapter 7
Func _fromJDtoTDT($JD)
	Local $A, $alpha
	Local $Z = Int($JD + 0.5)
	Local $F = ($JD + 0.5) - $Z
	If $Z < 2299161 Then
		$A = $Z
	Else
		$alpha = Int(($Z - 1867216.25) / 36524.25)
		$A = $Z + 1 + $alpha - Int($alpha / 4)
	EndIf
	Local $B = $A + 1524
	Local $C = Int(($B - 122.1) / 365.25)
	Local $D = Int(365.25 * $C)
	Local $E = Int(($B - $D) / 30.6001)
	Local $DT = $B - $D - Int(30.6001 * $E) + $F ; Day of Month with decimals for time
	Local $Mon = $E - ($E < 14 ? 1 : 13) ;         Month Number
	Local $Yr = $C - ($Mon > 2 ? 4716 : 4715) ;    Year
	Local $Day = Int($DT) ;                        Day of Month without decimals for time
	Local $H = 24 * ($DT - $Day) ;                 Hours and fractional hours
	Local $Hr = Int($H) ;                          Integer Hours
	Local $M = 60 * ($H - $Hr) ;                   Minutes and fractional minutes
	Local $Min = Int($M) ;                         Integer Minutes
	Local $Sec = Int(60 * ($M - $Min)) ;           Integer Seconds (Milliseconds discarded)
	Return StringFormat('%04d/%02d/%02d %02d:%02d:%02d', $Yr, $Mon, $Day, $Hr, $Min, $Sec)
EndFunc   ;==>_fromJDtoTDT

; -----Correct TDT to UTC----------------------------------------------------------------
; TDT (Terrestial Dynamical Time) was used 1984-2000
; was replaced by TT (Terrestial Time) in 2001.
Func _fromTDTtoUTC($TDT)
	; from Meeus Astronmical Algroithms Chapter 10
	; Correction lookup table has entry for every even year between TBLfirst and TBLlast
	Local $TBLfirst = 1620, $TBLlast = 2018 ; Range of years in lookup table
	Local $TBL[] = [ _ ; Corrections in Seconds
			121, 112, 103, 95, 88, 82, 77, 72, 68, 63, 60, 56, 53, 51, 48, 46, 44, 42, 40, 38, _ ; 1620
			35, 33, 31, 29, 26, 24, 22, 20, 18, 16, 14, 12, 11, 10, 9, 8, 7, 7, 7, 7, _ ; 1660
			7, 7, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, _ ; 1700
			11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, _ ; 1740
			16, 16, 16, 16, 16, 16, 15, 15, 14, 13, _ ; 1780
			13.1, 12.5, 12.2, 12.0, 12.0, 12.0, 12.0, 12.0, 12.0, 11.9, 11.6, 11.0, 10.2, 9.2, 8.2, _ ; 1800
			7.1, 6.2, 5.6, 5.4, 5.3, 5.4, 5.6, 5.9, 6.2, 6.5, 6.8, 7.1, 7.3, 7.5, 7.6, _ ; 1830
			7.7, 7.3, 6.2, 5.2, 2.7, 1.4, -1.2, -2.8, -3.8, -4.8, -5.5, -5.3, -5.6, -5.7, -5.9, _ ; 1860
			 - 6.0, -6.3, -6.5, -6.2, -4.7, -2.8, -0.1, 2.6, 5.3, 7.7, 10.4, 13.3, 16.0, 18.2, 20.2, _ ; 1890
			21.1, 22.4, 23.5, 23.8, 24.3, 24.0, 23.9, 23.9, 23.7, 24.0, 24.3, 25.3, 26.2, 27.3, 28.2, _ ; 1920
			29.1, 30.0, 30.7, 31.4, 32.2, 33.1, 34.0, 35.0, 36.5, 38.3, 40.2, 42.2, 44.5, 46.5, 48.5, _ ; 1950
			50.5, 52.5, 53.8, 54.9, 55.8, 56.9, 58.3, 60.0, 61.6, 63.0, _  ; 1980
			63.8, 64.3, 64.5, 64.8, 65.4, 66.0, 66.6, 67.2, 68.1, 69.2] ; 2000 - 2018 (2018 = prediction)
	Local $deltaT = 0 ; deltaT = TDT - UTC (in Seconds)
	Local $year = Number(StringLeft($TDT, 4))
	Local $T = ($year - 2000) / 100 ; Centuries from the epoch 2000
	If $year >= $TBLfirst And $year <= $TBLlast Then ; Find correction in table
		If Mod($year, 2) Then ; Odd year - Interpolate
			$deltaT = ($TBL[($year - $TBLfirst - 1) / 2] + $TBL[($year - $TBLfirst + 1) / 2]) / 2
		Else ; Even year - direct table lookup
			$deltaT = $TBL[($year - $TBLfirst) / 2]
		EndIf
	ElseIf $year < 948 Then
		$deltaT = 2177 + 497 * $T + 44.1 * $T ^ 2
	ElseIf $year >= 948 Then
		$deltaT = 102 + 102 * $T + 25.3 * $T ^ 2
		If $year >= 2000 And $year <= 2100 Then
			$deltaT += 0.37 * ($year - 2100) ; Special correction to avoid discontinurity in 2000
		EndIf
	Else
		Return SetError(1, 0, 0)
	EndIf
	Return _DateAdd('s', -Int($deltaT), $TDT)
EndFunc   ;==>_fromTDTtoUTC
