KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > lib > ExsltDatetime


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: ExsltDatetime.java,v 1.13 2004/02/11 17:56:36 minchau Exp $
18  */

19
20 package org.apache.xalan.lib;
21
22
23 import java.text.ParseException JavaDoc;
24 import java.text.SimpleDateFormat JavaDoc;
25 import java.util.Calendar JavaDoc;
26 import java.util.Date JavaDoc;
27 import java.util.TimeZone JavaDoc;
28
29 import org.apache.xpath.objects.XBoolean;
30 import org.apache.xpath.objects.XNumber;
31 import org.apache.xpath.objects.XObject;
32
33 /**
34  * This class contains EXSLT dates and times extension functions.
35  * It is accessed by specifying a namespace URI as follows:
36  * <pre>
37  * xmlns:datetime="http://exslt.org/dates-and-times"
38  * </pre>
39  *
40  * The documentation for each function has been copied from the relevant
41  * EXSLT Implementer page.
42  *
43  * @see <a HREF="http://www.exslt.org/">EXSLT</a>
44  * @xsl.usage general
45  */

46
47 public class ExsltDatetime
48 {
49     // Datetime formats (era and zone handled separately).
50
static final String JavaDoc dt = "yyyy-MM-dd'T'HH:mm:ss";
51     static final String JavaDoc d = "yyyy-MM-dd";
52     static final String JavaDoc gym = "yyyy-MM";
53     static final String JavaDoc gy = "yyyy";
54     static final String JavaDoc gmd = "--MM-dd";
55     static final String JavaDoc gm = "--MM--";
56     static final String JavaDoc gd = "---dd";
57     static final String JavaDoc t = "HH:mm:ss";
58     static final String JavaDoc EMPTY_STR = "";
59
60     /**
61      * The date:date-time function returns the current date and time as a date/time string.
62      * The date/time string that's returned must be a string in the format defined as the
63      * lexical representation of xs:dateTime in
64      * <a HREF="http://www.w3.org/TR/xmlschema-2/#dateTime">[3.2.7 dateTime]</a> of
65      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
66      * The date/time format is basically CCYY-MM-DDThh:mm:ss, although implementers should consult
67      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and
68      * <a HREF="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
69      * The date/time string format must include a time zone, either a Z to indicate Coordinated
70      * Universal Time or a + or - followed by the difference between the difference from UTC
71      * represented as hh:mm.
72      */

73     public static String JavaDoc dateTime()
74     {
75       Calendar JavaDoc cal = Calendar.getInstance();
76       Date JavaDoc datetime = cal.getTime();
77       // Format for date and time.
78
SimpleDateFormat JavaDoc dateFormat = new SimpleDateFormat JavaDoc(dt);
79       
80       StringBuffer JavaDoc buff = new StringBuffer JavaDoc(dateFormat.format(datetime));
81       // Must also include offset from UTF.
82
// Get the offset (in milliseconds).
83
int offset = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET);
84       // If there is no offset, we have "Coordinated
85
// Universal Time."
86
if (offset == 0)
87         buff.append("Z");
88       else
89       {
90         // Convert milliseconds to hours and minutes
91
int hrs = offset/(60*60*1000);
92         // In a few cases, the time zone may be +/-hh:30.
93
int min = offset%(60*60*1000);
94         char posneg = hrs < 0? '-': '+';
95         buff.append(posneg + formatDigits(hrs) + ':' + formatDigits(min));
96       }
97       return buff.toString();
98     }
99     
100     /**
101      * Represent the hours and minutes with two-digit strings.
102      * @param q hrs or minutes.
103      * @return two-digit String representation of hrs or minutes.
104      */

105     private static String JavaDoc formatDigits(int q)
106     {
107       String JavaDoc dd = String.valueOf(Math.abs(q));
108       return dd.length() == 1 ? '0' + dd : dd;
109     }
110
111     /**
112      * The date:date function returns the date specified in the date/time string given
113      * as the argument. If no argument is given, then the current local date/time, as
114      * returned by date:date-time is used as a default argument.
115      * The date/time string that's returned must be a string in the format defined as the
116      * lexical representation of xs:dateTime in
117      * <a HREF="http://www.w3.org/TR/xmlschema-2/#dateTime">[3.2.7 dateTime]</a> of
118      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
119      * If the argument is not in either of these formats, date:date returns an empty string ('').
120      * The date/time format is basically CCYY-MM-DDThh:mm:ss, although implementers should consult
121      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and
122      * <a HREF="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
123      * The date is returned as a string with a lexical representation as defined for xs:date in
124      * [3.2.9 date] of [XML Schema Part 2: Datatypes]. The date format is basically CCYY-MM-DD,
125      * although implementers should consult [XML Schema Part 2: Datatypes] and [ISO 8601] for details.
126      * If no argument is given or the argument date/time specifies a time zone, then the date string
127      * format must include a time zone, either a Z to indicate Coordinated Universal Time or a + or -
128      * followed by the difference between the difference from UTC represented as hh:mm. If an argument
129      * is specified and it does not specify a time zone, then the date string format must not include
130      * a time zone.
131      */

