[libgda] Added date, time and timestamp parsing tests



commit fb8a1153b2c71bcef21e135e71a37e35be469631
Author: Vivien Malerba <malerba gnome-db org>
Date:   Thu Oct 21 20:23:01 2010 +0200

    Added date, time and timestamp parsing tests

 doc/C/libgda-sections.txt          |    1 +
 libgda/gda-util.c                  |  300 ++++++++++++---------
 libgda/handlers/gda-handler-time.c |  271 +++++++++++--------
 libgda/libgda.symbols              |    1 +
 tests/.gitignore                   |    1 +
 tests/Makefile.am                  |   11 +-
 tests/test-input-parsers.c         |  522 ++++++++++++++++++++++++++++++++++++
 7 files changed, 865 insertions(+), 242 deletions(-)
---
diff --git a/doc/C/libgda-sections.txt b/doc/C/libgda-sections.txt
index 355e9a1..6ac52dc 100644
--- a/doc/C/libgda-sections.txt
+++ b/doc/C/libgda-sections.txt
@@ -852,6 +852,7 @@ GdaHandlerTimePriv
 gda_handler_time_new
 gda_handler_time_new_no_locale
 gda_handler_time_set_sql_spec
+gda_handler_time_set_str_spec
 gda_handler_time_get_format
 <SUBSECTION Standard>
 GDA_HANDLER_TIME
diff --git a/libgda/gda-util.c b/libgda/gda-util.c
index 941c641..cfa3384 100644
--- a/libgda/gda-util.c
+++ b/libgda/gda-util.c
@@ -27,6 +27,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <ctype.h>
 #include <string.h>
 #include <glib/gi18n-lib.h>
 #include <libgda/gda-log.h>
@@ -2516,37 +2517,48 @@ gda_connection_string_split (const gchar *string, gchar **out_cnc_params, gchar
 	gda_rfc1738_decode (*out_password);
 }
 
