{"record":{"id":"95c8ee298c2d8c52","repo":"angular/components","slug":"invalid-hours-hours-hours-value-must-be-betw-95c8ee","errorCode":null,"errorMessage":"Invalid hours \"${hours}\". Hours value must be between 0 and 23.","messagePattern":"Invalid hours \"(.+?)\"\\. Hours value must be between 0 and 23\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/material-moment-adapter/adapter/moment-date-adapter.ts","lineNumber":248,"sourceCode":"    return super.deserialize(value);\n  }\n\n  isDateInstance(obj: unknown): obj is Moment {\n    return moment.isMoment(obj);\n  }\n\n  isValid(date: Moment): boolean {\n    return this.clone(date).isValid();\n  }\n\n  invalid(): Moment {\n    return moment.invalid();\n  }\n\n  override setTime(target: Moment, hours: number, minutes: number, seconds: number): Moment {\n    if (typeof ngDevMode === 'undefined' || ngDevMode) {\n      if (hours < 0 || hours > 23) {\n        throw Error(`Invalid hours \"${hours}\". Hours value must be between 0 and 23.`);\n      }\n\n      if (minutes < 0 || minutes > 59) {\n        throw Error(`Invalid minutes \"${minutes}\". Minutes value must be between 0 and 59.`);\n      }\n\n      if (seconds < 0 || seconds > 59) {\n        throw Error(`Invalid seconds \"${seconds}\". Seconds value must be between 0 and 59.`);\n      }\n    }\n\n    return this.clone(target).set({hours, minutes, seconds, milliseconds: 0});\n  }\n\n  override getHours(date: Moment): number {\n    return date.hours();\n  }\n","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/material-moment-adapter/adapter/moment-date-adapter.ts#L230-L266","documentation":"MomentDateAdapter.setTime validates the hours argument (0-23) before mutating the target Moment. Out-of-range hours would produce an invalid or rolled-over date, so the adapter throws this descriptive error in ngDevMode. The same method separately guards minutes and seconds.","triggerScenarios":"Calling setTime(target, hours, minutes, seconds) with hours < 0 or hours > 23 — e.g. passing 12-hour-clock values like 24, or 1-12 hour fields from an AM/PM picker without conversion.","commonSituations":"12-hour to 24-hour conversion mistakes (PM 12 vs 0/12), adding durations in hours and passing the raw sum, unvalidated inputs, misordered arguments so minutes land in the hours slot.","solutions":["Clamp/validate hours to 0-23 before calling setTime.","Convert 12-hour input correctly: hour % 12 + (pm ? 12 : 0).","If adding durations, use addCalendarHours on a base time instead of pre-summing hours.","Confirm argument order (target, hours, minutes, seconds)."],"exampleFix":"// before\nadapter.setTime(date, pickerHour + (isPm ? 12 : 0), 0, 0); // 12 PM becomes 24\n// after\nconst hours24 = pickerHour % 12 + (isPm ? 12 : 0);\nadapter.setTime(date, hours24, 0, 0);","handlingStrategy":"validation","validationCode":"function canSetTime(h: number, m: number, s: number): boolean {\n  return [h, m, s].every(Number.isInteger) && h >= 0 && h <= 23 && m >= 0 && m <= 59 && s >= 0 && s <= 59;\n}","typeGuard":"function isValidHours(h: unknown): h is number {\n  return typeof h === 'number' && Number.isInteger(h) && h >= 0 && h <= 23;\n}","tryCatchPattern":"try {\n  adapter.setTime(date, h, m, s);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('Invalid hours')) {\n    adapter.setTime(date, ((h % 24) + 24) % 24, m, s);\n  } else throw e;\n}","preventionTips":["Convert 12-hour input with hour % 12 + (pm ? 12 : 0)","Clamp hour inputs at the UI boundary","Use addCalendarHours for duration addition instead of summed values","Keep setTime argument order consistent via a wrapper function"],"tags":["date-adapter","moment","validation","time"],"backgroundTag":"invalid-time-component","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-09-01T08:17:40.651Z"}