Bug 113339 - Sunset & sunrise times are crazy in UK
Summary: Sunset & sunrise times are crazy in UK
Status: RESOLVED FIXED
Alias: None
Product: kweather-kde3
Classification: Applications
Component: general (show other bugs)
Version: unspecified
Platform: openSUSE Linux
: NOR normal
Target Milestone: ---
Assignee: geiseri
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-09-26 06:54 UTC by Francois C.
Modified: 2006-12-25 16:10 UTC (History)
0 users

See Also:
Latest Commit:
Version Fixed In:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Francois C. 2005-09-26 06:54:40 UTC
Version:           2.1.0 (using KDE KDE 3.4.0)
Installed from:    SuSE RPMs
Compiler:          gcc-3.3.5 
OS:                Linux

I first noticed this bug in kdetoys-3.4 package of Suse 9.3 but even if there is a lot of topics in this forum stated that this bug is fixed, I don't this so.

Today, I compiled from sources kdetoys-3.4.2 using the KDE-3.4-devel files because KDE 3.4 is running on my box.

Sunset et sunrise times of some cities in the UK are ...

London,UK : SR=06:00 SS=19:00
Paris,FR : SR=06:00 SS=19:00 (strange)
Glasgow,UK : SR=15:41 SS=19:00 (pretty dark over there)
Edinburgh,UK : SR=15:36 SS=19:00 (not better than Glasgow)

Where are live, times returned are better but not very accurate ...

Adelaide,AU : SR=6:59 SS=19:00

According to weather.com the correct times should be ...

London, UK : SR=6:53 SS=18:49
Paris, FR : SR=7:43 SS=19:38
Edinburgh, UK : SR=7:06 SS=19:01
Glasgow, UK : SR=7:11 SS=19:06
Adelaide, AU : SR=05:30 SS=17:45

This bug leads also to a mess up in icons displayed by the applet ...
Comment 1 Thiago Macieira 2005-09-26 07:43:33 UTC
Looks like your timezone setting is wrong.
Comment 2 Francois C. 2005-09-26 09:09:21 UTC
Not logical because times displayed by Clock applet are all right.

Local TimeZone : 2005/09/26 @ 16:22
America/Montreal : 2005/09/26 @ 02:52
Europe/London : 2005/09/26 @ 07:53

and

belgix@edinburgh:~> date
Mon Sep 26 16:26:13 CST 2005

Never mind, it really weird to have a sunset time difference of more than 9 hrs for 2 cities located 400 km apart (London vs Scotland).

The only unusual thing for Linux system is ... I set the local time instead of UTC time on my laptop because I'm also running W2K in a virtual machine.
Comment 3 Francois C. 2006-03-26 11:58:45 UTC
Problem found & it happens when the user's timezone is not divisible by 60 (i.e Adelaide, AU GMT+10.5 amd/or St-John, Newfoundland, CA GMT-4.5). In such case MyString.setHMS(hours, minutes, seconds) return an error if hours and/or minutes value(s) is invalid. How is it possible ?

Case 1. Set UTC at 15:45. For Adelaide, we must add 10:30 to UTC time to get local time. Buzz. MyString.setHMS(25, 75, 0) return invalid value.

Case 2. Set UTC at 12:00. For St-John, we must substract 4:30 to UTC time to get local time. Buzz again. MyString.setHMS(8, -30, 0) return invalid value too.

I submitted a patch to Novell to fix this issue. More explanation take a look at https://bugzilla.novell.com/show_bug.cgi?id=160808

Please apply the patch submitted to SuSE to fix this issue for all distros.
Comment 4 Francois C. 2006-03-27 13:48:52 UTC
Sorry for a stupid mistake with MetarParser::isNight() logic for Midnight Sun / Polar Night ... Take this patches instead.

--- sun.cpp	2006-03-26 15:30:00.000000000 +0930
+++ kdetoys-3.5.1/kweather/sun.cpp	2006-03-26 08:39:39.000000000 +0930
@@ -12,6 +12,8 @@
         Released to the public domain by Paul Schlyter, December 1992
         Portions Modified to SUNDOWN.NLM by Cliff Haas 98-05-22
 	Converted to C++ and modified by John Ratke
