Skip to content

feat(#590): add time question type#674

Open
latin-panda wants to merge 10 commits intomainfrom
time-question-type
Open

feat(#590): add time question type#674
latin-panda wants to merge 10 commits intomainfrom
time-question-type

Conversation

@latin-panda
Copy link
Collaborator

@latin-panda latin-panda commented Feb 24, 2026

Closes #590

I have verified this PR works in these browsers (latest versions):

  • Chrome
  • Firefox
  • Safari (macOS)
  • Safari (iOS)
  • Chrome for Android
  • Not applicable

What else has been done to verify that this works as intended?

Tested in Firefox, Chrome, Safari, and Chrome for Android
Tested editing submission in Central

Why is this the best possible solution? Were any other approaches considered?

How does this change affect users? Describe intentional changes to behavior and behavior that could have accidentally been affected by code changes. In other words, what are the regression risks?

Do we need any specific form for testing your changes? If so, please attach one.

Test server available in team's channel

What's changed

  • Adds a Vue component that uses PrimeVue's datepicker to show only time in a 12-hour format for now, pending further user feedback. I have opened a ticket to explore the possibility of supporting a 24-hour display.
  • Add time codec and test coverage in scenario

@changeset-bot
Copy link

changeset-bot bot commented Feb 24, 2026

🦋 Changeset detected

Latest commit: 9554fac

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@getodk/xforms-engine Minor
@getodk/web-forms Minor
@getodk/scenario Patch
@getodk/common Patch
@getodk/xpath Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

import { Temporal } from 'temporal-polyfill';
import { type CodecDecoder, type CodecEncoder, ValueCodec } from './ValueCodec.ts';

export type TimeRuntimeValue = string | null;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Temporal doesn't have a type that represents only time with an offset. PlainTime is time only.
I think string is okay for now.

export type TimeRuntimeValue = string | null;

export type TimeInputValue =
| Date
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

PrimeVue uses Date.

@latin-panda latin-panda marked this pull request as ready for review February 24, 2026 18:52
@latin-panda
Copy link
Collaborator Author

@garethbowen this is ready for review :)

return new Date(`${yyyy}-${mm}-${dd}T${temporalValue}`);
},
set: (newTime) => {
// Clear seconds and milliseconds to match Collect and Enketo behavior (a client's responsibility).
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Enketo and Collect behavior:

  • If the question has a predefined value with seconds and milliseconds, e.g., 22:02:10.562+06:00, and it wasn't modified, the seconds and milliseconds are preserved.
  • If the question has a predefined value with seconds and milliseconds, and the value was modified, then seconds and milliseconds are zero.
  • If no predefined value exists and a new one is set, then seconds and milliseconds are zero.
  • All values captured using the time picker are saved in the format HH:mm:ss.SSSXXX, e.g., 22:02:10.562+06:00

Copy link
Collaborator

@garethbowen garethbowen left a comment

Choose a reason for hiding this comment

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

Nice work! Some minor suggestions inline...

Times having timezones broke my brain a little. I think it's more correct that they don't but the XML spec isn't clear: https://www.w3.org/TR/xmlschema-2/#time

Regardless I'm comfortable with the inclusion of timezone until proven wrong!

Comment on lines +22 to +26
const today = new Date();
const yyyy = today.getFullYear();
const mm = String(today.getMonth() + 1).padStart(2, '0');
const dd = String(today.getDate()).padStart(2, '0');
return new Date(`${yyyy}-${mm}-${dd}T${temporalValue}`);
Copy link
Collaborator

Choose a reason for hiding this comment

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

We have the Temporal plugin in web-forms, right?

If so, I think this can be replaced with...

Suggested change
const today = new Date();
const yyyy = today.getFullYear();
const mm = String(today.getMonth() + 1).padStart(2, '0');
const dd = String(today.getDate()).padStart(2, '0');
return new Date(`${yyyy}-${mm}-${dd}T${temporalValue}`);
const today = Temporal.Now.plainDateISO();
return new Date(`${today}T${temporalValue}`);

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, we only use Temporal in xpath, xforms-engine, and scenario right now. Perhaps we can hold off until we see more usage before including it. What do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ok leave it for now. Ideally it would be a peer dependency in the xforms-engine too so it wouldn't get bundled and then it would be "free" to use in all packages. Anyway, stick with this for now.

</script>

<template>
<DatePicker v-model="value" time-only hour-format="12" :disabled="isDisabled" />
Copy link
Collaborator

Choose a reason for hiding this comment

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

It would be nice to showIcon here like we do with the date picker, though ideally it would be a clock icon not a calendar. Not sure how hard that is to do...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done!

cc: @alyblenkin

@latin-panda
Copy link
Collaborator Author

Times having timezones broke my brain a little. I think it's more correct that they don't but the XML spec isn't clear: https://www.w3.org/TR/xmlschema-2/#time

I was thinking the same! But then the ODK spec says this:

The time widget stores the time along with a time zone. This can cause unexpected behavior around Daylight saving time...

I've resolved the feedback :)

Copy link
Collaborator

@garethbowen garethbowen left a comment

Choose a reason for hiding this comment

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

Beautiful!

Don't forget to update the feature matrix while you're at it!

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.

Add support to the time question type

2 participants