datetime tools #96

Open
opened 2026-04-20 04:32:28 +03:00 by skobkin · 0 comments
Owner

PRD: datetime_math and datetime_format

Overview

Add two deterministic utility tools for date/time handling:

  • datetime_math: perform date/time calculations and timezone conversions
  • datetime_format: format a normalized timestamp for user-facing output

These tools must be:

  • deterministic
  • compact in output
  • safe to call frequently
  • independent from any LLM logic
  • easy to test in Go

They are intended for tool-calling flows where the model needs exact time reasoning without guessing.


Tool 1: datetime_math

Goal

Provide exact date/time calculations for the model, including differences, shifting, weekday detection, and timezone conversion.

Non-Goals

This tool must not:

  • parse vague natural language like "next Friday evening"
  • guess missing timezone information unless explicitly configured
  • return verbose prose
  • do scheduling by itself

Supported Operations

1. diff

Compute the difference between two timestamps.

Example use cases:

  • "How many days are left?"
  • "What is the gap between these two dates?"

2. shift

Shift a timestamp by a structured duration.

Example use cases:

  • "Move this by 2 days"
  • "What time is it 3 hours later?"

3. weekday

Return the weekday for a timestamp.

Example use cases:

  • "What day of week is this?"
  • "Does this fall on Monday?"

4. convert_timezone

Convert a timestamp to another timezone without changing the instant.

Example use cases:

  • "What is this in Europe/Oslo?"
  • "Show this in UTC"

Input Contract

Input must be JSON with:

  • operation (required): one of diff, shift, weekday, convert_timezone
  • timestamp (required for shift, weekday, convert_timezone): RFC3339 timestamp
  • left and right (required for diff): RFC3339 timestamps
  • target_timezone (required for convert_timezone): IANA timezone name
  • shift fields (optional for shift):
    • years
    • months
    • days
    • hours
    • minutes
    • seconds

Output Contract

Output must be compact JSON.

diff output

{
  "operation": "diff",
  "left": "2026-04-20T10:00:00+03:00",
  "right": "2026-04-22T15:30:00+03:00",
  "duration_seconds": 192600,
  "duration_minutes": 3210,
  "duration_hours": 53.5,
  "duration_days": 2.2291666667,
  "sign": 1
}

shift output

{
  "operation": "shift",
  "input": "2026-04-20T10:00:00+03:00",
  "result": "2026-04-22T07:00:00+03:00"
}

weekday output

{
  "operation": "weekday",
  "timestamp": "2026-04-20T10:00:00+03:00",
  "weekday": "Monday",
  "weekday_index": 1
}

convert_timezone output

{
  "operation": "convert_timezone",
  "input": "2026-04-20T10:00:00+03:00",
  "target_timezone": "Europe/Oslo",
  "result": "2026-04-20T09:00:00+02:00"
}

Validation Rules

  • All timestamps must be valid RFC3339 strings.
  • target_timezone must be a valid IANA timezone.
  • operation must be recognized.
  • shift must reject requests with no shift fields at all.
  • The tool must fail fast on invalid input and never silently guess.

Error Contract

Errors must be structured and compact:

{
  "error": {
    "code": "invalid_timezone",
    "message": "target_timezone must be a valid IANA timezone"
  }
}

Recommended error codes:

  • invalid_operation
  • invalid_timestamp
  • invalid_timezone
  • missing_required_field
  • empty_shift
  • internal_error

Behavior Notes

  • Use RFC3339 as the only timestamp input/output format.
  • Preserve exact instants during timezone conversion.
  • Use Go time.Time and time.Location.
  • For shift, use calendar-aware shifting for years/months/days, not raw second math.
  • For diff, return signed difference (sign = -1, 0, 1).

