FeaturesSecurityPricingCompareDevelopersBlogStart Free
BlogAugust 4, 2026

Arabic, Hijri and right-to-left grids in a data room

One Saudi budget sheet, rendered by three engines. LibreOffice prints the calendar modifier as literal text, the widely used ssf library puts a US dollar sign on a Saudi number, and both are wrong in ways a reader cannot see.

Method

A fixture workbook holds the same date serial, 45662, in three cells with three different format codes, plus two numeric cells carrying the Saudi locale tag. The serial corresponds to 5 January 2025 in the 1900 epoch, and the correct Umm al-Qura answer is 05/07/1446.

Three engines read the same file:

  1. ssf 0.11.2, the format engine most JavaScript spreadsheet tooling uses, called directly with the code and the value.
  2. LibreOffice 26.2.1.2, converted headless to both HTML and PDF. Its HTML export records the number format it resolved for each cell, so its failures are visible rather than inferred.
  3. The Sifrsys viewer, rendered in headless Chromium, with the display strings read back from the live DOM.

The reference for the date is not any of the three. It is Intl.DateTimeFormat with the islamic-umalqura calendar, which is the ICU implementation of the calendar in civil use in Saudi Arabia. That choice matters, because ICU also ships islamic-tbla, the arithmetic tabular calendar, and the two disagree.

Reproducing it

Two lines are enough to see the calendars diverge, in any recent Node or browser console:

const d = new Date(Date.UTC(2025, 0, 5))
const f = (cal) => new Intl.DateTimeFormat(`en-u-ca-${cal}-nu-latn`,
  { day: 'numeric', month: 'numeric', year: 'numeric', timeZone: 'UTC' }).format(d)
f('islamic-umalqura')  // 7/5/1446   -> 05/07/1446
f('islamic-tbla')      // 7/6/1446   -> 06/07/1446

For the full three-engine comparison, node tests/fidelity/run.mjs renders both sides and scores the Saudi cells against the specification rather than against LibreOffice. Its LibreOffice output is cached under tests/fidelity/.cache/, so the resolved format codes can be read directly out of the exported HTML.

Results

Same value, same format code, three engines. Serial 45662 is 5 January 2025; the correct Umm al-Qura date is 05/07/1446.
Criterionssf 0.11.2LibreOffice 26.2Sifrsys
B2dd/mm/yyyyHijri via the B2 calendar modifier05/01/1444B205/01/202505/07/1446
[$-060401]dd/mm/yyyyHijri via the ar-SA locale tag05/01/202506/07/144605/07/1446
[$-2060401]dd/mm/yyyyHijri plus Arabic-Indic digits05/01/2025not applied٠٥/٠٧/١٤٤٦
[$-2060401]#,##0.00Saudi locale, native digits, no symbol$45,231,000.0045231000٤٥٬٢٣١٬٠٠٠٫٠٠
[$-2060401]#,##0Same, integer$14,131,00014131000١٤٬١٣١٬٠٠٠
[$ر.س-401]#,##0.00Control: a real currency symbolر.س45,231,000.00correctر.س45,231,000.00
0.0%Control: a code every engine gets right62.3%correct62.3%
Same value, same format code, three engines. Serial 45662 is 5 January 2025; the correct Umm al-Qura date is 05/07/1446.

Four failures are worth naming individually, because each has a different cause.

The dollar sign. [$-2060401] carries no currency symbol at all. The $ is the delimiter that opens the locale token, and ssf reads a bare tag as a currency, so a Saudi figure comes back with a US dollar sign in front of it. We shipped that defect ourselves before we found it. The fix rewrites the format string before the engine sees it: a locale token that carries no symbol is removed, and a real one such as [$ر.س-401] is preserved as a literal.

The literal B2. LibreOffice does not honour the B2 modifier and prints the two characters as text in front of a Gregorian date, producing B205/01/2025in a cell whose column header reads "Hijri date".

