[xquery-talk] function to get week number of a date?

Jakob Fix jakob.fix at gmail.com
Tue Nov 9 01:11:58 PST 2010


I was happily coding away reimplementing the date:week-in-year
function in Oxygen, when I noticed that this function was already
recognized by Oxygen

xquery version "1.0";
declare namespace date = "http://exslt.org/dates-and-times";
date:week-in-year( "2010-01-04T00:00:00Z" )

=> 1

I guess that this is Saxon 9.x's implementation of this function
kicking in as Saxon implements a number of EXSLT extensions:
http://saxonica.com/documentation/extensions/exslt.xml.

However, for those implementations that do not implement exslt
functions, I've converted the XSLT version to Xquery (all the heavy
lifting of leap years and what have you had already been taken care of
so that was rather easy), just in case it helps somebody ....


xquery version "1.0";
declare namespace exslt = "http://exslt.org/dates-and-times";
(: for those implementations without exslt extensions :)
declare namespace date = "http://noexslt.org/dates-and-times";
declare variable $date-time := "2010-01-02T00:00:00Z";
declare variable $month-lengths := (0, 31, 28, 31, 30, 31, 30, 31, 31,
30, 31, 30, 31);

(:
 : returns the week of the year as a number.
 :)
declare function date:week-in-year( $date-time as xs:dateTime ) as xs:integer
{
    let $year := fn:year-from-dateTime( $date-time )
    let $day := fn:day-from-dateTime( $date-time )
    let $month := fn:month-from-dateTime( $date-time )

    let $days := sum( subsequence( $month-lengths, 1, $month ) )
    let $is-leap := ($year mod 4 = 0 and $year mod 100 != 0) or $year
mod 400 = 0
    return date:_week-in-year($year, $days + $day + (if ($is-leap and
$month > 2) then 1 else 0))
};

declare function date:_week-in-year( $year as xs:integer, $month-days
as xs:integer) as xs:integer
{
    let $previous-year := $year - 1
    let $is-leap := ($year mod 4 = 0 and $year mod 100 != 0) or $year
mod 400 = 0
    let $dow := ($previous-year + floor($previous-year div 4) -
        floor($previous-year div 100) + floor($previous-year div 400) +
        $month-days) mod 7
    let $day-of-week := if ($dow > 0) then $dow else 7
    let $start-day := ($month-days - $day-of-week + 7) mod 7
    let $week-number := floor(($month-days - $day-of-week + 7) div 7)
cast as xs:integer
    return
        if ($start-day >= 4) then $week-number + 1
        else if ($week-number = 0) then
            let $leap-day := if ((not($previous-year mod 4) and
$previous-year mod 100) or not($previous-year mod 400)) then 1 else 0
            return date:_week-in-year( $previous-year, 365 + $leap-day )
            else $week-number
};

exslt:week-in-year( $date-time ),
date:week-in-year( $date-time cast as xs:dateTime )



thanks,
Jakob.



On Mon, Nov 8, 2010 at 16:42, Michael Kay <mike at saxonica.com> wrote:
> On 08/11/2010 14:45, Jakob Fix wrote:
>>
>> Hi, before starting to writing my own function, I was wondering if
>> somebody among the readers of this list has already written a function
>> to find out the week number of a given date and is willing to share? I
>> haven't found anything on xqueryfunctions.com, for example.
>>
>> thanks,
>> Jakob.
>> _______________________________________________
>> talk at x-query.com
>> http://x-query.com/mailman/listinfo/talk
>>
> EXSLT has a suitable function (starting from a string rather than an
> xs:date) and there are pointers to a number of implementations you could
> crib from:
>
> http://www.exslt.org/date/functions/week-in-year/index.html
>
> Michael Kay
> Saxonica
> _______________________________________________
> talk at x-query.com
> http://x-query.com/mailman/listinfo/talk
>


More information about the talk mailing list