Implementation Notes (Go)

  • Package suggestion: internal/tools/datetime
  • Public entrypoint suggestion:
    • func ExecuteDatetimeMath(ctx context.Context, input DatetimeMathInput) (DatetimeMathOutput, error)
  • Use typed request/response structs.
  • Keep JSON schema simple and explicit.
  • Do not mix formatting concerns into this tool.
  • Keep outputs stable for snapshot tests.

Testing Requirements

Add table-driven tests for:

  • valid RFC3339 parsing
  • invalid timestamps
  • invalid timezone names
  • diff positive and negative results
  • shift with mixed units
  • weekday
  • timezone conversion across DST boundaries
  • zero-delta cases

Acceptance Criteria

  • Tool accepts only structured input and returns structured output.
  • Tool never uses natural-language parsing.
  • Tool output is small and stable.
  • DST-sensitive conversions behave correctly.
  • All major cases are covered by table-driven tests.

Tool 2: datetime_format

Goal

Convert a normalized timestamp into a compact user-facing representation.

Non-Goals

This tool must not:

  • compute date arithmetic
  • compare timestamps
  • parse vague natural language
  • guess timezones from free text

Supported Styles

  • short
  • long
  • date_only
  • time_only
  • weekday_date

Input Contract

Input must be JSON with:

  • timestamp (required): RFC3339 timestamp
  • style (required): one of the supported styles
  • target_timezone (optional): IANA timezone name
  • locale (optional, future-safe): string such as en or ru

If target_timezone is provided, the timestamp must first be converted to that timezone before formatting.

Output Contract

Output must be compact JSON.

Example:

{
  "input": "2026-04-20T10:00:00+03:00",
  "target_timezone": "Europe/Oslo",
  "style": "long",
  "formatted": "2026-04-20 09:00 CEST",
  "timezone": "Europe/Oslo",
  "utc_offset": "+02:00"
}

Formatting Rules

Suggested defaults:

  • shortYYYY-MM-DD HH:MM
  • longYYYY-MM-DD HH:MM TZ
  • date_onlyYYYY-MM-DD
  • time_onlyHH:MM
  • weekday_dateMonday, 2026-04-20

Keep formatting intentionally simple and machine-stable unless locale support is explicitly expanded later.

Validation Rules

  • timestamp must be valid RFC3339
  • style must be recognized
  • target_timezone, if present, must be a valid IANA timezone

Error Contract

Same structure as datetime_math:

{
  "error": {
    "code": "invalid_style",
    "message": "style must be one of short, long, date_only, time_only, weekday_date"
  }
}

Recommended error codes:

  • invalid_timestamp
  • invalid_timezone
  • invalid_style
  • missing_required_field
  • internal_error

Behavior Notes

  • This tool is presentation-only.
  • It must never perform arithmetic.
  • If no target_timezone is provided, format the timestamp in its own offset/location.
  • Locale support may start as English-only even if the field exists in the schema.

Implementation Notes (Go)

  • Public entrypoint suggestion:
    • func ExecuteDatetimeFormat(ctx context.Context, input DatetimeFormatInput) (DatetimeFormatOutput, error)
  • Keep formatting logic separate from math logic.
  • Use a small internal formatter map keyed by style.
  • Locale can be ignored in v1 or accepted only as "en".

Testing Requirements

Add table-driven tests for:

  • each style
  • timezone conversion before formatting
  • invalid style
  • invalid timestamp
  • invalid timezone
  • formatting around DST transitions

Acceptance Criteria

  • Tool formats normalized timestamps predictably.
  • Tool output is compact and stable.
  • Tool never performs arithmetic.
  • Tool can be safely used in tool-calling loops without bloating context.

Shared Design Constraints

Both tools must:

  • be deterministic
  • be cheap to execute
  • use compact JSON outputs
  • avoid hidden heuristics
  • avoid natural-language interpretation
  • return explicit structured errors
  • be easy to snapshot-test
  • remain independent from scheduler/reminder business logic

Future Extensions (Not Required in V1)

