Re: [xsl] Function converting RFC 2822 date to xsd:dateTime

Subject: Re: [xsl] Function converting RFC 2822 date to xsd:dateTime
From: "Martynas Jusevičius martynas@xxxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Tue, 9 Apr 2019 08:09:23 -0000
Thanks all, parse-ietf-date() makes most sense indeed. That is what I went with:

        <xsl:try>
            <triple>
                <xsl:copy-of select="$subject"/>
                <uri>&nmo;sentDate</uri>
                <plainLiteral><xsl:sequence
select="parse-ietf-date($date-time)"/></plainLiteral>
            </triple>

            <xsl:catch>
                <xsl:message><xsl:value-of select="$err:description"/>
Message ID: <xsl:value-of select="$subject"/></xsl:message>
            </xsl:catch>
        </xsl:try>
    </xsl:template>

On Tue, Apr 9, 2019 at 5:45 AM Syd Bauman s.bauman@xxxxxxxxxxxxxxxx
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>
> Martynas --
>
> As Michael Kay brought up, switching to XSLT 3.0 and using
> parse-ietf-date() is probably the best way to go. And I don't pretend
> to be a good enough programmer to know if there are improvements to
> be made to your algorithm. But when dealing with unwieldy stuff like
> this, I find it very helpful to name bits of code and to use
> whitespace liberally, especially within the regular expression (using
> the 'x' flag).
>
> Here is an XSLT 2.0 program that runs a modified version of your
> function. The only other changes I've made to the function are:
>  * signature of $months is now '+', not '*'
>  * different mechanism for inserting colon into TZ
>  * return a dateTime even when there's an error in parsing
>
> #######################
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>   xmlns:xs="http://www.w3.org/2001/XMLSchema";
>   exclude-result-prefixes="#all"
>   xmlns:aex="http://idunno.example.org/";
>   version="2.0">
>
>   <xsl:param name="dt" select="'Tue, 9 Apr 2019 00:07:24 +1200 (NZST)'" as="xs:string"/>
>
>   <xsl:output method="text"/>
>
>   <xsl:template match="/">
>     <xsl:text>Result: </xsl:text>
>     <xsl:value-of select="aex:rfc2822dateTime-to-dateTime( $dt )"/>
>     <xsl:text>&#x0A;</xsl:text>
>   </xsl:template>
>
>   <xsl:function name="aex:rfc2822dateTime-to-dateTime" as="xs:dateTime">
>     <xsl:param name="date-time" as="xs:string"/>
>     <xsl:variable name="months" as="xs:string+" select="
>         'Jan', 'Feb', 'Mar','Apr', 'May', 'Jun',
>         'Jul', 'Aug', 'Sep','Oct', 'Nov', 'Dec'"/>
>     <xsl:analyze-string select="$date-time" flags="x" regex="
>       ^
>       (?:  (Sun|Mon|Tue|Wed|Thu|Fri|Sat),\s+  )?
>       ( 0[1-9] | [1-2]?[0-9] | 3[01] )
>       \s+
>       (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
>       \s+
>       ( 19[0-9]{{2}} | [2-9][0-9]{{3}} )
>       \s+
>       ( 2[0-3] | [0-1][0-9] )
>       :
>       ( [0-5][0-9] )
>       (?: :( 60 | [0-5][0-9] ) )?
>       \s+
>       (
>         [-\+]
>         [0-9]{{2}}[0-5][0-9]
>         |
>         (?: UT | GMT | (?:E|C|M|P) (?:ST|DT) | [A-IK-Z] )
>       )
>       (\s+|\(([^\(\)]+|\\\(|\\\))*\))*$">
>       <xsl:matching-substring>
>         <xsl:variable name="day" select="regex-group(1)"/><!-- unused -->
>         <xsl:variable name="date" select="xs:integer( regex-group(2) )"/>
>         <xsl:variable name="month" select="index-of( $months, regex-group(3) )"/>
>         <xsl:variable name="year" select="xs:integer( regex-group(4) )"/>
>         <xsl:variable name="hour" select="xs:integer( regex-group(5) )"/>
>         <xsl:variable name="minute" select="xs:integer( regex-group(6) )"/>
>         <xsl:variable name="second" select="xs:integer( regex-group(7) )"/>
>         <xsl:variable name="timezone" select="replace( regex-group(8),'^(...)(.*)$','$1:$2' )"/>
>         <xsl:variable name="dateTimeString" select="concat(
>           format-number( $year,'0001'),
>           '-',
>           format-number( $month,'01'),
>           '-',
>           format-number( $date,'01'),
>           'T',
>           format-number( $hour,'01'),
>           ':',
>           format-number( $minute,'01'),
>           ':',
>           format-number( $second,'01'),
>           $timezone )"/>
>         <xsl:value-of select="$dateTimeString"/>
>       </xsl:matching-substring>
>       <xsl:non-matching-substring>
>         <xsl:message>Invalid RFC 2822 datetime: <xsl:value-of select="$date-time"/></xsl:message>
>         <!--
>           2 points to anyone who can say what happened at the date and time
>           I've chosen to return in case of error. 2 hints: 1) I made up the
>           seconds, to my knowledge it was only recorded to the minute; 2) it
>           was pronounced "seventeen October nineteen forty-five" in the musical.
>         -->
>         <xsl:value-of select="xs:dateTime('1945-10-17T23:10:30-03:00')"/>
>       </xsl:non-matching-substring>
>     </xsl:analyze-string>
>   </xsl:function>
>
> </xsl:stylesheet>
> #######################
>
> Hope this is at least food for thought, if not outright helpful.

Current Thread