Dates and times inside RTL interfaces
Learn which date and time formats reorder in Arabic text and how to handle locale, calendars, time zones and ranges without changing their meaning.
By Omran Khleifat, Founder of Ritla
Guide13 min read
An observatory booking summary shows a slash-separated date and a clock time correctly, then reverses the groups of an ISO-style date copied from the API. Another view shows the right characters but the wrong calendar day because it formats the booking in the viewer's time zone instead of the venue's.
Those are different defects. Direction controls how text is arranged. Locale controls the displayed date and time pattern. Calendar, digit system and time zone describe additional choices that cannot be repaired by moving characters.
Start by establishing the booking's intended date, time and zone. Then compare the stored value, formatted string and browser rendering. A readable Arabic schedule needs all three to agree; a date looking familiar in an English editor is insufficient evidence.
Slash dates and colon times already stay together#
These observatory fixtures do not need a reversal workaround:
<p lang="ar" dir="rtl">تاريخ الزيارة: 23/08/2034</p><p lang="ar" dir="rtl">بداية الزيارة: 22:52</p>The date displays as 23/08/2034, and the clock time as 22:52. The slash and colon preserve these numeric groups in their written order after Arabic text. Do not reverse the source groups because the paragraph is RTL.
These browser patterns were measured in Chromium 151 on September 24, 2026. Firefox and Safari were not included in those measurements, so verify the fixtures in your supported browsers.
Keeping the sequence intact does not establish that its format is appropriate. The slash date above explicitly means day, month and year. A different field order can be wrong for the interface even when every character appears exactly where it was typed.
Use a day above twelve when checking field order, as this fixture does. It prevents a month/day ambiguity from concealing a wrong formatter setting. Also test a date whose day could be mistaken for a month when reviewing the product's actual acceptance criteria.
Do not make every successful date display LTR as a reflex. A value boundary can still be useful for reusable components, but first distinguish a convention choice from a demonstrated rendering failure.
Hyphenated date groups need an explicit contract#
An API's ISO-style date has a fixed year-month-day sequence. Placing that literal after an Arabic label exposes a different separator behavior:
Problem
<p lang="ar" dir="rtl">التاريخ المسجل: 2034-08-23</p>Its displayed numeric sequence becomes 23-08-2034. The browser has not changed the stored string, but the display no longer preserves the API notation's year-first sequence.
Preserve the technical notation
<p lang="ar" dir="rtl"> التاريخ المسجل: <span dir="ltr">2034-08-23</span></p>The isolated technical date displays as 2034-08-23. A plain span without a direction declaration would not isolate it. With no preceding Arabic in the same paragraph, hyphenated numeric groups can also appear intact, so a passing bare table cell does not establish that the labelled summary works.
This fix preserves a technical format. For customer-facing booking copy, a localized date may be a better choice. Do not assume that every view should display the API serialization simply because isolation can keep it in order.
Keep the machine value and the display value separate. Never rewrite the stored date groups to compensate for one paragraph's visual order. The next English page, export or parser would then receive the modified sequence.
Locale, calendar, digits and zone answer different questions#
The observatory chooses Arabic presentation, the Gregorian calendar, Western digits and venue-local time for its booking summary. Those choices form a display policy:
| Choice | What it controls |
|---|---|
| Locale | Date and time patterns, month names and other localized text |
| Calendar | The calendar used to derive year, month and day |
| Numbering system | The digits used in the formatted value |
| Time zone | The local date and clock time representing the instant |
| Hour cycle | The selected twelve-hour or twenty-four-hour convention |
| Direction | The formatted text's interaction with its surroundings |
Arabic does not automatically mean a Hijri calendar, Arabic-Indic digits or a particular time zone. Locale defaults depend on runtime data. If a choice is part of the booking contract, request it explicitly and inspect what the formatter selected.
Changing digit glyphs does not change the calendar. Changing the calendar does not move the booking to another instant. Changing the display zone can change the local day as well as the hour. Treat these as separate controls in the implementation and the test fixture.
The DateTimeFormat constructor reference documents these options. The product still needs to choose them: the browser cannot determine whether an observatory ticket should show venue time or the visitor's home time.
Format the booking with an explicit venue time zone#
The API supplies an instant with a UTC designator. This example formats it under the observatory's stated policy:
<p lang="ar" dir="rtl"> موعد الزيارة: <time id="visit-start" dir="auto"></time></p>Run this JavaScript after the markup:
const visitStart = new Date("2034-08-23T18:52:00Z");const venueTimeZone = "Asia/Dubai"; const visitFormatter = new Intl.DateTimeFormat("ar-AE", { calendar: "gregory", numberingSystem: "latn", timeZone: venueTimeZone, dateStyle: "long", timeStyle: "short", hourCycle: "h23"}); const visitOutput = document.getElementById("visit-start");if (!visitOutput) throw new Error("Visit start element is missing");visitOutput.dateTime = visitStart.toISOString();visitOutput.textContent = visitFormatter.format(visitStart);In a formatter inspection using Node 24.16.0 with ICU 78.3, this fixture produced August 23, 2034 at 22:52 in Arabic wording. That establishes the runtime's formatted fields, not a browser visual test. Review the complete string in the actual booking layout.
The Arabic label stays outside the automatically directed value. The complete formatted date and time stay together, including localized words and literals. Do not isolate each digit group independently or reconstruct their order from the English interface.
The time element keeps a machine-readable datetime value separate from its visible content. In this example, the attribute identifies the UTC instant while the displayed text uses the venue zone. The attribute does not format the text or establish its direction by itself.
The sample instant is a controlled fixture. A production component also needs the API's validation contract and a distinct unavailable state for missing or invalid timestamps. Do not substitute the current time when booking data is absent.
Decide whether the data is an instant or a calendar date#
A scheduled visit start can identify an instant. A selected visit date can instead be a calendar date without an associated clock time. An opening time repeated each day can be a local wall-clock rule rather than one particular instant.
Do not make those representations interchangeable because they all look like dates in the interface. JavaScript Date represents an instant; its local interpretation depends on the zone used to inspect or format it.
A date-only ISO string passed to Date is interpreted using UTC midnight. Formatting that instant in another zone can produce a different local day. That may be correct for an instant but wrong for a date-only booking field. Preserve the intended date semantics instead of fixing the displayed day afterward with string manipulation.
Likewise, an offset-free local date-time needs a defined zone before it can identify a venue instant. Do not let the viewer's device silently supply that missing business context.
If the product supports recurring schedules or venues with clock changes, define how ambiguous or nonexistent local times are resolved. That belongs to the scheduling model. Bidi isolation can preserve the characters of an incorrect appointment just as neatly as a correct one.
Venue time and viewer time can fall on different days#
For the visit fixture, the formatter inspection produces these local fields from the same instant:
| Display zone | Calendar date | Clock time |
|---|---|---|
| UTC | 2034-08-23 | 18:52 |
| Asia/Dubai | 2034-08-23 | 22:52 |
| Asia/Tokyo | 2034-08-24 | 03:52 |
The visitor-local version can therefore show the next calendar day without any character reordering. Comparing screenshots by their day number alone would misdiagnose the difference. Compare the instant and the selected zone first.
For an on-site observatory visit, the product may choose venue time throughout booking and confirmation. If it additionally shows viewer time, label the two representations so the visitor can tell which date governs entry. Do not silently switch policies between the schedule list and the confirmation screen.
Language and zone should remain independently selectable in the implementation. An Arabic-speaking visitor can be in Tokyo, and an English-speaking visitor can be at the venue. Selecting an Arabic locale does not select the visitor's location.
Use this cross-day fixture when testing another device zone. It exposes a default-zone call that a midday fixture could conceal. Check both the clock and the date in summaries, reminders and detail views that present the booking. Those surfaces may use different rendering paths even when they share the same stored instant.
If an interface offers a zone toggle, changing it should change the representation while preserving the booking instant and product identity. Confirm that toggling back restores the venue fields rather than saving the viewer-local display string over the original record.
Make the selected calendar part of the date contract#
The sample deliberately requests calendar: "gregory". A product that offers another calendar needs a corresponding policy for its labels, controls and interpretation of numeric dates. Changing the calendar is not a decorative digit substitution.
When two calendar representations are shown, label them and derive both from the same intended date or instant under the product's data model. Do not copy the displayed year, month and day from one calendar into a parser that assumes the other. Those fields can describe different civil dates.
Keep calendar-specific expectations in the fixture. The assertion that this visit has day twenty-three in August belongs to the Gregorian display policy. It is not a test that every alternate-calendar label should repeat the same visible fields.
Also distinguish the calendar used by a browser's date-picker interface from the format of a read-only label generated with Intl.DateTimeFormat. Configuring the latter does not configure every native input's calendar presentation. Test the picker and the rendered summary independently, comparing the selected underlying date after submission.
If the product supports only Gregorian booking dates, state that in the content where ambiguity matters and preserve it through language changes. Do not assume an Arabic route implies a calendar switch that the booking system never requested.
Use localized month names and day periods#
An Arabic booking page can accidentally show English month names when a server or client formatter uses its default locale. Adding dir="rtl" to that output changes its layout, not its language.
Use the selected Arabic locale to generate the visible date. Avoid hard-coded arrays of English month names or a string template that appends an English day-period marker to an otherwise localized clock.
For twelve-hour presentation, keep the hour, minute and localized day period as one formatted value. A day-period marker is not an independent badge to position on whichever side looks familiar. Inspect the exact string and its wrapper in the browser, including punctuation and any spacing supplied by the formatter.
For the observatory's twenty-four-hour convention, hourCycle: "h23" expresses the selected cycle. Do not add a conflicting hour12 option: it takes precedence over hourCycle. Check the resolved settings instead of inferring the cycle from one evening-time screenshot.
Test times around midday and midnight as well as the visit fixture. A period label that seems redundant in an evening sample can be necessary to distinguish morning from evening in a twelve-hour display.
If an English date or time phrase is intentionally quoted inside Arabic copy, give that complete phrase appropriate language and direction metadata. That is a deliberate foreign-language value, distinct from an accidentally untranslated booking date.
A time range is a reading sequence, not an identifier#
The observatory visit runs from 22:52 to 23:37. A compact range contains two clock values and a relationship between them. Its correctness cannot be decided solely by which endpoint appears at the physical left edge.
An Arabic reader starting from the right can encounter the start time first even when the endpoints occupy the opposite physical order from an English range. Do not call that arrangement corrupted merely because it differs from an LTR screenshot. An identifier's groups have fixed order; a range has start and end semantics.
For a verbose Arabic booking summary, make those semantics explicit:
<p lang="ar" dir="rtl"> تبدأ الزيارة عند <span dir="ltr">22:52</span> وتنتهي عند <span dir="ltr">23:37</span>.</p>For a compact technical display that intentionally uses an LTR range, wrap the complete range. Do not isolate the endpoints separately while leaving their separator to establish an unintended context.
Test the exact range string and the intended reading with an Arabic reviewer. Numeric separators, localized words and day-period labels make ranges more complex than a single colon time. Do not predict every combination from the behavior of one unsigned clock value.
Let range formatting own shared fields#
If the design calls for a localized compact interval, use the formatter's range facility instead of joining two independently shortened strings:
const visitEnd = new Date("2034-08-23T19:37:00Z");const clockFormatter = new Intl.DateTimeFormat("ar-AE", { calendar: "gregory", numberingSystem: "latn", timeZone: venueTimeZone, hour: "2-digit", minute: "2-digit", hourCycle: "h23"}); const clockRange = clockFormatter.formatRange(visitStart, visitEnd);console.log(clockRange);Run this after the previous JavaScript example. In the inspected runtime, the resulting string was 22:52–23:37. Review its direction when inserted into the Arabic summary; the console's text preview does not establish that result's visual reading there.
formatRange() can collapse shared fields according to the locale and selected precision. Keep its complete result, including separator and literals. Do not assume it always repeats every date or day-period label.
Do not assume that requesting clock fields means formatRange() will always return only clocks. In the inspected runtime, extending this fixture past venue midnight caused the same formatter to include dates as well as times. The formatter can add context needed to distinguish the endpoints.
For an overnight visit, verify that the displayed interval communicates the change of date. Use a reviewed date-and-time range or explicit date labels where the compact output is unclear. Test intervals spanning midday, midnight, a month boundary and a year boundary where the product permits them.
This pattern expansion also matters to layout. A compact same-day range may fit in a schedule column, while its overnight counterpart needs much more space. Keep all generated context available instead of deleting the added dates to recover the shorter width. Check the complete interval in the mobile card and its full-detail presentation.
Validate that the end instant follows the start under the booking contract. Swapping the endpoints to make a visual range look familiar changes the interval rather than fixing its presentation.
Inspect parts before rebuilding a date label#
Designs sometimes style the date and clock fields differently. Use formatter parts when that is necessary, while keeping the locale's sequence and literal characters:
const visitParts = visitFormatter.formatToParts(visitStart);console.table(visitParts);This snippet uses the formatter and instant defined earlier. formatToParts() exposes fields such as year, month, day, hour and literal text. Preserve the parts in their original order rather than selecting the numeric fields and concatenating them under an English template.
Literal parts can include punctuation, spacing or direction-related characters. Treat them as formatter output, not debris to remove. If multiple spans are required for styling, keep one outer boundary around the complete displayed date or date-time.
Do not assume that Western digits imply English wording. The observatory fixture deliberately combines Arabic date text with the latn numbering system. A different approved policy can use Arabic-Indic digits without changing the event's calendar or zone.
Inspect resolvedOptions() when the rendered fields disagree with expectations. Compare locale, calendar, numbering system, zone and hour cycle before trying to move individual spans with CSS.
Tables and tooltips need the same date policy#
A schedule table may show a time alone on desktop and add an Arabic label when it becomes a mobile card. Preserve each value's boundary during that conversion. A technical hyphenated date can otherwise look correct in a bare cell and reorder in the labelled card.
Keep the table's Arabic headings and row reading order independent from the internal direction of each date value. Making the entire table LTR to stabilize a few timestamps also changes the presentation of the surrounding Arabic structure.
Tooltips deserve separate inspection because they often use another formatting path. A localized visible date can still have an English tooltip generated by a default-locale call. Compare the tooltip's calendar date, clock, zone and wording with the visible value.
An HTML tooltip can contain a complete formatted value with its own direction metadata. A native title attribute is plain text; it cannot contain a working span or time element. Do not paste markup into the attribute and expect the same boundary as the visible label. Review its exact text and behavior in supported browsers, or use a suitable accessible HTML description when the information is important.
If a compact cell omits the zone or end date, make the full meaning available through an appropriate detail view. Do not make a hover-only tooltip the sole explanation of which day a visitor has booked.
Date inputs have a display format and a submitted value#
A date-selection control does not submit the same localized text that a person sees. For a date-only visit selection:
<form lang="ar" dir="rtl"> <label for="visit-date">تاريخ الزيارة</label> <input id="visit-date" name="visitDate" type="date" value="2034-08-23"> <button type="submit">عرض المواعيد</button></form>The date-input reference distinguishes its normalized year-month-day value from its browser-dependent visible format. Test both selection behavior and the submitted value. Do not infer the field's displayed format from the attribute's literal order.
For a date-time editor, datetime-local does not include a time zone in its value. The application must associate the local value with the intended venue or user zone under its scheduling rules.
Keep persistent Arabic labels and explain the chosen zone where it matters. Keyboard entry, calendar popovers, hour controls and mobile presentation need testing in supported browsers. A correct read-only summary does not establish that the input control behaves the same way.
Validate missing input separately from a real date. Do not parse a locale-formatted display string back through Date as though it were the control's normalized machine value.
Verify fields, time zone and visible order separately#
Test the booking fixture on a device configured outside the venue zone. The venue-time summary should continue to use its declared policy. If the product intentionally offers viewer-local time, label that choice and test the corresponding date as well as the clock.
Compare server-rendered and client-updated labels under the same explicit settings. Record runtime differences when strings disagree; locale and zone data can vary between environments. Explicit options document the policy without guaranteeing identical locale data in every runtime.
Keep formatter assertions and visual checks distinct. Parts can establish the date, clock and calendar fields. DOM text can establish that the rendered string matches the formatter. Neither proves which sequence an Arabic reader sees or how an interval reads.
Include a narrow schedule row and a long localized date at supported zoom settings. A clipped day period or hidden end date can change the meaning even when bidi order is correct. Reveal the complete value before diagnosing reordering.
For the release fixture set, include a slash date, a hyphenated technical date after Arabic text, a localized month-name date, a twelve-hour value, an interval crossing midnight and a missing timestamp. Confirm the underlying booking identity and instants while reviewing each display context.
A free Ritla scan can report : English month/day names or MM/DD/YYYY dates in Arabic text. Calendar choice, time-zone conversion and the intended reading of a range still need the targeted checks above. Continue with Arabic localization testing for date acceptance criteria or bidi isolation in HTML when a date component loses its boundary.