Possible later additions:

  • locale-aware month and weekday names
  • unix timestamp input/output
  • range formatting
  • "is past / is future" helper
  • support for explicit default timezone from config

Follow-up of #92

# PRD: `datetime_math` and `datetime_format` ## Overview Add two deterministic utility tools for date/time handling: - `datetime_math`: perform date/time calculations and timezone conversions - `datetime_format`: format a normalized timestamp for user-facing output These tools must be: - deterministic - compact in output - safe to call frequently - independent from any LLM logic - easy to test in Go They are intended for tool-calling flows where the model needs exact time reasoning without guessing. --- # Tool 1: `datetime_math` ## Goal Provide exact date/time calculations for the model, including differences, shifting, weekday detection, and timezone conversion. ## Non-Goals This tool must **not**: - parse vague natural language like "next Friday evening" - guess missing timezone information unless explicitly configured - return verbose prose - do scheduling by itself ## Supported Operations ### 1. `diff` Compute the difference between two timestamps. Example use cases: - "How many days are left?" - "What is the gap between these two dates?" ### 2. `shift` Shift a timestamp by a structured duration. Example use cases: - "Move this by 2 days" - "What time is it 3 hours later?" ### 3. `weekday` Return the weekday for a timestamp. Example use cases: - "What day of week is this?" - "Does this fall on Monday?" ### 4. `convert_timezone` Convert a timestamp to another timezone without changing the instant. Example use cases: - "What is this in Europe/Oslo?" - "Show this in UTC" ## Input Contract Input must be JSON with: - `operation` (required): one of `diff`, `shift`, `weekday`, `convert_timezone` - `timestamp` (required for `shift`, `weekday`, `convert_timezone`): RFC3339 timestamp - `left` and `right` (required for `diff`): RFC3339 timestamps - `target_timezone` (required for `convert_timezone`): IANA timezone name - shift fields (optional for `shift`): - `years` - `months` - `days` - `hours` - `minutes` - `seconds` ## Output Contract Output must be compact JSON. ### `diff` output { "operation": "diff", "left": "2026-04-20T10:00:00+03:00", "right": "2026-04-22T15:30:00+03:00", "duration_seconds": 192600, "duration_minutes": 3210, "duration_hours": 53.5, "duration_days": 2.2291666667, "sign": 1 } ### `shift` output { "operation": "shift", "input": "2026-04-20T10:00:00+03:00", "result": "2026-04-22T07:00:00+03:00" } ### `weekday` output { "operation": "weekday", "timestamp": "2026-04-20T10:00:00+03:00", "weekday": "Monday", "weekday_index": 1 } ### `convert_timezone` output { "operation": "convert_timezone", "input": "2026-04-20T10:00:00+03:00", "target_timezone": "Europe/Oslo", "result": "2026-04-20T09:00:00+02:00" } ## Validation Rules - All timestamps must be valid RFC3339 strings. - `target_timezone` must be a valid IANA timezone. - `operation` must be recognized. - `shift` must reject requests with no shift fields at all. - The tool must fail fast on invalid input and never silently guess. ## Error Contract Errors must be structured and compact: { "error": { "code": "invalid_timezone", "message": "target_timezone must be a valid IANA timezone" } } Recommended error codes: - `invalid_operation` - `invalid_timestamp` - `invalid_timezone` - `missing_required_field` - `empty_shift` - `internal_error` ## Behavior Notes - Use RFC3339 as the only timestamp input/output format. - Preserve exact instants during timezone conversion. - Use Go `time.Time` and `time.Location`. - For `shift`, use calendar-aware shifting for years/months/days, not raw second math. - For `diff`, return signed difference (`sign = -1, 0, 1`). ## Implementation Notes (Go) - Package suggestion: `internal/tools/datetime` - Public entrypoint suggestion: - `func ExecuteDatetimeMath(ctx context.Context, input DatetimeMathInput) (DatetimeMathOutput, error)` - Use typed request/response structs. - Keep JSON schema simple and explicit. - Do not mix formatting concerns into this tool. - Keep outputs stable for snapshot tests. ## Testing Requirements Add table-driven tests for: - valid RFC3339 parsing - invalid timestamps - invalid timezone names - `diff` positive and negative results - `shift` with mixed units - `weekday` - timezone conversion across DST boundaries - zero-delta cases ## Acceptance Criteria - Tool accepts only structured input and returns structured output. - Tool never uses natural-language parsing. - Tool output is small and stable. - DST-sensitive conversions behave correctly. - All major cases are covered by table-driven tests. --- # Tool 2: `datetime_format` ## Goal Convert a normalized timestamp into a compact user-facing representation. ## Non-Goals This tool must **not**: - compute date arithmetic - compare timestamps - parse vague natural language - guess timezones from free text ## Supported Styles - `short` - `long` - `date_only` - `time_only` - `weekday_date` ## Input Contract Input must be JSON with: - `timestamp` (required): RFC3339 timestamp - `style` (required): one of the supported styles - `target_timezone` (optional): IANA timezone name - `locale` (optional, future-safe): string such as `en` or `ru` If `target_timezone` is provided, the timestamp must first be converted to that timezone before formatting. ## Output Contract Output must be compact JSON. Example: { "input": "2026-04-20T10:00:00+03:00", "target_timezone": "Europe/Oslo", "style": "long", "formatted": "2026-04-20 09:00 CEST", "timezone": "Europe/Oslo", "utc_offset": "+02:00" } ## Formatting Rules Suggested defaults: - `short` → `YYYY-MM-DD HH:MM` - `long` → `YYYY-MM-DD HH:MM TZ` - `date_only` → `YYYY-MM-DD` - `time_only` → `HH:MM` - `weekday_date` → `Monday, 2026-04-20` Keep formatting intentionally simple and machine-stable unless locale support is explicitly expanded later. ## Validation Rules - `timestamp` must be valid RFC3339 - `style` must be recognized - `target_timezone`, if present, must be a valid IANA timezone ## Error Contract Same structure as `datetime_math`: { "error": { "code": "invalid_style", "message": "style must be one of short, long, date_only, time_only, weekday_date" } } Recommended error codes: - `invalid_timestamp` - `invalid_timezone` - `invalid_style` - `missing_required_field` - `internal_error` ## Behavior Notes - This tool is presentation-only. - It must never perform arithmetic. - If no `target_timezone` is provided, format the timestamp in its own offset/location. - Locale support may start as English-only even if the field exists in the schema. ## Implementation Notes (Go) - Public entrypoint suggestion: - `func ExecuteDatetimeFormat(ctx context.Context, input DatetimeFormatInput) (DatetimeFormatOutput, error)` - Keep formatting logic separate from math logic. - Use a small internal formatter map keyed by style. - Locale can be ignored in v1 or accepted only as `"en"`. ## Testing Requirements Add table-driven tests for: - each style - timezone conversion before formatting - invalid style - invalid timestamp - invalid timezone - formatting around DST transitions ## Acceptance Criteria - Tool formats normalized timestamps predictably. - Tool output is compact and stable. - Tool never performs arithmetic. - Tool can be safely used in tool-calling loops without bloating context. --- # Shared Design Constraints Both tools must: - be deterministic - be cheap to execute - use compact JSON outputs - avoid hidden heuristics - avoid natural-language interpretation - return explicit structured errors - be easy to snapshot-test - remain independent from scheduler/reminder business logic ## Future Extensions (Not Required in V1) Possible later additions: - locale-aware month and weekday names - unix timestamp input/output - range formatting - "is past / is future" helper - support for explicit default timezone from config --- Follow-up of #92
skobkin self-assigned this 2026-04-20 04:32:28 +03:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
skobkin/telegram-ollama-reply-bot#96
No description provided.