[notmuch] [PATCH] Make the date parser nicer. This is v3 and considered to be final (but the documentation).

Sebastian Spaeth Sebastian at SSpaeth.de
Mon Jan 25 02:50:34 PST 2010


Currently we have to enter mail dates as timestamps. This approach does 2 things:
1) it requires the prefix 'date:'
2) it allows dates to be specified in a flexible way. So a notmuch show date:2005..2006-05-12 will find all mails from 2005-01-01 until 2006-05-12.

Possible time formats: YYYY-MM-DD, YYYY-MM (from/through that month) , YYYY (from/through that year), MM-DD (month-day in current year), DD (day in current month).

Signed-off-by: Sebastian Spaeth <Sebastian at SSpaeth.de>
---
 lib/database.cc |   80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 79 insertions(+), 1 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 5b12320..da2fda8 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -494,6 +494,84 @@ _notmuch_database_ensure_writable (notmuch_database_t *notmuch)
     return NOTMUCH_STATUS_SUCCESS;
 }
 
+struct MaildateValueRangeProcessor : public Xapian::ValueRangeProcessor {
+    MaildateValueRangeProcessor() {}
+
+  time_t
+  parsedate(std::string &str, bool early) {
+    /* Parse the date to a 'time_t', return NULL on error            */
+    /* possible time formats: YYYY-MM-DD, YYYY-MM, YYYY,             */
+    /* MM-DD (current month), DD (day in current month).             */
+    /* Uses start of time unit when 'early', end otherwise, e.g.     */
+    /* 2001:=2001-01-01:00:00:00 when 'early' or 2001-12-31:23:59:59 */
+    struct tm *timeinfo;
+    time_t timet;
+    int year = 0, month = 0, day = 0;
+
+    if (str.size() == 2) {
+      /* We got just current day in month, parse & remove it */
+      day = atoi(str.c_str());
+      str.erase(0,2);
+    }
+    
+    if (str.size() == 4 or str.size() > 5) {
+      /* expect a year, parse & remove it */
+      year = atoi(str.c_str());
+      str.erase(0,5);
+    }
+
+    /* parse & remove month if there is sth left in the string */
+    month = atoi(str.c_str());
+    str.erase(0,3);
+
+    /* Parse day if we have one left */
+    if (str.size())
+      day = atoi(str.c_str());	
+
+    if (year == 0 && month == 0 && day == 0)
+      // no expected time format
+      return -1 ;
+
+    timet = time(NULL);                /* init timeinfo with current time */
+    timeinfo = gmtime(&timet);
+    /* add timeunit if !early (1 second too much, which we deduct later   */
+    if (!early) {
+      if (year && !month)        ++year;  /* only year given              */
+      if (year && month && !day) ++month; /* year & month given           */
+    }
+    if (year)  timeinfo -> tm_year = year - 1900;
+    if (month) timeinfo -> tm_mon = month - 1;
+    if (day)   timeinfo -> tm_mday = (early ? day : ++day);
+    else       timeinfo -> tm_mday = 1;
+
+    timeinfo -> tm_hour = 0;
+    timeinfo -> tm_min  = 0;
+    timeinfo -> tm_sec  = (early ? 0 : -1); /* -1 sec if !early */
+    timet = mktime(timeinfo);
+
+    return timet;
+  }
+
+    Xapian::valueno operator()(std::string &begin, std::string &end) {
+      time_t begintime, endtime;
+
+      if (begin.substr(0, 5) != "date:")
+	 return Xapian::BAD_VALUENO;
+      begin.erase(0, 5);
+
+      begintime = parsedate(begin, true);
+      endtime   = parsedate(end, false);
+      if ((begintime == -1) || (endtime == -1))
+	// parsedate failed, no valid time format
+	return Xapian::BAD_VALUENO;
+
+      begin.assign(Xapian::sortable_serialise(begintime));
+      end.assign(Xapian::sortable_serialise(endtime));
+
+      return NOTMUCH_VALUE_TIMESTAMP;
+    }
+};
+
 notmuch_database_t *
 notmuch_database_open (const char *path,
 		       notmuch_database_mode_t mode)
@@ -570,8 +648,7 @@ notmuch_database_open (const char *path,
 	notmuch->query_parser = new Xapian::QueryParser;
 	notmuch->term_gen = new Xapian::TermGenerator;
 	notmuch->term_gen->set_stemmer (Xapian::Stem ("english"));
-	notmuch->value_range_processor = new Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_TIMESTAMP);
+	notmuch->value_range_processor = new MaildateValueRangeProcessor();
 
 	notmuch->query_parser->set_default_op (Xapian::Query::OP_AND);
 	notmuch->query_parser->set_database (*notmuch->xapian_db);
-- 
1.6.3.3



More information about the notmuch mailing list