Le calcul du numéro de semaine, TSQL

Le mode de calcul du numéro de semaine est différent d’un pays à l’autre : quelle est la semaine 1 d’une année ? Cela dépend du mode de calcul de notre pays et de quel jour nous sommes le jour de l’an ! Cette année, le jour de l'an est semaine 52 en France et semaine 1 aux USA...
Quelle prise en charge de notre mode de calcul à la norme ISO et comment obtenir le bon numéro de semaine à partir d'une date avec TSQL ?

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.


Commentaires

1. Le lundi 6 février 2012, 11:57 par Fleid

Salut Arian!

Tu pourrais pas nous faire aussi le script pour l'année ISO?

Parce que si la semaine 1-2012 devient la semaine 53, il ne faut pas oublier de changer également l'année, sinon on bascule sur la semaine 53-2012 qui n'est pas vraiment la même :)

En tout cas merci pour l'info!

2. Le mardi 20 novembre 2012, 17:57 par AndrewWalnut

Un fait intéressant (particulièrement pour les années ou le 1 janvier est un dimanche). Remarquer que la semaine 1 (US) ne comporte que le dimanche, car toute autre jour de semaine tombe dans l'année précédente. Chercher la date du lundi de la semaine 1 n'est pas en 2012, le premier lundi est obligatoirement dans la semaine 2.
Pour la semaine ISO on ne peu avoir plus de 3 jours manquant dans la semaine 1, soit Lu - Ma - Me. Et il ne manque pas puisque le calcul retournera un numéro de semaine de l'an précédent.
Par contre en ISO, les premiers jours de l'an courant peuvent se retrouver dans l'an précédent, chose qui ne peu arriver avec le calendrier US. (Mais vous l'aurez compris tout se calcule, il s'agit d'avoir le bon algorithme).
Le plaisir des calendriers...