132     public static String JavaDoc date(String JavaDoc datetimeIn)
133       throws ParseException JavaDoc
134     {
135       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
136       String JavaDoc leader = edz[0];
137       String JavaDoc datetime = edz[1];
138       String JavaDoc zone = edz[2];
139       if (datetime == null || zone == null)
140         return EMPTY_STR;
141                     
142       String JavaDoc[] formatsIn = {dt, d};
143       String JavaDoc formatOut = d;
144       Date JavaDoc date = testFormats(datetime, formatsIn);
145       if (date == null) return EMPTY_STR;
146       
147       SimpleDateFormat JavaDoc dateFormat = new SimpleDateFormat JavaDoc(formatOut);
148       dateFormat.setLenient(false);
149       String JavaDoc dateOut = dateFormat.format(date);
150       if (dateOut.length() == 0)
151           return EMPTY_STR;
152       else
153         return (leader + dateOut + zone);
154     }
155     
156     
157     /**
158      * See above.
159      */

160     public static String JavaDoc date()
161     {
162       String JavaDoc datetime = dateTime().toString();
163       String JavaDoc date = datetime.substring(0, datetime.indexOf("T"));
164       String JavaDoc zone = datetime.substring(getZoneStart(datetime));
165       return (date + zone);
166     }
167     
168     /**
169      * The date:time function returns the time specified in the date/time string given
170      * as the argument. If no argument is given, then the current local date/time, as
171      * returned by date:date-time is used as a default argument.
172      * The date/time string that's returned must be a string in the format defined as the
173      * lexical representation of xs:dateTime in
174      * <a HREF="http://www.w3.org/TR/xmlschema-2/#dateTime">[3.2.7 dateTime]</a> of
175      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
176      * If the argument string is not in this format, date:time returns an empty string ('').
177      * The date/time format is basically CCYY-MM-DDThh:mm:ss, although implementers should consult
178      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and
179      * <a HREF="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
180      * The date is returned as a string with a lexical representation as defined for xs:time in
181      * <a HREF="http://www.w3.org/TR/xmlschema-2/#time">[3.2.8 time]</a> of [XML Schema Part 2: Datatypes].
182      * The time format is basically hh:mm:ss, although implementers should consult [XML Schema Part 2:
183      * Datatypes] and [ISO 8601] for details.
184      * If no argument is given or the argument date/time specifies a time zone, then the time string
185      * format must include a time zone, either a Z to indicate Coordinated Universal Time or a + or -
186      * followed by the difference between the difference from UTC represented as hh:mm. If an argument
187      * is specified and it does not specify a time zone, then the time string format must not include
188      * a time zone.
189      */

190     public static String JavaDoc time(String JavaDoc timeIn)
191       throws ParseException JavaDoc
192     {
193       String JavaDoc[] edz = getEraDatetimeZone(timeIn);
194       String JavaDoc time = edz[1];
195       String JavaDoc zone = edz[2];
196       if (time == null || zone == null)
197         return EMPTY_STR;
198                     
199       String JavaDoc[] formatsIn = {dt, d};
200       String JavaDoc formatOut = t;
201       Date JavaDoc date = testFormats(time, formatsIn);
202       if (date == null) return EMPTY_STR;
203       SimpleDateFormat JavaDoc dateFormat = new SimpleDateFormat JavaDoc(formatOut);
204       String JavaDoc out = dateFormat.format(date);
205       return (out + zone);
206     }
207
208     /**
209      * See above.
210      */

211     public static String JavaDoc time()
212     {
213       String JavaDoc datetime = dateTime().toString();
214       String JavaDoc time = datetime.substring(datetime.indexOf("T")+1);
215       String JavaDoc zone = datetime.substring(getZoneStart(datetime));
216       return (time + zone);
217     }
218        
219     /**
220      * The date:year function returns the year of a date as a number. If no
221      * argument is given, then the current local date/time, as returned by
222      * date:date-time is used as a default argument.
223      * The date/time string specified as the first argument must be a right-truncated
224      * string in the format defined as the lexical representation of xs:dateTime in one
225      * of the formats defined in
226      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
227      * The permitted formats are as follows:
228      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
229      * xs:date (CCYY-MM-DD)
230      * xs:gYearMonth (CCYY-MM)
231      * xs:gYear (CCYY)
232      * If the date/time string is not in one of these formats, then NaN is returned.
233      */

234     public static double year(String JavaDoc datetimeIn)
235       throws ParseException JavaDoc
236     {
237       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
238       boolean ad = edz[0].length() == 0; // AD (Common Era -- empty leader)
239
String JavaDoc datetime = edz[1];
240       if (datetime == null)
241         return Double.NaN;
242       
243       String JavaDoc[] formats = {dt, d, gym, gy};
244       double yr = getNumber(datetime, formats, Calendar.YEAR);
245       if (ad || yr == Double.NaN)
246         return yr;
247       else
248         return -yr;
249     }
250      
251     /**
252      * See above.
253      */

