Selon la norme ISO-8601 appliquée en France et adoptée par la plupart des pays européens, la semaine 1 est la première série de 4 jours dans l'année (la semaine commençant le lundi) :

  • c’est donc celle qui contient le premier jeudi de l’année et le 4 janvier
  • si le jour de l’an arrive après le jeudi, il se situe donc dans la dernière semaine de l’année précédente
  • le nombre de semaines de l’année peut être 52 ou 53 - une semaine n’est affectée qu’à une seule année
  • cette année 2012, le premier janvier tombant un dimanche faisait donc partie de la semaine 52 de l’an dernier, et la semaine 1 commence le 2 janvier...

Aux US, la semaine commence le dimanche et la semaine 1 est celle contenant le 1er janvier (et aussi le premier samedi de l’année).

  • Une semaine peut donc être affectée deux fois, à la nouvelle année et à l’année précédente
  • Cette année 2012, le premier janvier tombant un dimanche était donc le premier jour de la semaine 1 ...

D’autres modes de calcul peuvent exister ailleurs, comme par exemple :

  • Un jour de début de semaine différent (le samedi), ou bien la semaine 1 est la première semaine entière de l’année

TSQL

En ce qui nous concerne pour calculer nos numéros de semaine ISO-8601, SQL Server 2008 offre l'option utile ISO_WEEK avec la fonction DATEPART :

  • SELECT DATEPART (ISO_WEEK, ‘20120101’) renvoie 52
  • SELECT DATEPART(ww,’20120101’) renvoie 1

Mais si vous n’êtes pas passé à SQL Server 2008, il faut faire le calcul. Chacun sa méthode, voici la mienne :

CREATE FUNCTION dbo.iso_week ( @thedate DATETIME )
RETURNS INT
AS BEGIN
    DECLARE @weeknumber INT    
    -- cas général
    SET  @weeknumber = DATEPART(ww, @thedate) -
            CASE WHEN DATEPART(dw,
                               DATEADD(dd,
                                       -( DATEPART(dy, @thedate) -
                                          1 ), @thedate)) > 4
                 THEN 1
                 ELSE 0
            END
    -- cas des premiers jours de l'année
    IF @weeknumber = 0
      SET @weeknumber = dbo.iso_week(DATEADD(dd, -1, @thedate))
    -- cas des derniers jours appartenant à l'année suivante
    RETURN CASE WHEN DATEPART(mm, @thedate) = 12 AND
                     DATEPART(dd, @thedate) - DATEPART(dw, @thedate) >= 28
                THEN 1
                ELSE @weeknumber
           END
   END       
GO

A voir, cette autre méthode plus élégante que la mienne sur ce blog.