[tracker/subsecond] libtracker-data: Ssupport fractional seconds in xsd:dateTime values
- From: JÃrg Billeter <juergbi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/subsecond] libtracker-data: Ssupport fractional seconds in xsd:dateTime values
- Date: Wed, 9 Nov 2011 15:22:04 +0000 (UTC)
commit 6ad321ad1a6717be54822f91b88106edb31daa17
Author: JÃrg Billeter <j bitron ch>
Date: Wed Nov 9 16:21:02 2011 +0100
libtracker-data: Ssupport fractional seconds in xsd:dateTime values
src/libtracker-common/Makefile.am | 3 +-
src/libtracker-common/libtracker-common.vapi | 2 +-
src/libtracker-common/tracker-date-time.c | 60 +++++++++++++------
src/libtracker-common/tracker-date-time.h | 8 +-
src/libtracker-data/Makefile.am | 3 +-
src/libtracker-data/tracker-data-update.c | 14 +++-
src/libtracker-data/tracker-sparql-expression.vala | 2 +-
src/libtracker-data/tracker-sparql-query.vala | 4 +-
tests/functional-tests/01-insertion.py | 4 +-
tests/libtracker-data/subqueries/subqueries-1.out | 4 +-
.../subqueries/subqueries-union-2.out | 10 ++--
11 files changed, 72 insertions(+), 42 deletions(-)
---
diff --git a/src/libtracker-common/Makefile.am b/src/libtracker-common/Makefile.am
index 406ca38..4e7f9f6 100644
--- a/src/libtracker-common/Makefile.am
+++ b/src/libtracker-common/Makefile.am
@@ -66,7 +66,8 @@ libtracker_common_la_LDFLAGS = \
libtracker_common_la_LIBADD = \
$(BUILD_LIBS) \
- $(LIBTRACKER_COMMON_LIBS)
+ $(LIBTRACKER_COMMON_LIBS) \
+ -lm
if HAVE_TRACKER_FTS
libtracker_common_la_LIBADD += $(top_builddir)/src/libstemmer/libstemmer.la
diff --git a/src/libtracker-common/libtracker-common.vapi b/src/libtracker-common/libtracker-common.vapi
index b9b9c43..4f38dbe 100644
--- a/src/libtracker-common/libtracker-common.vapi
+++ b/src/libtracker-common/libtracker-common.vapi
@@ -19,7 +19,7 @@
namespace Tracker {
[CCode (cheader_filename = "libtracker-common/tracker-date-time.h")]
- public int string_to_date (string date_string, out int offset) throws DateError;
+ public double string_to_date (string date_string, out int offset) throws DateError;
[CCode (cheader_filename = "libtracker-common/tracker-date-time.h")]
public errordomain DateError {
diff --git a/src/libtracker-common/tracker-date-time.c b/src/libtracker-common/tracker-date-time.c
index 49412c0..56eeed5 100644
--- a/src/libtracker-common/tracker-date-time.c
+++ b/src/libtracker-common/tracker-date-time.c
@@ -27,9 +27,10 @@
#include <strings.h>
#include <string.h>
+#include <math.h>
+#include <stdio.h>
#include <stdlib.h>
#include <time.h>
-#include <stdlib.h>
#include <glib.h>
@@ -40,7 +41,7 @@ GQuark tracker_date_error_quark (void) {
return g_quark_from_static_string ("tracker_date_error-quark");
}
-time_t
+gdouble
tracker_string_to_date (const gchar *date_string,
gint *offset_p,
GError **error)
@@ -54,7 +55,7 @@ tracker_string_to_date (const gchar *date_string,
GMatchInfo *match_info;
gchar *match;
struct tm tm;
- time_t t;
+ gdouble t;
gint offset;
g_return_val_if_fail (date_string, -1);
@@ -171,10 +172,20 @@ tracker_string_to_date (const gchar *date_string,
offset = -timezone + (tm.tm_isdst > 0 ? 3600 : 0);
#else
t2 = timegm (&tm);
- offset = t2 - t;
+ offset = t2 - (time_t) t;
#endif
}
+ match = g_match_info_fetch (match_info, 7);
+ if (match) {
+ char milliseconds[4] = "000\0";
+ /* first character of match is decimal point
+ we're interested in a maximum of 3 decimal places (milliseconds) */
+ memcpy (milliseconds, match + 1, MIN (3, strlen (match + 1)));
+ t += (gdouble) atoi (milliseconds) / 1000;
+ g_free (match);
+ }
+
g_match_info_free (match_info);
if (offset_p) {
@@ -185,19 +196,30 @@ tracker_string_to_date (const gchar *date_string,
}
gchar *
-tracker_date_to_string (time_t date_time)
+tracker_date_to_string (gdouble date_time)
{
gchar buffer[30];
+ time_t seconds;
+ gint milliseconds;
struct tm utc_time;
size_t count;
memset (buffer, '\0', sizeof (buffer));
memset (&utc_time, 0, sizeof (struct tm));
- gmtime_r (&date_time, &utc_time);
+ seconds = (time_t) date_time;
+ milliseconds = (gint) (fmod (date_time, 1) * 1000);
+ gmtime_r (&seconds, &utc_time);
+
+ /* Output is ISO 8601 format : "YYYY-MM-DDThh:mm:ss" */
+ count = strftime (buffer, sizeof (buffer), "%FT%T", &utc_time);
- /* Output is ISO 8601 format : "YYYY-MM-DDThh:mm:ssZ" */
- count = strftime (buffer, sizeof (buffer), "%FT%TZ", &utc_time);
+ /* Append milliseconds (if non-zero) and time zone */
+ if (milliseconds > 0) {
+ snprintf (buffer + count, sizeof (buffer) - count, ".%03dZ", milliseconds);
+ } else {
+ buffer[count] = 'Z';
+ }
return count > 0 ? g_strdup (buffer) : NULL;
}
@@ -205,7 +227,7 @@ tracker_date_to_string (time_t date_time)
static void
date_time_value_init (GValue *value)
{
- value->data[0].v_int64 = 0;
+ value->data[0].v_double = 0;
value->data[1].v_int = 0;
}
@@ -213,7 +235,7 @@ static void
date_time_value_copy (const GValue *src_value,
GValue *dest_value)
{
- dest_value->data[0].v_int64 = src_value->data[0].v_int64;
+ dest_value->data[0].v_double = src_value->data[0].v_double;
dest_value->data[1].v_int = src_value->data[1].v_int;
}
@@ -254,13 +276,13 @@ tracker_date_time_get_type (void)
void
tracker_date_time_set (GValue *value,
- gint64 time,
+ gdouble time,
gint offset)
{
g_return_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME));
g_return_if_fail (offset >= -14 * 3600 && offset <= 14 * 3600);
- value->data[0].v_int64 = time;
+ value->data[0].v_double = time;
value->data[1].v_int = offset;
}
@@ -269,7 +291,7 @@ tracker_date_time_set_from_string (GValue *value,
const gchar *date_time_string,
GError **error)
{
- gint64 time;
+ gdouble time;
gint offset;
GError *new_error = NULL;
@@ -286,13 +308,13 @@ tracker_date_time_set_from_string (GValue *value,
tracker_date_time_set (value, time, offset);
}
-gint64
+gdouble
tracker_date_time_get_time (const GValue *value)
{
g_return_val_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME), 0);
/* UTC timestamp */
- return value->data[0].v_int64;
+ return value->data[0].v_double;
}
gint
@@ -307,23 +329,23 @@ tracker_date_time_get_offset (const GValue *value)
gint
tracker_date_time_get_local_date (const GValue *value)
{
- gint64 local_timestamp;
+ gdouble local_timestamp;
g_return_val_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME), 0);
/* return number of days since epoch */
local_timestamp = tracker_date_time_get_time (value) + tracker_date_time_get_offset (value);
- return local_timestamp / 3600 / 24;
+ return (gint) (local_timestamp / 3600 / 24);
}
gint
tracker_date_time_get_local_time (const GValue *value)
{
- gint64 local_timestamp;
+ gdouble local_timestamp;
g_return_val_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME), 0);
/* return local time of day */
local_timestamp = tracker_date_time_get_time (value) + tracker_date_time_get_offset (value);
- return local_timestamp % (24 * 3600);
+ return (int) local_timestamp % (24 * 3600);
}
diff --git a/src/libtracker-common/tracker-date-time.h b/src/libtracker-common/tracker-date-time.h
index 09b97c1..fee7ba4 100644
--- a/src/libtracker-common/tracker-date-time.h
+++ b/src/libtracker-common/tracker-date-time.h
@@ -43,20 +43,20 @@ GQuark tracker_date_error_quark (void);
GType tracker_date_time_get_type (void);
void tracker_date_time_set (GValue *value,
- gint64 time,
+ gdouble time,
gint offset);
void tracker_date_time_set_from_string (GValue *value,
const gchar *date_time_string,
GError **error);
-gint64 tracker_date_time_get_time (const GValue *value);
+gdouble tracker_date_time_get_time (const GValue *value);
gint tracker_date_time_get_offset (const GValue *value);
gint tracker_date_time_get_local_date (const GValue *value);
gint tracker_date_time_get_local_time (const GValue *value);
-time_t tracker_string_to_date (const gchar *date_string,
+gdouble tracker_string_to_date (const gchar *date_string,
gint *offset,
GError **error);
-gchar * tracker_date_to_string (time_t date_time);
+gchar * tracker_date_to_string (gdouble date_time);
G_END_DECLS
diff --git a/src/libtracker-data/Makefile.am b/src/libtracker-data/Makefile.am
index 08b648b..72c02a0 100644
--- a/src/libtracker-data/Makefile.am
+++ b/src/libtracker-data/Makefile.am
@@ -49,7 +49,8 @@ libtracker_data_la_LIBADD = \
$(top_builddir)/src/gvdb/libgvdb.la \
$(top_builddir)/src/libtracker-common/libtracker-common.la \
$(BUILD_LIBS) \
- $(LIBTRACKER_DATA_LIBS)
+ $(LIBTRACKER_DATA_LIBS) \
+ -lm
if HAVE_TRACKER_FTS
libtracker_data_la_LIBADD += \
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index 5cfef9d..c14a8c9 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -22,6 +22,7 @@
#include <string.h>
#include <stdlib.h>
+#include <math.h>
#include <time.h>
#include <libtracker-common/tracker-date-time.h>
@@ -699,7 +700,7 @@ statement_bind_gvalue (TrackerDBStatement *stmt,
break;
default:
if (type == TRACKER_TYPE_DATE_TIME) {
- tracker_db_statement_bind_int (stmt, (*idx)++, tracker_date_time_get_time (value));
+ tracker_db_statement_bind_double (stmt, (*idx)++, tracker_date_time_get_time (value));
tracker_db_statement_bind_int (stmt, (*idx)++, tracker_date_time_get_local_date (value));
tracker_db_statement_bind_int (stmt, (*idx)++, tracker_date_time_get_local_time (value));
} else {
@@ -1287,8 +1288,9 @@ value_equal (GValue *value1,
if (type == TRACKER_TYPE_DATE_TIME) {
/* ignore UTC offset for comparison, irrelevant for comparison according to xsd:dateTime spec
* http://www.w3.org/TR/xmlschema-2/#dateTime
+ * also ignore sub-millisecond as this is a floating point comparison
*/
- return tracker_date_time_get_time (value1) == tracker_date_time_get_time (value2);
+ return fabs (tracker_date_time_get_time (value1) - tracker_date_time_get_time (value2)) < 0.001;
}
g_assert_not_reached ();
}
@@ -1394,9 +1396,13 @@ get_property_values (TrackerProperty *property)
tracker_db_cursor_get_value (cursor, 0, &gvalue);
if (G_VALUE_TYPE (&gvalue)) {
if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME) {
- gint time;
+ gdouble time;
- time = g_value_get_int64 (&gvalue);
+ if (G_VALUE_TYPE (&gvalue) == G_TYPE_INT64) {
+ time = g_value_get_int64 (&gvalue);
+ } else {
+ time = g_value_get_double (&gvalue);
+ }
g_value_unset (&gvalue);
g_value_init (&gvalue, TRACKER_TYPE_DATE_TIME);
/* UTC offset is irrelevant for comparison */
diff --git a/src/libtracker-data/tracker-sparql-expression.vala b/src/libtracker-data/tracker-sparql-expression.vala
index c04a5d1..e7100e9 100644
--- a/src/libtracker-data/tracker-sparql-expression.vala
+++ b/src/libtracker-data/tracker-sparql-expression.vala
@@ -322,7 +322,7 @@ class Tracker.Sparql.Expression : Object {
break;
case PropertyType.DATETIME:
// ISO 8601 format
- sql.insert (begin, "strftime (\"%Y-%m-%dT%H:%M:%SZ\", ");
+ sql.insert (begin, "strftime (\"%Y-%m-%dT%H:%M:%fZ\", ");
sql.append (", \"unixepoch\")");
break;
default:
diff --git a/src/libtracker-data/tracker-sparql-query.vala b/src/libtracker-data/tracker-sparql-query.vala
index cab2779..b84103d 100644
--- a/src/libtracker-data/tracker-sparql-query.vala
+++ b/src/libtracker-data/tracker-sparql-query.vala
@@ -514,9 +514,9 @@ public class Tracker.Sparql.Query : Object {
throw new Sparql.Error.TYPE ("`%s' is not a valid boolean".printf (binding.literal));
}
} else if (binding.data_type == PropertyType.DATE) {
- stmt.bind_int (i, string_to_date (binding.literal + "T00:00:00Z", null));
+ stmt.bind_int (i, (int) string_to_date (binding.literal + "T00:00:00Z", null));
} else if (binding.data_type == PropertyType.DATETIME) {
- stmt.bind_int (i, string_to_date (binding.literal, null));
+ stmt.bind_double (i, string_to_date (binding.literal, null));
} else if (binding.data_type == PropertyType.INTEGER) {
stmt.bind_int (i, int.parse (binding.literal));
} else {
diff --git a/tests/functional-tests/01-insertion.py b/tests/functional-tests/01-insertion.py
index 8d9942e..763e433 100755
--- a/tests/functional-tests/01-insertion.py
+++ b/tests/functional-tests/01-insertion.py
@@ -226,7 +226,7 @@ class TrackerStoreInsertionTests (CommonTrackerStoreTest):
self.assertEquals (len (result), 1)
self.assertEquals (len (result[0]), 2)
self.assertEquals (int (result[0][0]), i)
- self.assertEquals (result[0][1], "2000-01-01T00:4%d:47Z" % (i))
+ self.assertEquals (result[0][1], "2000-01-01T00:4%d:47.000Z" % (i))
self.tracker.update ("""
DELETE { <test://instance-1> a rdfs:Resource. }
@@ -257,7 +257,7 @@ class TrackerStoreInsertionTests (CommonTrackerStoreTest):
self.assertEquals (len (result), 1)
self.assertEquals (len (result[0]), 2)
self.assertEquals (int (result[0][0]), i)
- self.assertEquals (result[0][1], "2000-01-01T00:4%d:47Z" % (i))
+ self.assertEquals (result[0][1], "2000-01-01T00:4%d:47.000Z" % (i))
self.tracker.update ("""
DELETE { <test://instance-1> a rdfs:Resource. }
diff --git a/tests/libtracker-data/subqueries/subqueries-1.out b/tests/libtracker-data/subqueries/subqueries-1.out
index 905166a..c443a3d 100644
--- a/tests/libtracker-data/subqueries/subqueries-1.out
+++ b/tests/libtracker-data/subqueries/subqueries-1.out
@@ -1,2 +1,2 @@
-"http://example.org/ns#group2" "2009-12-05T00:00:00Z" "http://example.org/ns#msg5" "3"
-"http://example.org/ns#group1" "2009-12-02T00:00:00Z" "http://example.org/ns#msg2" "2"
+"http://example.org/ns#group2" "2009-12-05T00:00:00.000Z" "http://example.org/ns#msg5" "3"
+"http://example.org/ns#group1" "2009-12-02T00:00:00.000Z" "http://example.org/ns#msg2" "2"
diff --git a/tests/libtracker-data/subqueries/subqueries-union-2.out b/tests/libtracker-data/subqueries/subqueries-union-2.out
index 2de3f5d..838fe3b 100644
--- a/tests/libtracker-data/subqueries/subqueries-union-2.out
+++ b/tests/libtracker-data/subqueries/subqueries-union-2.out
@@ -1,5 +1,5 @@
-"http://example.org/ns#msg1" "2009-12-01T00:00:00Z"
-"http://example.org/ns#msg2" "2009-12-02T00:00:00Z"
-"http://example.org/ns#msg3" "2009-12-03T00:00:00Z"
-"http://example.org/ns#msg4" "2009-12-04T00:00:00Z"
-"http://example.org/ns#msg5" "2009-12-05T00:00:00Z"
+"http://example.org/ns#msg1" "2009-12-01T00:00:00.000Z"
+"http://example.org/ns#msg2" "2009-12-02T00:00:00.000Z"
+"http://example.org/ns#msg3" "2009-12-03T00:00:00.000Z"
+"http://example.org/ns#msg4" "2009-12-04T00:00:00.000Z"
+"http://example.org/ns#msg5" "2009-12-05T00:00:00.000Z"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]