254     public static double year()
255     {
256       Calendar JavaDoc cal = Calendar.getInstance();
257       return cal.get(Calendar.YEAR);
258     }
259     
260     /**
261      * The date:year function returns the month of a date as a number. If no argument
262      * is given, then the current local date/time, as returned by date:date-time is used
263      * as a default argument.
264      * The date/time string specified as the first argument is a left or right-truncated
265      * string in the format defined as the lexical representation of xs:dateTime in one of
266      * the formats defined in
267      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
268      * The permitted formats are as follows:
269      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
270      * xs:date (CCYY-MM-DD)
271      * xs:gYearMonth (CCYY-MM)
272      * xs:gMonth (--MM--)
273      * xs:gMonthDay (--MM-DD)
274      * If the date/time string is not in one of these formats, then NaN is returned.
275      */

276     public static double monthInYear(String JavaDoc datetimeIn)
277       throws ParseException JavaDoc
278     {
279       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
280       String JavaDoc datetime = edz[1];
281       if (datetime == null)
282         return Double.NaN;
283       
284       String JavaDoc[] formats = {dt, d, gym, gm, gmd};
285       return getNumber(datetime, formats, Calendar.MONTH);
286     }
287     
288     /**
289      * See above.
290      */

291     public static double monthInYear()
292     {
293       Calendar JavaDoc cal = Calendar.getInstance();
294       return cal.get(Calendar.MONTH);
295    }
296     
297     /**
298      * The date:week-in-year function returns the week of the year as a number. If no argument
299      * is given, then the current local date/time, as returned by date:date-time is used as the
300      * default argument. For the purposes of numbering, counting follows ISO 8601: week 1 in a year
301      * is the week containing the first Thursday of the year, with new weeks beginning on a Monday.
302      * The date/time string specified as the argument is a right-truncated string in the format
303      * defined as the lexical representation of xs:dateTime in one of the formats defined in
304      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>. The
305      * permitted formats are as follows:
306      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
307      * xs:date (CCYY-MM-DD)
308      * If the date/time string is not in one of these formats, then NaN is returned.
309      */

310     public static double weekInYear(String JavaDoc datetimeIn)
311       throws ParseException JavaDoc
312     {
313       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
314       String JavaDoc datetime = edz[1];
315       if (datetime == null)
316         return Double.NaN;
317       
318       String JavaDoc[] formats = {dt, d};
319       return getNumber(datetime, formats, Calendar.WEEK_OF_YEAR);
320     }
321         
322     /**
323      * See above.
324      */

325     public static double weekInYear()
326     {
327        Calendar JavaDoc cal = Calendar.getInstance();
328       return cal.get(Calendar.WEEK_OF_YEAR);
329    }
330
331     /**
332      * The date:day-in-year function returns the day of a date in a year
333      * as a number. If no argument is given, then the current local
334      * date/time, as returned by date:date-time is used the default argument.
335      * The date/time string specified as the argument is a right-truncated
336      * string in the format defined as the lexical representation of xs:dateTime
337      * in one of the formats defined in
338      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
339      * The permitted formats are as follows:
340      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
341      * xs:date (CCYY-MM-DD)
342      * If the date/time string is not in one of these formats, then NaN is returned.
343      */

344     public static double dayInYear(String JavaDoc datetimeIn)
345       throws ParseException JavaDoc
346     {
347       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
348       String JavaDoc datetime = edz[1];
349       if (datetime == null)
350         return Double.NaN;
351       
352       String JavaDoc[] formats = {dt, d};
353       return getNumber(datetime, formats, Calendar.DAY_OF_YEAR);
354     }
355     
356     /**
357      * See above.
358      */

359     public static double dayInYear()
360     {
361        Calendar JavaDoc cal = Calendar.getInstance();
362       return cal.get(Calendar.DAY_OF_YEAR);
363    }
364     
365
366     /**
367      * The date:day-in-month function returns the day of a date as a number.
368      * If no argument is given, then the current local date/time, as returned
369      * by date:date-time is used the default argument.
370      * The date/time string specified as the argument is a left or right-truncated
371      * string in the format defined as the lexical representation of xs:dateTime
372      * in one of the formats defined in
373      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
374      * The permitted formats are as follows:
375      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
376      * xs:date (CCYY-MM-DD)
377      * xs:gMonthDay (--MM-DD)
378      * xs:gDay (---DD)
379      * If the date/time string is not in one of these formats, then NaN is returned.
380      */

381     public static double dayInMonth(String JavaDoc datetimeIn)
382       throws ParseException JavaDoc
383     {
384       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
385       String JavaDoc datetime = edz[1];
386       String JavaDoc[] formats = {dt, d, gmd, gd};
387       double day = getNumber(datetime, formats, Calendar.DAY_OF_MONTH);
388       return day;
389     }
390     
391     /**
392      * See above.
393      */

394     public static double dayInMonth()
395     {
396       Calendar JavaDoc cal = Calendar.getInstance();
397       return cal.get(Calendar.DAY_OF_MONTH);
398    }
399     
400     /**
401      * The date:day-of-week-in-month function returns the day-of-the-week
402      * in a month of a date as a number (e.g. 3 for the 3rd Tuesday in May).
403      * If no argument is given, then the current local date/time, as returned
404      * by date:date-time is used the default argument.
405      * The date/time string specified as the argument is a right-truncated string
406      * in the format defined as the lexical representation of xs:dateTime in one
407      * of the formats defined in
408      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
409      * The permitted formats are as follows:
410      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
411      * xs:date (CCYY-MM-DD)
412      * If the date/time string is not in one of these formats, then NaN is returned.
413      */

