Fossil SCM

Improved processing of timestamp strings used as check-in identifiers. The ISO8601 date without punctuation (digits only) is now accept on the tag:date format. Also, incomplete ISO8601 date/time values are rounding up instead of rounded down, such that the match on 20200101 actually finds a check-in on 2020-01-01 (if any) rather than the last check-in on 2019-12-31.

drh 2020-04-05 19:02 trunk
Commit a5f3103111ee0866fd3a3768933a171949c38a5a47cc9409d2804ed7e971930a
2 files changed +48 -8 +7 -5
+48 -8
--- src/name.c
+++ src/name.c
@@ -105,10 +105,43 @@
105105
}
106106
107107
/* It looks like this may be a date. Return it with punctuation added. */
108108
return zEDate;
109109
}
110
+
111
+/*
112
+** The data-time string in the argument is going to be used as an
113
+** upper bound like this: mtime<=julianday(zDate,'localtime').
114
+** But if the zDate parameter omits the fractional seconds or the
115
+** seconds, or the time, that might mess up the == part of the
116
+** comparison. So add in missing factional seconds or seconds or time.
117
+**
118
+** The returned string is held in a static buffer that is overwritten
119
+** with each call, or else is just a copy of its input if there are
120
+** no changes.
121
+*/
122
+const char *fossil_roundup_date(const char *zDate){
123
+ static char zUp[24];
124
+ int n = (int)strlen(zDate);
125
+ if( n==19 ){ /* YYYY-MM-DD HH:MM:SS */
126
+ memcpy(zUp, zDate, 19);
127
+ memcpy(zUp+19, ".999", 5);
128
+ return zUp;
129
+ }
130
+ if( n==16 ){ /* YYYY-MM-DD HH:MM */
131
+ memcpy(zUp, zDate, 16);
132
+ memcpy(zUp+16, ":59.999", 8);
133
+ return zUp;
134
+ }
135
+ if( n==10 ){ /* YYYY-MM-DD */
136
+ memcpy(zUp, zDate, 10);
137
+ memcpy(zUp+10, " 23:59:59.999", 14);
138
+ return zUp;
139
+ }
140
+ return zDate;
141
+}
142
+
110143
111144
/*
112145
** Return the RID that is the "root" of the branch that contains
113146
** check-in "rid". Details depending on eType:
114147
**
@@ -235,19 +268,19 @@
235268
if( zDate==0 ) zDate = &zTag[5];
236269
rid = db_int(0,
237270
"SELECT objid FROM event"
238271
" WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
239272
" ORDER BY mtime DESC LIMIT 1",
240
- zDate, zType);
273
+ fossil_roundup_date(zDate), zType);
241274
return rid;
242275
}
243276
if( fossil_isdate(zTag) ){
244277
rid = db_int(0,
245278
"SELECT objid FROM event"
246279
" WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
247280
" ORDER BY mtime DESC LIMIT 1",
248
- zTag, zType);
281
+ fossil_roundup_date(zTag), zType);
249282
if( rid) return rid;
250283
}
251284
252285
/* Deprecated date & time formats: "local:" + date-time and
253286
** "utc:" + date-time */
@@ -262,11 +295,11 @@
262295
if( memcmp(zTag, "utc:", 4)==0 ){
263296
rid = db_int(0,
264297
"SELECT objid FROM event"
265298
" WHERE mtime<=julianday('%qz') AND type GLOB '%q'"
266299
" ORDER BY mtime DESC LIMIT 1",
267
- &zTag[4], zType);
300
+ fossil_roundup_date(&zTag[4]), zType);
268301
return rid;
269302
}
270303
271304
/* "tag:" + symbolic-name */
272305
if( memcmp(zTag, "tag:", 4)==0 ){
@@ -294,29 +327,36 @@
294327
return start_of_branch(rid, 2);
295328
}
296329
297330
/* symbolic-name ":" date-time */
298331
nTag = strlen(zTag);
299
- for(i=0; i<nTag-10 && zTag[i]!=':'; i++){}
300
- if( zTag[i]==':' && fossil_isdate(&zTag[i+1]) ){
332
+ for(i=0; i<nTag-8 && zTag[i]!=':'; i++){}
333
+ if( zTag[i]==':'
334
+ && (fossil_isdate(&zTag[i+1]) || fossil_expand_datetime(&zTag[i+1],0)!=0)
335
+ ){
301336
char *zDate = mprintf("%s", &zTag[i+1]);
302337
char *zTagBase = mprintf("%.*s", i, zTag);
338
+ char *zXDate;
303339
int nDate = strlen(zDate);
304340
if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){
305341
zDate[nDate-3] = 'z';
306342
zDate[nDate-2] = 0;
307343
}
344
+ zXDate = fossil_expand_datetime(zDate,0);
345
+ if( zXDate==0 ) zXDate = zDate;
308346
rid = db_int(0,
309347
"SELECT event.objid, max(event.mtime)"
310348
" FROM tag, tagxref, event"
311349
" WHERE tag.tagname='sym-%q' "
312350
" AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
313351
" AND event.objid=tagxref.rid "
314
- " AND event.mtime<=julianday(%Q)"
352
+ " AND event.mtime<=julianday(%Q,fromLocal())"
315353
" AND event.type GLOB '%q'",
316
- zTagBase, zDate, zType
354
+ zTagBase, fossil_roundup_date(zXDate), zType
317355
);
356
+ fossil_free(zDate);
357
+ fossil_free(zTagBase);
318358
return rid;
319359
}
320360
321361
/* Remove optional [...] */
322362
zXTag = zTag;
@@ -381,11 +421,11 @@
381421
if( zDate ){
382422
rid = db_int(0,
383423
"SELECT objid FROM event"
384424
" WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
385425
" ORDER BY mtime DESC LIMIT 1",
386
- zDate, zType);
426
+ fossil_roundup_date(zDate), zType);
387427
if( rid) return rid;
388428
}
389429
390430
391431
/* Undocumented: numeric tags get translated directly into the RID */
392432
--- src/name.c
+++ src/name.c
@@ -105,10 +105,43 @@
105 }
106
107 /* It looks like this may be a date. Return it with punctuation added. */
108 return zEDate;
109 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
111 /*
112 ** Return the RID that is the "root" of the branch that contains
113 ** check-in "rid". Details depending on eType:
114 **
@@ -235,19 +268,19 @@
235 if( zDate==0 ) zDate = &zTag[5];
236 rid = db_int(0,
237 "SELECT objid FROM event"
238 " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
239 " ORDER BY mtime DESC LIMIT 1",
240 zDate, zType);
241 return rid;
242 }
243 if( fossil_isdate(zTag) ){
244 rid = db_int(0,
245 "SELECT objid FROM event"
246 " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
247 " ORDER BY mtime DESC LIMIT 1",
248 zTag, zType);
249 if( rid) return rid;
250 }
251
252 /* Deprecated date & time formats: "local:" + date-time and
253 ** "utc:" + date-time */
@@ -262,11 +295,11 @@
262 if( memcmp(zTag, "utc:", 4)==0 ){
263 rid = db_int(0,
264 "SELECT objid FROM event"
265 " WHERE mtime<=julianday('%qz') AND type GLOB '%q'"
266 " ORDER BY mtime DESC LIMIT 1",
267 &zTag[4], zType);
268 return rid;
269 }
270
271 /* "tag:" + symbolic-name */
272 if( memcmp(zTag, "tag:", 4)==0 ){
@@ -294,29 +327,36 @@
294 return start_of_branch(rid, 2);
295 }
296
297 /* symbolic-name ":" date-time */
298 nTag = strlen(zTag);
299 for(i=0; i<nTag-10 && zTag[i]!=':'; i++){}
300 if( zTag[i]==':' && fossil_isdate(&zTag[i+1]) ){
 
 
301 char *zDate = mprintf("%s", &zTag[i+1]);
302 char *zTagBase = mprintf("%.*s", i, zTag);
 
303 int nDate = strlen(zDate);
304 if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){
305 zDate[nDate-3] = 'z';
306 zDate[nDate-2] = 0;
307 }
 
 
308 rid = db_int(0,
309 "SELECT event.objid, max(event.mtime)"
310 " FROM tag, tagxref, event"
311 " WHERE tag.tagname='sym-%q' "
312 " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
313 " AND event.objid=tagxref.rid "
314 " AND event.mtime<=julianday(%Q)"
315 " AND event.type GLOB '%q'",
316 zTagBase, zDate, zType
317 );
 
 
318 return rid;
319 }
320
321 /* Remove optional [...] */
322 zXTag = zTag;
@@ -381,11 +421,11 @@
381 if( zDate ){
382 rid = db_int(0,
383 "SELECT objid FROM event"
384 " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
385 " ORDER BY mtime DESC LIMIT 1",
386 zDate, zType);
387 if( rid) return rid;
388 }
389
390
391 /* Undocumented: numeric tags get translated directly into the RID */
392
--- src/name.c
+++ src/name.c
@@ -105,10 +105,43 @@
105 }
106
107 /* It looks like this may be a date. Return it with punctuation added. */
108 return zEDate;
109 }
110
111 /*
112 ** The data-time string in the argument is going to be used as an
113 ** upper bound like this: mtime<=julianday(zDate,'localtime').
114 ** But if the zDate parameter omits the fractional seconds or the
115 ** seconds, or the time, that might mess up the == part of the
116 ** comparison. So add in missing factional seconds or seconds or time.
117 **
118 ** The returned string is held in a static buffer that is overwritten
119 ** with each call, or else is just a copy of its input if there are
120 ** no changes.
121 */
122 const char *fossil_roundup_date(const char *zDate){
123 static char zUp[24];
124 int n = (int)strlen(zDate);
125 if( n==19 ){ /* YYYY-MM-DD HH:MM:SS */
126 memcpy(zUp, zDate, 19);
127 memcpy(zUp+19, ".999", 5);
128 return zUp;
129 }
130 if( n==16 ){ /* YYYY-MM-DD HH:MM */
131 memcpy(zUp, zDate, 16);
132 memcpy(zUp+16, ":59.999", 8);
133 return zUp;
134 }
135 if( n==10 ){ /* YYYY-MM-DD */
136 memcpy(zUp, zDate, 10);
137 memcpy(zUp+10, " 23:59:59.999", 14);
138 return zUp;
139 }
140 return zDate;
141 }
142
143
144 /*
145 ** Return the RID that is the "root" of the branch that contains
146 ** check-in "rid". Details depending on eType:
147 **
@@ -235,19 +268,19 @@
268 if( zDate==0 ) zDate = &zTag[5];
269 rid = db_int(0,
270 "SELECT objid FROM event"
271 " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
272 " ORDER BY mtime DESC LIMIT 1",
273 fossil_roundup_date(zDate), zType);
274 return rid;
275 }
276 if( fossil_isdate(zTag) ){
277 rid = db_int(0,
278 "SELECT objid FROM event"
279 " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
280 " ORDER BY mtime DESC LIMIT 1",
281 fossil_roundup_date(zTag), zType);
282 if( rid) return rid;
283 }
284
285 /* Deprecated date & time formats: "local:" + date-time and
286 ** "utc:" + date-time */
@@ -262,11 +295,11 @@
295 if( memcmp(zTag, "utc:", 4)==0 ){
296 rid = db_int(0,
297 "SELECT objid FROM event"
298 " WHERE mtime<=julianday('%qz') AND type GLOB '%q'"
299 " ORDER BY mtime DESC LIMIT 1",
300 fossil_roundup_date(&zTag[4]), zType);
301 return rid;
302 }
303
304 /* "tag:" + symbolic-name */
305 if( memcmp(zTag, "tag:", 4)==0 ){
@@ -294,29 +327,36 @@
327 return start_of_branch(rid, 2);
328 }
329
330 /* symbolic-name ":" date-time */
331 nTag = strlen(zTag);
332 for(i=0; i<nTag-8 && zTag[i]!=':'; i++){}
333 if( zTag[i]==':'
334 && (fossil_isdate(&zTag[i+1]) || fossil_expand_datetime(&zTag[i+1],0)!=0)
335 ){
336 char *zDate = mprintf("%s", &zTag[i+1]);
337 char *zTagBase = mprintf("%.*s", i, zTag);
338 char *zXDate;
339 int nDate = strlen(zDate);
340 if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){
341 zDate[nDate-3] = 'z';
342 zDate[nDate-2] = 0;
343 }
344 zXDate = fossil_expand_datetime(zDate,0);
345 if( zXDate==0 ) zXDate = zDate;
346 rid = db_int(0,
347 "SELECT event.objid, max(event.mtime)"
348 " FROM tag, tagxref, event"
349 " WHERE tag.tagname='sym-%q' "
350 " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
351 " AND event.objid=tagxref.rid "
352 " AND event.mtime<=julianday(%Q,fromLocal())"
353 " AND event.type GLOB '%q'",
354 zTagBase, fossil_roundup_date(zXDate), zType
355 );
356 fossil_free(zDate);
357 fossil_free(zTagBase);
358 return rid;
359 }
360
361 /* Remove optional [...] */
362 zXTag = zTag;
@@ -381,11 +421,11 @@
421 if( zDate ){
422 rid = db_int(0,
423 "SELECT objid FROM event"
424 " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
425 " ORDER BY mtime DESC LIMIT 1",
426 fossil_roundup_date(zDate), zType);
427 if( rid) return rid;
428 }
429
430
431 /* Undocumented: numeric tags get translated directly into the RID */
432
+7 -5
--- src/timeline.c
+++ src/timeline.c
@@ -1113,15 +1113,17 @@
11131113
if( fossil_isdate(z) ){
11141114
mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", z);
11151115
if( mtime>0.0 ) return mtime;
11161116
}
11171117
zDate = fossil_expand_datetime(z, 1);
1118
- if( zDate!=0
1119
- && (mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", zDate))>0.0
1120
- ){
1121
- if( pzDisplay ) *pzDisplay = fossil_strdup(zDate);
1122
- return mtime;
1118
+ if( zDate!=0 ){
1119
+ mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())",
1120
+ fossil_roundup_date(zDate));
1121
+ if( mtime>0.0 ){
1122
+ if( pzDisplay ) *pzDisplay = fossil_strdup(zDate);
1123
+ return mtime;
1124
+ }
11231125
}
11241126
rid = symbolic_name_to_rid(z, "*");
11251127
if( rid ){
11261128
mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
11271129
}else{
11281130
--- src/timeline.c
+++ src/timeline.c
@@ -1113,15 +1113,17 @@
1113 if( fossil_isdate(z) ){
1114 mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", z);
1115 if( mtime>0.0 ) return mtime;
1116 }
1117 zDate = fossil_expand_datetime(z, 1);
1118 if( zDate!=0
1119 && (mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", zDate))>0.0
1120 ){
1121 if( pzDisplay ) *pzDisplay = fossil_strdup(zDate);
1122 return mtime;
 
 
1123 }
1124 rid = symbolic_name_to_rid(z, "*");
1125 if( rid ){
1126 mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
1127 }else{
1128
--- src/timeline.c
+++ src/timeline.c
@@ -1113,15 +1113,17 @@
1113 if( fossil_isdate(z) ){
1114 mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", z);
1115 if( mtime>0.0 ) return mtime;
1116 }
1117 zDate = fossil_expand_datetime(z, 1);
1118 if( zDate!=0 ){
1119 mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())",
1120 fossil_roundup_date(zDate));
1121 if( mtime>0.0 ){
1122 if( pzDisplay ) *pzDisplay = fossil_strdup(zDate);
1123 return mtime;
1124 }
1125 }
1126 rid = symbolic_name_to_rid(z, "*");
1127 if( rid ){
1128 mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
1129 }else{
1130

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button