mirror of
https://github.com/qdrant/qdrant.git
synced 2026-07-23 11:11:00 -05:00
Fix datetime parsing for YYYY-MM-DDTHH:MM format (T separator, no seconds) (#8719)
The documented format `2023-02-08T10:49` was not accepted because the parser only had `%Y-%m-%d %H:%M` (space separator) but was missing `%Y-%m-%dT%H:%M` (T separator). Add the missing format variant and tests. Closes #8718 Made-with: Cursor Co-authored-by: Cursor Agent <agent@cursor.com>
This commit is contained in:
committed by
timvisee
parent
45377af629
commit
eff3c50db3
@@ -126,11 +126,14 @@ impl FromStr for DateTimePayloadType {
|
||||
// Attempt to parse the input string in the specified formats:
|
||||
// - YYYY-MM-DD'T'HH:MM:SS (without timezone or Z)
|
||||
// - YYYY-MM-DD HH:MM:SS (without timezone or Z)
|
||||
// - YYYY-MM-DD HH:MM
|
||||
// - YYYY-MM-DD'T'HH:MM (without timezone and seconds)
|
||||
// - YYYY-MM-DD HH:MM (without timezone and seconds)
|
||||
// - YYYY-MM-DD
|
||||
// See: <https://github.com/qdrant/qdrant/issues/3529>
|
||||
// See: <https://github.com/qdrant/qdrant/issues/8718>
|
||||
let datetime = chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S%.f")
|
||||
.or_else(|_| chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S%.f"))
|
||||
.or_else(|_| chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M"))
|
||||
.or_else(|_| chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M"))
|
||||
.or_else(|_| chrono::NaiveDate::parse_from_str(s, "%Y-%m-%d").map(Into::into))?;
|
||||
|
||||
@@ -4173,6 +4176,9 @@ mod tests {
|
||||
#[case::without_z_and_decimals("2020-03-01T00:00:00.12")]
|
||||
#[case::space_sep_without_z("2020-03-01 00:00:00")]
|
||||
#[case::space_sep_without_z_and_decimals("2020-03-01 00:00:00.123456")]
|
||||
#[case::t_sep_without_seconds("2020-03-01T00:00")]
|
||||
#[case::space_sep_without_seconds("2020-03-01 00:00")]
|
||||
#[case::date_only("2020-03-01")]
|
||||
fn test_datetime_deserialization(#[case] datetime: &str) {
|
||||
let datetime = DateTimePayloadType::from_str(datetime).unwrap();
|
||||
let serialized = serde_json::to_string(&datetime).unwrap();
|
||||
|
||||
@@ -171,6 +171,8 @@ def test_datetime_indexing(collection_name):
|
||||
# create payload
|
||||
set_payload(collection_name, {datetime_key: "2015-01-01T00:00:00Z"}, [1])
|
||||
set_payload(collection_name, {datetime_key: "2015-02-01T08:00:00+02:00"}, [2])
|
||||
# Use YYYY-MM-DDTHH:MM format (T separator, without seconds) — https://github.com/qdrant/qdrant/issues/8718
|
||||
set_payload(collection_name, {datetime_key: "2015-03-01T12:30"}, [3])
|
||||
|
||||
# Create index
|
||||
response = request_with_validation(
|
||||
@@ -185,6 +187,20 @@ def test_datetime_indexing(collection_name):
|
||||
)
|
||||
assert response.ok
|
||||
|
||||
# Verify point with YYYY-MM-DDTHH:MM format was indexed (issue #8718)
|
||||
response = request_with_validation(
|
||||
api="/collections/{collection_name}/points/scroll",
|
||||
method="POST",
|
||||
path_params={"collection_name": collection_name},
|
||||
body={
|
||||
"with_vector": False,
|
||||
"filter": {"must": [{"key": datetime_key, "range": {"gte": "2015-03-01T12:30", "lte": "2015-03-01T12:30"}}]},
|
||||
},
|
||||
)
|
||||
assert response.ok, response.json()
|
||||
point_ids = [p["id"] for p in response.json()["result"]["points"]]
|
||||
assert 3 in point_ids, f"Point 3 with YYYY-MM-DDTHH:MM format not found in index results: {point_ids}"
|
||||
|
||||
# test with mixed datetime format
|
||||
data = [
|
||||
({"gte": "2015-01-01", "lte": "2015-01-01 00:00"}, [1]),
|
||||
@@ -192,6 +208,9 @@ def test_datetime_indexing(collection_name):
|
||||
({"gte": "2015-02-01T06:00:00", "lte": "2015-02-01T06:00:00Z"}, [2]),
|
||||
# date_optional_time
|
||||
({"gte": "2015-02-01T06:00:00.000000000", "lte": "2015-02-01T06:00:00.000000000"}, [2]),
|
||||
# YYYY-MM-DDTHH:MM (T separator, without seconds) — https://github.com/qdrant/qdrant/issues/8718
|
||||
({"gte": "2015-01-01T00:00", "lte": "2015-01-01T00:00"}, [1]),
|
||||
({"gte": "2015-02-01T06:00", "lte": "2015-02-01T06:00"}, [2]),
|
||||
]
|
||||
for range_, expected_ids in data:
|
||||
response = request_with_validation(
|
||||
|
||||
Reference in New Issue
Block a user