414     public static double dayOfWeekInMonth(String JavaDoc datetimeIn)
415       throws ParseException JavaDoc
416     {
417       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
418       String JavaDoc datetime = edz[1];
419       if (datetime == null)
420         return Double.NaN;
421
422       String JavaDoc[] formats = {dt, d};
423       return getNumber(datetime, formats, Calendar.DAY_OF_WEEK_IN_MONTH);
424     }
425     
426     /**
427      * See above.
428      */

429     public static double dayOfWeekInMonth()
430     {
431        Calendar JavaDoc cal = Calendar.getInstance();
432       return cal.get(Calendar.DAY_OF_WEEK_IN_MONTH);
433    }
434       
435     
436     /**
437      * The date:day-in-week function returns the day of the week given in a
438      * date as a number. If no argument is given, then the current local date/time,
439      * as returned by date:date-time is used the default argument.
440      * The date/time string specified as the argument is a right-truncated string
441      * in the format defined as the lexical representation of xs:dateTime in one
442      * of the formats defined in
443      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
444      * The permitted formats are as follows:
445      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
446      * xs:date (CCYY-MM-DD)
447      * If the date/time string is not in one of these formats, then NaN is returned.
448                             The numbering of days of the week starts at 1 for Sunday, 2 for Monday and so on up to 7 for Saturday.
449      */

450     public static double dayInWeek(String JavaDoc datetimeIn)
451       throws ParseException JavaDoc
452     {
453       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
454       String JavaDoc datetime = edz[1];
455       if (datetime == null)
456         return Double.NaN;
457
458       String JavaDoc[] formats = {dt, d};
459       return getNumber(datetime, formats, Calendar.DAY_OF_WEEK);
460     }
461     
462     /**
463      * See above.
464      */

465     public static double dayInWeek()
466     {
467        Calendar JavaDoc cal = Calendar.getInstance();
468       return cal.get(Calendar.DAY_OF_WEEK);
469    }
470
471     /**
472      * The date:hour-in-day function returns the hour of the day as a number.
473      * If no argument is given, then the current local date/time, as returned
474      * by date:date-time is used the default argument.
475      * The date/time string specified as the argument is a right-truncated
476      * string in the format defined as the lexical representation of xs:dateTime
477      * in one of the formats defined in
478      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
479      * The permitted formats are as follows:
480      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
481      * xs:time (hh:mm:ss)
482      * If the date/time string is not in one of these formats, then NaN is returned.
483      */

484     public static double hourInDay(String JavaDoc datetimeIn)
485       throws ParseException JavaDoc
486     {
487       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
488       String JavaDoc datetime = edz[1];
489       if (datetime == null)
490         return Double.NaN;
491       
492       String JavaDoc[] formats = {dt, t};
493       return getNumber(datetime, formats, Calendar.HOUR_OF_DAY);
494     }
495     
496     /**
497      * See above.
498      */

499     public static double hourInDay()
500     {
501        Calendar JavaDoc cal = Calendar.getInstance();
502       return cal.get(Calendar.HOUR_OF_DAY);
503    }
504     
505     /**
506      * The date:minute-in-hour function returns the minute of the hour
507      * as a number. If no argument is given, then the current local
508      * date/time, as returned by date:date-time is used the default argument.
509      * The date/time string specified as the argument is a right-truncated
510      * string in the format defined as the lexical representation of xs:dateTime
511      * in one of the formats defined in
512      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
513      * The permitted formats are as follows:
514      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
515      * xs:time (hh:mm:ss)
516      * If the date/time string is not in one of these formats, then NaN is returned.
517      */

518     public static double minuteInHour(String JavaDoc datetimeIn)
519       throws ParseException JavaDoc
520     {
521       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
522       String JavaDoc datetime = edz[1];
523       if (datetime == null)
524         return Double.NaN;
525       
526       String JavaDoc[] formats = {dt,t};
527       return getNumber(datetime, formats, Calendar.MINUTE);
528     }
529     
530     /**
531      * See above.
532      */

533    public static double minuteInHour()
534     {
535        Calendar JavaDoc cal = Calendar.getInstance();
536       return cal.get(Calendar.MINUTE);
537    }
538
539     /**
540      * The date:second-in-minute function returns the second of the minute
541      * as a number. If no argument is given, then the current local
542      * date/time, as returned by date:date-time is used the default argument.
543      * The date/time string specified as the argument is a right-truncated
544      * string in the format defined as the lexical representation of xs:dateTime
545      * in one of the formats defined in
546      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
547      * The permitted formats are as follows:
548      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
549      * xs:time (hh:mm:ss)
550      * If the date/time string is not in one of these formats, then NaN is returned.
551      */

552     public static double secondInMinute(String JavaDoc datetimeIn)
553       throws ParseException JavaDoc
554     {
555       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
556       String JavaDoc datetime = edz[1];
557       if (datetime == null)
558         return Double.NaN;
559       
560       String JavaDoc[] formats = {dt, t};
561       return getNumber(datetime, formats, Calendar.SECOND);
562     }
563
564     /**
565      * See above.
566      */

