1 <?xml version="1.0" encoding="UTF-8"?>
\r
2 <xsl:stylesheet version="1.0"
\r
3 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
\r
4 xmlns:date="http://exslt.org/dates-and-times"
\r
5 xmlns:str="http://exslt.org/strings"
\r
6 extension-element-prefixes="date str">
\r
9 Derived from date.format-date.template.xsl by Jeni Tennison.
\r
10 http://exslt.org/date/functions/format-date/date.format-date.template.xsl
\r
11 See also http://exslt.org/date/functions/format-date/index.html.
\r
15 2010-23-11 Ingo Kloecker
\r
16 * Commented out import of str.padding.template.xsl since xsltproc supports
\r
17 str:padding out-of-the-box.
\r
18 * Fixed a bug in date:_format-date with the handling of quoted text in the
\r
20 * Renamed template date:format-date to date:format-date-localized.
\r
21 * Added localization support (English and Spanish).
\r
25 <xsl:import href="../../../str/functions/padding/str.padding.template.xsl" />
\r
28 <date:months lang="en">
\r
29 <date:month length="31" abbr="Jan">January</date:month>
\r
30 <date:month length="28" abbr="Feb">February</date:month>
\r
31 <date:month length="31" abbr="Mar">March</date:month>
\r
32 <date:month length="30" abbr="Apr">April</date:month>
\r
33 <date:month length="31" abbr="May">May</date:month>
\r
34 <date:month length="30" abbr="Jun">June</date:month>
\r
35 <date:month length="31" abbr="Jul">July</date:month>
\r
36 <date:month length="31" abbr="Aug">August</date:month>
\r
37 <date:month length="30" abbr="Sep">September</date:month>
\r
38 <date:month length="31" abbr="Oct">October</date:month>
\r
39 <date:month length="30" abbr="Nov">November</date:month>
\r
40 <date:month length="31" abbr="Dec">December</date:month>
\r
43 <date:months lang="es">
\r
44 <date:month length="31" abbr="ene.">enero</date:month>
\r
45 <date:month length="28" abbr="feb.">febrero</date:month>
\r
46 <date:month length="31" abbr="mar.">marzo</date:month>
\r
47 <date:month length="30" abbr="abr.">abril</date:month>
\r
48 <date:month length="31" abbr="may.">mayo</date:month>
\r
49 <date:month length="30" abbr="jun.">junio</date:month>
\r
50 <date:month length="31" abbr="jul.">julio</date:month>
\r
51 <date:month length="31" abbr="ago.">agosto</date:month>
\r
52 <date:month length="30" abbr="sep.">septiembre</date:month>
\r
53 <date:month length="31" abbr="oct.">octubre</date:month>
\r
54 <date:month length="30" abbr="nov.">noviembre</date:month>
\r
55 <date:month length="31" abbr="dic.">diciembre</date:month>
\r
58 <date:days lang="en">
\r
59 <date:day abbr="Sun">Sunday</date:day>
\r
60 <date:day abbr="Mon">Monday</date:day>
\r
61 <date:day abbr="Tue">Tuesday</date:day>
\r
62 <date:day abbr="Wed">Wednesday</date:day>
\r
63 <date:day abbr="Thu">Thursday</date:day>
\r
64 <date:day abbr="Fri">Friday</date:day>
\r
65 <date:day abbr="Sat">Saturday</date:day>
\r
68 <date:days lang="es">
\r
69 <date:day abbr="D">domingo</date:day>
\r
70 <date:day abbr="L">lunes</date:day>
\r
71 <date:day abbr="M">martes</date:day>
\r
72 <date:day abbr="X">miércoles</date:day>
\r
73 <date:day abbr="J">jueves</date:day>
\r
74 <date:day abbr="V">viernes</date:day>
\r
75 <date:day abbr="S">sábado</date:day>
\r
78 <xsl:template name="date:format-date-localized">
\r
79 <xsl:param name="date-time" />
\r
80 <xsl:param name="pattern" />
\r
81 <xsl:variable name="formatted">
\r
83 <xsl:when test="starts-with($date-time, '---')">
\r
84 <xsl:call-template name="date:_format-date">
\r
85 <xsl:with-param name="year" select="'NaN'" />
\r
86 <xsl:with-param name="month" select="'NaN'" />
\r
87 <xsl:with-param name="day" select="number(substring($date-time, 4, 2))" />
\r
88 <xsl:with-param name="pattern" select="$pattern" />
\r
89 </xsl:call-template>
\r
91 <xsl:when test="starts-with($date-time, '--')">
\r
92 <xsl:call-template name="date:_format-date">
\r
93 <xsl:with-param name="year" select="'NaN'" />
\r
94 <xsl:with-param name="month" select="number(substring($date-time, 3, 2))" />
\r
95 <xsl:with-param name="day" select="number(substring($date-time, 6, 2))" />
\r
96 <xsl:with-param name="pattern" select="$pattern" />
\r
97 </xsl:call-template>
\r
100 <xsl:variable name="neg" select="starts-with($date-time, '-')" />
\r
101 <xsl:variable name="no-neg">
\r
103 <xsl:when test="$neg or starts-with($date-time, '+')">
\r
104 <xsl:value-of select="substring($date-time, 2)" />
\r
107 <xsl:value-of select="$date-time" />
\r
111 <xsl:variable name="no-neg-length" select="string-length($no-neg)" />
\r
112 <xsl:variable name="timezone">
\r
114 <xsl:when test="substring($no-neg, $no-neg-length) = 'Z'">Z</xsl:when>
\r
116 <xsl:variable name="tz" select="substring($no-neg, $no-neg-length - 5)" />
\r
117 <xsl:if test="(substring($tz, 1, 1) = '-' or
\r
118 substring($tz, 1, 1) = '+') and
\r
119 substring($tz, 4, 1) = ':'">
\r
120 <xsl:value-of select="$tz" />
\r
125 <xsl:if test="not(string($timezone)) or
\r
126 $timezone = 'Z' or
\r
127 (substring($timezone, 2, 2) <= 23 and
\r
128 substring($timezone, 5, 2) <= 59)">
\r
129 <xsl:variable name="dt" select="substring($no-neg, 1, $no-neg-length - string-length($timezone))" />
\r
130 <xsl:variable name="dt-length" select="string-length($dt)" />
\r
132 <xsl:when test="substring($dt, 3, 1) = ':' and
\r
133 substring($dt, 6, 1) = ':'">
\r
134 <xsl:variable name="hour" select="substring($dt, 1, 2)" />
\r
135 <xsl:variable name="min" select="substring($dt, 4, 2)" />
\r
136 <xsl:variable name="sec" select="substring($dt, 7)" />
\r
137 <xsl:if test="$hour <= 23 and
\r
140 <xsl:call-template name="date:_format-date">
\r
141 <xsl:with-param name="year" select="'NaN'" />
\r
142 <xsl:with-param name="month" select="'NaN'" />
\r
143 <xsl:with-param name="day" select="'NaN'" />
\r
144 <xsl:with-param name="hour" select="$hour" />
\r
145 <xsl:with-param name="minute" select="$min" />
\r
146 <xsl:with-param name="second" select="$sec" />
\r
147 <xsl:with-param name="timezone" select="$timezone" />
\r
148 <xsl:with-param name="pattern" select="$pattern" />
\r
149 </xsl:call-template>
\r
153 <xsl:variable name="year" select="substring($dt, 1, 4) * (($neg * -2) + 1)" />
\r
155 <xsl:when test="not(number($year))" />
\r
156 <xsl:when test="$dt-length = 4">
\r
157 <xsl:call-template name="date:_format-date">
\r
158 <xsl:with-param name="year" select="$year" />
\r
159 <xsl:with-param name="timezone" select="$timezone" />
\r
160 <xsl:with-param name="pattern" select="$pattern" />
\r
161 </xsl:call-template>
\r
163 <xsl:when test="substring($dt, 5, 1) = '-'">
\r
164 <xsl:variable name="month" select="substring($dt, 6, 2)" />
\r
166 <xsl:when test="not($month <= 12)" />
\r
167 <xsl:when test="$dt-length = 7">
\r
168 <xsl:call-template name="date:_format-date">
\r
169 <xsl:with-param name="year" select="$year" />
\r
170 <xsl:with-param name="month" select="$month" />
\r
171 <xsl:with-param name="timezone" select="$timezone" />
\r
172 <xsl:with-param name="pattern" select="$pattern" />
\r
173 </xsl:call-template>
\r
175 <xsl:when test="substring($dt, 8, 1) = '-'">
\r
176 <xsl:variable name="day" select="substring($dt, 9, 2)" />
\r
177 <xsl:if test="$day <= 31">
\r
179 <xsl:when test="$dt-length = 10">
\r
180 <xsl:call-template name="date:_format-date">
\r
181 <xsl:with-param name="year" select="$year" />
\r
182 <xsl:with-param name="month" select="$month" />
\r
183 <xsl:with-param name="day" select="$day" />
\r
184 <xsl:with-param name="timezone" select="$timezone" />
\r
185 <xsl:with-param name="pattern" select="$pattern" />
\r
186 </xsl:call-template>
\r
188 <xsl:when test="substring($dt, 11, 1) = 'T' and
\r
189 substring($dt, 14, 1) = ':' and
\r
190 substring($dt, 17, 1) = ':'">
\r
191 <xsl:variable name="hour" select="substring($dt, 12, 2)" />
\r
192 <xsl:variable name="min" select="substring($dt, 15, 2)" />
\r
193 <xsl:variable name="sec" select="substring($dt, 18)" />
\r
194 <xsl:if test="$hour <= 23 and
\r
197 <xsl:call-template name="date:_format-date">
\r
198 <xsl:with-param name="year" select="$year" />
\r
199 <xsl:with-param name="month" select="$month" />
\r
200 <xsl:with-param name="day" select="$day" />
\r
201 <xsl:with-param name="hour" select="$hour" />
\r
202 <xsl:with-param name="minute" select="$min" />
\r
203 <xsl:with-param name="second" select="$sec" />
\r
204 <xsl:with-param name="timezone" select="$timezone" />
\r
205 <xsl:with-param name="pattern" select="$pattern" />
\r
206 </xsl:call-template>
\r
221 <xsl:value-of select="$formatted" />
\r
224 <xsl:template name="date:_format-date">
\r
225 <xsl:param name="year" />
\r
226 <xsl:param name="month" select="1" />
\r
227 <xsl:param name="day" select="1" />
\r
228 <xsl:param name="hour" select="0" />
\r
229 <xsl:param name="minute" select="0" />
\r
230 <xsl:param name="second" select="0" />
\r
231 <xsl:param name="timezone" select="'Z'" />
\r
232 <xsl:param name="pattern" select="''" />
\r
233 <xsl:variable name="char" select="substring($pattern, 1, 1)" />
\r
235 <xsl:when test="not($pattern)" />
\r
236 <xsl:when test='$char = "'"'>
\r
238 <xsl:when test='substring($pattern, 2, 1) = "'"'>
\r
239 <xsl:text>'</xsl:text>
\r
240 <xsl:call-template name="date:_format-date">
\r
241 <xsl:with-param name="year" select="$year" />
\r
242 <xsl:with-param name="month" select="$month" />
\r
243 <xsl:with-param name="day" select="$day" />
\r
244 <xsl:with-param name="hour" select="$hour" />
\r
245 <xsl:with-param name="minute" select="$minute" />
\r
246 <xsl:with-param name="second" select="$second" />
\r
247 <xsl:with-param name="timezone" select="$timezone" />
\r
248 <xsl:with-param name="pattern" select="substring($pattern, 3)" />
\r
249 </xsl:call-template>
\r
252 <xsl:variable name="literal-value" select='substring-before(substring($pattern, 2), "'")' />
\r
253 <xsl:value-of select="$literal-value" />
\r
254 <xsl:call-template name="date:_format-date">
\r
255 <xsl:with-param name="year" select="$year" />
\r
256 <xsl:with-param name="month" select="$month" />
\r
257 <xsl:with-param name="day" select="$day" />
\r
258 <xsl:with-param name="hour" select="$hour" />
\r
259 <xsl:with-param name="minute" select="$minute" />
\r
260 <xsl:with-param name="second" select="$second" />
\r
261 <xsl:with-param name="timezone" select="$timezone" />
\r
262 <xsl:with-param name="pattern" select="substring($pattern, string-length($literal-value) + 3)" />
\r
263 <!-- In the original file this was
\r
264 <xsl:with-param name="pattern" select="substring($pattern, string-length($literal-value) + 2)" />
\r
266 </xsl:call-template>
\r
270 <xsl:when test="not(contains('abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', $char))">
\r
271 <xsl:value-of select="$char" />
\r
272 <xsl:call-template name="date:_format-date">
\r
273 <xsl:with-param name="year" select="$year" />
\r
274 <xsl:with-param name="month" select="$month" />
\r
275 <xsl:with-param name="day" select="$day" />
\r
276 <xsl:with-param name="hour" select="$hour" />
\r
277 <xsl:with-param name="minute" select="$minute" />
\r
278 <xsl:with-param name="second" select="$second" />
\r
279 <xsl:with-param name="timezone" select="$timezone" />
\r
280 <xsl:with-param name="pattern" select="substring($pattern, 2)" />
\r
281 </xsl:call-template>
\r
283 <xsl:when test="not(contains('GyMdhHmsSEDFwWakKz', $char))">
\r
285 Invalid token in format string: <xsl:value-of select="$char" />
\r
287 <xsl:call-template name="date:_format-date">
\r
288 <xsl:with-param name="year" select="$year" />
\r
289 <xsl:with-param name="month" select="$month" />
\r
290 <xsl:with-param name="day" select="$day" />
\r
291 <xsl:with-param name="hour" select="$hour" />
\r
292 <xsl:with-param name="minute" select="$minute" />
\r
293 <xsl:with-param name="second" select="$second" />
\r
294 <xsl:with-param name="timezone" select="$timezone" />
\r
295 <xsl:with-param name="pattern" select="substring($pattern, 2)" />
\r
296 </xsl:call-template>
\r
299 <xsl:variable name="next-different-char" select="substring(translate($pattern, $char, ''), 1, 1)" />
\r
300 <xsl:variable name="pattern-length">
\r
302 <xsl:when test="$next-different-char">
\r
303 <xsl:value-of select="string-length(substring-before($pattern, $next-different-char))" />
\r
306 <xsl:value-of select="string-length($pattern)" />
\r
311 <xsl:when test="$char = 'G'">
\r
313 <xsl:when test="string($year) = 'NaN'" />
\r
314 <xsl:when test="$year > 0">AD</xsl:when>
\r
315 <xsl:otherwise>BC</xsl:otherwise>
\r
318 <xsl:when test="$char = 'M'">
\r
320 <xsl:when test="string($month) = 'NaN'" />
\r
321 <xsl:when test="$pattern-length >= 3">
\r
322 <xsl:variable name="month-node" select="document('')/*/date:months[@lang=$language]/date:month[number($month)]" />
\r
324 <xsl:when test="$pattern-length >= 4">
\r
325 <xsl:value-of select="$month-node" />
\r
328 <xsl:value-of select="$month-node/@abbr" />
\r
332 <xsl:when test="$pattern-length = 2">
\r
333 <xsl:value-of select="format-number($month, '00')" />
\r
336 <xsl:value-of select="$month" />
\r
340 <xsl:when test="$char = 'E'">
\r
342 <xsl:when test="string($year) = 'NaN' or string($month) = 'NaN' or string($day) = 'NaN'" />
\r
344 <xsl:variable name="month-days" select="sum(document('')/*/date:months[@lang=$language]/date:month[position() < $month]/@length)" />
\r
345 <xsl:variable name="days" select="$month-days + $day + boolean(((not($year mod 4) and $year mod 100) or not($year mod 400)) and $month > 2)" />
\r
346 <xsl:variable name="y-1" select="$year - 1" />
\r
347 <xsl:variable name="dow"
\r
348 select="(($y-1 + floor($y-1 div 4) -
\r
349 floor($y-1 div 100) + floor($y-1 div 400) +
\r
352 <xsl:variable name="day-node" select="document('')/*/date:days[@lang=$language]/date:day[number($dow)]" />
\r
354 <xsl:when test="$pattern-length >= 4">
\r
355 <xsl:value-of select="$day-node" />
\r
358 <xsl:value-of select="$day-node/@abbr" />
\r
364 <xsl:when test="$char = 'a'">
\r
366 <xsl:when test="string($hour) = 'NaN'" />
\r
367 <xsl:when test="$hour >= 12">PM</xsl:when>
\r
368 <xsl:otherwise>AM</xsl:otherwise>
\r
371 <xsl:when test="$char = 'z'">
\r
373 <xsl:when test="$timezone = 'Z'">UTC</xsl:when>
\r
374 <xsl:otherwise>UTC<xsl:value-of select="$timezone" /></xsl:otherwise>
\r
378 <xsl:variable name="padding">
\r
380 <xsl:when test="$pattern-length > 10">
\r
381 <xsl:call-template name="str:padding">
\r
382 <xsl:with-param name="length" select="$pattern-length" />
\r
383 <xsl:with-param name="chars" select="'0'" />
\r
384 </xsl:call-template>
\r
387 <xsl:value-of select="substring('0000000000', 1, $pattern-length)" />
\r
392 <xsl:when test="$char = 'y'">
\r
394 <xsl:when test="string($year) = 'NaN'" />
\r
395 <xsl:when test="$pattern-length > 2"><xsl:value-of select="format-number($year, $padding)" /></xsl:when>
\r
396 <xsl:otherwise><xsl:value-of select="format-number(substring($year, string-length($year) - 1), $padding)" /></xsl:otherwise>
\r
399 <xsl:when test="$char = 'd'">
\r
401 <xsl:when test="string($day) = 'NaN'" />
\r
402 <xsl:otherwise><xsl:value-of select="format-number($day, $padding)" /></xsl:otherwise>
\r
405 <xsl:when test="$char = 'h'">
\r
406 <xsl:variable name="h" select="$hour mod 12" />
\r
408 <xsl:when test="string($hour) = 'NaN'"></xsl:when>
\r
409 <xsl:when test="$h"><xsl:value-of select="format-number($h, $padding)" /></xsl:when>
\r
410 <xsl:otherwise><xsl:value-of select="format-number(12, $padding)" /></xsl:otherwise>
\r
413 <xsl:when test="$char = 'H'">
\r
415 <xsl:when test="string($hour) = 'NaN'" />
\r
417 <xsl:value-of select="format-number($hour, $padding)" />
\r
421 <xsl:when test="$char = 'k'">
\r
423 <xsl:when test="string($hour) = 'NaN'" />
\r
424 <xsl:when test="$hour"><xsl:value-of select="format-number($hour, $padding)" /></xsl:when>
\r
425 <xsl:otherwise><xsl:value-of select="format-number(24, $padding)" /></xsl:otherwise>
\r
428 <xsl:when test="$char = 'K'">
\r
430 <xsl:when test="string($hour) = 'NaN'" />
\r
431 <xsl:otherwise><xsl:value-of select="format-number($hour mod 12, $padding)" /></xsl:otherwise>
\r
434 <xsl:when test="$char = 'm'">
\r
436 <xsl:when test="string($minute) = 'NaN'" />
\r
438 <xsl:value-of select="format-number($minute, $padding)" />
\r
442 <xsl:when test="$char = 's'">
\r
444 <xsl:when test="string($second) = 'NaN'" />
\r
446 <xsl:value-of select="format-number($second, $padding)" />
\r
450 <xsl:when test="$char = 'S'">
\r
452 <xsl:when test="string($second) = 'NaN'" />
\r
454 <xsl:value-of select="format-number(substring-after($second, '.'), $padding)" />
\r
458 <xsl:when test="$char = 'F'">
\r
460 <xsl:when test="string($day) = 'NaN'" />
\r
462 <xsl:value-of select="floor($day div 7) + 1" />
\r
466 <xsl:when test="string($year) = 'NaN' or string($month) = 'NaN' or string($day) = 'NaN'" />
\r
468 <xsl:variable name="month-days" select="sum(document('')/*/date:months[@lang=$language]/date:month[position() < $month]/@length)" />
\r
469 <xsl:variable name="days" select="$month-days + $day + boolean(((not($year mod 4) and $year mod 100) or not($year mod 400)) and $month > 2)" />
\r
471 <xsl:when test="$char = 'D'">
\r
472 <xsl:value-of select="format-number($days, $padding)" />
\r
474 <xsl:when test="$char = 'w'">
\r
475 <xsl:call-template name="date:_week-in-year">
\r
476 <xsl:with-param name="days" select="$days" />
\r
477 <xsl:with-param name="year" select="$year" />
\r
478 </xsl:call-template>
\r
480 <xsl:when test="$char = 'W'">
\r
481 <xsl:variable name="y-1" select="$year - 1" />
\r
482 <xsl:variable name="day-of-week"
\r
483 select="(($y-1 + floor($y-1 div 4) -
\r
484 floor($y-1 div 100) + floor($y-1 div 400) +
\r
488 <xsl:when test="($day - $day-of-week) mod 7">
\r
489 <xsl:value-of select="floor(($day - $day-of-week) div 7) + 2" />
\r
492 <xsl:value-of select="floor(($day - $day-of-week) div 7) + 1" />
\r
501 <xsl:call-template name="date:_format-date">
\r
502 <xsl:with-param name="year" select="$year" />
\r
503 <xsl:with-param name="month" select="$month" />
\r
504 <xsl:with-param name="day" select="$day" />
\r
505 <xsl:with-param name="hour" select="$hour" />
\r
506 <xsl:with-param name="minute" select="$minute" />
\r
507 <xsl:with-param name="second" select="$second" />
\r
508 <xsl:with-param name="timezone" select="$timezone" />
\r
509 <xsl:with-param name="pattern" select="substring($pattern, $pattern-length + 1)" />
\r
510 </xsl:call-template>
\r
515 <xsl:template name="date:_week-in-year">
\r
516 <xsl:param name="days" />
\r
517 <xsl:param name="year" />
\r
518 <xsl:variable name="y-1" select="$year - 1" />
\r
519 <!-- this gives the day of the week, counting from Sunday = 0 -->
\r
520 <xsl:variable name="day-of-week"
\r
521 select="($y-1 + floor($y-1 div 4) -
\r
522 floor($y-1 div 100) + floor($y-1 div 400) +
\r
525 <!-- this gives the day of the week, counting from Monday = 1 -->
\r
526 <xsl:variable name="dow">
\r
528 <xsl:when test="$day-of-week"><xsl:value-of select="$day-of-week" /></xsl:when>
\r
529 <xsl:otherwise>7</xsl:otherwise>
\r
532 <xsl:variable name="start-day" select="($days - $dow + 7) mod 7" />
\r
533 <xsl:variable name="week-number" select="floor(($days - $dow + 7) div 7)" />
\r
535 <xsl:when test="$start-day >= 4">
\r
536 <xsl:value-of select="$week-number + 1" />
\r
540 <xsl:when test="not($week-number)">
\r
541 <xsl:call-template name="date:_week-in-year">
\r
542 <xsl:with-param name="days" select="365 + ((not($y-1 mod 4) and $y-1 mod 100) or not($y-1 mod 400))" />
\r
543 <xsl:with-param name="year" select="$y-1" />
\r
544 </xsl:call-template>
\r
547 <xsl:value-of select="$week-number" />
\r