-/**
- * gda_parse_iso8601_date
- * @gdate: a pointer to a #GDate structure which will be filled
- * @value: a string
- *
- * Extracts date parts from @value, and sets @gdate's contents
- *
- * Accepted date format is "YYYY-MM-DD".
- *
- * Returns: TRUE if no error occurred
- */
-gboolean
-gda_parse_iso8601_date (GDate *gdate, const gchar *value)
+static gboolean
+_parse_iso8601_date (GDate *gdate, const gchar *value, char **out_endptr)
 {
 	GDateYear year;
 	GDateMonth month;
 	GDateDay day;
-	gint tmp;
+	unsigned long int tmp;
+	char *endptr;
+
+	g_date_clear (gdate, 1);
 
-	tmp = atoi (value); /* Flawfinder: ignore */
-	year = tmp > 0 ? tmp : 0;
-	value += 5;
-	tmp = atoi (value); /* Flawfinder: ignore */
+	if (! isdigit (*value))
+		return FALSE;
+	tmp = strtoul (value, &endptr, 10);
+	if (tmp <= G_MAXUINT16)
+		year = tmp;
+	else
+		return FALSE;
+	if (*endptr != '-')
+		return FALSE;
+
+	value = endptr + 1;
+	if (! isdigit (*value))
+		return FALSE;
+	tmp = strtoul (value, &endptr, 10);
 	month = tmp > 0 ? (tmp <= G_DATE_DECEMBER ? tmp : G_DATE_BAD_MONTH) : G_DATE_BAD_MONTH;
-	value += 3;
-	tmp = atoi (value); /* Flawfinder: ignore */
+	if (month == G_DATE_BAD_MONTH)
+		return FALSE;
+	if (*endptr != '-')
+		return FALSE;
+
+	value = endptr + 1;
+	if (! isdigit (*value))
+		return FALSE;
+	tmp = strtoul (value, &endptr, 10);
 	day = tmp > 0 ? (tmp <= G_MAXUINT8 ? tmp : G_DATE_BAD_DAY) : G_DATE_BAD_DAY;
-	
-	g_date_clear (gdate, 1);
+	if (day == G_DATE_BAD_DAY)
+		return FALSE;
+
 	if (g_date_valid_dmy (day, month, year)) {
 		g_date_set_dmy (gdate, day, month, year);
+		*out_endptr = endptr;
 		return TRUE;
 	}
 	else {
@@ -2556,69 +2568,126 @@ gda_parse_iso8601_date (GDate *gdate, const gchar *value)
 }
 
 /**
- * gda_parse_iso8601_time
- * @timegda: a pointer to a #GdaTime structure which will be filled
+ * gda_parse_iso8601_date
+ * @gdate: a pointer to a #GDate structure which will be filled
  * @value: a string
  *
- * Extracts time parts from @value, and sets @timegda's contents
+ * Extracts date parts from @value, and sets @gdate's contents
  *
- * Accepted date format is "HH:MM:SS[.ms][TZ]" where TZ is +hour or -hour
+ * Accepted date format is "YYYY-MM-DD" (more or less than 4 digits for years and
+ * less than 2 digits for month and day are accepted). Years must be in the 1-65535 range,
+ * a limitation imposed by #GDate.
  *
- * Returns: TRUE if no error occurred
+ * Returns: %TRUE if no error occurred
  */
 gboolean
-gda_parse_iso8601_time (GdaTime *timegda, const gchar *value)
+gda_parse_iso8601_date (GDate *gdate, const gchar *value)
+{
+	g_return_val_if_fail (gdate, FALSE);
+
+	char *endptr;
+	if (!value)
+		return FALSE;
+
+	if (! _parse_iso8601_date (gdate, value, &endptr))
+		return FALSE;
+	if (*endptr)
+		return FALSE;
+	return TRUE;
+}
+
+static gboolean
+_parse_iso8601_time (GdaTime *timegda, const gchar *value, char **out_endptr)
 {
-	gint tmp;
+	unsigned long int tmp;
+	char *endptr;
 
 	memset (timegda, 0, sizeof (GdaTime));
+	timegda->timezone = GDA_TIMEZONE_INVALID;
 
-	tmp = atoi (value); /* Flawfinder: ignore */
-	if ((tmp < 0) || (tmp > 24))
+	if (! isdigit (*value))
 		return FALSE;
-	timegda->hour = tmp;
-	value += 3;
-	tmp = atoi (value); /* Flawfinder: ignore */
-	if ((tmp < 0) || (tmp > 60))
+	tmp = strtoul (value, &endptr, 10);
+	if (tmp <= 23)
+		timegda->hour = tmp;
+	else
 		return FALSE;
-	timegda->minute = tmp;
-	value += 3;
-	tmp = atoi (value); /* Flawfinder: ignore */
-	if ((tmp < 0) || (tmp > 60))
+	if (*endptr != ':')
+		return FALSE;
+	
+	value = endptr + 1;
+	if (! isdigit (*value))
+		return FALSE;
+	tmp = strtoul (value, &endptr, 10);
+	if (tmp < 60)
+		timegda->minute = tmp;
+	else
+		return FALSE;
+	if (*endptr != ':')
 		return FALSE;
-	timegda->second = tmp;
-	value += 2;
-	if (*value != '.') {
-		timegda->fraction = 0;
-	} else {
-		gint ndigits = 0;
-		gint64 fraction;
-
-		value++;
-		fraction = atol (value); /* Flawfinder: ignore */
-		if (fraction < 0)
-			return FALSE;
 
-		while (*value && (*value != '+') && (*value != '-')) {
-			value++;
-			ndigits++;
-		}
+	value = endptr + 1;
+	if (! isdigit (*value))
+		return FALSE;
+	tmp = strtoul (value, &endptr, 10);
+	if (tmp < 60)
+		timegda->second = tmp;
+	else
+		return FALSE;
 
-		while (fraction > 0 && ndigits > 3) {
-			fraction /= 10;
-			ndigits--;
-		}
-		
-		timegda->fraction = fraction;
+	if (*endptr && (*endptr != '.') && (*endptr != '+') && (*endptr != '-')) {
+		*out_endptr = endptr;
+		return TRUE; /* end of the parsing */
 	}
 
-	if (*value) {
-		tmp = atol (value); /* Flawfinder: ignore */
-		if ((tmp < 0) || (tmp >= 24))
+	if (*endptr == '.') {
+		value = endptr + 1;
+		if (! isdigit (*value))
+			return FALSE;
+		tmp = strtoul (value, &endptr, 10);
+		if (tmp < G_MAXULONG)
+			timegda->fraction = tmp;
+		else
 			return FALSE;
-		timegda->timezone = tmp * 60 * 60;
 	}
+	if ((*endptr == '+') || (*endptr == '-')) {
+		long int stmp;
+		value = endptr;
+		stmp = strtol (value, &endptr, 10);
+		if ((stmp >= -24) && (stmp <= 24))
+			timegda->timezone = stmp * 60 * 60;
+		else
+			return FALSE;
+	}
+
+	*out_endptr = endptr;
+	return TRUE;
+}
+
+/**
+ * gda_parse_iso8601_time
+ * @timegda: a pointer to a #GdaTime structure which will be filled
+ * @value: a string
+ *
+ * Extracts time parts from @value, and sets @timegda's contents
+ *
+ * Accepted date format is "HH:MM:SS[.ms][TZ]" where TZ is +hour or -hour
+ *
+ * Returns: TRUE if no error occurred
+ */
+gboolean
+gda_parse_iso8601_time (GdaTime *timegda, const gchar *value)
+{
+	g_return_val_if_fail (timegda, FALSE);
+
+	char *endptr;
+	if (!value)
+		return FALSE;
 
+	if (! _parse_iso8601_time (timegda, value, &endptr))
+		return FALSE;
+	if (*endptr)
+		return FALSE;
 	return TRUE;
 }
 
@@ -2636,78 +2705,51 @@ gda_parse_iso8601_time (GdaTime *timegda, const gchar *value)
 gboolean
 gda_parse_iso8601_timestamp (GdaTimestamp *timestamp, const gchar *value)
 {
-	GDateYear year;
-	GDateMonth month;
-	GDateDay day;
-	gint tmp;
+	g_return_val_if_fail (timestamp, FALSE);
+
+	gboolean retval = TRUE;
+	char *endptr;
+	GDate gdate;
+	GdaTime timegda;
 
 	memset (timestamp, 0, sizeof (GdaTimestamp));
+	memset (&timegda, 0, sizeof (GdaTime));
+	timegda.timezone = GDA_TIMEZONE_INVALID;
 
-	/* date part */
-	tmp = atoi (value); /* Flawfinder: ignore */
-	year = tmp > 0 ? tmp : 0;
-	value += 5;
-	tmp = atoi (value); /* Flawfinder: ignore */
-	month = tmp > 0 ? (tmp <= G_DATE_DECEMBER ? tmp : G_DATE_BAD_MONTH) : G_DATE_BAD_MONTH;
-	value += 3;
-	tmp = atoi (value); /* Flawfinder: ignore */
-	day = tmp > 0 ? (tmp <= G_MAXUINT8 ? tmp : G_DATE_BAD_DAY) : G_DATE_BAD_DAY;
-	value += 3;
-	
-	if (g_date_valid_dmy (day, month, year)) {
-		timestamp->year = year;
-		timestamp->month = month;
-		timestamp->day = day;
-	}
-	else
+	if (!value)
 		return FALSE;
 
-	/* time part */
-	tmp = atoi (value); /* Flawfinder: ignore */
-	if ((tmp < 0) || (tmp > 24))
-		return FALSE;
-	timestamp->hour = tmp;
-	value += 3;
-	tmp = atoi (value); /* Flawfinder: ignore */
-	if ((tmp < 0) || (tmp > 60))
-		return FALSE;
-	timestamp->minute = tmp;
-	value += 3;
-	tmp = atoi (value); /* Flawfinder: ignore */
-	if ((tmp < 0) || (tmp > 60))
-		return FALSE;
-	timestamp->second = tmp;
-	value += 2;
-	if (*value != '.') {
-		timestamp->fraction = 0;
-	} else {
-		gint ndigits = 0;
-		gint64 fraction;
-
-		value++;
-		fraction = atol (value); /* Flawfinder: ignore */
-		if (fraction < 0)
-			return FALSE;
+	/* date part */
+	if (! _parse_iso8601_date (&gdate, value, &endptr)) {
+		retval = FALSE;
+		goto out;
+	}
+	timestamp->year = g_date_get_year (&gdate);
+	timestamp->month = g_date_get_month (&gdate);
+	timestamp->day = g_date_get_day (&gdate);
 
-		while (*value && (*value != '+') && (*value != '-')) {
-			value++;
-			ndigits++;
-		}
+	/* separator */
+	if (!*endptr)
+		goto out;
 
-		while (fraction > 0 && ndigits > 3) {
-			fraction /= 10;
-			ndigits--;
-		}
-		
-		timestamp->fraction = fraction;
+	if (*endptr != ' ') {
+		retval = FALSE;
+		goto out;
 	}
+	value = endptr + 1;
+	if (!*value)
+		goto out;
 
-	if (*value) {
-		tmp = atol (value); /* Flawfinder: ignore */
-		if ((tmp < 0) || (tmp >= 24))
-			return FALSE;
-		timestamp->timezone = tmp * 60 * 60;
-	}
+	/* time part */
+	if (! _parse_iso8601_time (&timegda, value, &endptr) ||
+	    *endptr) 
+		retval = FALSE;
+ out:
+	timestamp->hour = timegda.hour;
+	timestamp->minute = timegda.minute;
+	timestamp->second = timegda.second;
+	timestamp->fraction = timegda.fraction;
+	timestamp->timezone = timegda.timezone;
 
-	return TRUE;
+	return retval;
 }
diff --git a/libgda/handlers/gda-handler-time.c b/libgda/handlers/gda-handler-time.c
index 6f2286d..39e54af 100644
--- a/libgda/handlers/gda-handler-time.c
+++ b/libgda/handlers/gda-handler-time.c
@@ -20,6 +20,7 @@
 
 #include "gda-handler-time.h"
 #include <string.h>
+#include <ctype.h>
 #include <glib/gi18n-lib.h>
 
 static void gda_handler_time_class_init (GdaHandlerTimeClass *class);
@@ -263,6 +264,41 @@ gda_handler_time_set_sql_spec  (GdaHandlerTime *dh, GDateDMY first, GDateDMY sec
 	dh->priv->sql_locale->separator = separator;
 }
 
+/**
+ * gda_handler_time_set_str_spec
+ * @dh: a #GdaHandlerTime object
+ * @first: what comes first in the date representation
+ * @sec: what comes second in the date representation
+ * @third: what comes third in the date representation
+ * @separator: separator character used between year, month and day
+ * @twodigits_years: TRUE if year part of date must be rendered on 2 digits
+ *
+ * Specifies the human readable output style of the @dh data handler.
+ * The general format is "FIRSTsSECsTHIRD"
+ * where FIRST, SEC and THIRD are specified by @first, @sec and @trird and 's' is the separator,
+ * specified by @separator.
+ *
+ * The default implementation depends on the current locale, except if @dh was created
+ * using gda_handler_time_new_no_locale().
+ *
+ * Since: 4.2.1
+ */
+void
+gda_handler_time_set_str_spec  (GdaHandlerTime *dh, GDateDMY first, GDateDMY sec,
+				GDateDMY third, gchar separator, gboolean twodigits_years)
+{
+	g_return_if_fail (GDA_IS_HANDLER_TIME (dh));
+	g_return_if_fail (dh->priv);
+	g_return_if_fail (first != sec);
+	g_return_if_fail (sec != third);
+	g_return_if_fail (first != third);
+
+	dh->priv->str_locale->dmy_order[0] = first;
+	dh->priv->str_locale->dmy_order[1] = sec;
+	dh->priv->str_locale->dmy_order[2] = third;
+	dh->priv->str_locale->twodigit_years = twodigits_years;
+	dh->priv->str_locale->separator = separator;
+}
 
 static void
 handler_compute_locale (GdaHandlerTime *hdl)
@@ -744,7 +780,8 @@ gda_handler_time_get_value_from_str (GdaDataHandler *iface, const gchar *sql, GT
 
 static gboolean make_timestamp (GdaHandlerTime *hdl, GdaTimestamp *timestamp, 
 				const gchar *value, LocaleSetting *locale);
-static gboolean make_date (GdaHandlerTime *hdl, GDate *date, const gchar *value, LocaleSetting *locale);
+static gboolean make_date (GdaHandlerTime *hdl, GDate *date, const gchar *value,
+			   LocaleSetting *locale, const gchar **out_endptr);
 static gboolean make_time (GdaHandlerTime *hdl, GdaTime *timegda, const gchar *value);
 static GValue *
 gda_handler_time_get_value_from_locale (GdaDataHandler *iface, const gchar *sql, 
@@ -762,7 +799,7 @@ gda_handler_time_get_value_from_locale (GdaDataHandler *iface, const gchar *sql,
 	g_return_val_if_fail (hdl->priv, NULL);
 
 	if (type == G_TYPE_DATE) {
-		if (make_date (hdl, &date, sql, locale)) {
+		if (make_date (hdl, &date, sql, locale, NULL)) {
 			value = g_value_init (g_new0 (GValue, 1), G_TYPE_DATE);
 			g_value_set_boxed (value, (gconstpointer) &date);
 		}
@@ -793,30 +830,29 @@ static gboolean
 make_timestamp (GdaHandlerTime *hdl, GdaTimestamp *timestamp, const gchar *value, LocaleSetting *locale)
 {
 	gboolean retval;
-	gchar *str, *ptr;
+	const gchar *end_ptr;
 	GDate vdate;
 	GdaTime vtime;
-	char *buff;
+	memset (&vtime, 0, sizeof (GdaTime));
+	vtime.timezone = GDA_TIMEZONE_INVALID;
+
+	retval = make_date (hdl, &vdate, value, locale, &end_ptr);
+	timestamp->day = vdate.day;
+	timestamp->month = vdate.month;
+	timestamp->year = vdate.year;
 
-	str = g_strdup (value);
-	ptr = strtok_r (str, " ", &buff);
-	retval = make_date (hdl, &vdate, ptr, locale);
 	if (retval) {
-		ptr = strtok_r (NULL, " ", &buff);
-		retval = make_time (hdl, &vtime, ptr);
-		if (retval) {
-			timestamp->day = vdate.day;
-			timestamp->month = vdate.month;
-			timestamp->year = vdate.year;
-
-			timestamp->hour = vtime.hour;
-			timestamp->minute = vtime.minute;
-			timestamp->second = vtime.second;
-			timestamp->fraction = vtime.fraction;
-			timestamp->timezone = vtime.timezone;
-		}
+		if (*end_ptr != ' ')
+			retval = FALSE;
+		else
+			retval = make_time (hdl, &vtime, end_ptr + 1);
 	}
-	g_free (str);
+
+	timestamp->hour = vtime.hour;
+	timestamp->minute = vtime.minute;
+	timestamp->second = vtime.second;
+	timestamp->fraction = vtime.fraction;
+	timestamp->timezone = vtime.timezone;
 
 	/*g_print ("Value #%s# => %d\n", value, retval);*/
 
@@ -829,7 +865,7 @@ get_uint_from_string (const gchar *str, guint16 *out_int)
 	long int li;
 	char *endptr = NULL;
 	li = strtol (str, &endptr, 10);
-	if (!*endptr && (li >= 0) && (li < G_MAXUINT16)) {
+	if (!*endptr && (li >= 0) && (li <= G_MAXUINT16)) {
 		*out_int = (guint16) li;
 		return TRUE;
 	}
@@ -839,9 +875,14 @@ get_uint_from_string (const gchar *str, guint16 *out_int)
 	}
 }
 
-/* Makes a GDate from a string like "24-12-2003" */
+/* Makes a GDate from a string like "24-12-2003"
+ * If @out_endptr is %NULL, then all the @value has to be consumed and there must not
+ * be any character left. If it's not %NULL, then it will point on the first unused character
+ * of @value.
+ */
 static gboolean
-make_date (G_GNUC_UNUSED GdaHandlerTime *hdl, GDate *date, const gchar *value, LocaleSetting *locale)
+make_date (G_GNUC_UNUSED GdaHandlerTime *hdl, GDate *date, const gchar *value,
+	   LocaleSetting *locale, const gchar **out_endptr)
 {
 	gboolean retval = TRUE;
 	guint16 nums[3];
@@ -849,6 +890,9 @@ make_date (G_GNUC_UNUSED GdaHandlerTime *hdl, GDate *date, const gchar *value, L
 	gchar *ptr, *numstart, *tofree;
 	gint i;
 
+	if (out_endptr)
+		*out_endptr = NULL;
+
 	if (!value)
 		return FALSE;
 
@@ -871,40 +915,51 @@ make_date (G_GNUC_UNUSED GdaHandlerTime *hdl, GDate *date, const gchar *value, L
 
 	/* 2nd number */
 	if (!error) {
-		ptr++;
-		numstart = ptr;
-		while (*ptr && g_ascii_isdigit (*ptr))
+		if (value [ptr-tofree] != locale->separator)
+			error = TRUE;
+		else {
 			ptr++;
-		if ((ptr != numstart) && *ptr) {
-			*ptr = 0;
-			if (! get_uint_from_string (numstart, &(nums[1])))
+			numstart = ptr;
+			while (*ptr && g_ascii_isdigit (*ptr))
+				ptr++;
+			if ((ptr != numstart) && *ptr) {
+				*ptr = 0;
+				if (! get_uint_from_string (numstart, &(nums[1])))
+					error = TRUE;
+			}
+			else
 				error = TRUE;
 		}
-		else
-			error = TRUE;
 	}
 
 	/* 3rd number */
 	if (!error) {
-		ptr++;
-		numstart = ptr;
-		while (*ptr && g_ascii_isdigit (*ptr))
+		if (value [ptr-tofree] != locale->separator)
+			error = TRUE;
+		else {
 			ptr++;
-		*ptr = 0;
-		if (ptr != numstart) {
-			if (! get_uint_from_string (numstart, &(nums[2])))
+			numstart = ptr;
+			while (*ptr && g_ascii_isdigit (*ptr))
+				ptr++;
+			*ptr = 0;
+			if (ptr != numstart) {
+				if (! get_uint_from_string (numstart, &(nums[2])))
+					error = TRUE;
+			}
+			else
 				error = TRUE;
 		}
-		else
-			error = TRUE;
 	}
 
+	/* test if there are some characters left */
 	if (!error) {
-		ptr++;
-		if (*ptr)
+		if (out_endptr)
+			*out_endptr = value + (ptr-tofree);
+		else if (value [ptr-tofree])
 			error = TRUE;
 	}
 
+	/* analyse what's parsed */
 	if (!error) {
 		for (i=0; i<3; i++) {
 			switch (locale->dmy_order[i]) {
@@ -957,101 +1012,95 @@ make_time (G_GNUC_UNUSED GdaHandlerTime *hdl, GdaTime *timegda, const gchar *val
 {
 	const gchar *ptr;
 
+	memset (timegda, 0, sizeof (GdaTime));
+	timegda->timezone = GDA_TIMEZONE_INVALID;
+
 	if (!value)
 		return FALSE;
 
 	/* hour */
-	timegda->fraction = 0;
-	timegda->timezone = GDA_TIMEZONE_INVALID;
 	ptr = value;
-	if ((*ptr >= '0') && (*ptr <= '9') &&
-	    (*(ptr+1) >= '0') && (*(ptr+1) <= '9')) {
-		timegda->hour = (*ptr - '0') * 10 + *(ptr+1) - '0';
-		ptr += 2;
-	}
-	else if ((*ptr >= '0') && (*ptr <= '9') && (ptr[1] == ':')) {
-		timegda->hour = *ptr - '0';
+	if (!isdigit (*ptr))
+		return FALSE;
+
+	timegda->hour = *ptr - '0';
+	ptr++;
+	if (isdigit (*ptr)) {
+		timegda->hour = timegda->hour * 10 + (*ptr - '0');
 		ptr++;
 	}
-	else if (*ptr == ':')
-		timegda->hour = 0;
-	else
+	if (timegda->hour >= 24)
 		return FALSE;
 
-	/* minute */
-	if (! *ptr)
-		return FALSE;
 	if (*ptr == ':')
 		ptr++;
-	if ((*ptr >= '0') && (*ptr <= '9') &&
-	    (*(ptr+1) >= '0') && (*(ptr+1) <= '9')) {
-		timegda->minute = (*ptr - '0') * 10 + *(ptr+1) - '0';
-		ptr += 2;
-	}
-	else if ((*ptr >= '0') && (*ptr <= '9') && (ptr[1] == ':')) {
-		timegda->minute = *ptr - '0';
-		ptr++;
-	}
-	else if (*ptr == ':')
-		timegda->minute = 0;
-	else
+	else if (!isdigit (*ptr))
 		return FALSE;
 
-	/* second */
-	timegda->second = 0;
-	if (! *ptr) {
-		if ((timegda->hour > 24) || (timegda->minute > 60))
-			return FALSE;
-		else
-			return TRUE;
+	/* minute */
+	timegda->minute = *ptr - '0';
+	ptr++;
+	if (isdigit (*ptr)) {
+		timegda->minute = timegda->minute * 10 + (*ptr - '0');
+		ptr++;
 	}
+	if (timegda->minute >= 60)
+		return FALSE;
 	if (*ptr == ':')
 		ptr++;
-	if ((*ptr >= '0') && (*ptr <= '9') &&
-	    (*(ptr+1) >= '0') && (*(ptr+1) <= '9')) {
-		timegda->second = (*ptr - '0') * 10 + *(ptr+1) - '0';
-		ptr += 2;
-	}
-	else if ((*ptr >= '0') && (*ptr <= '9')) {
-		timegda->second = *ptr - '0';
+	else if (!isdigit (*ptr))
+		return FALSE;
+
+	/* second */
+	timegda->second = *ptr - '0';
+	ptr++;
+	if (isdigit (*ptr)) {
+		timegda->second = timegda->second * 10 + (*ptr - '0');
 		ptr++;
 	}
-	else if (*ptr == ':')
-		timegda->second = 0;
-	
-	/* extra */
-	if (! *ptr) {
-		if ((timegda->hour > 24) || (timegda->minute > 60) || 
-		    (timegda->second > 60))
-			return FALSE;
-		else
-			return TRUE;
-	}
+	if (timegda->second >= 60)
+		return FALSE;
 
+	/* fraction */
+	if (*ptr && (*ptr != '.') && (*ptr != '+') && (*ptr != '-'))
+		return FALSE;
 	if (*ptr == '.') {
-		ptr ++;
-		while (*ptr && (*ptr >= '0') && (*ptr <= '9')) {
-			timegda->fraction = timegda->fraction * 10 + *ptr - '0';
+		ptr++;
+		if (!isdigit (*ptr))
+			return FALSE;
+		while (isdigit (*ptr)) {
+			unsigned long long lu;
+			lu = timegda->fraction * 10 + (*ptr - '0');
+			if (lu < G_MAXULONG)
+				timegda->fraction = lu;
+			else
+				return FALSE;
 			ptr++;
 		}
 	}
-
-	if ((*ptr == '+') || (*ptr == '-')) {
-		glong sign = (*ptr == '+') ? 1 : -1;
-		ptr ++;
-		timegda->timezone = 0;
-		while (*ptr && (*ptr >= '0') && (*ptr <= '9')) {
-			timegda->timezone = timegda->timezone * 10 + sign * ((*ptr) - '0');
+	
+	/* timezone */
+	if ((*ptr == '-') || (*ptr == '+')) {
+		gint sign = (*ptr == '+') ? 1 : -1;
+		ptr++;
+		if (!isdigit (*ptr))
+			return FALSE;
+		timegda->timezone = sign * (*ptr - '0');
+		ptr++;
+		if (isdigit (*ptr)) {
+			timegda->timezone = timegda->minute * 10 + sign * (*ptr - '0');
 			ptr++;
 		}
-		timegda->timezone *= 3600;
+		if (*ptr)
+			return FALSE;
+		if ((timegda->timezone >= -24) && (timegda->timezone <= 24))
+			timegda->timezone *= 60*60;
+		else {
+			timegda->timezone = 0;
+			return FALSE;
+		}
 	}
-	
-	/* checks */
-	if ((timegda->hour > 24) || (timegda->minute > 60) || (timegda->second > 60))
-		return FALSE;
-	else
-		return TRUE;
+	return TRUE;
 }
 
 
diff --git a/libgda/libgda.symbols b/libgda/libgda.symbols
index 357cfcb..6e749fb 100644
--- a/libgda/libgda.symbols
+++ b/libgda/libgda.symbols
@@ -353,6 +353,7 @@
 	gda_handler_time_new
 	gda_handler_time_new_no_locale
 	gda_handler_time_set_sql_spec
+	gda_handler_time_set_str_spec
 	gda_handler_type_get_type
 	gda_handler_type_new
 	gda_holder_attributes_manager
diff --git a/tests/.gitignore b/tests/.gitignore
index 746b555..a56365c 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -4,3 +4,4 @@ test-sql-identifier
 test-identifiers-quotes
 test-sql-builder
 test-connection-string-split
+test-input-parsers
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d0aeb48..1ba8ee4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,6 +1,6 @@
 noinst_LTLIBRARIES = libgda-test-4.0.la
-TESTS = test-ddl-creator test-bin-converter test-sql-identifier test-identifiers-quotes test-sql-builder test-connection-string-split
-check_PROGRAMS = test-ddl-creator test-bin-converter test-sql-identifier test-identifiers-quotes test-sql-builder test-connection-string-split
+TESTS = test-ddl-creator test-bin-converter test-sql-identifier test-identifiers-quotes test-sql-builder test-connection-string-split test-input-parsers
+check_PROGRAMS = test-ddl-creator test-bin-converter test-sql-identifier test-identifiers-quotes test-sql-builder test-connection-string-split test-input-parsers
 
 
 SUBDIRS = providers parser value-holders meta-store data-models multi-threading
@@ -75,4 +75,11 @@ test_connection_string_split_LDADD = \
         $(top_builddir)/libgda/libgda-4.0.la \
         $(LIBGDA_LIBS)
 
+test_input_parsers_SOURCES = \
+        test-input-parsers.c
+
+test_input_parsers_LDADD = \
+        $(top_builddir)/libgda/libgda-4.0.la \
+        $(LIBGDA_LIBS)
+
 EXTRA_DIST = dbstruct.xml
\ No newline at end of file
diff --git a/tests/test-input-parsers.c b/tests/test-input-parsers.c
new file mode 100644
index 0000000..cd26a5a
--- /dev/null
+++ b/tests/test-input-parsers.c
@@ -0,0 +1,522 @@
+/* 
+ * Copyright (C) 2010 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <libgda/libgda.h>
+static gboolean test_parse_iso8601_date (void);
+static gboolean test_parse_iso8601_time (void);
+static gboolean test_parse_iso8601_timestamp (void);
+static gboolean test_date_handler (void);
+static gboolean test_time_handler (void);
+static gboolean test_timestamp_handler (void);
+
+int
+main (int argc, char** argv)
+{
+	gint nfailed = 0;
+
+	if (! test_parse_iso8601_date ())
+		nfailed++;
+	if (! test_parse_iso8601_time ())
+		nfailed++;
+	if (! test_parse_iso8601_timestamp ())
+		nfailed++;
+
+	gda_init ();
+	if (! test_date_handler ())
+		nfailed++;
+	if (! test_time_handler ())
+		nfailed++;
+	if (! test_timestamp_handler ())
+		nfailed++;
+
+	if (nfailed > 0) {
+		g_print ("FAILED: %d tests failed\n", nfailed);
+		return EXIT_FAILURE;
+	}
+	else {
+		g_print ("All tests passed\n");
+		return EXIT_SUCCESS;
+	}
+}
+
+typedef struct {
+	gchar   *in_string;
+	gboolean exp_retval;
+	gint     exp_day;
+	gint     exp_month;
+	gint     exp_year;
+} TestDate;
+
+TestDate datedata[] = {
+	{"1996-11-22", TRUE, 22, 11, 1996},
+	{"1996-22-23", FALSE, 0, 0, 0},
+	{"96-7-23", TRUE, 23, 7, 96},
+	{"2050-12-31", TRUE, 31, 12, 2050},
+	{"2050-11-31", FALSE, 0, 0, 0},
+	{"1996-02-29", TRUE, 29, 2, 1996},
+	{"1997-02-29", FALSE, 0, 0, 0},
+	{"1900-5-22", TRUE, 22, 5, 1900},
+	{"1900.05-22", FALSE, 0, 0, 0},
+	{"1900-05.22", FALSE, 0, 0, 0},
+	{"1900-05-22 ", FALSE, 0, 0, 0},
+	{" 1900-05-22", FALSE, 0, 0, 0},
+	{"1900 -05-22", FALSE, 0, 0, 0},
+	{"1900- 05-22", FALSE, 0, 0, 0},
+	{"1900-05 -22", FALSE, 0, 0, 0},
+	{"1900-05- 22", FALSE, 0, 0, 0},
+	{"65535-05-22", TRUE, 22, 5, 65535},
+	{"1-05-22", TRUE, 22, 5, 1},
+	{"65536-05-22", FALSE, 0, 0, 0},
+};
+
+static gboolean
+test_parse_iso8601_date (void)
+{
+	gint i;
+
+	for (i = 0; i < sizeof (datedata) / sizeof (TestDate); i++) {
+		TestDate td = datedata[i];
+		GDate date;
+		/*g_print ("[%s]\n", td.in_string);*/
+		if (gda_parse_iso8601_date (&date, td.in_string) != td.exp_retval) {
+			g_print ("Wrong result for gda_parse_iso8601_date (\"%s\"): got %s\n",
+				 td.in_string, td.exp_retval ? "FALSE" : "TRUE");
+			return FALSE;
+		}
+		if (td.exp_retval &&
+		    ((g_date_get_day (&date) != td.exp_day) ||
+		     (g_date_get_month (&date) != td.exp_month) ||
+		     (g_date_get_year (&date) != td.exp_year))) {
+			g_print ("Wrong result for gda_parse_iso8601_date (\"%s\"):\n"
+				 "   exp: DD=%d MM=%d YYYY=%d\n"
+				 "   got: DD=%d MM=%d YYYY=%d\n",
+				 td.in_string, td.exp_day, td.exp_month, td.exp_year,
+				 g_date_get_day (&date), g_date_get_month (&date),
+				 g_date_get_year (&date));
+			return FALSE;
+		}
+	}
+	g_print ("All %d iso8601 date parsing tests passed\n", i);
+
+	return TRUE;
+}
+
+typedef struct {
+	gchar   *in_string;
+	gboolean exp_retval;
+	GdaTime  exp_time;
+} TestTime;
+
+TestTime timedata[] = {
+	{"11:22:56", TRUE, {11, 22, 56, 0, GDA_TIMEZONE_INVALID}},
+	{"1:22:56", TRUE, {1, 22, 56, 0, GDA_TIMEZONE_INVALID}},
+	{"1:22:60", FALSE, {1, 22, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"1:60:45", FALSE, {1, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"24:23:45", FALSE, {0, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"23:59:59", TRUE, {23, 59, 59, 0, GDA_TIMEZONE_INVALID}},
+	{"0:0:00", TRUE, {0, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"12:1:0", TRUE, {12, 1, 0, 0, GDA_TIMEZONE_INVALID}},
+	{" 12:00:00", FALSE, {0, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"12 :00:00", FALSE, {12, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"12: 00:00", FALSE, {12, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"12: 00:00", FALSE, {12, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"12:1 :00", FALSE, {12, 1, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"12:1:2 ", FALSE, {12, 1, 2, 0, GDA_TIMEZONE_INVALID}},
+	{"12:1:2.", FALSE, {12, 1, 2, 0, GDA_TIMEZONE_INVALID}},
+	{"12:1:2:", FALSE, {12, 1, 2, 0, GDA_TIMEZONE_INVALID}},
+	{"12:1:2.123", TRUE, {12, 1, 2, 123, GDA_TIMEZONE_INVALID}},
+	{"12:1:2-2", TRUE, {12, 1, 2, 0, -2*60*60}},
+	{"12:1:2+11", TRUE, {12, 1, 2, 0, 11*60*60}},
+	{"12:1:2.1234+11", TRUE, {12, 1, 2, 1234, 11*60*60}},
+	{"12:1:2.12345678-3", TRUE, {12, 1, 2, 12345678, -3*60*60}},
+};
+
+static gboolean
+test_parse_iso8601_time (void)
+{
+	gint i;
+
+	for (i = 0; i < sizeof (timedata) / sizeof (TestTime); i++) {
+		TestTime td = timedata[i];
+		GdaTime time;
+		/*g_print ("[%s]\n", td.in_string);*/
+		if (gda_parse_iso8601_time (&time, td.in_string) != td.exp_retval) {
+			g_print ("Wrong result for gda_parse_iso8601_time (\"%s\"): got %s\n",
+				 td.in_string, td.exp_retval ? "FALSE" : "TRUE");
+			return FALSE;
+		}
+		if ((time.hour != td.exp_time.hour) ||
+		    (time.minute != td.exp_time.minute) ||
+		    (time.second != td.exp_time.second) ||
+		    (time.fraction != td.exp_time.fraction) ||
+		    (time.timezone != td.exp_time.timezone)) {
+			g_print ("Wrong result for gda_parse_iso8601_time (\"%s\"):\n"
+				 "   exp: HH=%d MM=%d SS=%d FF=%ld TZ=%ld\n"
+				 "   got: HH=%d MM=%d SS=%d FF=%ld TZ=%ld\n",
+				 td.in_string, 
+				 td.exp_time.hour, td.exp_time.minute, td.exp_time.second,
+				 td.exp_time.fraction, td.exp_time.timezone,
+				 time.hour, time.minute, time.second,
+				 time.fraction, time.timezone);
+			return FALSE;
+		}
+	}
+	g_print ("All %d iso8601 time parsing tests passed\n", i);
+
+	return TRUE;
+}
+
+static gboolean
+test_parse_iso8601_timestamp (void)
+{
+	gint idate, itime;
+
+	for (idate = 0; idate < sizeof (datedata) / sizeof (TestTime); idate++) {
+		TestDate td = datedata [idate];
+		for (itime = 0; itime < sizeof (timedata) / sizeof (TestTime); itime++) {
+			TestTime tt = timedata[itime];
+			gchar *str;
+			str = g_strdup_printf ("%s %s", td.in_string, tt.in_string);
+
+			GdaTimestamp timestamp;
+			gboolean exp_result = td.exp_retval && tt.exp_retval;
+			/*g_print ("[%s]\n", str);*/
+			if (gda_parse_iso8601_timestamp (&timestamp, str) != exp_result) {
+				g_print ("Wrong result for gda_parse_iso8601_timestamp (\"%s\"): got %s\n",
+					 td.in_string, exp_result ? "FALSE" : "TRUE");
+				return FALSE;
+			}
+
+			if ((td.exp_retval &&
+			     ((timestamp.year != td.exp_year) ||
+			      (timestamp.month != td.exp_month) ||
+			      (timestamp.day != td.exp_day))) &&
+			    (((timestamp.hour != tt.exp_time.hour) ||
+			      (timestamp.minute != tt.exp_time.minute) ||
+			      (timestamp.second != tt.exp_time.second) ||
+			      (timestamp.fraction != tt.exp_time.fraction) ||
+			      (timestamp.timezone != tt.exp_time.timezone)))) {
+				g_print ("Wrong result for gda_parse_iso8601_timestamp (\"%s\"):\n"
+					 "   exp: DD=%d MM=%d YYYY=%d HH=%d MM=%d SS=%d FF=%ld TZ=%ld\n"
+					 "   got: DD=%d MM=%d YYYY=%d HH=%d MM=%d SS=%d FF=%ld TZ=%ld\n",
+					 str, td.exp_day, td.exp_month, td.exp_year,
+					 tt.exp_time.hour, tt.exp_time.minute, tt.exp_time.second, tt.exp_time.fraction, tt.exp_time.timezone,
+					 timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute,
+					 timestamp.second, timestamp.fraction, timestamp.timezone);
+					 
+				g_free (str);
+				return FALSE;
+			}
+			g_free (str);
+		}
+	}
+	g_print ("All %d iso8601 timestamp parsing tests passed\n", idate * itime);
+
+	return TRUE;
+}
+
+
+static gboolean
+test_date_handler (void)
+{
+	GdaDataHandler *dh;
+	gint i;
+	dh = gda_handler_time_new_no_locale ();
+	gda_handler_time_set_str_spec (GDA_HANDLER_TIME (dh),
+				       G_DATE_YEAR, G_DATE_MONTH, G_DATE_DAY, '-', FALSE);
+
+	for (i = 0; i < sizeof (datedata) / sizeof (TestDate); i++) {
+		TestDate td = datedata[i];
+		GValue *value;
+		/*g_print ("[%s]\n", td.in_string);*/
+
+		value = gda_data_handler_get_value_from_str (dh, td.in_string, G_TYPE_DATE);
+		if ((!value && td.exp_retval) ||
+		    (value && !td.exp_retval)) {
+			g_print ("Wrong result for gda_data_handler_get_value_from_str (\"%s\", G_TYPE_DATE): got %s\n",
+				 td.in_string, td.exp_retval ? "FALSE" : "TRUE");
+			g_object_unref (dh);
+			return FALSE;
+		}
+
+		if (! td.exp_retval)
+			continue;
+		GDate *pdate, date;
+		pdate = g_value_get_boxed (value);
+		date = *pdate;
+		gda_value_free (value);
+
+		if ((g_date_get_day (&date) != td.exp_day) ||
+		    (g_date_get_month (&date) != td.exp_month) ||
+		    (g_date_get_year (&date) != td.exp_year)) {
+			g_print ("Wrong result for gda_parse_iso8601_date (\"%s\"):\n"
+				 "   exp: DD=%d MM=%d YYYY=%d\n"
+				 "   got: DD=%d MM=%d YYYY=%d\n",
+				 td.in_string, td.exp_day, td.exp_month, td.exp_year,
+				 g_date_get_day (&date), g_date_get_month (&date),
+				 g_date_get_year (&date));
+			g_object_unref (dh);
+			return FALSE;
+		}
+	}
+	g_print ("All %d GdaDataHandler (G_TYPE_DATE) parsing tests passed\n", i);
+	g_object_unref (dh);
+	return TRUE;
+}
+
+TestTime timedata2[] = {
+	{"112256", TRUE, {11, 22, 56, 0, GDA_TIMEZONE_INVALID}},
+	{"012256", TRUE, {1, 22, 56, 0, GDA_TIMEZONE_INVALID}},
+	{"012260", FALSE, {1, 22, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"016045", FALSE, {1, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"242345", FALSE, {0, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"235959", TRUE, {23, 59, 59, 0, GDA_TIMEZONE_INVALID}},
+	{"000000", TRUE, {0, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"120100", TRUE, {12, 1, 0, 0, GDA_TIMEZONE_INVALID}},
+	{" 120000", FALSE, {0, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"12 0000", FALSE, {12, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"12 0000", FALSE, {12, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"12 0000", FALSE, {12, 0, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"1201 00", FALSE, {12, 1, 0, 0, GDA_TIMEZONE_INVALID}},
+	{"120102 ", FALSE, {12, 1, 2, 0, GDA_TIMEZONE_INVALID}},
+	{"120102.", FALSE, {12, 1, 2, 0, GDA_TIMEZONE_INVALID}},
+	{"120102:", FALSE, {12, 1, 2, 0, GDA_TIMEZONE_INVALID}},
+	{"120102.123", TRUE, {12, 1, 2, 123, GDA_TIMEZONE_INVALID}},
+	{"120102-2", TRUE, {12, 1, 2, 0, -2*60*60}},
+	{"120102+11", TRUE, {12, 1, 2, 0, 11*60*60}},
+	{"120102.1234+11", TRUE, {12, 1, 2, 1234, 11*60*60}},
+	{"120102.12345678-3", TRUE, {12, 1, 2, 12345678, -3*60*60}},
+};
+
+static gboolean
+test_time_handler (void)
+{
+	GdaDataHandler *dh;
+	gint i, j;
+	dh = gda_get_default_handler (GDA_TYPE_TIME);
+	g_assert (dh);
+
+	for (i = 0; i < sizeof (timedata) / sizeof (TestTime); i++) {
+		TestTime td = timedata[i];
+		GValue *value;
+		/*g_print ("[%s]\n", td.in_string);*/
+
+		value = gda_data_handler_get_value_from_str (dh, td.in_string, GDA_TYPE_TIME);
+		if ((!value && td.exp_retval) ||
+		    (value && !td.exp_retval)) {
+			g_print ("Wrong result for gda_data_handler_get_value_from_str (\"%s\", GDA_TYPE_TIME): got %s\n",
+				 td.in_string, td.exp_retval ? "FALSE" : "TRUE");
+			g_object_unref (dh);
+			return FALSE;
+		}
+
+		if (! td.exp_retval)
+			continue;
+		const GdaTime *ptime;
+		GdaTime time;
+		ptime = gda_value_get_time (value);
+		time = *ptime;
+		gda_value_free (value);
+
+		if ((time.hour != td.exp_time.hour) ||
+		    (time.minute != td.exp_time.minute) ||
+		    (time.second != td.exp_time.second) ||
+		    (time.fraction != td.exp_time.fraction) ||
+		    (time.timezone != td.exp_time.timezone)) {
+			g_print ("Wrong result forgda_data_handler_get_value_from_str (\"%s\", GDA_TYPE_TIME):\n"
+				 "   exp: HH=%d MM=%d SS=%d FF=%ld TZ=%ld\n"
+				 "   got: HH=%d MM=%d SS=%d FF=%ld TZ=%ld\n",
+				 td.in_string, 
+				 td.exp_time.hour, td.exp_time.minute, td.exp_time.second,
+				 td.exp_time.fraction, td.exp_time.timezone,
+				 time.hour, time.minute, time.second,
+				 time.fraction, time.timezone);
+			return FALSE;
+		}
+	}
+
+	for (j = 0; j < sizeof (timedata2) / sizeof (TestTime); j++) {
+		TestTime td = timedata2[j];
+		GValue *value;
+		/*g_print ("[%s]\n", td.in_string);*/
+
+		value = gda_data_handler_get_value_from_str (dh, td.in_string, GDA_TYPE_TIME);
+		if ((!value && td.exp_retval) ||
+		    (value && !td.exp_retval)) {
+			g_print ("Wrong result for gda_data_handler_get_value_from_str (\"%s\", GDA_TYPE_TIME): got %s\n",
+				 td.in_string, td.exp_retval ? "FALSE" : "TRUE");
+			g_object_unref (dh);
+			return FALSE;
+		}
+
+		if (! td.exp_retval)
+			continue;
+		const GdaTime *ptime;
+		GdaTime time;
+		ptime = gda_value_get_time (value);
+		time = *ptime;
+		gda_value_free (value);
+
+		if ((time.hour != td.exp_time.hour) ||
+		    (time.minute != td.exp_time.minute) ||
+		    (time.second != td.exp_time.second) ||
+		    (time.fraction != td.exp_time.fraction) ||
+		    (time.timezone != td.exp_time.timezone)) {
+			g_print ("Wrong result forgda_data_handler_get_value_from_str (\"%s\", GDA_TYPE_TIME):\n"
+				 "   exp: HH=%d MM=%d SS=%d FF=%ld TZ=%ld\n"
+				 "   got: HH=%d MM=%d SS=%d FF=%ld TZ=%ld\n",
+				 td.in_string, 
+				 td.exp_time.hour, td.exp_time.minute, td.exp_time.second,
+				 td.exp_time.fraction, td.exp_time.timezone,
+				 time.hour, time.minute, time.second,
+				 time.fraction, time.timezone);
+			return FALSE;
+		}
+	}
+
+	g_print ("All %d GdaDataHandler (GDA_TYPE_TIME) parsing tests passed\n", i + j);
+	g_object_unref (dh);
+	return TRUE;
+}
+
+static gboolean
+test_timestamp_handler (void)
+{
+	GdaDataHandler *dh;
+	gint idate, itime, itime2;
+	dh = gda_handler_time_new_no_locale ();
+	gda_handler_time_set_str_spec (GDA_HANDLER_TIME (dh),
+				       G_DATE_YEAR, G_DATE_MONTH, G_DATE_DAY, '-', FALSE);
+
+	for (idate = 0; idate < sizeof (datedata) / sizeof (TestTime); idate++) {
+		TestDate td = datedata [idate];
+		for (itime = 0; itime < sizeof (timedata) / sizeof (TestTime); itime++) {
+			TestTime tt = timedata[itime];
+			gchar *str;
+			str = g_strdup_printf ("%s %s", td.in_string, tt.in_string);
+
+			GValue *value;
+			gboolean exp_result = td.exp_retval && tt.exp_retval;
+			/*g_print ("[%s]\n", str);*/
+
+			value = gda_data_handler_get_value_from_str (dh, str, GDA_TYPE_TIMESTAMP);
+			if ((!value && exp_result) ||
+			    (value && !exp_result)) {
+				g_print ("Wrong result for gda_data_handler_get_value_from_str (\"%s\", GDA_TYPE_TIMESTAMP): got %s\n",
+					 str, exp_result ? "FALSE" : "TRUE");
+				g_object_unref (dh);
+				return FALSE;
+			}
+
+			if (! exp_result) {
+				g_free (str);
+				continue;
+			}
+			const GdaTimestamp *ptimestamp;
+			GdaTimestamp timestamp;
+			ptimestamp = gda_value_get_timestamp (value);
+			timestamp = *ptimestamp;
+			gda_value_free (value);
+			
+			if ((td.exp_retval &&
+			     ((timestamp.year != td.exp_year) ||
+			      (timestamp.month != td.exp_month) ||
+			      (timestamp.day != td.exp_day))) &&
+			    ((tt.exp_retval) &&
+			     ((timestamp.hour != tt.exp_time.hour) ||
+			      (timestamp.minute != tt.exp_time.minute) ||
+			      (timestamp.second != tt.exp_time.second) ||
+			      (timestamp.fraction != tt.exp_time.fraction) ||
+			      (timestamp.timezone != tt.exp_time.timezone)))) {
+				g_print ("Wrong result for gda_data_handler_get_value_from_str (\"%s\", GDA_TYPE_TIMESTAMP):\n"
+					 "   exp: DD=%d MM=%d YYYY=%d HH=%d MM=%d SS=%d FF=%ld TZ=%ld\\n"
+					 "   got: DD=%d MM=%d YYYY=%d HH=%d MM=%d SS=%d FF=%ld TZ=%ld\\n",
+					 str, td.exp_day, td.exp_month, td.exp_year,
+					 tt.exp_time.hour, tt.exp_time.minute, tt.exp_time.second, tt.exp_time.fraction, tt.exp_time.timezone,
+					 timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute,
+					 timestamp.second, timestamp.fraction, timestamp.timezone);
+					 
+				g_object_unref (dh);
+				g_free (str);
+				return FALSE;
+			}
+			g_free (str);
+		}
+	}
+
+	for (idate = 0; idate < sizeof (datedata) / sizeof (TestTime); idate++) {
+		TestDate td = datedata [idate];
+		for (itime2 = 0; itime2 < sizeof (timedata2) / sizeof (TestTime); itime2++) {
+			TestTime tt = timedata2[itime2];
+			gchar *str;
+			str = g_strdup_printf ("%s %s", td.in_string, tt.in_string);
+
+			GValue *value;
+			gboolean exp_result = td.exp_retval && tt.exp_retval;
+			/*g_print ("[%s]\n", str);*/
+
+			value = gda_data_handler_get_value_from_str (dh, str, GDA_TYPE_TIMESTAMP);
+			if ((!value && exp_result) ||
+			    (value && !exp_result)) {
+				g_print ("Wrong result for gda_data_handler_get_value_from_str (\"%s\", GDA_TYPE_TIMESTAMP): got %s\n",
+					 str, exp_result ? "FALSE" : "TRUE");
+				g_object_unref (dh);
+				return FALSE;
+			}
+
+			if (! exp_result) {
+				g_free (str);
+				continue;
+			}
+			const GdaTimestamp *ptimestamp;
+			GdaTimestamp timestamp;
+			ptimestamp = gda_value_get_timestamp (value);
+			timestamp = *ptimestamp;
+			gda_value_free (value);
+			
+			if ((timestamp.year != td.exp_year) ||
+			    (timestamp.month != td.exp_month) ||
+			    (timestamp.day != td.exp_day) ||
+			    (timestamp.hour != tt.exp_time.hour) ||
+			    (timestamp.minute != tt.exp_time.minute) ||
+			    (timestamp.second != tt.exp_time.second) ||
+			    (timestamp.fraction != tt.exp_time.fraction) ||
+			    (timestamp.timezone != tt.exp_time.timezone)) {
+				g_print ("Wrong result for gda_data_handler_get_value_from_str (\"%s\", GDA_TYPE_TIMESTAMP):\n"
+					 "   exp: DD=%d MM=%d YYYY=%d HH=%d MM=%d SS=%d FF=%ld TZ=%ld\\n"
+					 "   got: DD=%d MM=%d YYYY=%d HH=%d MM=%d SS=%d FF=%ld TZ=%ld\\n",
+					 str, td.exp_day, td.exp_month, td.exp_year,
+					 tt.exp_time.hour, tt.exp_time.minute, tt.exp_time.second, tt.exp_time.fraction, tt.exp_time.timezone,
+					 timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute,
+					 timestamp.second, timestamp.fraction, timestamp.timezone);
+					 
+				g_object_unref (dh);
+				g_free (str);
+				return FALSE;
+			}
+			g_free (str);
+		}
+	}
+	
+	g_print ("All %d GdaDataHandler (GDA_TYPE_TIMESTAMP) parsing tests passed\n", idate * (itime + itime2));
+	g_object_unref (dh);
+	return TRUE;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]