Found while implementing #7443 (giving the datetime display convention one home). Source-confirmed on origin/main 1bae75bb. Filing unassigned — recording, not claiming.
The claim
#7443 counted three spellings of the datetime convention. There is a fourth, and unlike the other three it does not merely differ in its option bag — it ships under the same exported name from a sibling barrel.
Measured for 2024-07-04T07:00:00.000Z, en-US, Node 22 / ICU:
| symbol |
defined in |
signature |
renders |
formatDateTime |
packages/core/src/utils/date-display.ts |
(value, style?, options?) |
Jul 4, 2024, 07:00 AM |
formatDateTime |
packages/i18n/src/utils/formatting.ts |
(date, options?), options = { locale, style, dateStyle, timeStyle } |
Jul 4, 2024, 7:00 AM |
⭐ The two faces differ by one leading zero — core asks for hour: '2-digit', i18n's 'medium' style asks for hour: 'numeric'. That is the sharpest part of this card: the drift is not visible enough for anyone to report it, and both are locale-correct.
The barrels hand a consumer one or the other depending on which package they import from:
packages/fields/src/index.tsx re-exports core's (export { formatDate, formatDateTime, formatDateTimeCompactParts, formatRelativeDate }).
packages/react/src/index.ts re-exports i18n's, inside its i18n block alongside formatDate, formatRelativeTime, formatCurrency, formatNumber.
So import { formatDateTime } from '@object-ui/react' and import { formatDateTime } from '@object-ui/fields' are two different functions with incompatible parameter shapes and a one-character difference in output. formatDate sits in exactly the same position: core's is (value, style?, options?), i18n's is (date, options?), and the two barrels disagree the same way.
Why this is worth a card
This is #7443's disease one level up, and worse in one respect. #7443's three spellings lived at distinct call sites, so a reader comparing them could see two things. Here the name is identical, so the fourth author does not copy the nearest spelling — they import the nearest barrel and get a function they never chose. TypeScript is a weak net: both take Date | string | number first, so a call with no second argument compiles under either and silently renders the other convention's face.
The precedent is the one #7443 and objectui#4576 both cite: two Intl option bags for one concept, kept in step by nothing.
What this card is NOT
⛔ Not a request to delete either function. packages/i18n's formatter is a general locale-formatting helper with its own 'short' | 'medium' | 'long' | 'full' vocabulary and dateStyle/timeStyle passthrough; core's is the field-display path behind cells, grid cards, gantt tooltips and dataset measures. They may both deserve to exist. The defect is that they are indistinguishable at the import site.
Grading
Observation-class. Nothing is wrong on screen today: no in-repo call site reaches the i18n one at all — grep finds it only in packages/react's re-export line, never called. The reusable half is the name collision across two published barrels, not a user-facing defect.
Found while implementing #7443 (giving the
datetimedisplay convention one home). Source-confirmed onorigin/main1bae75bb. Filing unassigned — recording, not claiming.The claim
#7443 counted three spellings of the datetime convention. There is a fourth, and unlike the other three it does not merely differ in its option bag — it ships under the same exported name from a sibling barrel.
Measured for
2024-07-04T07:00:00.000Z,en-US, Node 22 / ICU:formatDateTimepackages/core/src/utils/date-display.ts(value, style?, options?)Jul 4, 2024, 07:00 AMformatDateTimepackages/i18n/src/utils/formatting.ts(date, options?),options={ locale, style, dateStyle, timeStyle }Jul 4, 2024, 7:00 AM⭐ The two faces differ by one leading zero — core asks for
hour: '2-digit', i18n's'medium'style asks forhour: 'numeric'. That is the sharpest part of this card: the drift is not visible enough for anyone to report it, and both are locale-correct.The barrels hand a consumer one or the other depending on which package they import from:
packages/fields/src/index.tsxre-exports core's (export { formatDate, formatDateTime, formatDateTimeCompactParts, formatRelativeDate }).packages/react/src/index.tsre-exports i18n's, inside its i18n block alongsideformatDate,formatRelativeTime,formatCurrency,formatNumber.So
import { formatDateTime } from '@object-ui/react'andimport { formatDateTime } from '@object-ui/fields'are two different functions with incompatible parameter shapes and a one-character difference in output.formatDatesits in exactly the same position: core's is(value, style?, options?), i18n's is(date, options?), and the two barrels disagree the same way.Why this is worth a card
This is #7443's disease one level up, and worse in one respect. #7443's three spellings lived at distinct call sites, so a reader comparing them could see two things. Here the name is identical, so the fourth author does not copy the nearest spelling — they import the nearest barrel and get a function they never chose. TypeScript is a weak net: both take
Date | string | numberfirst, so a call with no second argument compiles under either and silently renders the other convention's face.The precedent is the one #7443 and objectui#4576 both cite: two
Intloption bags for one concept, kept in step by nothing.What this card is NOT
⛔ Not a request to delete either function.
packages/i18n's formatter is a general locale-formatting helper with its own'short' | 'medium' | 'long' | 'full'vocabulary anddateStyle/timeStylepassthrough; core's is the field-display path behind cells, grid cards, gantt tooltips and dataset measures. They may both deserve to exist. The defect is that they are indistinguishable at the import site.Grading
Observation-class. Nothing is wrong on screen today: no in-repo call site reaches the i18n one at all —
grepfinds it only inpackages/react's re-export line, never called. The reusable half is the name collision across two published barrels, not a user-facing defect.