[libgdata] Fixed handling of ISO 8601 dates (not date times) in calendar events
- From: Philip Withnall <pwithnall src gnome org>
- To: svn-commits-list gnome org
- Subject: [libgdata] Fixed handling of ISO 8601 dates (not date times) in calendar events
- Date: Thu, 23 Apr 2009 16:04:40 -0400 (EDT)
commit ff36399a92ced3c6a478a5961963d6ac2547d46f
Author: Philip Withnall <philip tecnocode co uk>
Date: Thu Apr 23 20:04:37 2009 +0100
Fixed handling of ISO 8601 dates (not date times) in calendar events
Pure dates (not including a time) were not being handled at all. Parsing
and producing XML for them now works, and a date parsing test case has been
added.
---
gdata/gdata-gdata.c | 4 +-
gdata/gdata-gdata.h | 6 +-
gdata/gdata-parser.c | 30 ++++++++
gdata/gdata-private.h | 2 +
gdata/services/calendar/gdata-calendar-event.c | 31 +++++++--
gdata/tests/calendar.c | 89 +++++++++++++++++++++++-
6 files changed, 153 insertions(+), 9 deletions(-)
diff --git a/gdata/gdata-gdata.c b/gdata/gdata-gdata.c
index e9c4833..e85fdac 100644
--- a/gdata/gdata-gdata.c
+++ b/gdata/gdata-gdata.c
@@ -119,6 +119,7 @@ gdata_gd_feed_link_free (GDataGDFeedLink *self)
* gdata_gd_when_new:
* @start_time: when the event starts or (for zero-duration events) when it occurs
* @end_time: when the event ends, or %NULL
+ * @is_date: %TRUE if @start_time and @end_time specify dates rather than times, %FALSE otherwise
* @value_string: a string to represent the time period, or %NULL
* @reminders: a #GList of #GDataGDReminder<!-- -->s for the time period, or %NULL
*
@@ -131,7 +132,7 @@ gdata_gd_feed_link_free (GDataGDFeedLink *self)
* Return value: a new #GDataGDWhen, or %NULL on error
**/
GDataGDWhen *
-gdata_gd_when_new (GTimeVal *start_time, GTimeVal *end_time, const gchar *value_string, GList *reminders)
+gdata_gd_when_new (GTimeVal *start_time, GTimeVal *end_time, gboolean is_date, const gchar *value_string, GList *reminders)
{
GDataGDWhen *self;
@@ -147,6 +148,7 @@ gdata_gd_when_new (GTimeVal *start_time, GTimeVal *end_time, const gchar *value_
self->end_time.tv_usec = 0;
}
+ self->is_date = is_date;
self->value_string = g_strdup (value_string);
self->reminders = reminders;
diff --git a/gdata/gdata-gdata.h b/gdata/gdata-gdata.h
index a7372fe..ed162b0 100644
--- a/gdata/gdata-gdata.h
+++ b/gdata/gdata-gdata.h
@@ -75,13 +75,14 @@ void gdata_gd_feed_link_free (GDataGDFeedLink *self);
* GDataGDWhen:
* @start_time: when the event starts or (for zero-duration events) when it occurs
* @end_time: when the event ends
+ * @is_date: %TRUE if @start_time and @end_time specify dates rather than times, %FALSE otherwise
* @value_string: a string to represent the time period, or %NULL
* @reminders: a #GList of #GDataGDReminder<!-- -->s for the time period, or %NULL
*
* A structure fully representing a GData "when" element. The @start_time field is required, but the others are optional.
*
* If @end_time is empty (all fields are zero), the structure is considered to represent: an instance in time if
- * @start_time is a time, or an entire day if @start_time is a date.
+ * @start_time is a time (if @is_date is %FALSE), or an entire day if @start_time is a date (if @is_date is %TRUE).
*
* See the <ulink type="http" url="http://code.google.com/apis/gdata/elements.html#gdWhen">GData specification</ulink>
* for more information.
@@ -89,11 +90,12 @@ void gdata_gd_feed_link_free (GDataGDFeedLink *self);
typedef struct {
GTimeVal start_time;
GTimeVal end_time;
+ gboolean is_date;
gchar *value_string;
GList *reminders;
} GDataGDWhen;
-GDataGDWhen *gdata_gd_when_new (GTimeVal *start_time, GTimeVal *end_time, const gchar *value_string, GList *reminders);
+GDataGDWhen *gdata_gd_when_new (GTimeVal *start_time, GTimeVal *end_time, gboolean is_date, const gchar *value_string, GList *reminders);
void gdata_gd_when_free (GDataGDWhen *self);
/**
diff --git a/gdata/gdata-parser.c b/gdata/gdata-parser.c
index f0d713a..7c5f960 100644
--- a/gdata/gdata-parser.c
+++ b/gdata/gdata-parser.c
@@ -20,6 +20,8 @@
#include <config.h>
#include <glib.h>
#include <glib/gi18n-lib.h>
+#include <sys/time.h>
+#include <time.h>
#include "gdata-service.h"
#include "gdata-parser.h"
@@ -93,3 +95,31 @@ gdata_parser_error_duplicate_element (const gchar *element_name, const gchar *pa
element_name, parent_element_name);
return FALSE;
}
+
+gboolean
+gdata_parser_time_val_from_date (const gchar *date, GTimeVal *_time)
+{
+ gchar *iso8601_date;
+ gboolean success;
+
+ if (strlen (date) != 10 && strlen (date) != 8)
+ return FALSE;
+
+ iso8601_date = g_strdup_printf ("%sT00:00:00Z", date);
+ success = g_time_val_from_iso8601 (iso8601_date, _time);
+ g_free (iso8601_date);
+
+ return success;
+}
+
+gchar *
+gdata_parser_date_from_time_val (GTimeVal *_time)
+{
+ time_t secs;
+ struct tm *tm;
+
+ secs = _time->tv_sec;
+ tm = gmtime (&secs);
+
+ return g_strdup_printf ("%4d-%02d-%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
+}
diff --git a/gdata/gdata-private.h b/gdata/gdata-private.h
index 41d7fcb..6bb994d 100644
--- a/gdata/gdata-private.h
+++ b/gdata/gdata-private.h
@@ -53,6 +53,8 @@ gboolean gdata_parser_error_unknown_property_value (const gchar *element_name, c
gboolean gdata_parser_error_required_property_missing (const gchar *element_name, const gchar *property_name, GError **error);
gboolean gdata_parser_error_required_element_missing (const gchar *element_name, const gchar *parent_element_name, GError **error);
gboolean gdata_parser_error_duplicate_element (const gchar *element_name, const gchar *parent_element_name, GError **error);
+gboolean gdata_parser_time_val_from_date (const gchar *date, GTimeVal *_time);
+gchar *gdata_parser_date_from_time_val (GTimeVal *_time) G_GNUC_WARN_UNUSED_RESULT;
G_END_DECLS
diff --git a/gdata/services/calendar/gdata-calendar-event.c b/gdata/services/calendar/gdata-calendar-event.c
index ae9ba47..450a39a 100644
--- a/gdata/services/calendar/gdata-calendar-event.c
+++ b/gdata/services/calendar/gdata-calendar-event.c
@@ -466,10 +466,13 @@ parse_xml (GDataEntry *entry, xmlDoc *doc, xmlNode *node, GError **error)
xmlChar *start_time, *end_time, *value_string;
GTimeVal start_time_timeval, end_time_timeval;
GDataGDWhen *when;
+ gboolean is_date = FALSE;
/* Start time */
start_time = xmlGetProp (node, (xmlChar*) "startTime");
- if (g_time_val_from_iso8601 ((gchar*) start_time, &start_time_timeval) == FALSE) {
+ if (gdata_parser_time_val_from_date ((gchar*) start_time, &start_time_timeval) == TRUE) {
+ is_date = TRUE;
+ } else if (g_time_val_from_iso8601 ((gchar*) start_time, &start_time_timeval) == FALSE) {
/* Error */
gdata_parser_error_not_iso8601_format ("gd:when", "entry", (gchar*) start_time, error);
xmlFree (start_time);
@@ -480,7 +483,14 @@ parse_xml (GDataEntry *entry, xmlDoc *doc, xmlNode *node, GError **error)
/* End time (optional) */
end_time = xmlGetProp (node, (xmlChar*) "endTime");
if (end_time != NULL) {
- if (g_time_val_from_iso8601 ((gchar*) end_time, &end_time_timeval) == FALSE) {
+ gboolean success;
+
+ if (is_date == TRUE)
+ success = gdata_parser_time_val_from_date ((gchar*) end_time, &end_time_timeval);
+ else
+ success = g_time_val_from_iso8601 ((gchar*) end_time, &end_time_timeval);
+
+ if (success == FALSE) {
/* Error */
gdata_parser_error_not_iso8601_format ("gd:when", "entry", (gchar*) end_time, error);
xmlFree (end_time);
@@ -490,7 +500,7 @@ parse_xml (GDataEntry *entry, xmlDoc *doc, xmlNode *node, GError **error)
}
value_string = xmlGetProp (node, (xmlChar*) "value");
- when = gdata_gd_when_new (&start_time_timeval, (end_time == NULL) ? NULL : &end_time_timeval, (gchar*) value_string, NULL);
+ when = gdata_gd_when_new (&start_time_timeval, (end_time == NULL) ? NULL : &end_time_timeval, is_date, (gchar*) value_string, NULL);
xmlFree (value_string);
gdata_calendar_event_add_time (self, when);
@@ -613,14 +623,25 @@ get_xml (GDataEntry *entry, GString *xml_string)
g_string_append (xml_string, "<gCal:anyoneCanAddSelf value='false'/>");
for (i = priv->times; i != NULL; i = i->next) {
+ gchar *start_time;
GDataGDWhen *when = (GDataGDWhen*) i->data;
- gchar *start_time = g_time_val_to_iso8601 (&(when->start_time));
+ if (when->is_date == TRUE)
+ start_time = gdata_parser_date_from_time_val (&(when->start_time));
+ else
+ start_time = g_time_val_to_iso8601 (&(when->start_time));
+
g_string_append_printf (xml_string, "<gd:when startTime='%s'", start_time);
g_free (start_time);
if (when->end_time.tv_sec != 0 || when->end_time.tv_usec != 0) {
- gchar *end_time = g_time_val_to_iso8601 (&(when->end_time));
+ gchar *end_time;
+
+ if (when->is_date == TRUE)
+ end_time = gdata_parser_date_from_time_val (&(when->end_time));
+ else
+ end_time = g_time_val_to_iso8601 (&(when->end_time));
+
g_string_append_printf (xml_string, " endTime='%s'", end_time);
g_free (end_time);
}
diff --git a/gdata/tests/calendar.c b/gdata/tests/calendar.c
index 912cbc7..f59b848 100644
--- a/gdata/tests/calendar.c
+++ b/gdata/tests/calendar.c
@@ -247,7 +247,7 @@ test_insert_simple (void)
gdata_calendar_event_add_person (event, who);
g_time_val_from_iso8601 ("2009-04-17T15:00:00.000Z", &start_time);
g_time_val_from_iso8601 ("2009-04-17T17:00:00.000Z", &end_time);
- when = gdata_gd_when_new (&start_time, &end_time, NULL, NULL);
+ when = gdata_gd_when_new (&start_time, &end_time, FALSE, NULL, NULL);
gdata_calendar_event_add_time (event, when);
/* Check the XML */
@@ -286,6 +286,92 @@ test_insert_simple (void)
g_object_unref (new_event);
}
+static void
+test_xml_dates (void)
+{
+ GDataCalendarEvent *event;
+ GList *times, *i;
+ GDataGDWhen *when;
+ gchar *xml;
+ GError *error = NULL;
+
+ event = gdata_calendar_event_new_from_xml (
+ "<entry xmlns='http://www.w3.org/2005/Atom' "
+ "xmlns:gd='http://schemas.google.com/g/2005' "
+ "xmlns:gCal='http://schemas.google.com/gCal/2005' "
+ "xmlns:app='http://www.w3.org/2007/app'>"
+ "<title type='text'>Tennis with Beth</title>"
+ "<content type='text'>Meet for a quick lesson.</content>"
+ "<category term='http://schemas.google.com/g/2005#event' scheme='http://schemas.google.com/g/2005#kind'/>"
+ "<gd:when startTime='2009-04-17'/>"
+ "<gd:when startTime='2009-04-17T15:00:00Z'/>"
+ "<gd:when startTime='2009-04-27' endTime='20090506'/>"
+ "</entry>", -1, &error);
+ g_assert_no_error (error);
+ g_assert (GDATA_IS_ENTRY (event));
+ g_clear_error (&error);
+
+ /* Check the times */
+ times = i = gdata_calendar_event_get_times (event);
+
+ /* First time */
+ when = (GDataGDWhen*) i->data;
+ g_assert (i->next != NULL);
+ g_assert (when->is_date == TRUE);
+ g_assert_cmpint (when->start_time.tv_sec, ==, 1239926400);
+ g_assert_cmpint (when->start_time.tv_usec, ==, 0);
+ g_assert_cmpint (when->end_time.tv_sec, ==, 0);
+ g_assert_cmpint (when->end_time.tv_usec, ==, 0);
+ g_assert (when->value_string == NULL);
+ g_assert (when->reminders == NULL);
+
+ /* Second time */
+ i = i->next;
+ when = (GDataGDWhen*) i->data;
+ g_assert (i->next != NULL);
+ g_assert (when->is_date == FALSE);
+ g_assert_cmpint (when->start_time.tv_sec, ==, 1239926400 + 54000);
+ g_assert_cmpint (when->start_time.tv_usec, ==, 0);
+ g_assert_cmpint (when->end_time.tv_sec, ==, 0);
+ g_assert_cmpint (when->end_time.tv_usec, ==, 0);
+ g_assert (when->value_string == NULL);
+ g_assert (when->reminders == NULL);
+
+ /* Third time */
+ i = i->next;
+ when = (GDataGDWhen*) i->data;
+ g_assert (i->next == NULL);
+ g_assert (when->is_date == TRUE);
+ g_assert_cmpint (when->start_time.tv_sec, ==, 1239926400 + 864000);
+ g_assert_cmpint (when->start_time.tv_usec, ==, 0);
+ g_assert_cmpint (when->end_time.tv_sec, ==, 1241568000);
+ g_assert_cmpint (when->end_time.tv_usec, ==, 0);
+ g_assert (when->value_string == NULL);
+ g_assert (when->reminders == NULL);
+
+ /* Check the XML */
+ xml = gdata_entry_get_xml (GDATA_ENTRY (event));
+ g_assert_cmpstr (xml, ==,
+ "<entry xmlns='http://www.w3.org/2005/Atom' "
+ "xmlns:gd='http://schemas.google.com/g/2005' "
+ "xmlns:gCal='http://schemas.google.com/gCal/2005' "
+ "xmlns:app='http://www.w3.org/2007/app'>"
+ "<title type='text'>Tennis with Beth</title>"
+ "<content type='text'>Meet for a quick lesson.</content>"
+ "<category term='http://schemas.google.com/g/2005#event' scheme='http://schemas.google.com/g/2005#kind'/>"
+ "<gCal:guestsCanModify value='false'/>"
+ "<gCal:guestsCanInviteOthers value='false'/>"
+ "<gCal:guestsCanSeeGuests value='false'/>"
+ "<gCal:anyoneCanAddSelf value='false'/>"
+ "<gd:when startTime='2009-04-17'/>"
+ "<gd:when startTime='2009-04-17T15:00:00Z'/>"
+ "<gd:when startTime='2009-04-27' endTime='2009-05-06'/>"
+ "</entry>");
+ g_free (xml);
+
+ g_object_unref (event);
+}
+
int
main (int argc, char *argv[])
{
@@ -308,6 +394,7 @@ main (int argc, char *argv[])
g_test_add_func ("/calendar/query/events", test_query_events);
if (g_test_slow () == TRUE)
g_test_add_func ("/calendar/insert/simple", test_insert_simple);
+ g_test_add_func ("/calendar/xml/dates", test_xml_dates);
retval = g_test_run ();
if (service != NULL)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]