custom date/time formats

This commit is contained in:
Gamosoft 2026-05-06 16:06:03 +02:00
parent d67e2d458a
commit 83b2397c87
3 changed files with 75 additions and 8 deletions

View File

@ -964,31 +964,64 @@ def get_template_content(notes_dir: str, template_name: str) -> Optional[str]:
return None
# Matches custom strftime placeholders like {{date:%Y%m%d}} or {{time:%H%M%S}}.
# The three prefixes mirror the bare {{date}}, {{time}}, {{datetime}} placeholders;
# disallowing '{' and '}' inside the format keeps parsing unambiguous and
# guarantees we never swallow an adjacent placeholder.
_STRFTIME_PLACEHOLDER_RE = re.compile(r'\{\{(date|time|datetime):([^{}]+)\}\}')
def apply_template_placeholders(content: str, note_path: str) -> str:
"""
Replace template placeholders with actual values.
Supported placeholders:
Built-in named placeholders (fixed default formats):
{{date}} - Current date (YYYY-MM-DD)
{{time}} - Current time (HH:MM:SS)
{{datetime}} - Current datetime (YYYY-MM-DD HH:MM:SS)
{{timestamp}} - Unix timestamp
{{timestamp}} - Unix timestamp (seconds)
{{year}} - Current year (YYYY)
{{month}} - Current month (MM)
{{day}} - Current day (DD)
{{title}} - Note name without extension
{{folder}} - Parent folder name
Custom date/time formats (strftime escape hatch):
{{date:FMT}}, {{time:FMT}}, {{datetime:FMT}}
Any of the three date/time placeholders above also accepts an
optional ":FMT" suffix where FMT is a Python strftime() format
string. Pick the prefix whose default format covers the same
components you want to format. Examples:
{{datetime:%Y%m%d%H%M%S}} -> 20260506154200 (filename-safe stamp)
{{date:%d/%m/%Y}} -> 06/05/2026 (European date)
{{date:%A}} -> Wednesday (full weekday name)
{{time:%H%M%S}} -> 154200 (compact time)
{{date:%V}} -> 19 (ISO week number)
Invalid format strings are left in the output unchanged so a typo
is visible rather than silently swallowed.
Args:
content: Template content with placeholders
note_path: Path of the note being created
Returns:
Content with placeholders replaced
"""
now = datetime.now()
note = Path(note_path)
def _strftime_sub(match: 're.Match[str]') -> str:
fmt = match.group(2)
try:
return now.strftime(fmt)
except (ValueError, TypeError):
return match.group(0)
content = _STRFTIME_PLACEHOLDER_RE.sub(_strftime_sub, content)
replacements = {
'{{date}}': now.strftime('%Y-%m-%d'),
'{{time}}': now.strftime('%H:%M:%S'),
@ -1000,11 +1033,11 @@ def apply_template_placeholders(content: str, note_path: str) -> str:
'{{title}}': note.stem,
'{{folder}}': note.parent.name if str(note.parent) != '.' else 'Root',
}
result = content
for placeholder, value in replacements.items():
result = result.replace(placeholder, value)
return result

View File

@ -287,6 +287,7 @@ Create notes from reusable templates with dynamic placeholder replacement.
- `{{day}}` - Current day (DD)
- `{{title}}` - Note name (without extension)
- `{{folder}}` - Parent folder name
- `{{date:FORMAT}}` / `{{time:FORMAT}}` / `{{datetime:FORMAT}}` - Custom format using any Python `strftime()` string, e.g. `{{datetime:%Y%m%d%H%M%S}}``20251126143045`. See [Templates](TEMPLATES.md#custom-datetime-formats) for the full recipe list.
### Example Template
```markdown

View File

@ -46,6 +46,39 @@ Templates support dynamic placeholders that are replaced when you create a note:
| `{{title}}` | Note name (without .md) | `Weekly Meeting` |
| `{{folder}}` | Parent folder name | `Projects` |
### Custom date/time formats
Need a different format than the defaults above? Any of the three
date/time placeholders — `{{date}}`, `{{time}}`, `{{datetime}}` — accepts
an optional `:FORMAT` suffix to override its default format. `FORMAT` is
any [Python `strftime()` format string](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes),
so anything `strftime` can do, your template can do.
> **One rule to remember:** pick the prefix whose default already covers
> the components you want to format. Use `{{date:…}}` for date-only
> formats, `{{time:…}}` for time-only formats, and `{{datetime:…}}` when
> you need both.
#### Common recipes
| Template | Result | Use case |
|---|---|---|
| `{{date:%Y%m%d}}` | `20251126` | Date stamp for filenames |
| `{{time:%H%M%S}}` | `143045` | Time stamp for filenames |
| `{{datetime:%Y%m%d%H%M%S}}` | `20251126143045` | Sortable, filename-safe full stamp |
| `{{datetime:%Y%m%dT%H%M%S}}` | `20251126T143045` | ISO-8601 basic, no separators |
| `{{datetime:%Y-%m-%dT%H:%M:%S}}` | `2025-11-26T14:30:45` | ISO-8601 extended |
| `{{date:%d/%m/%Y}}` | `26/11/2025` | European-style date |
| `{{date:%m/%d/%Y}}` | `11/26/2025` | US-style date |
| `{{date:%A}}` | `Wednesday` | Full weekday name |
| `{{date:%a}}` | `Wed` | Short weekday name |
| `{{date:%B}}` | `November` | Full month name |
| `{{date:%V}}` | `48` | ISO week number |
| `{{date:%j}}` | `330` | Day of year (1366) |
> Invalid format strings (typos) are left in the output unchanged so the
> mistake is visible rather than silently swallowed.
### Example Template
```markdown