| | @@ -1312,39 +1312,78 @@ |
| 1312 | 1312 | ** Add missing "-" characters into a date/time. Examples: |
| 1313 | 1313 | ** |
| 1314 | 1314 | ** 20190419 => 2019-04-19 |
| 1315 | 1315 | ** 201904 => 2019-04 |
| 1316 | 1316 | */ |
| 1317 | | -const char *timeline_expand_datetime(const char *zIn){ |
| 1318 | | - static char zEDate[20]; |
| 1319 | | - static const char aPunct[] = { 0, 0, '-', '-', ' ', ':', ':' }; |
| 1317 | +const char *timeline_expand_datetime(const char *zIn, int *pbZulu){ |
| 1318 | + static char zEDate[16]; |
| 1320 | 1319 | int n = (int)strlen(zIn); |
| 1321 | 1320 | int i, j; |
| 1322 | 1321 | |
| 1323 | | - /* Only three forms allowed: |
| 1322 | + /* These forms are recognized: |
| 1323 | + ** |
| 1324 | 1324 | ** (1) YYYYMMDD |
| 1325 | 1325 | ** (2) YYYYMM |
| 1326 | 1326 | ** (3) YYYYWW |
| 1327 | 1327 | */ |
| 1328 | + if( n && (zIn[n-1]=='Z' || zIn[n-1]=='z') ){ |
| 1329 | + n--; |
| 1330 | + if( pbZulu ) *pbZulu = 1; |
| 1331 | + }else{ |
| 1332 | + if( pbZulu ) *pbZulu = 0; |
| 1333 | + } |
| 1328 | 1334 | if( n!=8 && n!=6 ) return zIn; |
| 1329 | 1335 | |
| 1330 | 1336 | /* Every character must be a digit */ |
| 1331 | | - for(i=0; fossil_isdigit(zIn[i]); i++){} |
| 1337 | + for(i=0; i<n && fossil_isdigit(zIn[i]); i++){} |
| 1332 | 1338 | if( i!=n ) return zIn; |
| 1333 | 1339 | |
| 1334 | 1340 | /* Expand the date */ |
| 1335 | | - for(i=j=0; zIn[i]; i++){ |
| 1336 | | - if( i>=4 && (i%2)==0 ){ |
| 1337 | | - zEDate[j++] = aPunct[i/2]; |
| 1338 | | - } |
| 1341 | + for(i=j=0; i<n; i++){ |
| 1342 | + if( j==4 || j==7 ) zEDate[j++] = '-'; |
| 1339 | 1343 | zEDate[j++] = zIn[i]; |
| 1340 | 1344 | } |
| 1341 | 1345 | zEDate[j] = 0; |
| 1342 | 1346 | |
| 1343 | 1347 | /* It looks like this may be a date. Return it with punctuation added. */ |
| 1344 | 1348 | return zEDate; |
| 1345 | 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 | +} |
| 1346 | 1385 | |
| 1347 | 1386 | /* |
| 1348 | 1387 | ** Find the first check-in encountered with a particular tag |
| 1349 | 1388 | ** when moving either forwards are backwards in time from a |
| 1350 | 1389 | ** particular starting point (iFrom). Return the rid of that |
| | @@ -1594,15 +1633,17 @@ |
| 1594 | 1633 | ** deltabg Background color red for delta manifests or green |
| 1595 | 1634 | ** for baseline manifests |
| 1596 | 1635 | ** namechng Show only check-ins that have filename changes |
| 1597 | 1636 | ** forks Show only forks and their children |
| 1598 | 1637 | ** cherrypicks Show all cherrypicks |
| 1599 | | -** ym=YYYY-MM Show only events for the given year/month |
| 1600 | | -** yw=YYYY-WW Show only events for the given week of the given year |
| 1601 | | -** yw=YYYY-MM-DD Show events for the week that includes the given day |
| 1602 | | -** ymd=YYYY-MM-DD Show only events on the given day. The use "ymd=now" |
| 1603 | | -** 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. |
| 1604 | 1645 | ** year=YYYY Show only events on the given year. The use "year=0" |
| 1605 | 1646 | ** to see all changes for the current year. |
| 1606 | 1647 | ** days=N Show events over the previous N days |
| 1607 | 1648 | ** datefmt=N Override the date format: 0=HH:MM, 1=HH:MM:SS, |
| 1608 | 1649 | ** 2=YYYY-MM-DD HH:MM:SS, 3=YYMMDD HH:MM, and 4 means "off". |
| | @@ -2372,46 +2413,55 @@ |
| 2372 | 2413 | if( bisectLocal || zBisect!=0 ){ |
| 2373 | 2414 | blob_append_sql(&cond, " AND event.objid IN (SELECT rid FROM bilog)\n"); |
| 2374 | 2415 | } |
| 2375 | 2416 | if( zYearMonth ){ |
| 2376 | 2417 | char *zNext; |
| 2377 | | - zYearMonth = timeline_expand_datetime(zYearMonth); |
| 2378 | | - if( strlen(zYearMonth)>7 ){ |
| 2379 | | - zYearMonth = mprintf("%.7s", zYearMonth); |
| 2380 | | - } |
| 2418 | + int bZulu = 0; |
| 2419 | + const char *zTZMod; |
| 2420 | + zYearMonth = timeline_expand_datetime(zYearMonth, &bZulu); |
| 2421 | + zYearMonth = mprintf("%.7s", zYearMonth); |
| 2381 | 2422 | if( db_int(0,"SELECT julianday('%q-01') IS NULL", zYearMonth) ){ |
| 2382 | 2423 | zYearMonth = db_text(0, "SELECT strftime('%%Y-%%m','now');"); |
| 2383 | 2424 | } |
| 2384 | | - zNext = db_text(0, "SELECT strftime('%%Y-%%m','%q-01','+1 month');", |
| 2385 | | - zYearMonth); |
| 2386 | | - if( db_int(0, |
| 2387 | | - "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" |
| 2388 | | - " WHERE blob.rid=event.objid AND mtime>=julianday('%q-01')%s)", |
| 2389 | | - zNext, blob_sql_text(&cond)) |
| 2390 | | - ){ |
| 2391 | | - zNewerButton = fossil_strdup(url_render(&url, "ym", zNext, 0, 0)); |
| 2392 | | - zNewerButtonLabel = "Following month"; |
| 2393 | | - } |
| 2394 | | - fossil_free(zNext); |
| 2395 | | - zNext = db_text(0, "SELECT strftime('%%Y-%%m','%q-01','-1 month');", |
| 2396 | | - zYearMonth); |
| 2397 | | - if( db_int(0, |
| 2398 | | - "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" |
| 2399 | | - " WHERE blob.rid=event.objid AND mtime<julianday('%q-01')%s)", |
| 2400 | | - zYearMonth, blob_sql_text(&cond)) |
| 2401 | | - ){ |
| 2402 | | - zOlderButton = fossil_strdup(url_render(&url, "ym", zNext, 0, 0)); |
| 2403 | | - zOlderButtonLabel = "Previous month"; |
| 2404 | | - } |
| 2405 | | - fossil_free(zNext); |
| 2406 | | - blob_append_sql(&cond, " AND %Q=strftime('%%Y-%%m',event.mtime) ", |
| 2407 | | - zYearMonth); |
| 2408 | | - nEntry = -1; |
| 2425 | + zTZMod = (bZulu==0 && fossil_ui_localtime()) ? "utc" : "+00:00"; |
| 2426 | + if( db_int(0, |
| 2427 | + "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" |
| 2428 | + " WHERE blob.rid=event.objid" |
| 2429 | + " AND mtime>=julianday('%q-01',%Q)%s)", |
| 2430 | + zYearMonth, zTZMod, blob_sql_text(&cond)) |
| 2431 | + ){ |
| 2432 | + zNext = db_text(0, "SELECT strftime('%%Y%%m%q','%q-01','+1 month');", |
| 2433 | + &"Z"[!bZulu], zYearMonth); |
| 2434 | + zNewerButton = fossil_strdup(url_render(&url, "ym", zNext, 0, 0)); |
| 2435 | + zNewerButtonLabel = "Following month"; |
| 2436 | + fossil_free(zNext); |
| 2437 | + } |
| 2438 | + if( db_int(0, |
| 2439 | + "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" |
| 2440 | + " WHERE blob.rid=event.objid" |
| 2441 | + " AND mtime<julianday('%q-01',%Q)%s)", |
| 2442 | + zYearMonth, zTZMod, blob_sql_text(&cond)) |
| 2443 | + ){ |
| 2444 | + zNext = db_text(0, "SELECT strftime('%%Y%%m%q','%q-01','-1 month');", |
| 2445 | + &"Z"[!bZulu], zYearMonth); |
| 2446 | + zOlderButton = fossil_strdup(url_render(&url, "ym", zNext, 0, 0)); |
| 2447 | + zOlderButtonLabel = "Previous month"; |
| 2448 | + fossil_free(zNext); |
| 2449 | + } |
| 2450 | + blob_append_sql(&cond, |
| 2451 | + " AND event.mtime>=julianday('%q-01',%Q)" |
| 2452 | + " AND event.mtime<julianday('%q-01',%Q,'+1 month')\n", |
| 2453 | + zYearMonth, zTZMod, zYearMonth, zTZMod); |
| 2454 | + nEntry = -1; |
| 2455 | + /* Adjust the zYearMonth for the title */ |
| 2456 | + zYearMonth = mprintf("%z-01%s", zYearMonth, &"Z"[!bZulu]); |
| 2409 | 2457 | } |
| 2410 | 2458 | else if( zYearWeek ){ |
| 2411 | 2459 | char *z, *zNext; |
| 2412 | | - zYearWeek = timeline_expand_datetime(zYearWeek); |
| 2460 | + int bZulu = 0; |
| 2461 | + const char *zTZMod; |
| 2462 | + zYearWeek = timeline_expand_datetime(zYearWeek, &bZulu); |
| 2413 | 2463 | z = db_text(0, "SELECT strftime('%%Y-%%W',%Q)", zYearWeek); |
| 2414 | 2464 | if( z && z[0] ){ |
| 2415 | 2465 | zYearWeekStart = db_text(0, "SELECT date(%Q,'-6 days','weekday 1')", |
| 2416 | 2466 | zYearWeek); |
| 2417 | 2467 | zYearWeek = z; |
| | @@ -2428,64 +2478,152 @@ |
| 2428 | 2478 | "SELECT date('now','-6 days','weekday 1');"); |
| 2429 | 2479 | zYearWeek = db_text(0, |
| 2430 | 2480 | "SELECT strftime('%%Y-%%W','now','-6 days','weekday 1')"); |
| 2431 | 2481 | } |
| 2432 | 2482 | } |
| 2433 | | - zNext = db_text(0, "SELECT date(%Q,'+7 day');", zYearWeekStart); |
| 2434 | | - if( db_int(0, |
| 2435 | | - "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" |
| 2436 | | - " WHERE blob.rid=event.objid AND mtime>=julianday(%Q)%s)", |
| 2437 | | - zNext, blob_sql_text(&cond)) |
| 2438 | | - ){ |
| 2439 | | - zNewerButton = fossil_strdup(url_render(&url, "yw", zNext, 0, 0)); |
| 2440 | | - zNewerButtonLabel = "Following week"; |
| 2441 | | - } |
| 2442 | | - fossil_free(zNext); |
| 2443 | | - zNext = db_text(0, "SELECT date(%Q,'-7 days');", zYearWeekStart); |
| 2444 | | - if( db_int(0, |
| 2445 | | - "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" |
| 2446 | | - " WHERE blob.rid=event.objid AND mtime<julianday(%Q)%s)", |
| 2447 | | - zYearWeekStart, blob_sql_text(&cond)) |
| 2448 | | - ){ |
| 2449 | | - zOlderButton = fossil_strdup(url_render(&url, "yw", zNext, 0, 0)); |
| 2450 | | - zOlderButtonLabel = "Previous week"; |
| 2451 | | - } |
| 2452 | | - fossil_free(zNext); |
| 2453 | | - blob_append_sql(&cond, " AND %Q=strftime('%%Y-%%W',event.mtime) ", |
| 2454 | | - zYearWeek); |
| 2455 | | - nEntry = -1; |
| 2483 | + zTZMod = (bZulu==0 && fossil_ui_localtime()) ? "utc" : "+00:00"; |
| 2484 | + if( db_int(0, |
| 2485 | + "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" |
| 2486 | + " WHERE blob.rid=event.objid" |
| 2487 | + " AND mtime>=julianday(%Q,%Q)%s)", |
| 2488 | + zYearWeekStart, zTZMod, blob_sql_text(&cond)) |
| 2489 | + ){ |
| 2490 | + zNext = db_text(0, "SELECT strftime('%%Y%%W%q',%Q,'+7 day');", |
| 2491 | + &"Z"[!bZulu], zYearWeekStart); |
| 2492 | + zNewerButton = fossil_strdup(url_render(&url, "yw", zNext, 0, 0)); |
| 2493 | + zNewerButtonLabel = "Following week"; |
| 2494 | + fossil_free(zNext); |
| 2495 | + } |
| 2496 | + if( db_int(0, |
| 2497 | + "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" |
| 2498 | + " WHERE blob.rid=event.objid" |
| 2499 | + " AND mtime<julianday(%Q,%Q)%s)", |
| 2500 | + zYearWeekStart, zTZMod, blob_sql_text(&cond)) |
| 2501 | + ){ |
| 2502 | + zNext = db_text(0, "SELECT strftime('%%Y%%W%q',%Q,'-7 days');", |
| 2503 | + &"Z"[!bZulu], zYearWeekStart); |
| 2504 | + zOlderButton = fossil_strdup(url_render(&url, "yw", zNext, 0, 0)); |
| 2505 | + zOlderButtonLabel = "Previous week"; |
| 2506 | + fossil_free(zNext); |
| 2507 | + } |
| 2508 | + blob_append_sql(&cond, |
| 2509 | + " AND event.mtime>=julianday(%Q,%Q)" |
| 2510 | + " AND event.mtime<julianday(%Q,%Q,'+7 days')\n", |
| 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 and %zZ", nDay, zStart, zEnd); |
| 2577 | + }else{ |
| 2578 | + zDay = mprintf("%d days between %z and %z", nDay, zStart, zEnd); |
| 2579 | + } |
| 2456 | 2580 | } |
| 2457 | 2581 | else if( zDay ){ |
| 2458 | 2582 | char *zNext; |
| 2459 | | - zDay = timeline_expand_datetime(zDay); |
| 2583 | + int bZulu = 0; |
| 2584 | + const char *zTZMod; |
| 2585 | + single_ymd: |
| 2586 | + bZulu = 0; |
| 2587 | + zDay = timeline_expand_datetime(zDay, &bZulu); |
| 2460 | 2588 | zDay = db_text(0, "SELECT date(%Q)", zDay); |
| 2461 | 2589 | if( zDay==0 || zDay[0]==0 ){ |
| 2462 | 2590 | zDay = db_text(0, "SELECT date('now')"); |
| 2463 | 2591 | } |
| 2464 | | - zNext = db_text(0, "SELECT date(%Q,'+1 day');", zDay); |
| 2465 | | - if( db_int(0, |
| 2466 | | - "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" |
| 2467 | | - " WHERE blob.rid=event.objid AND mtime>=julianday(%Q)%s)", |
| 2468 | | - zNext, blob_sql_text(&cond)) |
| 2469 | | - ){ |
| 2470 | | - zNewerButton = fossil_strdup(url_render(&url, "ymd", zNext, 0, 0)); |
| 2471 | | - zNewerButtonLabel = "Following day"; |
| 2472 | | - } |
| 2473 | | - fossil_free(zNext); |
| 2474 | | - zNext = db_text(0, "SELECT date(%Q,'-1 day');", zDay); |
| 2475 | | - if( db_int(0, |
| 2476 | | - "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" |
| 2477 | | - " WHERE blob.rid=event.objid AND mtime<julianday(%Q)%s)", |
| 2478 | | - zDay, blob_sql_text(&cond)) |
| 2479 | | - ){ |
| 2480 | | - zOlderButton = fossil_strdup(url_render(&url, "ymd", zNext, 0, 0)); |
| 2481 | | - zOlderButtonLabel = "Previous day"; |
| 2482 | | - } |
| 2483 | | - fossil_free(zNext); |
| 2484 | | - blob_append_sql(&cond, " AND %Q=date(event.mtime) ", |
| 2485 | | - zDay); |
| 2486 | | - nEntry = -1; |
| 2592 | + zTZMod = (bZulu==0 && fossil_ui_localtime()) ? "utc" : "+00:00"; |
| 2593 | + if( db_int(0, |
| 2594 | + "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" |
| 2595 | + " WHERE blob.rid=event.objid" |
| 2596 | + " AND mtime>=julianday(%Q,'+1 day',%Q)%s)", |
| 2597 | + zDay, zTZMod, blob_sql_text(&cond)) |
| 2598 | + ){ |
| 2599 | + zNext = db_text(0,"SELECT strftime('%%Y%%m%%d%q',%Q,'+1 day');", |
| 2600 | + &"Z"[!bZulu], zDay); |
| 2601 | + zNewerButton = fossil_strdup(url_render(&url, "ymd", zNext, 0, 0)); |
| 2602 | + zNewerButtonLabel = "Following day"; |
| 2603 | + fossil_free(zNext); |
| 2604 | + } |
| 2605 | + if( db_int(0, |
| 2606 | + "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" |
| 2607 | + " WHERE blob.rid=event.objid" |
| 2608 | + " AND mtime<julianday(%Q,'-1 day',%Q)%s)", |
| 2609 | + zDay, zTZMod, blob_sql_text(&cond)) |
| 2610 | + ){ |
| 2611 | + zNext = db_text(0,"SELECT strftime('%%Y%%m%%d%q',%Q,'-1 day');", |
| 2612 | + &"Z"[!bZulu], zDay); |
| 2613 | + zOlderButton = fossil_strdup(url_render(&url, "ymd", zNext, 0, 0)); |
| 2614 | + zOlderButtonLabel = "Previous day"; |
| 2615 | + fossil_free(zNext); |
| 2616 | + } |
| 2617 | + blob_append_sql(&cond, |
| 2618 | + " AND event.mtime>=julianday(%Q,%Q)" |
| 2619 | + " AND event.mtime<julianday(%Q,%Q,'+1 day')\n", |
| 2620 | + zDay, zTZMod, zDay, zTZMod); |
| 2621 | + nEntry = -1; |
| 2622 | + if( fossil_ui_localtime() && bZulu ){ |
| 2623 | + zDay = mprintf("%zZ", zDay); /* Add Z suffix to day for the title */ |
| 2624 | + } |
| 2487 | 2625 | } |
| 2488 | 2626 | else if( zNDays ){ |
| 2489 | 2627 | nDays = atoi(zNDays); |
| 2490 | 2628 | if( nDays<1 ) nDays = 1; |
| 2491 | 2629 | blob_append_sql(&cond, " AND event.mtime>=julianday('now','-%d days') ", |
| | @@ -2728,11 +2866,11 @@ |
| 2728 | 2866 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 2729 | 2867 | |
| 2730 | 2868 | n = db_int(0, "SELECT count(*) FROM timeline WHERE etype!='div' /*scan*/"); |
| 2731 | 2869 | zPlural = n==1 ? "" : "s"; |
| 2732 | 2870 | if( zYearMonth ){ |
| 2733 | | - blob_appendf(&desc, "%d %s%s for the month beginning %h-01", |
| 2871 | + blob_appendf(&desc, "%d %s%s for the month beginning %h", |
| 2734 | 2872 | n, zEType, zPlural, zYearMonth); |
| 2735 | 2873 | }else if( zYearWeek ){ |
| 2736 | 2874 | blob_appendf(&desc, "%d %s%s for week %h beginning on %h", |
| 2737 | 2875 | n, zEType, zPlural, zYearWeek, zYearWeekStart); |
| 2738 | 2876 | }else if( zDay ){ |
| | @@ -3617,10 +3755,11 @@ |
| 3617 | 3755 | const char *zToday; |
| 3618 | 3756 | char *zStartOfProject; |
| 3619 | 3757 | int i; |
| 3620 | 3758 | Stmt q; |
| 3621 | 3759 | char *z; |
| 3760 | + int bZulu = 0; |
| 3622 | 3761 | |
| 3623 | 3762 | login_check_credentials(); |
| 3624 | 3763 | if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum) ){ |
| 3625 | 3764 | login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki); |
| 3626 | 3765 | return; |
| | @@ -3627,11 +3766,11 @@ |
| 3627 | 3766 | } |
| 3628 | 3767 | style_set_current_feature("timeline"); |
| 3629 | 3768 | style_header("Today In History"); |
| 3630 | 3769 | zToday = (char*)P("today"); |
| 3631 | 3770 | if( zToday ){ |
| 3632 | | - zToday = timeline_expand_datetime(zToday); |
| 3771 | + zToday = timeline_expand_datetime(zToday, &bZulu); |
| 3633 | 3772 | if( !fossil_isdate(zToday) ) zToday = 0; |
| 3634 | 3773 | } |
| 3635 | 3774 | if( zToday==0 ){ |
| 3636 | 3775 | zToday = db_text(0, "SELECT date('now',toLocal())"); |
| 3637 | 3776 | } |
| 3638 | 3777 | |