| | @@ -59,34 +59,41 @@ |
| 59 | 59 | ** the punctuation. Example: "20190327084549" instead of |
| 60 | 60 | ** "2019-03-27 08:45:49". If the string is of the appropriate form, |
| 61 | 61 | ** then return an alternative string (in static space) that is the same |
| 62 | 62 | ** string with punctuation inserted. |
| 63 | 63 | ** |
| 64 | | -** Assume the maximum allowed value for unspecified digits. In other |
| 65 | | -** words: 202503171234 -> 2025-03-17 12:34:59 |
| 66 | | -** ^^--- Added seconds. |
| 67 | | -** and: 20250317 -> 2025-03-17 23:59:59 |
| 68 | | -** ^^^^^^^^--- Added time. |
| 64 | +** If the bRoundUp parameter is true, then round the resulting date-time |
| 65 | +** up to the largest date/time that is consistent with the input value. |
| 66 | +** This is because the result will be used for an mtime<=julianday($DATE) |
| 67 | +** comparison. In other words: |
| 68 | +** |
| 69 | +** 20250317123421 -> 2025-03-17 12:34:21.999 |
| 70 | +** ^^^^--- Added |
| 71 | +** |
| 72 | +** 202503171234 -> 2025-03-17 12:34:59.999 |
| 73 | +** ^^^^^^^--- Added |
| 74 | +** 20250317 -> 2025-03-17 23:59:59.999 |
| 75 | +** ^^^^^^^^^^^^--- Added |
| 69 | 76 | ** |
| 70 | 77 | ** If the bVerifyNotAHash flag is true, then a check is made to see if |
| 71 | 78 | ** the input string is a hash prefix and NULL is returned if it is. If the |
| 72 | 79 | ** bVerifyNotAHash flag is false, then the result is determined by syntax |
| 73 | 80 | ** of the input string only, without reference to the artifact table. |
| 74 | 81 | */ |
| 75 | | -char *fossil_expand_datetime(const char *zIn, int bVerifyNotAHash){ |
| 82 | +char *fossil_expand_datetime(const char *zIn,int bVerifyNotAHash,int bRoundUp){ |
| 76 | 83 | static char zEDate[24]; |
| 77 | 84 | static const char aPunct[] = { 0, 0, '-', '-', ' ', ':', ':' }; |
| 78 | 85 | int n = (int)strlen(zIn); |
| 79 | 86 | int i, j; |
| 80 | 87 | int addZulu = 0; |
| 81 | 88 | |
| 82 | 89 | /* These forms are allowed: |
| 83 | 90 | ** |
| 84 | | - ** 123456789 1234 123456789 123456789 |
| 85 | | - ** (1) YYYYMMDD => YYYY-MM-DD 23:59:59 |
| 86 | | - ** (2) YYYYMMDDHHMM => YYYY-MM-DD HH:MM:59 |
| 87 | | - ** (3) YYYYMMDDHHMMSS => YYYY-MM-DD HH:MM:SS |
| 91 | + ** 123456789 1234 123456789 123456789 1234 |
| 92 | + ** (1) YYYYMMDD => YYYY-MM-DD 23:59:59.999 |
| 93 | + ** (2) YYYYMMDDHHMM => YYYY-MM-DD HH:MM:59.999 |
| 94 | + ** (3) YYYYMMDDHHMMSS => YYYY-MM-DD HH:MM:SS.999 |
| 88 | 95 | ** |
| 89 | 96 | ** An optional "Z" zulu timezone designator is allowed at the end. |
| 90 | 97 | */ |
| 91 | 98 | if( n>0 && (zIn[n-1]=='Z' || zIn[n-1]=='z') ){ |
| 92 | 99 | n--; |
| | @@ -105,16 +112,21 @@ |
| 105 | 112 | if( i>=4 && (i%2)==0 ){ |
| 106 | 113 | zEDate[j++] = aPunct[i/2]; |
| 107 | 114 | } |
| 108 | 115 | zEDate[j++] = zIn[i]; |
| 109 | 116 | } |
| 110 | | - if( j==10 ){ |
| 111 | | - memcpy(&zEDate[10], " 23:59:59", 9); |
| 112 | | - j += 9; |
| 113 | | - }else if( j==16 ){ |
| 114 | | - memcpy(&zEDate[16], ":59",3); |
| 115 | | - j += 3; |
| 117 | + if( bRoundUp ){ |
| 118 | + if( j==10 ){ |
| 119 | + memcpy(&zEDate[10], " 23:59:59.999", 13); |
| 120 | + j += 13; |
| 121 | + }else if( j==16 ){ |
| 122 | + memcpy(&zEDate[16], ":59.999",7); |
| 123 | + j += 7; |
| 124 | + }else if( j==19 ){ |
| 125 | + memcpy(&zEDate[19], ".999", 4); |
| 126 | + j += 4; |
| 127 | + } |
| 116 | 128 | } |
| 117 | 129 | if( addZulu ){ |
| 118 | 130 | zEDate[j++] = 'Z'; |
| 119 | 131 | } |
| 120 | 132 | zEDate[j] = 0; |
| | @@ -488,11 +500,11 @@ |
| 488 | 500 | if( rid ) return rid; |
| 489 | 501 | } |
| 490 | 502 | |
| 491 | 503 | /* Date and times */ |
| 492 | 504 | if( memcmp(zTag, "date:", 5)==0 ){ |
| 493 | | - zDate = fossil_expand_datetime(&zTag[5],0); |
| 505 | + zDate = fossil_expand_datetime(&zTag[5],0,1); |
| 494 | 506 | if( zDate==0 ) zDate = &zTag[5]; |
| 495 | 507 | rid = db_int(0, |
| 496 | 508 | "SELECT objid FROM event" |
| 497 | 509 | " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'" |
| 498 | 510 | " ORDER BY mtime DESC LIMIT 1", |
| | @@ -554,21 +566,21 @@ |
| 554 | 566 | |
| 555 | 567 | /* symbolic-name ":" date-time */ |
| 556 | 568 | nTag = strlen(zTag); |
| 557 | 569 | for(i=0; i<nTag-8 && zTag[i]!=':'; i++){} |
| 558 | 570 | if( zTag[i]==':' |
| 559 | | - && (fossil_isdate(&zTag[i+1]) || fossil_expand_datetime(&zTag[i+1],0)!=0) |
| 571 | + && (fossil_isdate(&zTag[i+1]) || fossil_expand_datetime(&zTag[i+1],0,0)!=0) |
| 560 | 572 | ){ |
| 561 | 573 | char *zDate = mprintf("%s", &zTag[i+1]); |
| 562 | 574 | char *zTagBase = mprintf("%.*s", i, zTag); |
| 563 | 575 | char *zXDate; |
| 564 | 576 | int nDate = strlen(zDate); |
| 565 | 577 | if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){ |
| 566 | 578 | zDate[nDate-3] = 'z'; |
| 567 | 579 | zDate[nDate-2] = 0; |
| 568 | 580 | } |
| 569 | | - zXDate = fossil_expand_datetime(zDate,0); |
| 581 | + zXDate = fossil_expand_datetime(zDate,0,1); |
| 570 | 582 | if( zXDate==0 ) zXDate = zDate; |
| 571 | 583 | rid = db_int(0, |
| 572 | 584 | "SELECT event.objid, max(event.mtime)" |
| 573 | 585 | " FROM tag, tagxref, event" |
| 574 | 586 | " WHERE tag.tagname='sym-%q' " |
| | @@ -640,11 +652,11 @@ |
| 640 | 652 | if( startOfBranch ) rid = start_of_branch(rid,1); |
| 641 | 653 | return rid; |
| 642 | 654 | } |
| 643 | 655 | |
| 644 | 656 | /* Pure numeric date/time */ |
| 645 | | - zDate = fossil_expand_datetime(zTag, 0); |
| 657 | + zDate = fossil_expand_datetime(zTag, 0,1); |
| 646 | 658 | if( zDate ){ |
| 647 | 659 | rid = db_int(0, |
| 648 | 660 | "SELECT objid FROM event" |
| 649 | 661 | " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'" |
| 650 | 662 | " ORDER BY mtime DESC LIMIT 1", |
| 651 | 663 | |