[Xfce4-commits] <xfce4-weather-plugin:master> Rework code to get current weather.

Harald Judt noreply at xfce.org
Fri Jul 13 16:50:01 CEST 2012


Updating branch refs/heads/master
         to 3e338a930c21ecd707b4d3da20a74d0fa52f7a18 (commit)
       from cc67b84f3104e88deb3c26263c0ccc7e5c529685 (commit)

commit 3e338a930c21ecd707b4d3da20a74d0fa52f7a18
Author: Harald Judt <h.judt at gmx.at>
Date:   Tue Jul 10 13:30:58 2012 +0200

    Rework code to get current weather.
    
    For future plans we need to rework the code which gets data about
    the current weather. We do this in a manner similar to getting
    data for a forecast, only this time we search for the shortest
    interval possible, preferring a timeslice near the current time.
    
    While this commit won't break compilation, it introduces
    memory leaks which will be solved in subsequent commits.

 panel-plugin/weather-data.c    |  130 ++++++++++++++++++++++++++++------------
 panel-plugin/weather-parsers.c |   72 ++++++++++++----------
 2 files changed, 131 insertions(+), 71 deletions(-)

diff --git a/panel-plugin/weather-data.c b/panel-plugin/weather-data.c
index 9a9a5eb..f42aa8d 100644
--- a/panel-plugin/weather-data.c
+++ b/panel-plugin/weather-data.c
@@ -215,6 +215,7 @@ time_calc(struct tm tm_time, gint year, gint month, gint day, gint hour, gint mi
     time_t result;
     struct tm tm_new;
     tm_new = tm_time;
+    tm_new.tm_isdst = -1;
     if (year)
         tm_new.tm_year += year;
     if (month)
@@ -242,43 +243,82 @@ time_calc_day(struct tm tm_time, gint days) {
 }
 
 /*
- * Find a timeslice that best matches the start and end times within
- * reasonable limits.
+ * Find timeslice of the given interval near start and end
+ * times. Shift maximum prev_hours_limit hours into the past and
+ * next_hours_limit hours into the future.
  */
 xml_time *
-find_timeslice(xml_weather *data, struct tm tm_start, struct tm tm_end)
+find_timeslice(xml_weather *data, struct tm tm_start, struct tm tm_end,
+			   gint prev_hours_limit, gint next_hours_limit)
 {
-    time_t start_t, end_t;
-    gint hours, hours_limit = 3, interval = 0, interval_limit;
-
-    /* first search for intervals of the same length */
-    start_t = mktime(&tm_start);
-    end_t = mktime(&tm_end);
-    interval_limit = (gint) (difftime(end_t, start_t) / 3600);
-
-    while (interval <= interval_limit) {
-        hours = 0;
-        while (hours <= hours_limit) {
-            /* check with previous hours */
-            start_t = time_calc_hour(tm_start, 0 - hours);
-            end_t = time_calc_hour(tm_end, 0 - hours - interval);
-
-            if (has_timeslice(data, start_t, end_t))
-                return get_timeslice(data, start_t, end_t);
-
-            /* check with later hours */
-            start_t = time_calc_hour(tm_start, hours);
-            end_t = time_calc_hour(tm_end, hours - interval);
-
-            if (has_timeslice(data, start_t, end_t))
-                return get_timeslice(data, start_t, end_t);
+	time_t start_t, end_t;
+	gint hours = 0;
+
+	/* set start and end times to the exact hour */
+	tm_end.tm_min = tm_start.tm_min = 0;
+	tm_end.tm_sec = tm_start.tm_sec = 0;
+
+	while (hours >= prev_hours_limit && hours <= next_hours_limit) {
+		/* check previous hours */
+		if ((0 - hours) >= prev_hours_limit) {
+			start_t = time_calc_hour(tm_start, 0 - hours);
+			end_t = time_calc_hour(tm_end, 0 - hours);
+
+			if (has_timeslice(data, start_t, end_t))
+				return get_timeslice(data, start_t, end_t);
+		}
+
+		/* check later hours */
+		if (hours != 0 && hours <= next_hours_limit) {
+			start_t = time_calc_hour(tm_start, hours);
+			end_t = time_calc_hour(tm_end, hours);
+
+			if (has_timeslice(data, start_t, end_t))
+				return get_timeslice(data, start_t, end_t);
+		}
+		hours++;
+	}
+	return NULL;
+}
 
-            hours++;
-        }
-        interval++;
-    }
+/*
+ * Find the timeslice with the shortest interval near the given start and end times
+ */
+xml_time *
+find_shortest_timeslice(xml_weather *data, struct tm tm_start, struct tm tm_end,
+						gint prev_hours_limit, gint next_hours_limit, gint interval_limit)
+{
+	xml_time *interval_data;
+	time_t start_t, end_t;
+	gint hours, interval;
+
+	/* set start and end times to the exact hour */
+	tm_end.tm_min = tm_start.tm_min = 0;
+	tm_end.tm_sec = tm_start.tm_sec = 0;
+
+	start_t = mktime(&tm_start);
+	end_t = mktime(&tm_end);
+
+	tm_start = *localtime(&start_t);
+	tm_end = *localtime(&end_t);
+
+	/* minimum interval is provided by tm_start and tm_end */
+	interval = (gint) (difftime(end_t, start_t) / 3600);
+
+	while (interval <= interval_limit) {
+		interval_data = find_timeslice(data, tm_start, tm_end,
+									   prev_hours_limit, next_hours_limit);
+		if (interval_data != NULL)
+			return interval_data;
+
+		interval++;
+		start_t = mktime(&tm_start);
+		end_t = time_calc_hour(tm_end, interval);
+		tm_start = *localtime(&start_t);
+		tm_end = *localtime(&end_t);
+	}
 
-    return NULL;
+	return NULL;
 }
 
 /*
@@ -346,29 +386,41 @@ make_combined_timeslice(xml_time *point, xml_time *interval)
 xml_time *
 make_forecast_data(xml_weather *data, int day, daytime dt)
 {
-	xml_time *forecast, *point, *interval;
+	xml_time *forecast, *point_data, *interval_data;
 	struct tm tm_now, tm_start, tm_end;
 	time_t now, start_t, end_t;
+	gint interval;
 
 	/* initialize times to the current day */
 	time(&now);
 	tm_start = *localtime(&now);
 	tm_end = *localtime(&now);
 
-	/* calculate daytime interval start and end times for the  requested day */
+	/* calculate daytime interval start and end times for the requested day */
 	tm_start.tm_mday += day;
 	tm_end.tm_mday += day;
 	get_daytime_interval(&tm_start, &tm_end, dt);
     start_t = mktime(&tm_start);
     end_t = mktime(&tm_end);
 
-	/* find point data */
-    point = find_timeslice(data, tm_start, tm_start);
+	/* find point data using a maximum variance of ±3 hours*/
+	point_data = find_timeslice(data, tm_start, tm_start, -3, 3);
+	if (point_data == NULL)
+		return NULL;
 
-	/* next find interval data */
-    interval = find_timeslice(data, tm_start, tm_end);
+	/* next find biggest possible (limited by daytime) interval data
+	   using a maximum deviation of ±3 hours */
+	while ((interval = (gint) (difftime(end_t, start_t) / 3600)) > 0) {
+		interval_data = find_timeslice(data, tm_start, tm_end, -3, 3);
+		if (interval_data != NULL)
+			break;
+		end_t = time_calc_hour(tm_end, -1);
+		tm_end = *localtime(&tm_end);
+	}
+	if (interval_data == NULL)
+		return NULL;
 
     /* create a new timeslice with combined point and interval data */
-    forecast = make_combined_timeslice(point, interval);
+    forecast = make_combined_timeslice(point_data, interval_data);
 	return forecast;
 }
