Skip to content

Add a Date and time custom field format - #14

Merged
dkastl merged 2 commits into
mainfrom
feature/datetime-custom-field
Jul 30, 2026
Merged

Add a Date and time custom field format#14
dkastl merged 2 commits into
mainfrom
feature/datetime-custom-field

Conversation

@dkastl

@dkastl dkastl commented Jul 30, 2026

Copy link
Copy Markdown
Member

Closes #9, taking the approach you suggested rather than the one the issue originally sketched.

Why a format, not a sidecar

Registers a new datetime format alongside Redmine's built-in date, so a field either wants a time or it does not, and that stays a per-field choice. Redmine 7 ships 13 formats and date is the only temporal one, so nothing is being duplicated.

The important part: this needs no sidecar table and no mirroring. That machinery exists elsewhere in this plugin for exactly one reason, that issues.start_date is a real date column which cannot be changed. A custom value lives in a string column, so a timestamp fits natively and there is nothing to keep in sync, and no drift to check for.

Deliberately not the approach of nanego/redmine_datetime_custom_field, which patches the built-in date format and migrates existing date fields; keeping the built-in intact was the requirement.

Storage: naive local in the reference zone

2026-08-03T09:15, no offset. Three reasons, all of which the tests pin:

  1. It matches how the built-in date format stores.
  2. ISO 8601 sorts correctly as a plain string, so ordering needs no special casing.
  3. It is consistent with the one-clock decision from Render times in the user's time zone preference #5.

That third point has a consequence worth reviewing: formatted_value deliberately does not use the view's format_time helper, because that converts to the viewer's own zone and would reintroduce exactly the per-viewer ambiguity #5 rejected. A test asserts formatting is unaffected by User.current's zone.

The interval

The input carries the configured step, so the picker moves on the same grid as the start and due time fields. Off-grid minutes are accepted rather than snapped, which is a deliberate difference from those fields: they feed the optimizer and belong on a grid, whereas an arbitrary datetime field may legitimately record when something happened, such as an incident report time.

One thing my own test caught

The first version fell back to I18n.l(time, format: :short) when the admin date/time settings are blank, which renders 03 Aug 09:15 with no year. Ambiguous for anything outside the current year. Formatting now uses explicit fallbacks (%Y-%m-%d %H:%M) and still honours the admin settings when they are set.

Testing

73 tests green against Redmine 7.0.0 / Ruby 4.0.6 with the full plugin set. New coverage: registration alongside date, round-trip through a real custom field, casting into the reference zone, rejection of a date without a time / a value carrying an offset / an impossible time, blank allowed, formatting completeness and admin settings, viewer-zone independence, string sortability, the declared filter type, and off-grid acceptance.

Verified end to end in the dev instance: "Date and time" appears in the admin format picker with "Date" still present, the issue form renders type=datetime-local with step=900, and the value shows as 2026-08-03 09:07 on the issue page. Demo field and settings removed afterwards.

Follow-up filed for widening beyond issue custom fields.

Closes #9

Registers a new 'datetime' format alongside Redmine's built-in 'date'
rather than patching it, so a field either wants a time or it does not and
that stays a per-field choice. Redmine 7 has no datetime format of its own
(13 built-ins, date is the only temporal one).

No sidecar is involved. The mirror machinery elsewhere in this plugin
exists only because issues.start_date is a real date column that cannot be
changed; a custom value is a string column, so a timestamp fits natively
and there is nothing to keep in sync.

Stored as naive local time in the reference zone (2026-08-03T09:15, no
offset): it matches how the built-in date format stores, keeps ISO strings
sortable as plain strings so ordering needs no special casing, and is
consistent with this plugin showing one clock rather than converting per
viewer. Formatting therefore avoids the view's format_time helper, which
would convert to the viewer's own zone.

The input carries the configured interval as its step, so the picker moves
on the same grid as the start/due fields, but off-grid minutes are
accepted: unlike the scheduling times, an arbitrary datetime field may
legitimately record when something actually happened.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new datetime custom field format to the plugin, registered alongside Redmine’s built-in date format, storing values as naive ISO-8601 local timestamps and formatting them consistently in the configured reference time zone.

Changes:

  • Introduces RedmineIssueDatetime::DatetimeFormat as a new Redmine custom field format (field_format: 'datetime') with validation, casting, formatting, and filter typing.
  • Adds the admin UI partial for configuring datetime custom fields (including the reference-zone hint) plus EN/JA translations.
  • Adds unit tests covering registration, round-tripping, rejection cases, formatting behavior, sorting, and query filter options.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/unit/datetime_format_test.rb New unit coverage for the datetime field format behaviors and constraints.
lib/redmine_issue_datetime/field_format.rb Implements the new datetime custom field format (parse/validate/format/input rendering).
lib/redmine_issue_datetime.rb Ensures the new field format is loaded during plugin initialization.
config/locales/ja.yml Adds Japanese translations for the new format label and zone hint text.
config/locales/en.yml Adds English translations for the new format label and zone hint text.
app/views/custom_fields/formats/_datetime.html.erb Adds the admin form partial for datetime custom field defaults and hinting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/unit/datetime_format_test.rb
The eager-load gate caught this on its own author: the file was
field_format.rb while the class is DatetimeFormat, so Zeitwerk expected
RedmineIssueDatetime::FieldFormat and a production boot would have died
with a NameError. Every test passed, because test and development load
lazily - exactly the gap the gate exists for, and the same shape as
karida-org/redmine_gtt_sync#81.

Renamed to datetime_format.rb, with a comment so the next person does not
reintroduce it. Also restores the previous User.current in the test
teardown rather than assuming it was nil.
@dkastl
dkastl merged commit 0642992 into main Jul 30, 2026
7 checks passed
@dkastl
dkastl deleted the feature/datetime-custom-field branch July 30, 2026 02:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Time of day for date custom fields

2 participants