logo  How To Calculate Sunrise and Sunset Times
This Chapter
Sun and Moon
Equinox&Solstice
Moon Phases
Sun Rise&Set
Chapters
Home Page
Colours, RGB
Computer Specifications
Dates&Times
Disk Drives
Files
Folders
GPS and OS Ref
VB.Net Forms
Image Files
If & Select
List/Array
Mathematics
NuGet
Sound
String Functions
Sun and Moon
User Controls
Validation
DigitalDan Sites
My Other Sites
Contact Site

Note
Some pages
may contain
inaccuracies
Hits=7
This formula calculates times for Normal, Civil, Nautical and Astrological Sunrise and Sunset. It is based on a spreadsheet publised by the National Oceanic and Atmospheric Administration (NOAA). However, as with any Calendrical Calculation, programmers need to be aware of certain limitations.
At the time of writing this page, the NOAA spreadsheetwas available via https://gml.noaa.gov/grad/solcalc/NOAA_Solar_Calculations_day.xls

' Notes
' Times are approximate, usually within a couple of minutes but larger errors possible in polar regions
' Some timezone/latitude/longitude/sunrise-type combinations can result in sunrises before midnight
' or sunsets after midnight. You may need to check sunrise/sunset dates as well as the times.
' You must check the SunError flag on the returned value.
' SunError = True means that the sun will not rise/set on requested date/lat/long
'
' Returned times are always GMT.
' They can be converted into local time using the VB.Net "built in" function .ToLocalTime()
'
' RiseType.Normal is the most frequently used value for RiseType1
'
Public Function SunRise(Dat As Date, Lat As Double, lon As Double, RiseType1 As RiseType) As SunTimes
 Dim B3, B4, E2, F2, G2, I2, J2, K2, L2, M2, N2, O2, P2 As Double
 Dim Q2, R_I2, R_J2, R2, S2, T2, U2, V2, W2, W2_a, X2, Y2, Z2, sunAngle As Double
 Dim tempDate As Date
 Dim st As SunTimes
 Select Case RiseType1
  Case RiseType.Normal : sunAngle = 90 + 50 / 60
  Case RiseType.Civil : sunAngle = 96
  Case RiseType.Nautical : sunAngle = 102
  Case RiseType.Astrological : sunAngle = 108
 End Select
 B3 = Lat
 B4 = lon
 E2 = Dat.Hour / 24 + (Dat.Minute / (24 * 60))
 F2 = Gregorian_To_JulianDay(Dat)
 G2 = (F2 - 2451545) / 36525
 I2 = 280.46646
 I2 += G2 * (36000.76983 + G2 * 0.0003032) Mod 360 '
 I2 = Zero_360(I2)
 J2 = 357.52911
 J2 += G2 * (35999.05029 - 0.0001537 * G2) '
 K2 = 0.016708634
 K2 -= G2 * (0.000042037 + 0.0000001267 * G2)
 L2 = Math.Sin(Radians(J2)) * (1.914602 - G2 * (0.004817 + 0.000014 * G2))
 L2 += Math.Sin(Radians(2 * J2)) * (0.019993 - 0.000101 * G2)
 L2 += Math.Sin(Radians(3 * J2)) * 0.000289
 M2 = I2 + L2
 N2 = J2 + L2
 O2 = (1.000001018 * (1 - K2 * K2)) / (1 + K2 * Math.Cos(Radians(N2)))
 P2 = M2 - 0.00569
 P2 -= 0.00478 * Math.Sin(Radians(125.04 - 1934.136 * G2))
 Q2 = 23 + (26 + ((21.448 - G2 * (46.815 + G2 * (0.00059 - G2 * 0.001813)))) / 60) / 60
 R2 = Q2 + 0.00256 * Math.Cos(Radians(125.04 - 1934.136 * G2))
 S2 = Degrees(Math.Atan2(Math.Cos(Radians(R2)) * Math.Sin(Radians(P2)), Math.Cos(Radians(P2))))
 T2 = Degrees(Math.Asin(Math.Sin(Radians(R2)) * Math.Sin(Radians(P2)))) '
 U2 = Math.Tan(Radians(R2 / 2)) * Math.Tan(Radians(R2 / 2))
 ' changes made to shorten lines, avoid excessively long lines on (minor browser issues)
 ' the changes do not affect the results of V2 or W2 calculations
 R_I2 = Radians(I2)
 R_J2 = Radians(J2)
 V2 = U2 * Math.Sin(2 * R_I2)
 V2 -= 2 * K2 * Math.Sin(R_J2)
 V2 += 4 * K2 * U2 * Math.Sin(R_J2) * Math.Cos(2 * R_I2)
 V2 -= 0.5 * U2 * U2 * Math.Sin(4 * R_I2)
 V2 -= 1.25 * K2 * K2 * Math.Sin(2 * R_J2)
 V2 = 4 * Degrees(V2)
 W2_a = Math.Cos(Radians(sunAngle)) / (Math.Cos(Radians(B3)) * Math.Cos(Radians(T2)))
 W2_a -= Math.Tan(Radians(B3)) * Math.Tan(Radians(T2))
 If W2_a <= -1 OrElse W2_a >= 1 Then ' the sun does not rise or set
     Return FlagError()
 End If
 W2 = Degrees(Math.Acos(W2_a))
 X2 = (720 - 4 * B4 - V2) / 1440
 Y2 = X2 - W2 * 4 / 1440
 Z2 = X2 + W2 * 4 / 1440
 st.RiseTime = ExcelDate_To_Gregorian(Y2)
 tempDate = New Date(Dat.Year, Dat.Month, Dat.Day, 0, 0, 0, 0, 0)
 tempDate = tempDate.AddHours(st.RiseTime.Hour)
 tempDate = tempDate.AddMinutes(st.RiseTime.Minute)
 tempDate = tempDate.AddSeconds(st.RiseTime.Second)
 st.RiseTime = tempDate
 st.SetTime = ExcelDate_To_Gregorian(Z2)
 tempDate = New Date(Dat.Year, Dat.Month, Dat.Day, 0, 0, 0, 0, 0)
 tempDate = tempDate.AddHours(st.SetTime.Hour)
 tempDate = tempDate.AddMinutes(st.SetTime.Minute)
 tempDate = tempDate.AddSeconds(st.SetTime.Second)
 st.SetTime = tempDate
 st.SunError = False
 Return st