567     public static double secondInMinute()
568     {
569        Calendar JavaDoc cal = Calendar.getInstance();
570       return cal.get(Calendar.SECOND);
571     }
572        
573     /**
574      * The date:leap-year function returns true if the year given in a date
575      * is a leap year. If no argument is given, then the current local
576      * date/time, as returned by date:date-time is used as a default argument.
577      * The date/time string specified as the first argument must be a
578      * right-truncated string in the format defined as the lexical representation
579      * of xs:dateTime in one of the formats defined in
580      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
581      * The permitted formats are as follows:
582      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
583      * xs:date (CCYY-MM-DD)
584      * xs:gYearMonth (CCYY-MM)
585      * xs:gYear (CCYY)
586      * If the date/time string is not in one of these formats, then NaN is returned.
587      */

588     public static XObject leapYear(String JavaDoc datetimeIn)
589       throws ParseException JavaDoc
590     {
591       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
592       String JavaDoc datetime = edz[1];
593       if (datetime == null)
594         return new XNumber(Double.NaN);
595             
596       String JavaDoc[] formats = {dt, d, gym, gy};
597       double dbl = getNumber(datetime, formats, Calendar.YEAR);
598       if (dbl == Double.NaN)
599         return new XNumber(Double.NaN);
600       int yr = (int)dbl;
601       return new XBoolean(yr % 400 == 0 || (yr % 100 != 0 && yr % 4 == 0));
602     }
603     
604     /**
605      * See above.
606      */

607     public static boolean leapYear()
608     {
609       Calendar JavaDoc cal = Calendar.getInstance();
610       int yr = (int)cal.get(Calendar.YEAR);
611       return (yr % 400 == 0 || (yr % 100 != 0 && yr % 4 == 0));
612     }
613        
614     /**
615      * The date:month-name function returns the full name of the month of a date.
616      * If no argument is given, then the current local date/time, as returned by
617      * date:date-time is used the default argument.
618      * The date/time string specified as the argument is a left or right-truncated
619      * string in the format defined as the lexical representation of xs:dateTime in
620      * one of the formats defined in
621      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
622      * The permitted formats are as follows:
623      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
624      * xs:date (CCYY-MM-DD)
625      * xs:gYearMonth (CCYY-MM)
626      * xs:gMonth (--MM--)
627      * If the date/time string is not in one of these formats, then an empty string ('')
628      * is returned.
629      * The result is an English month name: one of 'January', 'February', 'March',
630      * 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November'
631      * or 'December'.
632      */

633     public static String JavaDoc monthName(String JavaDoc datetimeIn)
634       throws ParseException JavaDoc
635     {
636       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
637       String JavaDoc datetime = edz[1];
638       if (datetime == null)
639         return EMPTY_STR;
640       
641       String JavaDoc[] formatsIn = {dt, d, gym, gm};
642       String JavaDoc formatOut = "MMMM";
643       return getNameOrAbbrev(datetimeIn, formatsIn, formatOut);
644     }
645     
646     /**
647      * See above.
648      */

649     public static String JavaDoc monthName()
650     {
651       Calendar JavaDoc cal = Calendar.getInstance();
652       String JavaDoc format = "MMMM";
653       return getNameOrAbbrev(format);
654     }
655         
656     /**
657      * The date:month-abbreviation function returns the abbreviation of the month of
658      * a date. If no argument is given, then the current local date/time, as returned
659      * by date:date-time is used the default argument.
660      * The date/time string specified as the argument is a left or right-truncated
661      * string in the format defined as the lexical representation of xs:dateTime in
662      * one of the formats defined in
663      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
664      * The permitted formats are as follows:
665      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
666      * xs:date (CCYY-MM-DD)
667      * xs:gYearMonth (CCYY-MM)
668      * xs:gMonth (--MM--)
669      * If the date/time string is not in one of these formats, then an empty string ('')
670      * is returned.
671      * The result is a three-letter English month abbreviation: one of 'Jan', 'Feb', 'Mar',
672      * 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov' or 'Dec'.
673      * An implementation of this extension function in the EXSLT date namespace must conform
674      * to the behaviour described in this document.
675      */

676     public static String JavaDoc monthAbbreviation(String JavaDoc datetimeIn)
677       throws ParseException JavaDoc
678     {
679       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
680       String JavaDoc datetime = edz[1];
681       if (datetime == null)
682         return EMPTY_STR;
683       
684       String JavaDoc[] formatsIn = {dt, d, gym, gm};
685       String JavaDoc formatOut = "MMM";
686       return getNameOrAbbrev(datetimeIn, formatsIn, formatOut);
687     }
688     
689     /**
690      * See above.
691      */

692     public static String JavaDoc monthAbbreviation()
693     {
694       String JavaDoc format = "MMM";
695       return getNameOrAbbrev(format);
696     }
697         
698     /**
699      * The date:day-name function returns the full name of the day of the week
700      * of a date. If no argument is given, then the current local date/time,
701      * as returned by date:date-time is used the default argument.
702      * The date/time string specified as the argument is a left or right-truncated
703      * string in the format defined as the lexical representation of xs:dateTime
704      * in one of the formats defined in
705      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
706      * The permitted formats are as follows:
707      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
708      * xs:date (CCYY-MM-DD)
709      * If the date/time string is not in one of these formats, then the empty string ('')
710      * is returned.
711      * The result is an English day name: one of 'Sunday', 'Monday', 'Tuesday', 'Wednesday',
712      * 'Thursday' or 'Friday'.
713      * An implementation of this extension function in the EXSLT date namespace must conform
714      * to the behaviour described in this document.
715      */