The one-day error. Where LibreOffice does recognise the Hijri request, it rewrites the code into its own [$-401][~hijri] dialect and renders 06/07/1446. Its Islamic calendar is the tabular algorithm, not Umm al-Qura, so it is a day out. Locale environment, profile locale and alternate format spellings were all tried and none moved it.

The silent drop. For the two Arabic-Indic numeric cells, LibreOffice records the format as 1033;, which is the en-US locale and no format code, and prints the raw underlying number. The most dangerous of the four, because nothing on screen suggests a format was ever requested.

05/07/1446
Umm al-Qura, the civil calendar
ICU islamic-umalqura
06/07/1446
Tabular Hijri, one day later
ICU islamic-tbla
579 years
Error when the calendar byte is ignored
Gregorian rendered as if Hijri
LibreOffice PDF export of an Arabic budget sheet. The Hijri date column shows B205/01/2025 on two rows and 06/07/1446 on two others, and two cells lower down show unformatted numbers 45231000 and 14131000.
LibreOffice 26.2.1.2, PDF export at 150 DPI. Two rows show the B2 modifier printed as literal text, two show tabular Hijri a day late, and the Arabic-Indic cells lost their format entirely.
The Sifrsys spreadsheet viewer showing the same Arabic budget sheet with right-to-left column order, Hijri dates rendered as 05/07/1446, and numbers in Arabic-Indic digits.
The same file in the Sifrsys viewer, captured by the fidelity run. Column order runs right to left, every Hijri cell reads 05/07/1446, and the Arabic-Indic cells render as ٤٥٬٢٣١٬٠٠٠٫٠٠ and ١٤٬١٣١٬٠٠٠.

Right-to-left is not a font choice

Direction is a sheet property in the file, sheetView rightToLeft, and it changes four separate things. Column order reverses, so column A sits at the right edge. Frozen panes pin to the right rather than the left. Horizontal scroll offsets run negative in the browser, which means every scroll calculation needs its sign flipped. Data bar gradients fill in the other direction. The direction attribute goes on the table and deliberately not on the scrolling container, because normalising the scroll arithmetic in code and flipping the container as well would cancel out. The formula inspector is forced back to left-to-right, since a cell reference is not an Arabic phrase.

Everything above came out of the same run described in the fidelity test, where the Saudi format cells are scored against the specification precisely because the obvious reference gets them wrong.

Related: The spreadsheet fidelity test · What a citation has to point at · How we test our own data room · Pricing

Arabic, Hijri and RTL rendering are part of the viewer on every tier, with no per-page fees. See pricing.

FAQ

Questions about Arabic and Hijri rendering.

Umm al-Qura is the calendar in civil use in Saudi Arabia, based on published astronomical tables. Tabular Hijri is an arithmetic rule that inserts leap days on a fixed 30-year cycle. They agree most of the time and disagree by a day often enough to matter: for 5 January 2025, Umm al-Qura gives 5 Rajab 1446 and the tabular calendar gives 6 Rajab 1446. On a document with a filing deadline, one day is the whole question.
Because the calendar is requested through a format code most rendering libraries only partly understand. Excel writes either a B2 prefix or a locale tag whose middle byte carries a calendar id. A library that reads the tag as a currency locale, or ignores the calendar byte, renders a Gregorian date that looks perfectly plausible and is wrong by roughly 579 years.
It is a hexadecimal DWORD laid out as 0xNNCCLLLL. The low word 0401 is the ar-SA locale, the calendar byte 06 selects Hijri, and the leading 2 selects native digits, meaning Arabic-Indic. So the code asks for a Saudi Hijri date or number rendered in Arabic-Indic digits, and it carries no currency symbol at all.
Right-to-left is a sheet-level property in the file, not a language guess. It reverses the column order, moves the frozen-pane origin to the right edge, flips data bar gradients, and makes horizontal scroll offsets negative. A viewer that converts the workbook to an image inherits whatever its converter decided; a viewer that renders the grid has to implement each of those.
Start Free