End Function
'
Private Function JulianDay_To_Gregorian(JulianDay As Double) As Date
 ' The JulianDay epoch date is in in a year over 4000 years BC.
 ' VB.Net functions do not expect dates from ancient pre-historic times
 ' The number 2400000.5, combined with a "modified" epoch in 1858 avoids various problems
 Return New Date(1858, 11, 17, 0, 0, 0, 0, 0).AddDays(JulianDay - 2400000.5)
End Function
'
Private Function Gregorian_To_JulianDay(dat_Greg As Date) As Double
 ' Calculate Julian Day via Modified Julian Day because dotNet compiler dislikes the year -4712 used in Julian Day epoch
 Dim mjd As Double = DateDiff(DateInterval.Second, New Date(1858, 11, 17, 0, 0, 0, 0, 0), dat_Greg)
 Return (mjd / (24 * 3600)) + 2400000.5
End Function
'
Private Function Radians(a As Double) As Double
 Return a * Math.PI / 180
End Function
'
Private Function Degrees(a As Double) As Double
 Return a * 180 / Math.PI
End Function
'
Private Function ExcelDate_To_Gregorian(ExcelDate As Double) As Date
 ' Excel Time Stamp should not be used for dates prior to 1901
 Return New Date(1899, 12, 30, 0, 0, 0, 0, 0).AddDays(ExcelDate)
End Function
'
Private Function Zero_360(a As Double) As Double
 If a >= 0 Then Return a Mod 360
 Dim b As Integer = CInt(Math.Floor(Math.Abs(a) / 360)) + 1
 Return (a + (b * 360)) Mod 360
End Function
'
Private Function FlagError() As SunTimes
 Dim ret As SunTimes
 ret.RiseTime = New Date(1900, 1, 1, 0, 0, 0, 0, 0)
 ret.SetTime = New Date(1900, 1, 1, 0, 0, 0, 0, 0)
 ret.SunError = True
 Return ret
End Function
'
Public Structure SunTimes
 Dim RiseTime As Date
 Dim SetTime As Date
 Dim SunError As Boolean
End Structure
'
Public Enum RiseType
 Normal
 Civil
 Nautical
 Astrological
End Enum
  
How to Obtain SunRise/Sunset in UT (GMT or Time Zone 0)
Get Sunrise and Sunset for Normal Sunrise in Universal-Time for 24 January 2026 at latitude 51.7143 and Longitude -5.0427

Dim dat As New Date(2026, 1, 24, 12, 0, 0, 0, 0, 0)
Dim st as SunTimes = SunRise(dat, 51.7143, -5.0427, RiseType.Normal)
Dim result As String
If st.SunError Then
 result = "Sun does not rise/set"
Else
 result = "Sunrise "& st.RiseTime.ToString("ddd dd MMM yyyy - HH:mm")
 result &= " SunSet "& st.SetTime.ToString("ddd dd MMM yyyy - HH:mm")
End If
  
How to Obtain SunRise/Sunset in host computers Local Time
Get Sunrise and Sunset for Astrological Sunrise in Host-Computers_Local-Time for 24 January 2026 at latitude 51.7143 and Longitude -5.0427

Dim dat As New Date(2026, 1, 24, 12, 0, 0, 0, 0, 0)
Dim st as SunTimes = SunRise(dat, 51.7143, -5.0427, RiseType.Astological)
Dim result As String
If st.SunError Then
 result = "Sun does not rise/set"
Else
 result = "Sunrise "& st.RiseTime.ToLocalTime().ToString("ddd dd MMM yyyy - HH:mm")
 result &= " SunSet "& st.SetTime.ToLocalTime().ToString("ddd dd MMM yyyy - HH:mm")
End If
  

DigitalDan.co.uk