DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT <http://nagoya.apache.org/bugzilla/show_bug.cgi?id=18713>. ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND INSERTED IN THE BUG DATABASE.
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=18713 Please add format-date() to ExsltDatetime class Summary: Please add format-date() to ExsltDatetime class Product: XalanJ2 Version: 2.5Dx Platform: All OS/Version: All Status: NEW Severity: Enhancement Priority: Other Component: org.apache.xalan.lib AssignedTo: [EMAIL PROTECTED] ReportedBy: [EMAIL PROTECTED] I've coded the implementation as well as a test case for the format-date() function. Could you please let me know when this has been added to the next Xalan build. Feel free to email me any questions or comments <mailto:[EMAIL PROTECTED]> Add the following to ExsltDatetime (you'll also need to import the ava.util.TimeZone class). I haven't included the entire source code since it may have changed since and it's also quite big. <-------------- /** * The date:format-date function formats a date/time according to a pattern. * <p> * The first argument to date:format-date specifies the date/time to be * formatted. It must be right or left-truncated date/time strings in one of * the formats defined in * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>. * The permitted formats are as follows: * <ul> * <li>xs:dateTime (CCYY-MM-DDThh:mm:ss) * <li>xs:date (CCYY-MM-DD) * <li>xs:time (hh:mm:ss) * <li>xs:gYearMonth (CCYY-MM) * <li>xs:gYear (CCYY) * <li>xs:gMonthDay (--MM-DD) * <li>xs:gMonth (--MM--) * <li>xs:gDay (---DD) * </ul> * The second argument is a string that gives the format pattern used to * format the date. The format pattern must be in the syntax specified by * the JDK 1.1 SimpleDateFormat class. The format pattern string is * interpreted as described for the JDK 1.1 SimpleDateFormat class. * <p> * If the date/time format is right-truncated (i.e. in a format other than * xs:time, or xs:dateTime) then any missing components are assumed to be as * follows: if no month is specified, it is given a month of 01; if no day * is specified, it is given a day of 01; if no time is specified, it is * given a time of 00:00:00. * <p> * If the date/time format is left-truncated (i.e. xs:time, xs:gMonthDay, * xs:gMonth or xs:gDay) and the format pattern has a token that uses a * component that is missing from the date/time format used, then that token * is replaced with an empty string ('') within the result. * * @author Helg Bredow */ public static XString formatDate(String dateTime, String pattern) { final String yearSymbols = "Gy"; final String monthSymbols = "M"; final String daySymbols = "dDEFwW"; TimeZone timeZone; String zone; // Get the timezone information if it was supplied and modify the // dateTime so that SimpleDateFormat will understand it. if (dateTime.endsWith("Z") || dateTime.endsWith("z")) { timeZone = TimeZone.getTimeZone("GMT"); dateTime = dateTime.substring(0, dateTime.length()-1) + "GMT"; zone = "z"; } else if ((dateTime.length() >= 6) && (dateTime.charAt(dateTime.length()-3) == ':') && ((dateTime.charAt(dateTime.length()-6) == '+') || (dateTime.charAt(dateTime.length()-6) == '-'))) { String offset = dateTime.substring(dateTime.length()-6); if ("+00:00".equals(offset) || "-00:00".equals(offset)) { timeZone = TimeZone.getTimeZone("GMT"); } else { timeZone = TimeZone.getTimeZone("GMT" + offset); } zone = "z"; // Need to adjust it since SimpleDateFormat requires GMT+hh:mm but // we have +hh:mm. dateTime = dateTime.substring(0, dateTime.length()-6) + "GMT" + offset; } else { // Assume local time. timeZone = TimeZone.getDefault(); zone = ""; // Leave off the timezone since SimpleDateFormat will assume local // time if time zone is not included. } String[] formats = {dt + zone, d, gym, gy}; // Try the time format first. We need to do this to prevent // SimpleDateFormat from interpreting a time as a year. i.e we just need // to check if it's a time before we check it's a year. try { SimpleDateFormat inFormat = new SimpleDateFormat(t + zone); inFormat.setLenient(false); Date d= inFormat.parse(dateTime); SimpleDateFormat outFormat = new SimpleDateFormat(strip (yearSymbols + monthSymbols + daySymbols, pattern)); outFormat.setTimeZone(timeZone); return new XString(outFormat.format(d)); } catch (ParseException pe) { } // Try the right truncated formats. for (int i = 0; i < formats.length; i++) { try { SimpleDateFormat inFormat = new SimpleDateFormat(formats[i]); inFormat.setLenient(false); Date d = inFormat.parse(dateTime); SimpleDateFormat outFormat = new SimpleDateFormat(pattern); outFormat.setTimeZone(timeZone); return new XString(outFormat.format(d)); } catch (ParseException pe) { } } // Now try the left truncated ones. The Java format() function doesn't // return the correct strings in this case. We strip any pattern // symbols that shouldn't be output so that they are not defaulted to // inappropriate values in the output. try { SimpleDateFormat inFormat = new SimpleDateFormat(gmd); inFormat.setLenient(false); Date d = inFormat.parse(dateTime); SimpleDateFormat outFormat = new SimpleDateFormat(strip (yearSymbols, pattern)); outFormat.setTimeZone(timeZone); return new XString(outFormat.format(d)); } catch (ParseException pe) { } try { SimpleDateFormat inFormat = new SimpleDateFormat(gm); inFormat.setLenient(false); Date d = inFormat.parse(dateTime); SimpleDateFormat outFormat = new SimpleDateFormat(strip (yearSymbols, pattern)); outFormat.setTimeZone(timeZone); return new XString(outFormat.format(d)); } catch (ParseException pe) { } try { SimpleDateFormat inFormat = new SimpleDateFormat(gd); inFormat.setLenient(false); Date d = inFormat.parse(dateTime); SimpleDateFormat outFormat = new SimpleDateFormat(strip (yearSymbols + monthSymbols, pattern)); outFormat.setTimeZone(timeZone); return new XString(outFormat.format(d)); } catch (ParseException pe) { } return new XString(""); } /** * Strips occurrences of the given character from a date format pattern. * @param symbols list of symbols to strip. * @param pattern * @return */ private static String strip(String symbols, String pattern) { int quoteSemaphore = 0; int i = 0; StringBuffer result = new StringBuffer(pattern.length()); while (i < pattern.length()) { char ch = pattern.charAt(i); if (ch == '\'') { // Assume it's an openening quote so simply copy the quoted // text to the result. There is nothing to strip here. int endQuote = pattern.indexOf('\'', i + 1); if (endQuote == -1) { endQuote = pattern.length(); } result.append(pattern.substring(i, endQuote)); i = endQuote++; } else if (symbols.indexOf(ch) > -1) { // The char needs to be stripped. i++; } else { result.append(ch); i++; } } return result.toString(); } -----------> And heres a JUnit test case. <----------- package org.apache.xalan.lib; import java.util.TimeZone; import junit.framework.TestCase; import org.apache.xpath.objects.XString; public class ExsltDatetimeTest extends TestCase { public ExsltDatetimeTest(String s) { super(s); } protected void setUp() { } protected void tearDown() { } public void testFormatDate() { // Set the default time zone so that the test runs correctly in all // time zones. TimeZone.setDefault(TimeZone.getTimeZone("GMT+8:00")); // Try a bunch of valid date combinations. assertEquals(new XString("27 March 2003 14:22:12.0 GMT"), ExsltDatetime.formatDate("2003-03-27T14:22:12Z", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString("27 March 2003 14:22:12.0 GMT+08:00"), ExsltDatetime.formatDate("2003-03-27T14:22:12", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString("27 March 2003 14:22:12.0 GMT"), ExsltDatetime.formatDate("2003-03-27T14:22:12+00:00", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString("27 March 2003 14:22:12.0 GMT"), ExsltDatetime.formatDate("2003-03-27T14:22:12-00:00", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString("27 March 2003 14:22:12.0 GMT+02:00"), ExsltDatetime.formatDate("2003-03-27T14:22:12+02:00", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString("27 March 2003 14:22:12.0 GMT-01:30"), ExsltDatetime.formatDate("2003-03-27T14:22:12-01:30", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString("27 March 2003 00:00:00.0 GMT+08:00"), ExsltDatetime.formatDate("2003-03-27", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString("01 March 2003 00:00:00.0 GMT+08:00"), ExsltDatetime.formatDate("2003-03", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString("01 January 2003 00:00:00.0 GMT+08:00"), ExsltDatetime.formatDate("2003", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString("27 March 00:00:00.0 GMT+08:00"), ExsltDatetime.formatDate("--03-27", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString("01 March 00:00:00.0 GMT+08:00"), ExsltDatetime.formatDate("--03--", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString("27 00:00:00.0 GMT+08:00"), ExsltDatetime.formatDate("---27", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString(" 14:22:12.0 GMT+08:00"), ExsltDatetime.formatDate("14:22:12", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString("27 March 2003 HH:mm:ss.S GMT"), ExsltDatetime.formatDate("2003-03-27T14:22:12Z", "dd MMMM yyyy 'HH:mm:ss.S' z")); assertEquals(new XString("27 March 2003 HH:mm:ss.S 14:22 GMT"), ExsltDatetime.formatDate("2003-03-27T14:22:12Z", "dd MMMM yyyy 'HH:mm:ss.S' HH:mm z")); assertEquals(new XString("27 March 2003 '14:22:12.0"), ExsltDatetime.formatDate("2003-03-27T14:22:12Z", "dd MMMM yyyy ''HH:mm:ss.S")); // Try a few invalid ones. assertEquals(new XString(""), ExsltDatetime.formatDate("this is not even a date", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString("27 March 2003 HH:mm:ss.S"), ExsltDatetime.formatDate("2003-03-27T14:22:12Z", "dd MMMM yyyy 'HH:mm:ss.S")); assertEquals(new XString("dd MMMM yyyy HH:mm:ss.S z"), ExsltDatetime.formatDate("2003-03-27T14:22:12Z", "'dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString(""), ExsltDatetime.formatDate("2003-03- 27T14:22:12Z", "")); assertEquals(new XString(""), ExsltDatetime.formatDate("", "dd MMMM yyyy HH:mm:ss.S z")); assertEquals(new XString(""), ExsltDatetime.formatDate("", "")); // This test fails since SimpleDateFormat parses this as the year 0027 but // then there is no recommendation about what to do when the input is // invalid. At least it doesn't throw an exception. //assertEquals(new XString(""), ExsltDatetime.formatDate("27 March 2003 00:00:00.0", "dd MMMM yyyy HH:mm:ss.S z")); } } ----------->
