tags:

views:

2138

answers:

6

Is there some simple way to calculate a Weeknumber value from a date value stored in XML?

It needs to be pure XSLT solution. I cannot use any code :(

A: 

I program in Visual Basic, so I know how to do it using VB.NET. Read your XML date into a variable (let's call it SomeDate). Then you construct a new date that you know is the beginning of the year that contains your unknown date. Then, you let the DateDiff function do its work to tell you the week number.

Dim SomeDate As Date = ReadDateFromXML()
Dim YearStart As New Date(Year(SomeDate), 1, 1)
Dim WeekNumber As Integer = DateDiff(DateInterval.WeekOfYear, YearStart, SomeDate)
Mark
It needs to be pure XSLT solution. I cannot use any code :(
Toni Frankola
A: 

And in C#:

DateTime date = DateTime.Now;
int week = date.DayOfYear / 7;
Console.WriteLine(week);
Todd
It needs to be pure XSLT solution. I cannot use any code :(
Toni Frankola
This is incorrect... Have a look here to see why:http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/e38accde-7eaa-462e-95d0-5a47b7dab832/
Mischa Kroon
A: 

Week calculation can get pretty complicated if you always want the week to start on the same day, because the first day of the year is always changing. There's an ISO standard for calculating it, see this Wikipedia article.

Mark Ransom
I am aware of that, but it is not required. Everyweek can start with Sunday or Monday. I just need to calculate the difference between two dates (in weeks)
Toni Frankola
+4  A: 

If you can use EXSLT, there are several date functions available. All of them are implemented in Saxon, but if you're using MSXSL, Chris Bayes has implemented them as extension functions, which you can actually place within your transform inside an msxsl:script element. His implementations are linked from each specific date function page.

Is week-in-year() the function you're looking for?

Edit: Per JeniT's comment, there's a pure XSLT 1.0 template available on the same site with the same functionality as week-in-year() (which she wrote, I think), which might fit your requirements better.

James Sulak
And if you look on that site you'll find a pure XSLT 1.0 template that will do it for you: http://www.exslt.org/date/functions/week-in-year/date.week-in-year.template.xsl
JeniT
So there is. I missed that. Even better.
James Sulak
Thank you both very much. This is really nice implementation.
Toni Frankola
A: 

Check out the XSLT Cookbook by Sal Mangano. Interestingly enough it is available on books.google.com http://books.google.com/books?id=su4pWUPWwuEC&pg=PA125&lpg=PA125&dq=xslt+weeknumber&source=web&ots=nBBc3DVJYU&sig=l19cpOhwd9_PqrB72b9CCZk9wUA

The xslt 2.0 way is:

<xsl:function name="chkbk:calculate-week-number" as="xs:integer">
    <xsl:param name="date" as="xs:date" />
    <xsl:sequence select="xs:integer(format-date($date,'[W'))" />
</xsl:function>

For the 1.0 way, see the cookbox preview. BTW, I simply googled xslt weeknumber to locate this.

Chris Lively
Can you provide a sample on how two use these functions, because it seems I am missing something. Thanks.
Toni Frankola
Go to the link I added and do a search in this book. There is a complete example around page 143.
Chris Lively
The format for the date should be `'[W]'` (missing close square bracket in the above).
JeniT
Thanks, I'll correct when Jeff gives us our editing ability back.
Chris Lively
A: 

This is a pure XSLT 1.0 solution:

One can use the datetime_lib.xsl stylesheet module by Martin Rowlinson, which comes with the XSelerator (a nice XSLT IDE, recently made freely available on sourceforge). You will have to download and install this application, then you will find a wealth of additional libraries and samples of advanced techniques and solutions.

The datetime_lib.xsl file can be found (for a typical installation) on:

       C:\Program Files\Marrowsoft\Xselerator25\Samples\Libraries\

From this library, here is the template named "week-number":

<xsl:template name="week-number">
    <xsl:param name="year"/>
    <xsl:param name="month"/>
    <xsl:param name="day"/>
    <!-- or -->
    <xsl:param name="date" select="''"/>  <!-- format: yyyymmdd or yyyy-mm-dd -->
    <!-- or -->
    <xsl:param name="julian-day" select="''"/>
    <!-- trim down date -->
    <xsl:variable name="tdate" select="translate($date,'-','')"/>
    <!-- decide which params were passed -->
    <xsl:variable name="yyyy">
     <xsl:choose>
      <xsl:when test="string-length($date) > 0"><xsl:value-of select="substring($tdate,1,4)"/></xsl:when>
      <xsl:when test="string-length($julian-day) > 0">
       <xsl:variable name="jdate">
        <xsl:call-template name="julian-day-to-date">
         <xsl:with-param name="julian-day" select="$julian-day"/>
        </xsl:call-template>
       </xsl:variable>
       <xsl:value-of select="substring($jdate,1,4)"/>
      </xsl:when>
      <xsl:otherwise><xsl:value-of select="$year"/></xsl:otherwise>
     </xsl:choose>
    </xsl:variable>
    <!-- get the julian day number -->
    <xsl:variable name="jd">
     <xsl:choose>
      <xsl:when test="string-length($julian-day) > 0"><xsl:value-of select="$julian-day"/></xsl:when>
      <xsl:otherwise>
       <xsl:call-template name="date-to-julian-day">
        <xsl:with-param name="year" select="$year"/>
        <xsl:with-param name="month" select="$month"/>
        <xsl:with-param name="day" select="$day"/>
        <xsl:with-param name="date" select="$date"/>
       </xsl:call-template>
      </xsl:otherwise>
     </xsl:choose>
    </xsl:variable>
    <!-- get the julian day number for the first working day of next year -->
    <xsl:variable name="fyjd">
     <xsl:call-template name="first-day-of-year">
      <xsl:with-param name="year" select="$yyyy+1"/>
      <xsl:with-param name="as-julian-day" select="true()"/>
     </xsl:call-template>
    </xsl:variable>
    <!-- decide which the 'working' year for this date is -->
    <xsl:variable name="start-jd">
     <xsl:choose>
      <xsl:when test="$jd >= $fyjd"><xsl:value-of select="$fyjd"/></xsl:when>
      <xsl:otherwise>
       <xsl:call-template name="date-to-julian-day">
        <xsl:with-param name="date">
         <xsl:call-template name="first-day-of-year">
          <xsl:with-param name="year" select="$yyyy"/>
         </xsl:call-template>
        </xsl:with-param>
       </xsl:call-template>
      </xsl:otherwise>
     </xsl:choose>
    </xsl:variable>
    <!-- final calc output -->
    <xsl:value-of select="floor(($jd - $start-jd) div 7) + 1"/>
</xsl:template>



Here is a simple XSLT transformation using the"week-number" template:


<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt">

 <xsl:import href=
 "C:\Program Files\Marrowsoft\Xselerator25\Samples\Libraries\datetime_lib.xsl"/>

 <xsl:output method="text"/>

 <xsl:template match="/">
     <xsl:call-template name="week-number">
       <xsl:with-param name="date" select="'2008-11-16'"/>
     </xsl:call-template>
 </xsl:template>
</xsl:stylesheet>

When applied on any source XML document (not used), the wanted result is produced:

   46

Hope that this time the answer was really more helpful.

Cheers,

Dimitre Novatchev.

Dimitre Novatchev