fabro(01KKV8D20YYW55B3YSPE6Y11KF): solve (success)

Fabro-Run: 01KKV8D20YYW55B3YSPE6Y11KF
Fabro-Completed: 3
Fabro-Checkpoint: 3ba0d6b939

⚒️ Generated with [Fabro](https://fabro.sh)
This commit is contained in:
Fabro 2026-03-16 12:07:26 +00:00
parent 6ec39d8351
commit 64130715a7
2 changed files with 139 additions and 0 deletions

113
SOLUTION.md Normal file
View file

@ -0,0 +1,113 @@
# Django DurationField Error Message Format Correction
## Issue
The `DurationField` error message in Django incorrectly displayed the duration format. When users entered an invalid duration, they received an error message stating the format should be:
```
[DD] [HH:[MM:]]ss[.uuuuuu]
```
However, this format specification is **incorrect**. According to the actual behavior of the `parse_duration()` function, the correct format should be:
```
[DD] [[HH:]MM:]ss[.uuuuuu]
```
## Analysis
### Format Breakdown
Looking at the `standard_duration_re` regex pattern in `django/utils/dateparse.py`:
```python
standard_duration_re = re.compile(
r'^'
r'(?:(?P<days>-?\d+) (days?, )?)?' # Optional: days
r'(?P<sign>-?)' # Optional: sign
r'((?:(?P<hours>\d+):)(?=\d+:\d+))?' # Optional: hours (only if MM:ss follows)
r'(?:(?P<minutes>\d+):)?' # Optional: minutes
r'(?P<seconds>\d+)' # REQUIRED: seconds
r'(?:\.(?P<microseconds>\d{1,6})\d{0,6})?' # Optional: microseconds
r'$'
)
```
### Key Differences
| Component | Status | Old Format | New Format |
|-----------|--------|-----------|-----------|
| Days | Optional | `[DD]` | `[DD]` |
| Hours | Optional (only with MM) | `[HH:[MM:]]` | `[[HH:]MM:]` |
| Minutes | Optional | Implied in Hours | Explicit as `MM` |
| Seconds | **MANDATORY** | `ss` | `ss` |
| Microseconds | Optional | `[.uuuuuu]` | `[.uuuuuu]` |
### Why the Difference?
The old format `[HH:[MM:]]ss` implies that:
- Hours are optional
- If hours are present, minutes are optional
- But this doesn't clearly show that **minutes are required if hours are present**
The new format `[[HH:]MM:]ss` correctly shows that:
- Hours and minutes form an optional group: `[[HH:]MM:]`
- Minutes MUST be present if hours are present
- Seconds are always required
### Valid Examples
All these formats are valid according to the regex:
- `14` → 14 seconds
- `14:00` → 14 minutes, 0 seconds
- `1:14:00` → 1 hour, 14 minutes, 0 seconds
- `1 1:14:00` → 1 day, 1 hour, 14 minutes, 0 seconds
- `14:00:00.123456` → 14 hours, 0 minutes, 0 seconds, 123456 microseconds
- `10:30` → 10 minutes, 30 seconds
## Solution
The fix involves updating the error message format string in **two files**:
### 1. `django/db/models/fields/__init__.py` (Line 1590)
**Before:**
```python
default_error_messages = {
'invalid': _("'%(value)s' value has an invalid format. It must be in "
"[DD] [HH:[MM:]]ss[.uuuuuu] format.")
}
```
**After:**
```python
default_error_messages = {
'invalid': _("'%(value)s' value has an invalid format. It must be in "
"[DD] [[HH:]MM:]ss[.uuuuuu] format.")
}
```
### 2. `tests/model_fields/test_durationfield.py` (Line 78)
**Before:**
```python
"It must be in [DD] [HH:[MM:]]ss[.uuuuuu] format."
```
**After:**
```python
"It must be in [DD] [[HH:]MM:]ss[.uuuuuu] format."
```
## Impact
- **Minimal change**: Only 2 lines modified in 2 files
- **User-facing**: The error message users receive will now accurately reflect the accepted duration format
- **Backward compatibility**: No code behavior changes, only the error message text
- **Test update**: The test validates that the error message matches the implementation
## Verification
The fix has been verified by:
1. Confirming the regex pattern in `django/utils/dateparse.py`
2. Testing multiple valid duration formats against the regex
3. Ensuring all test cases pass with the updated error message

26
durationfield_fix.patch Normal file
View file

@ -0,0 +1,26 @@
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index f32ce64629..71005490f3 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -1587,7 +1587,7 @@ class DurationField(Field):
empty_strings_allowed = False
default_error_messages = {
'invalid': _("'%(value)s' value has an invalid format. It must be in "
- "[DD] [HH:[MM:]]ss[.uuuuuu] format.")
+ "[DD] [[HH:]MM:]ss[.uuuuuu] format.")
}
description = _("Duration")
diff --git a/tests/model_fields/test_durationfield.py b/tests/model_fields/test_durationfield.py
index b73994f86a..f1c82ab8bd 100644
--- a/tests/model_fields/test_durationfield.py
+++ b/tests/model_fields/test_durationfield.py
@@ -75,7 +75,7 @@ class TestValidation(SimpleTestCase):
self.assertEqual(
cm.exception.message % cm.exception.params,
"'not a datetime' value has an invalid format. "
- "It must be in [DD] [HH:[MM:]]ss[.uuuuuu] format."
+ "It must be in [DD] [[HH:]MM:]ss[.uuuuuu] format."
)