diff --git a/panel-plugin/weather-parsers.c b/panel-plugin/weather-parsers.c
index f4f29bc..415e83f 100644
--- a/panel-plugin/weather-parsers.c
+++ b/panel-plugin/weather-parsers.c
@@ -158,40 +158,48 @@ xml_time *get_timeslice(xml_weather *data, time_t start, time_t end)
 	return data->timeslice[data->num_timeslices - 1];
 }
 
-xml_time *get_current_timeslice(xml_weather *data, gboolean interval)
+xml_time *get_current_timeslice(xml_weather *data, gboolean need_interval)
 {
-	time_t now = time(NULL);
-	int closest = -1;
-	int min_found = 7 * 24 * 3600;
-	int i;
-
-	if (data == NULL)
-		return NULL;
-
-	for (i = 0; i < data->num_timeslices; i++) {
-		if (interval != 
-		    (data->timeslice[i]->start != data->timeslice[i]->end))
-			continue;
-		if (data->timeslice[i]->start <= now
-		 && data->timeslice[i]->end >= now)
-			return data->timeslice[i];
-		/* we also search for the closest before */
-		if (data->timeslice[i]->end < now
-		 && data->timeslice[i]->end - now < min_found) {
-			min_found = data->timeslice[i]->end - now;
-			closest = i;
-		}
-		/* and after */
-		if (data->timeslice[i]->start > now
-		 && data->timeslice[i]->start - now < min_found) {
-			min_found = data->timeslice[i]->start - now;
-			closest = i;
-		}
-	}
-	if (closest != -1)
-		return data->timeslice[closest];
+    xml_time *forecast, *point_data, *interval_data;
+    struct tm tm_now, tm_start, tm_end;
+    time_t now, start_t, end_t;
+    gint interval;
+
+    /* get the current time */
+    time(&now);
+    tm_now = *localtime(&now);
+
+    /* find nearest point data, starting with the current hour, with a
+     * deviation of 1 hour into the past and 6 hours into the future */
+    point_data = find_timeslice(data, tm_now, tm_now, -1, 6);
+    if (point_data == NULL)
+        return NULL;
+
+    /* now search for the nearest and shortest interval data
+     * available, using a maximum interval of 6 hours */
+    tm_end = tm_start = tm_now;
+    start_t = mktime(&tm_start);
+
+    /* set interval to 1 hour as minimum, we don't want to retrieve point data */
+    end_t = time_calc_hour(tm_end, 1);
+    tm_end = *localtime(&end_t);
+
+    /* We want to keep the hour deviation as small as possible,
+     * so let's try an interval with ±1 hour deviation first */
+    interval_data = find_shortest_timeslice(data, tm_start, tm_end, -1, 1, 6);
+    if (interval_data == NULL) {
+        /* in case we were unsuccessful we might need to enlarge the search radius */
+        interval_data = find_shortest_timeslice(data, tm_start, tm_end, -3, 3, 6);
+        if (interval_data == NULL)
+            /* and maybe it's necessary to try even harder... */
+            interval_data = find_shortest_timeslice(data, tm_start, tm_end, -3, 6, 6);
+    }
+    if (interval_data == NULL)
+        return NULL;
 
-	return NULL;	
+    /* create a new timeslice with combined point and interval data */
+    forecast = make_combined_timeslice(point_data, interval_data);
+    return forecast;
 }
 
 void parse_location (xmlNode * cur_node, xml_location *loc)


More information about the Xfce4-commits mailing list