716     public static String JavaDoc dayName(String JavaDoc datetimeIn)
717       throws ParseException JavaDoc
718     {
719       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
720       String JavaDoc datetime = edz[1];
721       if (datetime == null)
722         return EMPTY_STR;
723             
724       String JavaDoc[] formatsIn = {dt, d};
725       String JavaDoc formatOut = "EEEE";
726       return getNameOrAbbrev(datetimeIn, formatsIn, formatOut);
727     }
728     
729     /**
730      * See above.
731      */

732     public static String JavaDoc dayName()
733     {
734       String JavaDoc format = "EEEE";
735       return getNameOrAbbrev(format);
736     }
737     
738     /**
739      * The date:day-abbreviation function returns the abbreviation of the day
740      * of the week of a date. If no argument is given, then the current local
741      * date/time, as returned by date:date-time is used the default argument.
742      * The date/time string specified as the argument is a left or right-truncated
743      * string in the format defined as the lexical representation of xs:dateTime
744      * in one of the formats defined in
745      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
746      * The permitted formats are as follows:
747      * xs:dateTime (CCYY-MM-DDThh:mm:ss)
748      * xs:date (CCYY-MM-DD)
749      * If the date/time string is not in one of these formats, then the empty string
750      * ('') is returned.
751      * The result is a three-letter English day abbreviation: one of 'Sun', 'Mon', 'Tue',
752      * 'Wed', 'Thu' or 'Fri'.
753      * An implementation of this extension function in the EXSLT date namespace must conform
754      * to the behaviour described in this document.
755      */

756     public static String JavaDoc dayAbbreviation(String JavaDoc datetimeIn)
757       throws ParseException JavaDoc
758     {
759       String JavaDoc[] edz = getEraDatetimeZone(datetimeIn);
760       String JavaDoc datetime = edz[1];
761       if (datetime == null)
762         return EMPTY_STR;
763       
764       String JavaDoc[] formatsIn = {dt, d};
765       String JavaDoc formatOut = "EEE";
766       return getNameOrAbbrev(datetimeIn, formatsIn, formatOut);
767     }
768     
769     /**
770      * See above.
771      */

772     public static String JavaDoc dayAbbreviation()
773     {
774       String JavaDoc format = "EEE";
775       return getNameOrAbbrev(format);
776     }
777     
778     /**
779      * Returns an array with the 3 components that a datetime input string
780      * may contain: - (for BC era), datetime, and zone. If the zone is not
781      * valid, return null for that component.
782      */

783     private static String JavaDoc[] getEraDatetimeZone(String JavaDoc in)
784     {
785       String JavaDoc leader = "";
786       String JavaDoc datetime = in;
787       String JavaDoc zone = "";
788       if (in.charAt(0)=='-' && !in.startsWith("--"))
789       {
790         leader = "-"; // '+' is implicit , not allowed
791
datetime = in.substring(1);
792       }
793       int z = getZoneStart(datetime);
794       if (z > 0)
795       {
796         zone = datetime.substring(z);
797         datetime = datetime.substring(0, z);
798       }
799       else if (z == -2)
800         zone = null;
801       //System.out.println("'" + leader + "' " + datetime + " " + zone);
802
return new String JavaDoc[]{leader, datetime, zone};
803     }
804     
805     /**
806      * Get the start of zone information if the input ends
807      * with 'Z' or +/-hh:mm. If a zone string is not
808      * found, return -1; if the zone string is invalid,
809      * return -2.
810      */

811     private static int getZoneStart (String JavaDoc datetime)
812     {
813       if (datetime.indexOf("Z") == datetime.length()-1)
814         return datetime.length()-1;
815       else if (datetime.length() >=6
816             && datetime.charAt(datetime.length()-3) == ':'
817             && (datetime.charAt(datetime.length()-6) == '+'
818                 || datetime.charAt(datetime.length()-6) == '-'))
819       {
820         try
821         {
822           SimpleDateFormat JavaDoc dateFormat = new SimpleDateFormat JavaDoc("HH:mm");
823           dateFormat.setLenient(false);
824           Date JavaDoc d = dateFormat.parse(datetime.substring(datetime.length() -5));
825           return datetime.length()-6;
826         }
827         catch (ParseException JavaDoc pe)
828         {
829           System.out.println("ParseException " + pe.getErrorOffset());
830           return -2; // Invalid.
831
}
832
833       }
834         return -1; // No zone information.
835
}
836     
837     /**
838      * Attempt to parse an input string with the allowed formats, returning
839      * null if none of the formats work.
840      */

841     private static Date JavaDoc testFormats (String JavaDoc in, String JavaDoc[] formats)
842       throws ParseException JavaDoc
843     {
844       for (int i = 0; i <formats.length; i++)
845       {
846         try
847         {
848           SimpleDateFormat JavaDoc dateFormat = new SimpleDateFormat JavaDoc(formats[i]);
849           dateFormat.setLenient(false);
850           return dateFormat.parse(in);
851         }
852         catch (ParseException JavaDoc pe)
853         {
854         }
855       }
856       return null;
857     }
858     
859     
860     /**
861      * Parse the input string and return the corresponding calendar field
862      * number.
863      */

