VeeValidate Date Validation Across Time Zones: Where Should Normalization Happen
0 reputation · 21 Feb 2023, 01:23 UTC
0 reputation · 21 Feb 2023, 01:23 UTC
I am configuring VeeValidate (v4, Vue 3) to validate a date-time input that must be compared against a minimum boundary, such as "not in the past." The form collects a local date-time from the user, but the constraint is defined in UTC on the server side.
From the documented behavior, VeeValidate is agnostic to date formats and simply validates whatever value the input field provides. Timezone conversion is not handled by the library, so a raw ISO string or a locale-dependent string could validate differently depending on the client's regional settings. I am unsure whether normalization belongs in the application state (e.g., converting with date-fns or Luxon before the value reaches the field), inside a custom defineRule function, or in a Zod schema with .date() constraints attached to the form.
A secondary concern is that mixing a Zod schema with a manual rule could produce conflicting error messages if both layers interpret the same unconverted value differently.
defineRule check be removed entirely to avoid duplicate or conflicting errors?32775 reputation · 21 Feb 2023, 06:02 UTC
The most reliable place to convert the user’s local date‑time to UTC is in the component state (or a computed property) before the value reaches VeeValidate. By normalizing once, every downstream validator sees the same UTC value, eliminating locale‑dependent discrepancies.
If your Zod schema already applies the .date() boundary check, drop the corresponding defineRule from VeeValidate. Keeping both layers would produce two error messages for the same problem and can confuse users.
Whether validation runs on change, blur, or submit does not influence where the conversion should occur. The conversion is a pure data‑transformation step that is independent of the event that fires validation.
VeeValidate validates whatever value the field supplies; it does not perform any time‑zone conversion. If you let the raw input string (e.g., "2026‑10‑14T08:00") flow directly into the form, the validator will compare that string against a UTC boundary, which can yield incorrect results depending on the client’s locale. Normalizing early guarantees a consistent, UTC‑based value for every validator.
selectedDate.
change event, parse the raw value with a reliable library (date‑fns, Luxon, or native Date) and convert it to UTC:
const utc = new Date(selectedDate).toISOString(); // ISO string in UTC
this.selectedDate = utc;
selectedDate to VeeValidate. The rule can then perform a simple comparison:
defineRule('notPast', value => {
const now = new Date();
return new Date(value) >= now || 'Date cannot be in the past';
});
const schema = z.object({
eventDate: z.date().min(new Date(), { message: 'Date cannot be in the past' })
});
notPast rule from VeeValidate to avoid duplicate messages.
To fine‑tune the conversion logic, it would help to know the exact format the input field emits (ISO string, locale‑dependent string, or epoch milliseconds). If the format differs, the conversion step may need adjustment.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.