+    Bugfix: Sun::convertDoubleToLocalTime() returning invalid values when
+      m_localUTCOffset is not divisible by 60 - Francois Chenier 06-03-25

 ***************************************************************************/

@@ -199,10 +201,15 @@
 }


-QTime Sun::convertDoubleToLocalTime( const double time )
+QTime Sun::convertDoubleToLocalTime( const double UTCtime )
 {
 	QTime result;

+	// Converting to LocalTime after time is set in HMS format will lead to
+	// invalid time results when m_localUTCOffset is not divisible by 60.
+	double time = UTCtime + m_localUTCOffset / 60;
+	time += (time < 0) ? 24.0 : (time > 24) ? -24.0 : 0.0;
+
 	// Example:  say time is 17.7543  Then hours = 17 and minutes = 0.7543 * 60 = 45.258
 	int hours   = (int)floor(time);
 	int minutes = (int)floor((time - hours) * 60);
@@ -211,10 +218,8 @@
 	// Use rint instead of nearbyint because rint is in FreeBSD
 	int seconds = (int)rint( fabs( minutes - ((time - hours) * 60) ) * 60 );

-	// Try to set the hours, minutes and seconds for the local time.
-	// If this doesn't work, then we will return the invalid time.
-	result.setHMS( hours + (m_localUTCOffset / 60), minutes + (m_localUTCOffset % 60), seconds );
-
+	// Invalid time should never happens now!
+	result.setHMS( hours, minutes, seconds );
 	return result;
 }

--- metar_parser.cpp	2006-03-26 15:45:42.000000000 +0930
+++ kdetoys-3.5.1/kweather/metar_parser.cpp	2006-03-26 12:51:11.000000000 +0930
@@ -7,6 +7,11 @@
                      : (C) 2002-2004 Nadeem Hasan <nhasan@kde.org>
                      : (C) 2002-2004 Ian Geiser <geiseri@kde.org>
 email                : jratke@comcast.net