864     private static double getNumber(String JavaDoc in, String JavaDoc[] formats, int calField)
865       throws ParseException JavaDoc
866     {
867       Calendar JavaDoc cal = Calendar.getInstance();
868       cal.setLenient(false);
869       // Try the allowed formats, from longest to shortest.
870
Date JavaDoc date = testFormats(in, formats);
871       if (date == null) return Double.NaN;
872       cal.setTime(date);
873       return cal.get(calField);
874     }
875      
876     /**
877      * Get the full name or abbreviation of the month or day.
878      */

879     private static String JavaDoc getNameOrAbbrev(String JavaDoc in,
880                                          String JavaDoc[] formatsIn,
881                                          String JavaDoc formatOut)
882       throws ParseException JavaDoc
883     {
884       for (int i = 0; i <formatsIn.length; i++) // from longest to shortest.
885
{
886         try
887         {
888           SimpleDateFormat JavaDoc dateFormat = new SimpleDateFormat JavaDoc(formatsIn[i]);
889           dateFormat.setLenient(false);
890           Date JavaDoc dt = dateFormat.parse(in);
891           dateFormat.applyPattern(formatOut);
892           return dateFormat.format(dt);
893         }
894         catch (ParseException JavaDoc pe)
895         {
896         }
897       }
898       return "";
899     }
900     /**
901      * Get the full name or abbreviation for the current month or day
902      * (no input string).
903      */

904     private static String JavaDoc getNameOrAbbrev(String JavaDoc format)
905     {
906       Calendar JavaDoc cal = Calendar.getInstance();
907       SimpleDateFormat JavaDoc dateFormat = new SimpleDateFormat JavaDoc(format);
908       return dateFormat.format(cal.getTime());
909     }
910
911     /**
912      * The date:format-date function formats a date/time according to a pattern.
913      * <p>
914      * The first argument to date:format-date specifies the date/time to be
915      * formatted. It must be right or left-truncated date/time strings in one of
916      * the formats defined in
917      * <a HREF="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
918      * The permitted formats are as follows:
919      * <ul>
920      * <li>xs:dateTime (CCYY-MM-DDThh:mm:ss)
921      * <li>xs:date (CCYY-MM-DD)
922      * <li>xs:time (hh:mm:ss)
923      * <li>xs:gYearMonth (CCYY-MM)
924      * <li>xs:gYear (CCYY)
925      * <li>xs:gMonthDay (--MM-DD)
926      * <li>xs:gMonth (--MM--)
927      * <li>xs:gDay (---DD)
928      * </ul>
929      * The second argument is a string that gives the format pattern used to
930      * format the date. The format pattern must be in the syntax specified by
931      * the JDK 1.1 SimpleDateFormat class. The format pattern string is
932      * interpreted as described for the JDK 1.1 SimpleDateFormat class.
933      * <p>
934      * If the date/time format is right-truncated (i.e. in a format other than
935      * xs:time, or xs:dateTime) then any missing components are assumed to be as
936      * follows: if no month is specified, it is given a month of 01; if no day
937      * is specified, it is given a day of 01; if no time is specified, it is
938      * given a time of 00:00:00.
939      * <p>
940      * If the date/time format is left-truncated (i.e. xs:time, xs:gMonthDay,
941      * xs:gMonth or xs:gDay) and the format pattern has a token that uses a
942      * component that is missing from the date/time format used, then that token
943      * is replaced with an empty string ('') within the result.
944      *
945      * The author is Helg Bredow (helg.bredow@kalido.com)
946      */

