Fossil SCM

Allow the form ymd=YYYYMMDD-YYYYMMDD to show a range of days in the /timeline.

drh 2024-12-26 15:20 trunk
Commit 7e68a6f1e029c6eb4929cf769db699744ec1036e2555f680fdbd448882236c1d
1 file changed +108 -5
+108 -5
--- src/timeline.c
+++ src/timeline.c
@@ -1345,10 +1345,45 @@
13451345
zEDate[j] = 0;
13461346
13471347
/* It looks like this may be a date. Return it with punctuation added. */
13481348
return zEDate;
13491349
}
1350
+
1351
+/*
1352
+** Check to see if the argument is a date-span for the ymd= query
1353
+** parameter. A valid date-span is of the form:
1354
+**
1355
+** 0123456789 123456 <-- index
1356
+** YYYYMMDD-YYYYMMDD
1357
+**
1358
+** with an optional "Z" timeline modifier at the end. Return true if
1359
+** the input is a valid date space and false if not.
1360
+*/
1361
+static int timeline_is_datespan(const char *zDay){
1362
+ size_t n = strlen(zDay);
1363
+ int i, d, m;
1364
+
1365
+ if( n<17 || n>18 ) return 0;
1366
+ if( n==18 ){
1367
+ if( zDay[17]!='Z' && zDay[17]!='z' ) return 0;
1368
+ n--;
1369
+ }
1370
+ if( zDay[8]!='-' ) return 0;
1371
+ for(i=0; i<17 && (fossil_isdigit(zDay[i]) || i==8); i++){}
1372
+ if( i!=17 ) return 0;
1373
+ i = atoi(zDay);
1374
+ d = i%100;
1375
+ if( d<1 || d>31 ) return 0;
1376
+ m = (i/100)%100;
1377
+ if( m<1 || m>12 ) return 0;
1378
+ i = atoi(zDay+9);
1379
+ d = i%100;
1380
+ if( d<1 || d>31 ) return 0;
1381
+ m = (i/100)%100;
1382
+ if( m<1 || m>12 ) return 0;
1383
+ return 1;
1384
+}
13501385
13511386
/*
13521387
** Find the first check-in encountered with a particular tag
13531388
** when moving either forwards are backwards in time from a
13541389
** particular starting point (iFrom). Return the rid of that
@@ -1598,15 +1633,17 @@
15981633
** deltabg Background color red for delta manifests or green
15991634
** for baseline manifests
16001635
** namechng Show only check-ins that have filename changes
16011636
** forks Show only forks and their children
16021637
** cherrypicks Show all cherrypicks
1603
-** ym=YYYY-MM Show only events for the given year/month
1604
-** yw=YYYY-WW Show only events for the given week of the given year
1605
-** yw=YYYY-MM-DD Show events for the week that includes the given day
1606
-** ymd=YYYY-MM-DD Show only events on the given day. The use "ymd=now"
1607
-** to see all changes for the current week.
1638
+** ym=YYYYMM Show only events for the given year/month
1639
+** yw=YYYYWW Show only events for the given week of the given year
1640
+** yw=YYYYMMDD Show events for the week that includes the given day
1641
+** ymd=YYYYMMDD Show only events on the given day. The use "ymd=now"
1642
+** to see all changes for the current week. Add "z" at end
1643
+** to divide days at UTC instead of localtime days.
1644
+** Use ymd=YYYYMMDD-YYYYMMDD (with optional "z") for a range.
16081645
** year=YYYY Show only events on the given year. The use "year=0"
16091646
** to see all changes for the current year.
16101647
** days=N Show events over the previous N days
16111648
** datefmt=N Override the date format: 0=HH:MM, 1=HH:MM:SS,
16121649
** 2=YYYY-MM-DD HH:MM:SS, 3=YYMMDD HH:MM, and 4 means "off".
@@ -2474,15 +2511,81 @@
24742511
zYearWeekStart, zTZMod, zYearWeekStart, zTZMod);
24752512
nEntry = -1;
24762513
if( fossil_ui_localtime() && bZulu ){
24772514
zYearWeekStart = mprintf("%zZ", zYearWeekStart);
24782515
}
2516
+ }
2517
+ else if( zDay && timeline_is_datespan(zDay) ){
2518
+ char *zNext;
2519
+ char *zStart, *zEnd;
2520
+ int nDay;
2521
+ int bZulu = 0;
2522
+ const char *zTZMod;
2523
+ zEnd = db_text(0, "SELECT date(%Q)",
2524
+ timeline_expand_datetime(zDay+9, &bZulu));
2525
+ zStart = db_text(0, "SELECT date('%.4q-%.2q-%.2q')",
2526
+ zDay, zDay+4, zDay+6);
2527
+ nDay = db_int(0, "SELECT julianday(%Q)-julianday(%Q)", zEnd, zStart);
2528
+ if( nDay==0 ){
2529
+ zDay = &zDay[9];
2530
+ goto single_ymd;
2531
+ }
2532
+ if( nDay<0 ){
2533
+ char *zTemp = zEnd;
2534
+ zEnd = zStart;
2535
+ zStart = zTemp;
2536
+ nDay = 1 - nDay;
2537
+ }else{
2538
+ nDay += 1;
2539
+ }
2540
+ zTZMod = (bZulu==0 && fossil_ui_localtime()) ? "utc" : "+00:00";
2541
+ if( nDay>0 && db_int(0,
2542
+ "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2543
+ " WHERE blob.rid=event.objid"
2544
+ " AND mtime>=julianday(%Q,'1 day',%Q)%s)",
2545
+ zEnd, zTZMod, blob_sql_text(&cond))
2546
+ ){
2547
+ zNext = db_text(0,
2548
+ "SELECT strftime('%%Y%%m%%d-',%Q,'%d days')||"
2549
+ "strftime('%%Y%%m%%d%q',%Q,'%d day');",
2550
+ zStart, nDay, &"Z"[!bZulu], zEnd, nDay);
2551
+ zNewerButton = fossil_strdup(url_render(&url, "ymd", zNext, 0, 0));
2552
+ zNewerButtonLabel = mprintf("Following %d days", nDay);
2553
+ fossil_free(zNext);
2554
+ }
2555
+ if( nDay>1 && db_int(0,
2556
+ "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2557
+ " WHERE blob.rid=event.objid"
2558
+ " AND mtime<julianday(%Q,'-1 day',%Q)%s)",
2559
+ zStart, zTZMod, blob_sql_text(&cond))
2560
+ ){
2561
+ zNext = db_text(0,
2562
+ "SELECT strftime('%%Y%%m%%d-',%Q,'%d days')||"
2563
+ "strftime('%%Y%%m%%d%q',%Q,'%d day');",
2564
+ zStart, -nDay, &"Z"[!bZulu], zEnd, -nDay);
2565
+ zOlderButton = fossil_strdup(url_render(&url, "ymd", zNext, 0, 0));
2566
+ zOlderButtonLabel = mprintf("Previous %d days", nDay);
2567
+ fossil_free(zNext);
2568
+ }
2569
+ blob_append_sql(&cond,
2570
+ " AND event.mtime>=julianday(%Q,%Q)"
2571
+ " AND event.mtime<julianday(%Q,%Q,'+1 day')\n",
2572
+ zStart, zTZMod, zEnd, zTZMod);
2573
+ nEntry = -1;
2574
+
2575
+ if( fossil_ui_localtime() && bZulu ){
2576
+ zDay = mprintf("%d days between %zZ through %zZ", nDay, zStart, zEnd);
2577
+ }else{
2578
+ zDay = mprintf("%d days between %z through %z", nDay, zStart, zEnd);
2579
+ }
24792580
}
24802581
else if( zDay ){
24812582
char *zNext;
24822583
int bZulu = 0;
24832584
const char *zTZMod;
2585
+ single_ymd:
2586
+ bZulu = 0;
24842587
zDay = timeline_expand_datetime(zDay, &bZulu);
24852588
zDay = db_text(0, "SELECT date(%Q)", zDay);
24862589
if( zDay==0 || zDay[0]==0 ){
24872590
zDay = db_text(0, "SELECT date('now')");
24882591
}
24892592
--- src/timeline.c
+++ src/timeline.c
@@ -1345,10 +1345,45 @@
1345 zEDate[j] = 0;
1346
1347 /* It looks like this may be a date. Return it with punctuation added. */
1348 return zEDate;
1349 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1350
1351 /*
1352 ** Find the first check-in encountered with a particular tag
1353 ** when moving either forwards are backwards in time from a
1354 ** particular starting point (iFrom). Return the rid of that
@@ -1598,15 +1633,17 @@
1598 ** deltabg Background color red for delta manifests or green
1599 ** for baseline manifests
1600 ** namechng Show only check-ins that have filename changes
1601 ** forks Show only forks and their children
1602 ** cherrypicks Show all cherrypicks
1603 ** ym=YYYY-MM Show only events for the given year/month
1604 ** yw=YYYY-WW Show only events for the given week of the given year
1605 ** yw=YYYY-MM-DD Show events for the week that includes the given day
1606 ** ymd=YYYY-MM-DD Show only events on the given day. The use "ymd=now"
1607 ** to see all changes for the current week.
 
 
1608 ** year=YYYY Show only events on the given year. The use "year=0"
1609 ** to see all changes for the current year.
1610 ** days=N Show events over the previous N days
1611 ** datefmt=N Override the date format: 0=HH:MM, 1=HH:MM:SS,
1612 ** 2=YYYY-MM-DD HH:MM:SS, 3=YYMMDD HH:MM, and 4 means "off".
@@ -2474,15 +2511,81 @@
2474 zYearWeekStart, zTZMod, zYearWeekStart, zTZMod);
2475 nEntry = -1;
2476 if( fossil_ui_localtime() && bZulu ){
2477 zYearWeekStart = mprintf("%zZ", zYearWeekStart);
2478 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2479 }
2480 else if( zDay ){
2481 char *zNext;
2482 int bZulu = 0;
2483 const char *zTZMod;
 
 
2484 zDay = timeline_expand_datetime(zDay, &bZulu);
2485 zDay = db_text(0, "SELECT date(%Q)", zDay);
2486 if( zDay==0 || zDay[0]==0 ){
2487 zDay = db_text(0, "SELECT date('now')");
2488 }
2489
--- src/timeline.c
+++ src/timeline.c
@@ -1345,10 +1345,45 @@
1345 zEDate[j] = 0;
1346
1347 /* It looks like this may be a date. Return it with punctuation added. */
1348 return zEDate;
1349 }
1350
1351 /*
1352 ** Check to see if the argument is a date-span for the ymd= query
1353 ** parameter. A valid date-span is of the form:
1354 **
1355 ** 0123456789 123456 <-- index
1356 ** YYYYMMDD-YYYYMMDD
1357 **
1358 ** with an optional "Z" timeline modifier at the end. Return true if
1359 ** the input is a valid date space and false if not.
1360 */
1361 static int timeline_is_datespan(const char *zDay){
1362 size_t n = strlen(zDay);
1363 int i, d, m;
1364
1365 if( n<17 || n>18 ) return 0;
1366 if( n==18 ){
1367 if( zDay[17]!='Z' && zDay[17]!='z' ) return 0;
1368 n--;
1369 }
1370 if( zDay[8]!='-' ) return 0;
1371 for(i=0; i<17 && (fossil_isdigit(zDay[i]) || i==8); i++){}
1372 if( i!=17 ) return 0;
1373 i = atoi(zDay);
1374 d = i%100;
1375 if( d<1 || d>31 ) return 0;
1376 m = (i/100)%100;
1377 if( m<1 || m>12 ) return 0;
1378 i = atoi(zDay+9);
1379 d = i%100;
1380 if( d<1 || d>31 ) return 0;
1381 m = (i/100)%100;
1382 if( m<1 || m>12 ) return 0;
1383 return 1;
1384 }
1385
1386 /*
1387 ** Find the first check-in encountered with a particular tag
1388 ** when moving either forwards are backwards in time from a
1389 ** particular starting point (iFrom). Return the rid of that
@@ -1598,15 +1633,17 @@
1633 ** deltabg Background color red for delta manifests or green
1634 ** for baseline manifests
1635 ** namechng Show only check-ins that have filename changes
1636 ** forks Show only forks and their children
1637 ** cherrypicks Show all cherrypicks
1638 ** ym=YYYYMM Show only events for the given year/month
1639 ** yw=YYYYWW Show only events for the given week of the given year
1640 ** yw=YYYYMMDD Show events for the week that includes the given day
1641 ** ymd=YYYYMMDD Show only events on the given day. The use "ymd=now"
1642 ** to see all changes for the current week. Add "z" at end
1643 ** to divide days at UTC instead of localtime days.
1644 ** Use ymd=YYYYMMDD-YYYYMMDD (with optional "z") for a range.
1645 ** year=YYYY Show only events on the given year. The use "year=0"
1646 ** to see all changes for the current year.
1647 ** days=N Show events over the previous N days
1648 ** datefmt=N Override the date format: 0=HH:MM, 1=HH:MM:SS,
1649 ** 2=YYYY-MM-DD HH:MM:SS, 3=YYMMDD HH:MM, and 4 means "off".
@@ -2474,15 +2511,81 @@
2511 zYearWeekStart, zTZMod, zYearWeekStart, zTZMod);
2512 nEntry = -1;
2513 if( fossil_ui_localtime() && bZulu ){
2514 zYearWeekStart = mprintf("%zZ", zYearWeekStart);
2515 }
2516 }
2517 else if( zDay && timeline_is_datespan(zDay) ){
2518 char *zNext;
2519 char *zStart, *zEnd;
2520 int nDay;
2521 int bZulu = 0;
2522 const char *zTZMod;
2523 zEnd = db_text(0, "SELECT date(%Q)",
2524 timeline_expand_datetime(zDay+9, &bZulu));
2525 zStart = db_text(0, "SELECT date('%.4q-%.2q-%.2q')",
2526 zDay, zDay+4, zDay+6);
2527 nDay = db_int(0, "SELECT julianday(%Q)-julianday(%Q)", zEnd, zStart);
2528 if( nDay==0 ){
2529 zDay = &zDay[9];
2530 goto single_ymd;
2531 }
2532 if( nDay<0 ){
2533 char *zTemp = zEnd;
2534 zEnd = zStart;
2535 zStart = zTemp;
2536 nDay = 1 - nDay;
2537 }else{
2538 nDay += 1;
2539 }
2540 zTZMod = (bZulu==0 && fossil_ui_localtime()) ? "utc" : "+00:00";
2541 if( nDay>0 && db_int(0,
2542 "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2543 " WHERE blob.rid=event.objid"
2544 " AND mtime>=julianday(%Q,'1 day',%Q)%s)",
2545 zEnd, zTZMod, blob_sql_text(&cond))
2546 ){
2547 zNext = db_text(0,
2548 "SELECT strftime('%%Y%%m%%d-',%Q,'%d days')||"
2549 "strftime('%%Y%%m%%d%q',%Q,'%d day');",
2550 zStart, nDay, &"Z"[!bZulu], zEnd, nDay);
2551 zNewerButton = fossil_strdup(url_render(&url, "ymd", zNext, 0, 0));
2552 zNewerButtonLabel = mprintf("Following %d days", nDay);
2553 fossil_free(zNext);
2554 }
2555 if( nDay>1 && db_int(0,
2556 "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2557 " WHERE blob.rid=event.objid"
2558 " AND mtime<julianday(%Q,'-1 day',%Q)%s)",
2559 zStart, zTZMod, blob_sql_text(&cond))
2560 ){
2561 zNext = db_text(0,
2562 "SELECT strftime('%%Y%%m%%d-',%Q,'%d days')||"
2563 "strftime('%%Y%%m%%d%q',%Q,'%d day');",
2564 zStart, -nDay, &"Z"[!bZulu], zEnd, -nDay);
2565 zOlderButton = fossil_strdup(url_render(&url, "ymd", zNext, 0, 0));
2566 zOlderButtonLabel = mprintf("Previous %d days", nDay);
2567 fossil_free(zNext);
2568 }
2569 blob_append_sql(&cond,
2570 " AND event.mtime>=julianday(%Q,%Q)"
2571 " AND event.mtime<julianday(%Q,%Q,'+1 day')\n",
2572 zStart, zTZMod, zEnd, zTZMod);
2573 nEntry = -1;
2574
2575 if( fossil_ui_localtime() && bZulu ){
2576 zDay = mprintf("%d days between %zZ through %zZ", nDay, zStart, zEnd);
2577 }else{
2578 zDay = mprintf("%d days between %z through %z", nDay, zStart, zEnd);
2579 }
2580 }
2581 else if( zDay ){
2582 char *zNext;
2583 int bZulu = 0;
2584 const char *zTZMod;
2585 single_ymd:
2586 bZulu = 0;
2587 zDay = timeline_expand_datetime(zDay, &bZulu);
2588 zDay = db_text(0, "SELECT date(%Q)", zDay);
2589 if( zDay==0 || zDay[0]==0 ){
2590 zDay = db_text(0, "SELECT date('now')");
2591 }
2592

Keyboard Shortcuts

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