Baha'i Date Schema
The following is a Schematron schema to allow an unofficial scheme for the validation of Baha'i dates. The predictability of this schema could vary in the future, if a decision is made by the international governing body of the Baha'i Faith, the Universal House of Justice, as to the site for which Naw-Ruz, the new year, will be determined. At such a time, the beginning of the year will vary by one or two days, so it will not be as easy to detect the validity of dates which might change (in the first or last month, or intercalary days?). It is also certain whether the leap years will follow the current Gregorian calendar or not. Moreover, the representation of the separate intercalary days as being tagged on to the end of month 18 was simply for ease in calculation purposes.
Despite all of the above disclaimers, this should still ideally be helpful, and might offer an example of how dates or other attributes can be constrained depending on the value of multiple attributes, using Schematron.
<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2"> <ns prefix="tei" uri="http://www.tei-c.org/ns/1.0" /> <ns prefix="fn" uri="http://www.w3.org/2003/11/xpath-functions" /> <pattern id="Bahai_Date"> <rule context='tei:date[@calendar = "Baha'i"]'> <!-- Dates (allowable): (note: time is allowable on any of the following) [+-]YYYY (first +/- is optional; year can be of any length, but not start with 0; year one is 1844 A.D.) [+-]YYYY-MM (Baha'i months are 1-19 or 01-19) [+-]YYYY-MM-DD (Bahai' days are 1-19 or 01-19; intercalary days (Feb. 26 - March 1) are represented here as month 18, days 20-23 or 24, dependent on whether it is a leap year or not Time (allowable), set off by 'T' and then (note: all times allow a timezone): HH (hours are 00-23) HH:MM (minutes are 01-59) HH:MM:SS (seconds are 01-59) HH:MM:SS.s (fractional seconds are a period followed by any series of digits or no digit) Timezone (allowable): Z (UTC) [+-]HH (+ or - is required; hour offset from 01-14 per http://www.w3.org/TR/xmlschema-2/#dateTime-order) [+-]HH:MM (minute offset from 01-59) --> <let name="time" value="'T(([0-1][0-9])|(2[0-3]))(:[0-5][0-9](:[0-5][0-9](\.\d*)?)?)?'"/> <let name="time_zone" value="'(Z|[+-]((14)|(14:00)|(((0\d)|(1[0-3]))(:[0-5][0-9])?))?)?'"/> <let name="date" value="'^[+-]?([1-9]\d*)(-[0-1]?\d(-[0-1]?\d)?)?'"/> <let name="date_ayyamiha" value="'^[+-]?([1-9]\d*)-(18-2[0-4])'"/> <!-- Intercalary days, Feb. 26 - March 1 --> <let name="time_pattern" value="concat( '(', $time, $time_zone, ')?' )"/> <let name="pattern" value="concat($date, $time_pattern, '$')" /> <let name="pattern_ayyamiha" value="concat($date_ayyamiha, $time_pattern, '$')" /> <let name="bbe" value="number(matches(@when, '^-'))" /> <!-- Before "Baha'i Era" - i.e., a negative date --> <let name="year" value="number(replace(@when, $pattern, '$1'))" /> <let name="ayyamiha_leap" value="number(replace(@when, $pattern_ayyamiha, '$1'))" /> <let name="leap400" value='((($year - 1 + $bbe) mod 400) = 0) or ((($ayyamiha_leap - 1 + $bbe) mod 400) = 0)'/> <let name="nonleap100" value='((($year - 1 + $bbe) mod 100) = 0) or ((($ayyamiha_leap - 1 + $bbe) mod 100) = 0)'/> <let name="leap4" value='((($year - 1 + $bbe) mod 4) = 0) or ((($ayyamiha_leap - 1 + $bbe) mod 4) = 0)'/> <assert test="$leap400 or (not($nonleap100) and $leap4)">Such a date is only available in a leap year.</assert> <!-- Avoids year 0, but can't have year begin with a '0' either --> <assert test='matches(@when, $pattern) or matches(@when, $pattern_ayyamiha)'>The date's "when" attribute is not a correct Baha'i date.</assert> </rule> </pattern> </schema>