Patterns using date and time forms
1. | Standard XSD date and time pattern |
For those who aren't aware, it looks as shown below, and is defined at W3C. From that document, the definition is This lexical representation is the [ISO 8601] extended format CCYY-MM-DDThh:mm:ss where "CC" represents the century, "YY" the year, "MM" the month and "DD" the day, preceded by an optional leading "-" sign to indicate a negative number. If the sign is omitted, "+" is assumed. The letter "T" is the date/time separator and "hh", "mm", "ss" represent hour, minute and second respectively. Additional digits can be used to increase the precision of fractional seconds if desired i.e the format ss.ss... with any number of digits after the decimal point is supported. The fractional seconds part is optional; other parts of the lexical form are not optional. An example is easier to understand.
2003-05-31T13:20:05.50-05:00
which represents 31 May 2003, at 13:20, 5 hours behind UTC.
The pattern for this is shown below
<element name="startTime">
<data type="dateTime"
datatypeLibrary=
"http://www.w3.org/2001/XMLSchema-datatypes"/>
</element>
Note the definition of the datatype library from which this comes. | |
2. | Other date forms |
For more local use, it may be necessary to generate a pattern for a specified date and time class. For instance:
<mdate>Mon Jul 30 12:01:34 +05:00</mdate>
This is a more straightforward usage with the pattern below.
<element name="mdate">
<list>
<ref name="Dow"/>
<ref name="Month"/>
<ref name="Dom"/>
<ref name="Time"/>
<ref name="Tz"/>
</list>
</element>
Each item is defined separately, for possible future use. <define name="Dow"> <choice> <value>Mon</value> <value>Tue</value> <value>Wed</value> <value>Thu</value> <value>Fri</value> <value>Sat</value> <value>Sun</value> </choice> </define> <define name="Month"> <choice> <value>Jan</value> <value>Feb</value> <value>Mar</value> <value>Apr</value> <value>May</value> <value>Jun</value> <value>Jul</value> <value>Aug</value> <value>Sep</value> <value>Oct</value> <value>Nov</value> <value>Dec</value> </choice> </define> <define name="Dom"> <data type="integer"> <param name="minInclusive">1</param> <param name="maxInclusive">31</param> </data> </define> <define name="Time"> <data type="time"/> </define> The days of the week are straightforward, as are the months of the year, and the Day of the month, and integer between 1 and 31.
<define name="Tz">
<data type="string">
<param name="pattern">[+\-]?[0-9]{2}:[0-9]{2}</param>
</data>
</define>
The Timezone is built up from a regexp, with an optional plus or minus The overall result has a couple of weaknesses, not least that no validation is done to stop a date of Feb 31 etc. Whitespace is allowed between the tokens without penaltly, by means of the list pattern. Further validation would of course by possible using a Schematron insertion. | |
3. | Date validation, optional Z terminator |
<!-- 2001-10-26T21:32:52Z -->
<element name="modified">
<data type="dateTime">
<param name="minInclusive">2000-01-01T00:00:00</param>
<param name="maxInclusive">2099-12-31T23:59:59</param>
<param
name="pattern">.*T[^+\-]*</param>
</data>
</element>
which blocks the offset option as needed, and allows an optional Z which is what is needed | |
4. | ISO date format in Java |
Here is some code I use in standard Java. You might also check out http://joda-time.sourceforge.net/
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class Now {
public static void main(String[] args) {
System.out.println(Now.getISO8601DateTime());
}
public static String getISO8601DateTime() {
SimpleDateFormat ISO8601Local = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss");
TimeZone timeZone = TimeZone.getDefault();
ISO8601Local.setTimeZone(timeZone);
DecimalFormat twoDigits = new DecimalFormat("00");
Date now = new Date();
int offset = ISO8601Local.getTimeZone().getOffset(now.getTime());
String sign = "+";
if (offset < 0) {
offset = -offset;
sign = "-";
}
int hours = offset / 3600000;
int minutes = (offset - hours * 3600000) / 60000;
// As things stand any odd seconds in the offset are silently truncated.
// Uncomment the next 5 lines to detect that rare circumstance.
//if (offset != hours * 3600000 + minutes * 60000) {
// // E.g. TZ=Asia/Riyadh87
// throw new RuntimeException("TimeZone offset (" + sign + offset +
// " ms) is not an exact number of minutes");
//}
String ISO8601Now = ISO8601Local.format(now) + sign +
twoDigits.format(hours) + ":" + twoDigits.format(minutes);
return ISO8601Now;
}
}
|