+fixes                : Relative humidity > than 100% <belgix@kern.com.au>
+                     : IsNight() returning a wrong value when civilStart is
+                       greater than civilEnd <belgix@kern.com.au>
+                     : IsNight() returning a wrong value for people living
+                       inside the polar circle area <belgix@kern.com.au>
 ***************************************************************************/

 /***************************************************************************
@@ -411,6 +416,8 @@
 {
 #define E(t) ::pow(10, 7.5*t/(237.7+t))
 	float fRelHumidity = E(weatherInfo.dewC)/E(weatherInfo.tempC) * 100;
+	if (fRelHumidity > 100.0)
+		fRelHumidity = 100.0;
 	weatherInfo.qsRelHumidity.sprintf("%.1f", fRelHumidity);
 	removeTrailingDotZero(weatherInfo.qsRelHumidity);
 	weatherInfo.qsRelHumidity += "%";
@@ -830,18 +837,29 @@
 	else
 	{
 		Sun theSun( latitude, longitude , m_date, m_localUTCOffset );
 		QTime currently = m_time;

 		QTime civilStart = theSun.computeCivilTwilightStart();
 		QTime civilEnd   = theSun.computeCivilTwilightEnd();

		kdDebug (12006) << "station, current, lat, lon, start, end, offset: " <<
				upperStationID << " " << currently << " " << latitude << " " <<
 				longitude << " " << civilStart << " " << civilEnd << " " <<
 				m_localUTCOffset << endl;

-		return (currently < civilStart || currently > civilEnd);
+		if (civilStart != civilEnd)
+			if (civilStart < civilEnd)
+				// For people who lives on the eastern side of the Earth.
+				return (currently < civilStart || currently > civilEnd);
+			else
+				// For people who lives on the western side of the Earth.
+				return (currently < civilStart && currently > civilEnd);
+		else
+			// Midnight Sun & Polar Night - In summer, the Sun is always
+			// over the horizon line ... so use latitude & today date to
+			// set isNight() value.
+			return ((m_date.daysInYear() >= 80 || m_date.daysInYear() <= 264) && latitude.contains("S"));
 	}
 }

Comment 5 Martin Koller 2006-12-25 16:10:29 UTC
SVN commit 616456 by mkoller:

BUG: 136312
BUG: 129679
BUG: 115920
BUG: 113339
BUG: 87642

Fix the calculation of sunrise/sunset and the calculation of
isNight.
Patch provided by J.O. Aho


 M  +18 -1     metar_parser.cpp  
 M  +26 -4     sun.cpp  


--- branches/KDE/3.5/kdetoys/kweather/metar_parser.cpp #616455:616456
@@ -411,6 +411,8 @@
 {
 #define E(t) ::pow(10, 7.5*t/(237.7+t))
 	float fRelHumidity = E(weatherInfo.dewC)/E(weatherInfo.tempC) * 100;
+        if (fRelHumidity > 100.0) fRelHumidity = 100.0; 
+
 	weatherInfo.qsRelHumidity.sprintf("%.1f", fRelHumidity);
 	removeTrailingDotZero(weatherInfo.qsRelHumidity);
 	weatherInfo.qsRelHumidity += "%";
@@ -841,7 +843,22 @@
 				longitude << " " << civilStart << " " << civilEnd << " " <<
 				m_localUTCOffset << endl;
 
-		return (currently < civilStart || currently > civilEnd);
+		if (civilStart != civilEnd)
+		{
+			if (civilEnd < civilStart)
+				/* Handle daylight past midnight in local time     */
+				/* for weather stations located at other timezones */
+				return (currently < civilStart && currently > civilEnd);
+			else
+				return (currently < civilStart || currently > civilEnd);
+		}
+		else
+		{
+			// Midnight Sun & Polar Night - In summer, the Sun is always 
+			// over the horizon line ... so use latitude & today date to 
+			// set isNight() value. 
+			return ((m_date.daysInYear() >= 80 || m_date.daysInYear() <= 264) && latitude.contains("S")); 
+		}
 	}
 }
 
--- branches/KDE/3.5/kdetoys/kweather/sun.cpp #616455:616456
@@ -204,20 +204,42 @@
 	QTime result;
 	
 	// Example:  say time is 17.7543  Then hours = 17 and minutes = 0.7543 * 60 = 45.258
+        // We need to convert the time to CORRECT local hours
 	int hours   = (int)floor(time);
+	int localhours = hours + (m_localUTCOffset / 60);
+
+	// We need to convert the time to CORRECT local minutes
 	int minutes = (int)floor((time - hours) * 60);
+	int localminutes = minutes + (m_localUTCOffset % 60);
 
-	int localhours = hours + (m_localUTCOffset / 60); 
-	if (localhours < 0) { localhours += 24; } 
-	if (localhours >= 24) { localhours -= 24; } 
+	// We now have to adjust the time to be within the 60m boundary
+	if (localminutes < 0)
+	{
+		//As minutes is less than 0, we need to
+		//reduce a hour and add 60m to minutes.
+		localminutes += 60;
+		localhours--;
+	}
+	if (localminutes >= 60)
+  {
+		//As minutes are more than 60, we need to
+		//add one more hour and reduce the minutes to
+		//a value between 0 and 59.
+		localminutes -= 60;
+		localhours++;
+	}
 
 	// Round up or down to nearest second.
 	// Use rint instead of nearbyint because rint is in FreeBSD
 	int seconds = (int)rint( fabs( minutes - ((time - hours) * 60) ) * 60 );
 
+	// We now have to adjust the time to be within the 24h boundary
+	if (localhours < 0) { localhours += 24; }
+	if (localhours >= 24) { localhours -= 24; }
+
 	// Try to set the hours, minutes and seconds for the local time.
 	// If this doesn't work, then we will return the invalid time.
-	result.setHMS( localhours, minutes + (m_localUTCOffset % 60), seconds );
+	result.setHMS( localhours, localminutes, seconds );
 
 	return result;	
 }