view: Fix daylight saving issue in week view

This patch fixes an issue when creating new events in week view the week
after the daylight saving change.

The problem was in the calc of the selected date, that's done couting
the 30 minutes slots and adding that minutes to the week_start datetime.
When there's a daylight saving change, the real date to select should be
adjusted. This patch adds a new util function to make it easy to add
minutes ignoring the tz so we can make this calc directly with
gcal_date_time_add_floating_minutes.

This also includes a new test file with some checks for the new util
function and spring / autumn changes.

This new function could be used in other places to fix specific issues
that could be caused by the same logic error, calculate a selection or
event position based on GDateTime operations.

Fix https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/482
This commit is contained in:
Daniel Garcia Moreno
2023-11-09 13:17:20 +00:00
committed by Georges Basile Stavracas Neto
parent ba08425fce
commit 6afb5cf3a5
5 changed files with 162 additions and 4 deletions
+4 -4
View File
@@ -294,8 +294,8 @@ on_click_gesture_released_cb (GtkGestureClick *click_gesture,
if (ltr)
{
start = g_date_time_add_minutes (week_start, start_cell * 30);
end = g_date_time_add_minutes (week_start, (end_cell + 1) * 30);
start = gcal_date_time_add_floating_minutes (week_start, start_cell * 30);
end = gcal_date_time_add_floating_minutes (week_start, (end_cell + 1) * 30);
}
else
{
@@ -306,8 +306,8 @@ on_click_gesture_released_cb (GtkGestureClick *click_gesture,
rtl_start_cell = start_cell + (rtl_column - column) * 48;
rtl_end_cell = (rtl_column * MINUTES_PER_DAY + minute) / 30;
start = g_date_time_add_minutes (week_start, rtl_start_cell * 30);
end = g_date_time_add_minutes (week_start, (rtl_end_cell + 1) * 30);
start = gcal_date_time_add_floating_minutes (week_start, rtl_start_cell * 30);
end = gcal_date_time_add_floating_minutes (week_start, (rtl_end_cell + 1) * 30);
}
local_x = round ((column + 0.5) * (alloc.width / 7.0));
+28
View File
@@ -258,3 +258,31 @@ gcal_timezone_to_icaltimezone (GTimeZone *tz)
return ical_tz;
}
/**
* gcal_date_time_add_floating_minutes:
* @initial: Initial #GDateTime to add minutes
* @minutes: The number of minutes to add
*
* Calculate the datetime initial + minutes without caring about dayligh saving
* changes, so if it's 02:30 + 30 minutes, the result will be 03:00, always,
* independently of the daylight saving logic.
*
* Returns: (transfer full): A new #GDateTime with initial + minutes
*/
GDateTime*
gcal_date_time_add_floating_minutes (GDateTime *initial,
gint minutes)
{
g_autoptr (GDateTime) result = NULL;
GTimeSpan initial_offset = 0;
GTimeSpan result_offset = 0;
GTimeSpan offset = 0;
result = g_date_time_add_minutes (initial, minutes);
initial_offset = g_date_time_get_utc_offset (initial);
result_offset = g_date_time_get_utc_offset (result);
offset = initial_offset - result_offset;
// offset is in microseconds, convert to seconds
offset = offset / 1000000;
return g_date_time_add_seconds (result, offset);
}
+4
View File
@@ -53,4 +53,8 @@ GDateTime* gcal_date_time_from_icaltime (const ICalTime
ICalTimezone* gcal_timezone_to_icaltimezone (GTimeZone *tz);
GDateTime* gcal_date_time_add_floating_minutes (GDateTime *initial,
gint minutes);
G_END_DECLS
+1
View File
@@ -33,6 +33,7 @@ libgcal_test_dep = declare_dependency(
tests = [
'server',
'daylight-saving',
'discoverer',
'event',
'range',
+125
View File
@@ -0,0 +1,125 @@
/* test-daylight-saving.c
*
* Copyright © 2023 Daniel García Moreno <daniel.garcia@suse.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
#include "gcal-utils.h"
/*********************************************************************************************************************/
static void
floating_minutes (void)
{
g_autoptr (GDateTime) week_start = NULL;
g_autoptr (GDateTime) start = NULL;
g_autoptr (GDateTime) end = NULL;
g_autoptr (GTimeZone) cest = NULL;
int start_cell = 3 * 2; // three hours (daylight time starts at 3:00 AM)
int end_cell = start_cell;
g_test_bug ("482");
cest = g_time_zone_new_identifier ("Europe/Madrid");
// Without daylight saving change
week_start = g_date_time_new (cest, 2023, 11, 5, 0, 0, 0);
g_assert_cmpstr (g_date_time_format_iso8601 (week_start), ==, "2023-11-05T00:00:00+01");
g_assert_false (g_date_time_is_daylight_savings (week_start));
start = gcal_date_time_add_floating_minutes (week_start, start_cell * 30);
end = gcal_date_time_add_floating_minutes (week_start, (end_cell + 1) * 30);
g_assert_false (g_date_time_is_daylight_savings (start));
g_assert_false (g_date_time_is_daylight_savings (end));
g_assert_cmpstr (g_date_time_format_iso8601 (start), ==, "2023-11-05T03:00:00+01");
g_assert_cmpstr (g_date_time_format_iso8601 (end), ==, "2023-11-05T03:30:00+01");
}
static void
floating_minutes_october (void)
{
g_autoptr (GDateTime) week_start = NULL;
g_autoptr (GDateTime) start = NULL;
g_autoptr (GDateTime) end = NULL;
g_autoptr (GTimeZone) cest = NULL;
int start_cell = 3 * 2; // three hours (daylight time starts at 3:00 AM)
int end_cell = start_cell;
g_test_bug ("482");
cest = g_time_zone_new_identifier ("Europe/Madrid");
// With daylight saving change
week_start = g_date_time_new (cest, 2023, 10, 29, 0, 0, 0);
g_assert_cmpstr (g_date_time_format_iso8601 (week_start), ==, "2023-10-29T00:00:00+02");
g_assert_true (g_date_time_is_daylight_savings (week_start));
start = gcal_date_time_add_floating_minutes (week_start, start_cell * 30);
end = gcal_date_time_add_floating_minutes (week_start, (end_cell + 1) * 30);
g_assert_cmpstr (g_date_time_format_iso8601 (start), ==, "2023-10-29T03:00:00+01");
g_assert_cmpstr (g_date_time_format_iso8601 (end), ==, "2023-10-29T03:30:00+01");
}
static void
floating_minutes_march (void)
{
g_autoptr (GDateTime) week_start = NULL;
g_autoptr (GDateTime) start = NULL;
g_autoptr (GDateTime) end = NULL;
g_autoptr (GTimeZone) cest = NULL;
int start_cell = 3 * 2; // three hours (daylight time starts at 3:00 AM)
int end_cell = start_cell;
g_test_bug ("482");
cest = g_time_zone_new_identifier ("Europe/Madrid");
// With daylight saving change
week_start = g_date_time_new (cest, 2023, 3, 26, 0, 0, 0);
g_assert_cmpstr (g_date_time_format_iso8601 (week_start), ==, "2023-03-26T00:00:00+01");
g_assert_false (g_date_time_is_daylight_savings (week_start));
start = gcal_date_time_add_floating_minutes (week_start, start_cell * 30);
end = gcal_date_time_add_floating_minutes (week_start, (end_cell + 1) * 30);
g_assert_cmpstr (g_date_time_format_iso8601 (start), ==, "2023-03-26T03:00:00+02");
g_assert_cmpstr (g_date_time_format_iso8601 (end), ==, "2023-03-26T03:30:00+02");
}
/*********************************************************************************************************************/
gint
main (gint argc,
gchar *argv[])
{
g_setenv ("TZ", "UTC", TRUE);
g_test_init (&argc, &argv, NULL);
g_test_bug_base ("https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/");
g_test_add_func ("/daylight/floating-minutes", floating_minutes);
g_test_add_func ("/daylight/floating-minutes-october", floating_minutes_october);
g_test_add_func ("/daylight/floating-minutes-march", floating_minutes_march);
return g_test_run ();
}