You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by dl...@apache.org on 2002/06/05 18:14:43 UTC

cvs commit: xml-xalan/java/src/org/apache/xalan/lib ExsltDatetime.java

dleslie     2002/06/05 09:14:43

  Added:       java/src/org/apache/xalan/lib ExsltDatetime.java
  Log:
  Core EXSLT dates-and-times functions.
  
  Revision  Changes    Path
  1.1                  xml-xalan/java/src/org/apache/xalan/lib/ExsltDatetime.java
  
  Index: ExsltDatetime.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Xalan" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 1999, Lotus
   * Development Corporation., http://www.lotus.com.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.xalan.lib;
  
  
  import java.util.Date;
  import java.util.TimeZone;
  import java.util.Calendar;
  import java.text.SimpleDateFormat;
  import java.text.DateFormat;
  import java.text.ParseException;
  import org.apache.xpath.objects.XString;
  import org.apache.xpath.objects.XNumber;
  import org.apache.xpath.objects.XBoolean;
  import org.apache.xpath.objects.XObject;
  
  /**
   * <meta name="usage" content="general"/>
   * This class contains EXSLT dates and times extension functions.
   * It is accessed by specifying a namespace URI as follows:
   * <pre>
   *    xmlns:math="http://exslt.org/dates-and-times"
   * </pre>
   * 
   * The documentation for each function has been copied from the relevant
   * EXSLT Implementer page.
   * 
   * @see <a href="http://www.exslt.org/">EXSLT</a>
   */
  
  public class ExsltDatetime
  {
      // Datetime formats (era and zone handled separately).
      static final String dt = "yyyy-MM-dd'T'HH:mm:ss";
      static final String d = "yyyy-MM-dd";
      static final String gym = "yyyy-MM";
      static final String gy = "yyyy";
      static final String gmd = "MM-dd";
      static final String gm = "MM";
      static final String gd = "dd";
      static final String t = "HH:mm:ss";
  
      /**
       * The date:date-time function returns the current date and time as a date/time string. 
       * The date/time string that's returned must be a string in the format defined as the 
       * lexical representation of xs:dateTime in 
       * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime">[3.2.7 dateTime]</a> of
       * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
       * The date/time format is basically CCYY-MM-DDThh:mm:ss, although implementers should consult
       * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
       * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
       * The date/time string format must include a time zone, either a Z to indicate Coordinated 
       * Universal Time or a + or - followed by the difference between the difference from UTC 
       * represented as hh:mm. 
       */
      public static XString dateTime()
      {
        Calendar cal = Calendar.getInstance();
        Date datetime = cal.getTime();
        // Format for date and time.
        SimpleDateFormat dateFormat = new SimpleDateFormat(dt);
        
        StringBuffer buff = new StringBuffer(dateFormat.format(datetime));
        // Must also include offset from UTF.
        // Get the offset (in milliseconds).
        int offset = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET);
        // If there is no offset, we have "Coordinated
        // Universal Time."
        if (offset == 0)
          buff.append("Z");
        else
        {
          // Convert milliseconds to hours and minutes
          int hrs = offset/(60*60*1000);
          // In a few cases, the time zone may be +/-hh:30.
          int min = offset%(60*60*1000);
          char posneg = hrs < 0? '-': '+';
          buff.append(posneg + formatDigits(hrs) + ':' + formatDigits(min));
        }
        return new XString(buff.toString());
      }
      
      /**
       * Represent the hours and minutes with two-digit strings.
       * @param q hrs or minutes.
       * @return two-digit String representation of hrs or minutes.
       */
      private static String formatDigits(int q)
      {
        String dd = String.valueOf(Math.abs(q));
        return dd.length() == 1 ? '0' + dd : dd;
      }
  
      /**
       * The date:date function returns the date specified in the date/time string given 
       * as the argument. If no argument is given, then the current local date/time, as 
       * returned by date:date-time is used as a default argument. 
       * The date/time string that's returned must be a string in the format defined as the 
       * lexical representation of xs:dateTime in 
       * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime">[3.2.7 dateTime]</a> of
       * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
       * If the argument is not in either of these formats, date:date returns an empty string (''). 
       * The date/time format is basically CCYY-MM-DDThh:mm:ss, although implementers should consult 
       * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
       * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details. 
       * The date is returned as a string with a lexical representation as defined for xs:date in 
       * [3.2.9 date] of [XML Schema Part 2: Datatypes]. The date format is basically CCYY-MM-DD, 
       * although implementers should consult [XML Schema Part 2: Datatypes] and [ISO 8601] for details.
       * If no argument is given or the argument date/time specifies a time zone, then the date string 
       * format must include a time zone, either a Z to indicate Coordinated Universal Time or a + or - 
       * followed by the difference between the difference from UTC represented as hh:mm. If an argument 
       * is specified and it does not specify a time zone, then the date string format must not include 
       * a time zone. 
       */
      public static XString date(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String leader = edz[0];
        String datetime = edz[1];
        String zone = edz[2];
        if (datetime == null || zone == null) 
          return new XString("");
                      
        String[] formatsIn = {dt, d};
        String formatOut = d;
        Date date = testFormats(datetime, formatsIn);
        if (date == null) return new XString("");
        
        SimpleDateFormat dateFormat = new SimpleDateFormat(formatOut);
        dateFormat.setLenient(false);
        String dateOut = dateFormat.format(date);      
        if (dateOut.length() == 0)
            return new XString("");
        else        
          return new XString(leader + dateOut + zone);
      }
      
      
      /**
       * See above.
       */
      public static XString date()
      {
        String datetime = dateTime().toString();
        String date = datetime.substring(0, datetime.indexOf("T"));
        String zone = datetime.substring(getZoneStart(datetime));
        return new XString(date + zone);
      }
      
      /**
       * The date:time function returns the time specified in the date/time string given 
       * as the argument. If no argument is given, then the current local date/time, as 
       * returned by date:date-time is used as a default argument. 
       * The date/time string that's returned must be a string in the format defined as the 
       * lexical representation of xs:dateTime in 
       * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime">[3.2.7 dateTime]</a> of
       * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>. 
       * If the argument string is not in this format, date:time returns an empty string (''). 
       * The date/time format is basically CCYY-MM-DDThh:mm:ss, although implementers should consult 
       * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
       * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
       * The date is returned as a string with a lexical representation as defined for xs:time in 
       * <a href="http://www.w3.org/TR/xmlschema-2/#time">[3.2.8 time]</a> of [XML Schema Part 2: Datatypes].
       * The time format is basically hh:mm:ss, although implementers should consult [XML Schema Part 2: 
       * Datatypes] and [ISO 8601] for details. 
       * If no argument is given or the argument date/time specifies a time zone, then the time string 
       * format must include a time zone, either a Z to indicate Coordinated Universal Time or a + or - 
       * followed by the difference between the difference from UTC represented as hh:mm. If an argument 
       * is specified and it does not specify a time zone, then the time string format must not include 
       * a time zone. 
       */
      public static XString time(String timeIn)
        throws ParseException      
      {
        String[] edz = getEraDatetimeZone(timeIn);
        String time = edz[1];
        String zone = edz[2];
        if (time == null || zone == null) 
          return new XString("");
                      
        String[] formatsIn = {dt, d};
        String formatOut =  t;
        Date date = testFormats(time, formatsIn);
        if (date == null) return new XString("");
        SimpleDateFormat dateFormat = new SimpleDateFormat(formatOut);
        String out = dateFormat.format(date);
        return new XString(out + zone);
      }
  
      /**
       * See above.
       */
      public static XString time()
      {
        String datetime = dateTime().toString();
        String time = datetime.substring(datetime.indexOf("T")+1);
        String zone = datetime.substring(getZoneStart(datetime));      
        return new XString(time + zone);
      } 
         
      /**
       * The date:year function returns the year of a date as a number. If no 
       * argument is given, then the current local date/time, as returned by 
       * date:date-time is used as a default argument.
       * The date/time string specified as the first argument must be a right-truncated 
       * string in the format defined as the lexical representation of xs:dateTime 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: 
       *   xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *   xs:date (CCYY-MM-DD) 
       *   xs:gYearMonth (CCYY-MM) 
       *   xs:gYear (CCYY) 
       * If the date/time string is not in one of these formats, then NaN is returned. 
       */
      public static XNumber year(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        boolean ad = edz[0].length() == 0; // AD (Common Era -- empty leader)
        String datetime = edz[1];
        if (datetime == null) 
          return new XNumber(Double.NaN);
        
        String[] formats = {dt, d, gym, gy};
        double yr = getNumber(datetime, formats, Calendar.YEAR);
        if (ad || yr == Double.NaN)
          return new XNumber(yr);
        else
          return new XNumber(-yr);
      }
       
      /**
       * See above.
       */
      public static XNumber year()
      {
        Calendar cal = Calendar.getInstance();
        return new XNumber(cal.get(Calendar.YEAR));
      }
      
      /**
       * The date:year function returns the month of a date as a number. If no argument 
       * is given, then the current local date/time, as returned by date:date-time is used 
       * as a default argument. 
       * The date/time string specified as the first argument is a left or right-truncated 
       * string in the format defined as the lexical representation of xs:dateTime 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: 
       *    xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *    xs:date (CCYY-MM-DD) 
       *    xs:gYearMonth (CCYY-MM) 
       * If the date/time string is not in one of these formats, then NaN is returned. 
       */
      public static XNumber monthInYear(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        if (datetime == null)
          return new XNumber(Double.NaN);      
        
        String[] formats = {dt, d, gym};
        return new XNumber(getNumber(datetime, formats, Calendar.MONTH));
      }
      
      /**
       * See above.
       */
      public static XNumber monthInYear()
      {      
        Calendar cal = Calendar.getInstance();
        return new XNumber(cal.get(Calendar.MONTH));
     }
      
      /**
       * The date:week-in-year function returns the week of the year as a number. If no argument 
       * is given, then the current local date/time, as returned by date:date-time is used as the 
       * default argument. For the purposes of numbering, counting follows ISO 8601: week 1 in a year 
       * is the week containing the first Thursday of the year, with new weeks beginning on a Monday. 
       * The date/time string specified as the argument is a right-truncated string in the format 
       * defined as the lexical representation of xs:dateTime 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: 
       *    xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *    xs:date (CCYY-MM-DD) 
       * If the date/time string is not in one of these formats, then NaN is returned. 
       */
      public static XNumber weekInYear(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        if (datetime == null) 
          return new XNumber(Double.NaN);      
        
        String[] formats = {dt, d};
        return new XNumber(getNumber(datetime, formats, Calendar.WEEK_OF_YEAR));
      }
          
      /**
       * See above.
       */
      public static XNumber weekInYear()
      {
         Calendar cal = Calendar.getInstance();
        return new XNumber(cal.get(Calendar.WEEK_OF_YEAR));
     }
  
      /**
       * The date:day-in-year function returns the day of a date in a year 
       * as a number. If no argument is given, then the current local
       * date/time, as returned by date:date-time is used the default argument.
       * The date/time string specified as the argument is a right-truncated 
       * string in the format defined as the lexical representation of xs:dateTime
       * 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:
       *     xs:dateTime (CCYY-MM-DDThh:mm:ss)
       *     xs:date (CCYY-MM-DD) 
       * If the date/time string is not in one of these formats, then NaN is returned. 
       */
      public static XNumber dayInYear(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        if (datetime == null) 
          return new XNumber(Double.NaN);            
        
        String[] formats = {dt, d};
        return new XNumber(getNumber(datetime, formats, Calendar.DAY_OF_YEAR));
      }
      
      /**
       * See above.
       */
      public static XNumber dayInYear()
      {
         Calendar cal = Calendar.getInstance();
        return new XNumber(cal.get(Calendar.DAY_OF_YEAR));
     }
      
  
      /**
       * The date:day-in-month function returns the day of a date as a number. 
       * If no argument is given, then the current local date/time, as returned 
       * by date:date-time is used the default argument. 
       * The date/time string specified as the argument is a left or right-truncated 
       * string in the format defined as the lexical representation of xs:dateTime 
       * 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: 
       *      xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *      xs:date (CCYY-MM-DD) 
       *      xs:gMonthDay (--MM-DD) 
       *      xs:gDay (---DD) 
       * If the date/time string is not in one of these formats, then NaN is returned. 
       */
      public static XNumber dayInMonth(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        String[] formats = {dt, d, gmd, gd};
        double day = getNumber(datetime, formats, Calendar.DAY_OF_MONTH);
        return new XNumber(day);
      }
      
      /**
       * See above.
       */
      public static XNumber dayInMonth()
      {
        Calendar cal = Calendar.getInstance();
        return new XNumber(cal.get(Calendar.DAY_OF_MONTH));
     }
      
      /**
       * The date:day-of-week-in-month function returns the day-of-the-week 
       * in a month of a date as a number (e.g. 3 for the 3rd Tuesday in May). 
       * If no argument is given, then the current local date/time, as returned 
       * by date:date-time is used the default argument. 
       * The date/time string specified as the argument is a right-truncated string
       * in the format defined as the lexical representation of xs:dateTime 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: 
       *      xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *      xs:date (CCYY-MM-DD) 
       * If the date/time string is not in one of these formats, then NaN is returned. 
       */
      public static XNumber dayOfWeekInMonth(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        if (datetime == null) 
          return new XNumber(Double.NaN);            
  
        String[] formats =  {dt, d};
        return new XNumber(getNumber(datetime, formats, Calendar.DAY_OF_WEEK_IN_MONTH));
      }
      
      /**
       * See above.
       */
      public static XNumber dayOfWeekInMonth()
      {
         Calendar cal = Calendar.getInstance();
        return new XNumber(cal.get(Calendar.DAY_OF_WEEK_IN_MONTH));
     }
        
      
      /**
       * The date:day-in-week function returns the day of the week given in a 
       * date as a number. If no argument is given, then the current local date/time, 
       * as returned by date:date-time is used the default argument. 
       * The date/time string specified as the argument is a right-truncated string 
       * in the format defined as the lexical representation of xs:dateTime 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: 
       *      xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *      xs:date (CCYY-MM-DD) 
       * If the date/time string is not in one of these formats, then NaN is returned. 
                              The numbering of days of the week starts at 1 for Sunday, 2 for Monday and so on up to 7 for Saturday.  
       */
      public static XNumber dayInWeek(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        if (datetime == null) 
          return new XNumber(Double.NaN);            
  
        String[] formats = {dt, d};
        return new XNumber(getNumber(datetime, formats, Calendar.DAY_OF_WEEK));
      }
      
      /**
       * See above.
       */
      public static XNumber dayInWeek()
      {
         Calendar cal = Calendar.getInstance();
        return new XNumber(cal.get(Calendar.DAY_OF_WEEK));
     }        
  
      /**
       * The date:hour-in-day function returns the hour of the day as a number. 
       * If no argument is given, then the current local date/time, as returned 
       * by date:date-time is used the default argument. 
       * The date/time string specified as the argument is a right-truncated 
       * string  in the format defined as the lexical representation of xs:dateTime
       * 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: 
       *     xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *     xs:time (hh:mm:ss) 
       * If the date/time string is not in one of these formats, then NaN is returned. 
       */
      public static XNumber hourInDay(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        if (datetime == null) 
          return new XNumber(Double.NaN);            
        
        String[] formats = {d, t};
        return new XNumber(getNumber(datetime, formats, Calendar.HOUR_OF_DAY));
      }
      
      /**
       * See above.
       */
      public static XNumber hourInDay()
      {
         Calendar cal = Calendar.getInstance();
        return new XNumber(cal.get(Calendar.HOUR_OF_DAY));
     }
      
      /**
       * The date:minute-in-hour function returns the minute of the hour 
       * as a number. If no argument is given, then the current local
       * date/time, as returned by date:date-time is used the default argument. 
       * The date/time string specified as the argument is a right-truncated 
       * string in the format defined as the lexical representation of xs:dateTime
       * 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: 
       *      xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *      xs:time (hh:mm:ss) 
       * If the date/time string is not in one of these formats, then NaN is returned. 
       */
      public static XNumber minuteInHour(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        if (datetime == null) 
          return new XNumber(Double.NaN);            
        
        String[] formats = {dt,t};
        return new XNumber(getNumber(datetime, formats, Calendar.MINUTE));
      }    
      
      /**
       * See above.
       */
     public static XNumber minuteInHour()
      {
         Calendar cal = Calendar.getInstance();
        return new XNumber(cal.get(Calendar.MINUTE));
     }    
  
      /**
       * The date:second-in-minute function returns the second of the minute 
       * as a number. If no argument is given, then the current local 
       * date/time, as returned by date:date-time is used the default argument. 
       * The date/time string specified as the argument is a right-truncated 
       * string in the format defined as the lexical representation of xs:dateTime
       * 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: 
       *      xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *      xs:time (hh:mm:ss) 
       * If the date/time string is not in one of these formats, then NaN is returned. 
       */
      public static XNumber secondInMinute(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        if (datetime == null) 
          return new XNumber(Double.NaN);            
        
        String[] formats = {dt, t};
        return new XNumber(getNumber(datetime, formats, Calendar.SECOND));
      }
  
      /**
       * See above.
       */
      public static XNumber secondInMinute()
      {
         Calendar cal = Calendar.getInstance();
        return new XNumber(cal.get(Calendar.SECOND));
      }
         
      /**
       * The date:leap-year function returns true if the year given in a date 
       * is a leap year. If no argument is given, then the current local
       * date/time, as returned by date:date-time is used as a default argument. 
       * The date/time string specified as the first argument must be a 
       * right-truncated string in the format defined as the lexical representation
       * of xs:dateTime 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: 
       *    xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *    xs:date (CCYY-MM-DD) 
       *    xs:gYearMonth (CCYY-MM) 
       *    xs:gYear (CCYY) 
       * If the date/time string is not in one of these formats, then NaN is returned. 
       */
      public static XObject leapYear(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        if (datetime == null) 
          return new XNumber(Double.NaN);            
              
        String[] formats = {dt, d, gym, gy};
        double dbl = getNumber(datetime, formats, Calendar.YEAR);
        if (dbl == Double.NaN) 
          return new XNumber(Double.NaN);
        int yr = (int)dbl;
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, yr);
        cal.set(Calendar.MONTH, Calendar.FEBRUARY);
        return new XBoolean(cal.getActualMaximum(cal.DAY_OF_MONTH)==29);
      }
      
      /**
       * See above.
       */
      public static XBoolean leapYear()
      {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.MONTH, Calendar.FEBRUARY);
        return new XBoolean(cal.getActualMaximum(cal.DAY_OF_MONTH)==29);      
      }    
         
      /**
       * The date:month-name function returns the full name of the month of a date. 
       * If no argument is given, then the current local date/time, as returned by 
       * date:date-time is used the default argument. 
       * The date/time string specified as the argument is a left or right-truncated 
       * string in the format defined as the lexical representation of xs:dateTime 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: 
       *    xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *    xs:date (CCYY-MM-DD) 
       *    xs:gYearMonth (CCYY-MM) 
       *    xs:gMonth (--MM--) 
       * If the date/time string is not in one of these formats, then an empty string ('') 
       * is returned. 
       * The result is an English month name: one of 'January', 'February', 'March', 
       * 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November' 
       * or 'December'. 
       */
      public static XString monthName(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        if (datetime == null) 
          return new XString("");
        
        String[] formatsIn = {dt, d, gym, gm};
        String formatOut = "MMMM";
        return new XString (getNameOrAbbrev(datetimeIn, formatsIn, formatOut));    
      }
      
      /**
       * See above.
       */
      public static XString monthName()
      {
        Calendar cal = Calendar.getInstance();
        String format = "MMMM";
        return new XString(getNameOrAbbrev(format));  
      }
          
      /**
       * The date:month-abbreviation function returns the abbreviation of the month of 
       * a date. If no argument is given, then the current local date/time, as returned 
       * by date:date-time is used the default argument. 
       * The date/time string specified as the argument is a left or right-truncated 
       * string in the format defined as the lexical representation of xs:dateTime 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: 
       *    xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *    xs:date (CCYY-MM-DD) 
       *    xs:gYearMonth (CCYY-MM) 
       *    xs:gMonth (--MM--) 
       * If the date/time string is not in one of these formats, then an empty string ('') 
       * is returned. 
       * The result is a three-letter English month abbreviation: one of 'Jan', 'Feb', 'Mar', 
       * 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov' or 'Dec'. 
       * An implementation of this extension function in the EXSLT date namespace must conform 
       * to the behaviour described in this document. 
       */
      public static XString monthAbbreviation(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        if (datetime == null) 
          return new XString("");
        
        String[] formatsIn = {dt, d, gym, gm};
        String formatOut = "MMM";
        return new XString (getNameOrAbbrev(datetimeIn, formatsIn, formatOut));
      }
      
      /**
       * See above.
       */
      public static XString monthAbbreviation()
      {
        String format = "MMM";
        return new XString(getNameOrAbbrev(format));  
      }
          
      /**
       * The date:day-name function returns the full name of the day of the week 
       * of a date.  If no argument is given, then the current local date/time, 
       * as returned by date:date-time is used the default argument. 
       * The date/time string specified as the argument is a left or right-truncated 
       * string in the format defined as the lexical representation of xs:dateTime 
       * 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: 
       *     xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *     xs:date (CCYY-MM-DD) 
       * If the date/time string is not in one of these formats, then the empty string ('') 
       * is returned. 
       * The result is an English day name: one of 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 
       * 'Thursday' or 'Friday'. 
       * An implementation of this extension function in the EXSLT date namespace must conform 
       * to the behaviour described in this document. 
       */
      public static XString dayName(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        if (datetime == null) 
          return new XString("");
              
        String[] formatsIn = {dt, d};
        String formatOut = "EEEE";
        return new XString (getNameOrAbbrev(datetimeIn, formatsIn, formatOut));    
      }
      
      /**
       * See above.
       */
      public static XString dayName()
      {
        String format = "EEEE";
        return new XString(getNameOrAbbrev(format));        
      }    
      
      /**
       * The date:day-abbreviation function returns the abbreviation of the day 
       * of the week of a date. If no argument is given, then the current local 
       * date/time, as returned  by date:date-time is used the default argument. 
       * The date/time string specified as the argument is a left or right-truncated 
       * string in the format defined as the lexical representation of xs:dateTime 
       * 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: 
       *     xs:dateTime (CCYY-MM-DDThh:mm:ss) 
       *     xs:date (CCYY-MM-DD) 
       * If the date/time string is not in one of these formats, then the empty string 
       * ('') is returned. 
       * The result is a three-letter English day abbreviation: one of 'Sun', 'Mon', 'Tue', 
       * 'Wed', 'Thu' or 'Fri'. 
       * An implementation of this extension function in the EXSLT date namespace must conform 
       * to the behaviour described in this document. 
       */
      public static XString dayAbbreviation(String datetimeIn)
        throws ParseException
      {
        String[] edz = getEraDatetimeZone(datetimeIn);
        String datetime = edz[1];
        if (datetime == null) 
          return new XString("");            
        
        String[] formatsIn = {dt, d};
        String formatOut = "EEE";
        return new XString (getNameOrAbbrev(datetimeIn, formatsIn, formatOut));
      }
      
      /**
       * See above.
       */
      public static XString dayAbbreviation()
      {
        String format = "EEE";
        return new XString(getNameOrAbbrev(format));              
      }
      
      /**
       * Returns an array with the 3 components that a datetime input string 
       * may contain: - (for BC era), datetime, and zone. If the zone is not
       * valid, return null for that component.
       */
      private static String[] getEraDatetimeZone(String in)
      {
        String leader = "";
        String datetime = in;
        String zone = "";
        if (in.charAt(0)=='-')
        {
          leader = "-"; //  '+' is implicit , not allowed
          datetime = in.substring(1);
        }
        int z = getZoneStart(datetime);
        if (z > 0)
        {
          zone = datetime.substring(z);
          datetime = datetime.substring(0, z);
        }
        else if (z == -2)
          zone = null;
        //System.out.println("'" + leader + "' " + datetime + " " + zone);
        return new String[]{leader, datetime, zone};  
      }    
      
      /**
       * Get the start of zone information if the input ends
       * with 'Z' or +/-hh:mm. If a zone string is not
       * found, return -1; if the zone string is invalid,
       * return -2.
       */
      private static int getZoneStart (String datetime)
      {
        if (datetime.indexOf("Z") == datetime.length()-1)
          return datetime.indexOf("Z");
        else if (
                 (datetime.lastIndexOf("-") == datetime.length()-6 &&
                  datetime.charAt(datetime.length()-3) == ':')               
                  || 
                  (datetime.indexOf("+") == datetime.length() -6)
                )
        {
          try
          {
            SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm");
            dateFormat.setLenient(false);
            Date d = dateFormat.parse(datetime.substring(datetime.length() -5));
            return datetime.length()-6;
          }
          catch (ParseException pe)
          {
            System.out.println("ParseException " + pe.getErrorOffset());
            return -2; // Invalid.
          }
  
        }
          return -1; // No zone information.
      }
      
      /**
       * Attempt to parse an input string with the allowed formats, returning
       * null if none of the formats work. Input formats are passed in longest to shortest,
       * so if any parse operation fails with a parse error in the string, can
       * immediately return null.
       */
      private static Date testFormats (String in, String[] formats)
        throws ParseException
      {
        for (int i = 0; i <formats.length; i++)
        {
          try
          {
            SimpleDateFormat dateFormat = new SimpleDateFormat(formats[i]);
            dateFormat.setLenient(false);          
            return dateFormat.parse(in);
          }
          catch (ParseException pe)
          {
            if (pe.getErrorOffset() < in.length())
              return null;
          }
        }
        return null;
      }
      
      
      /**
       * Parse the input string and return the corresponding calendar field
       * number.
       */
      private static double getNumber(String in, String[] formats, int calField)
        throws ParseException
      {
        Calendar cal = Calendar.getInstance();
        cal.setLenient(false);
        // Try the allowed formats, from longest to shortest.
        Date date = testFormats(in, formats);
        if (date == null) return Double.NaN;
        cal.setTime(date);
        return cal.get(calField);
      }    
       
      /**
       *  Get the full name or abbreviation of the month or day.
       */
      private static String getNameOrAbbrev(String in, 
                                           String[] formatsIn,
                                           String formatOut)
        throws ParseException
      {
        for (int i = 0; i <formatsIn.length; i++) // from longest to shortest.
        {
          try
          {
            SimpleDateFormat dateFormat = new SimpleDateFormat(formatsIn[i]);
            dateFormat.setLenient(false);
            Date dt = dateFormat.parse(in);          
            dateFormat.applyPattern(formatOut);
            return dateFormat.format(dt);
          }
          catch (ParseException pe)
          {
            // If ParseException occurred during input string, input is invalid.
            // If the ParseException occurred at the end of the input string,
            // another format may work.
            if (pe.getErrorOffset() < in.length())
              return "";
          }
        }
        return "";
      }
      /**
       * Get the full name or abbreviation for the current month or day 
       * (no input string).
       */
      private static String getNameOrAbbrev(String format)
      {
        Calendar cal = Calendar.getInstance();
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        return dateFormat.format(cal.getTime());
      }
  
  }
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: xalan-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: xalan-cvs-help@xml.apache.org