947     public static String JavaDoc formatDate(String JavaDoc dateTime, String JavaDoc pattern)
948     {
949         final String JavaDoc yearSymbols = "Gy";
950         final String JavaDoc monthSymbols = "M";
951         final String JavaDoc daySymbols = "dDEFwW";
952         TimeZone JavaDoc timeZone;
953         String JavaDoc zone;
954
955         // Get the timezone information if it was supplied and modify the
956
// dateTime so that SimpleDateFormat will understand it.
957
if (dateTime.endsWith("Z") || dateTime.endsWith("z"))
958         {
959             timeZone = TimeZone.getTimeZone("GMT");
960             dateTime = dateTime.substring(0, dateTime.length()-1) + "GMT";
961             zone = "z";
962         }
963         else if ((dateTime.length() >= 6)
964                  && (dateTime.charAt(dateTime.length()-3) == ':')
965                  && ((dateTime.charAt(dateTime.length()-6) == '+')
966                     || (dateTime.charAt(dateTime.length()-6) == '-')))
967         {
968             String JavaDoc offset = dateTime.substring(dateTime.length()-6);
969             
970             if ("+00:00".equals(offset) || "-00:00".equals(offset))
971             {
972                 timeZone = TimeZone.getTimeZone("GMT");
973             }
974             else
975             {
976                 timeZone = TimeZone.getTimeZone("GMT" + offset);
977             }
978             zone = "z";
979             // Need to adjust it since SimpleDateFormat requires GMT+hh:mm but
980
// we have +hh:mm.
981
dateTime = dateTime.substring(0, dateTime.length()-6) + "GMT" + offset;
982         }
983         else
984         {
985             // Assume local time.
986
timeZone = TimeZone.getDefault();
987             zone = "";
988             // Leave off the timezone since SimpleDateFormat will assume local
989
// time if time zone is not included.
990
}
991         String JavaDoc[] formats = {dt + zone, d, gym, gy};
992         
993         // Try the time format first. We need to do this to prevent
994
// SimpleDateFormat from interpreting a time as a year. i.e we just need
995
// to check if it's a time before we check it's a year.
996
try
997         {
998             SimpleDateFormat JavaDoc inFormat = new SimpleDateFormat JavaDoc(t + zone);
999             inFormat.setLenient(false);
1000            Date JavaDoc d= inFormat.parse(dateTime);
1001            SimpleDateFormat JavaDoc outFormat = new SimpleDateFormat JavaDoc(strip
1002                (yearSymbols + monthSymbols + daySymbols, pattern));
1003            outFormat.setTimeZone(timeZone);
1004            return outFormat.format(d);
1005        }
1006        catch (ParseException JavaDoc pe)
1007        {
1008        }
1009        
1010        // Try the right truncated formats.
1011
for (int i = 0; i < formats.length; i++)
1012        {
1013            try
1014            {
1015                SimpleDateFormat JavaDoc inFormat = new SimpleDateFormat JavaDoc(formats[i]);
1016                inFormat.setLenient(false);
1017                Date JavaDoc d = inFormat.parse(dateTime);
1018                SimpleDateFormat JavaDoc outFormat = new SimpleDateFormat JavaDoc(pattern);
1019                outFormat.setTimeZone(timeZone);
1020                return outFormat.format(d);
1021            }
1022            catch (ParseException JavaDoc pe)
1023            {
1024            }
1025        }
1026        
1027        // Now try the left truncated ones. The Java format() function doesn't
1028
// return the correct strings in this case. We strip any pattern
1029
// symbols that shouldn't be output so that they are not defaulted to
1030
// inappropriate values in the output.
1031
try
1032        {
1033            SimpleDateFormat JavaDoc inFormat = new SimpleDateFormat JavaDoc(gmd);
1034            inFormat.setLenient(false);
1035            Date JavaDoc d = inFormat.parse(dateTime);
1036            SimpleDateFormat JavaDoc outFormat = new SimpleDateFormat JavaDoc(strip(yearSymbols, pattern));
1037            outFormat.setTimeZone(timeZone);
1038            return outFormat.format(d);
1039        }
1040        catch (ParseException JavaDoc pe)
1041        {
1042        }
1043        try
1044        {
1045            SimpleDateFormat JavaDoc inFormat = new SimpleDateFormat JavaDoc(gm);
1046            inFormat.setLenient(false);
1047            Date JavaDoc d = inFormat.parse(dateTime);
1048            SimpleDateFormat JavaDoc outFormat = new SimpleDateFormat JavaDoc(strip(yearSymbols, pattern));
1049            outFormat.setTimeZone(timeZone);
1050            return outFormat.format(d);
1051        }
1052        catch (ParseException JavaDoc pe)
1053        {
1054        }
1055        try
1056        {
1057            SimpleDateFormat JavaDoc inFormat = new SimpleDateFormat JavaDoc(gd);
1058            inFormat.setLenient(false);
1059            Date JavaDoc d = inFormat.parse(dateTime);
1060            SimpleDateFormat JavaDoc outFormat = new SimpleDateFormat JavaDoc(strip(yearSymbols + monthSymbols, pattern));
1061            outFormat.setTimeZone(timeZone);
1062            return outFormat.format(d);
1063        }
1064        catch (ParseException JavaDoc pe)
1065        {
1066        }
1067        return EMPTY_STR;
1068    }
1069    
1070    /**
1071     * Strips occurrences of the given character from a date format pattern.
1072     * @param symbols list of symbols to strip.
1073     * @param pattern
1074     * @return
1075     */

1076    private static String JavaDoc strip(String JavaDoc symbols, String JavaDoc pattern)
1077    {
1078        int quoteSemaphore = 0;
1079        int i = 0;
1080        StringBuffer JavaDoc result = new StringBuffer JavaDoc(pattern.length());
1081
1082        while (i < pattern.length())
1083        {
1084            char ch = pattern.charAt(i);
1085            if (ch == '\'')
1086            {
1087                // Assume it's an openening quote so simply copy the quoted
1088
// text to the result. There is nothing to strip here.
1089
int endQuote = pattern.indexOf('\'', i + 1);
1090                if (endQuote == -1)
1091                {
1092                    endQuote = pattern.length();
1093                }
1094                result.append(pattern.substring(i, endQuote));
1095                i = endQuote++;
1096            }
1097            else if (symbols.indexOf(ch) > -1)
1098            {
1099                // The char needs to be stripped.
1100
i++;
1101            }
1102            else
1103            {
1104                result.append(ch);
1105                i++;
1106            }
1107        }
1108        return result.toString();
1109    }
1110
1111}
1112
Popular Tags