A date MUST be formatted YYYY-MM-DD, in accordance to the "Calendar date complete representation" as specified by ISO 8601:2004, format YYYY-MM-DD.
What does this mean?
The rule is about the shape, not the value: the issue date (BT-2) in cbc:IssueDate, the supply date (KSA-5) in cac:Delivery/cbc:ActualDeliveryDate and the latest supply date (KSA-24) in cbc:LatestDeliveryDate are all written in the ISO 8601 «calendar date complete representation»: 2026-09-22. Four digits for the year, a hyphen, two digits for the month, a hyphen, two digits for the day. Nothing before it and nothing after it.
Three things look like dates and are not in that shape: a date with its time (2026-09-22T10:15:00Z), because the time has its own field, KSA-25, and its own rule, BR-KSA-70; a date without zero padding (2026-9-2), because month and day are always two digits; and a date with a time zone (2026-09-22+03:00), because a calendar date is bare. And the plainer cases: 22/09/2026, 09/22/2026, 22-09-2026 and Sep 22, 2026 are all outside the rule even when the day is right.
The calendar is Gregorian. A Hijri date in the same shape — 1448-04-10 — passes the format check, being four digits, two and two, and is then read as the year 1448 of the common era: a document dated six centuries ago. No rule in the list we index catches that; BR-KSA-04 rejects the future only and the past goes through. This code guards the shape; what lies between the shape and the truth is yours.
It is a warning: the invoice is accepted and the warning recorded with it. The cost is that the date is a field with consequences: it places the invoice in its tax period, it starts the reporting deadline on a simplified invoice, and the QR code's stamp is built from it. A date that is not read the same way by every party is a date that will be disputed.
Why does it happen?
Ordered from the most common to the least — your cause is most likely the first or the second.
-
JavaScript's default formatting:
new Date().toString()givesTue Sep 22 2026 10:15:00 GMT+0300, andtoLocaleDateString()gives9/22/2026on an English machine — and on one set toar-SA, a Hijri date in Arabic-Indic digits with invisible direction marks between its parts. By far the most common cause in web integrations. -
toISOString()and then the first ten characters: it looks like the right trick and is two traps. Uncut, it carries the time and aZ; cut, it gives the UTC date rather than the Riyadh one, so from midnight to three in the morning it produces yesterday — and yesterday passes BR-KSA-04 silently, and on the first of the month lands in the wrong VAT return. - The Hijri calendar: an accounting system running on the Umm al-Qura calendar, or a user who typed a Hijri date into the date field, comes out in ISO shape and is read as Gregorian.
-
Regional settings in Windows or Excel:
22/09/2026from a worksheet, or the date's serial number (46287) when a CSV is read without formatting. -
Other languages' defaults:
date('d/m/Y')in PHP,DateTime.Now.ToString()in .NET under the machine's culture, and Python'sstr(date.today()), which happens to be right whilestr(datetime.now())carries the time. -
A free-text field on the form with no check, or an invisible character in the value: a trailing space, or a direction mark
U+200Ethat locale formatting plants between the digits where the eye cannot see it.
How to fix it
4 steps, then send the invoice again.
-
1
Build the date from its parts, not from the default formatter
In JavaScript:
`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`from a local date object. In PHP:$date->format('Y-m-d'). In .NET:ToString("yyyy-MM-dd", CultureInfo.InvariantCulture). In Python:strftime('%Y-%m-%d'). The general rule: an explicit format spelled out in letters, never one that depends on the machine's locale. -
2
Compute the day in Riyadh time, then format it
Time zone first, formatting second: move the instant to
Asia/Riyadhand take the year, month and day from there. The reverse order — format in UTC, then send — gives a correct shape for the wrong day. The time that goes with the date is taken from the same instant; see BR-KSA-70. -
3
Gregorian in the XML, Hijri for the reader if you wish
If your system runs on the Hijri calendar, convert at the source with the Umm al-Qura tables to Gregorian before the document is built, and never send a Hijri triple dressed as ISO. A Hijri date has its place printed on the PDF beside the Gregorian one if your customers want it; the XML is Gregorian only.
-
4
Check the shape before signing
Before the invoice is signed, test every date with an expression that matches the shape letter by letter —
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$— then confirm it is a real calendar day (no 31 February) and that its year is a year of this era. A check on your side prevents the warning on every invoice instead of reading it in the response after signing.
This code does not block acceptance, so the invoice you have is compliant. Correct the data so the warnings disappear from future invoices.
Does ZATCA Tools prevent it?
Yes on every path, with two limits. A date is never written into the XML except from a date object formatted at the moment of sending in the correct shape — the issue date and the supply date alike — and the default day is computed in Riyadh time on the server, not in UTC and not on the user's device. The date field on the invoice form is our own, Gregorian, and carries its value as a YYYY-MM-DD string and nothing else, after the native field on a machine set to ar-SA answered in Hijri. The API reads issue_date as it arrives: what it cannot read fails the request before any document is built, and what it can read is rewritten in the correct shape. The two limits are the sender's: 09/10/2026 is read the American way and becomes the tenth of September, not the ninth of October, and a Hijri date in ISO shape such as 1448-04-10 passes with us as it passes with the Authority, as a Gregorian date.
Related codes
Frequently asked questions
Was my invoice rejected because of this code? +
errorMessages; on the date specifically, see BR-KSA-04 if it lies in the future and BR-KSA-70 if the time is what is missing. How to read the response is in ZATCA error codes explained.May I put the Hijri date on the invoice? +
I sent 2026-09-22T00:00:00 and got the warning. Is that not ISO 8601? +
hh:mm:ss, with its own rule, BR-KSA-70.My system runs on UTC. Should I change the server's time zone? +
Asia/Riyadh, then read the date and the time from it together. Changing the whole server's zone fixes this and breaks other things.Does the rule cover the supply date and the original invoice's date on a note? +
ZATCA Tools builds the signature, the PIH, the counter and the encoding for you, and validates your data before it is sent. Start free, with no credit card.
Start for free