Pour répondre à la question de savoir pourquoi vous recevez un lundi et non un dimanche :
Vous ajoutez un nombre de semaines à la date 0. Quelle est la date 0 ? 1900-01-01. Quel était le jour en 1900-01-01 ? Lundi. Donc, dans votre code, vous dites : combien de semaines se sont écoulées depuis le lundi 1er janvier 1900 ? Appelons cela [n]. Ok, maintenant ajoutez [n] semaines au lundi 1er janvier 1900. Vous ne devriez pas être surpris que cela finisse par être un lundi. DATEADD
n'a aucune idée que vous voulez ajouter des semaines mais seulement jusqu'à ce que vous arriviez à un dimanche, c'est juste ajouter 7 jours, puis ajouter 7 autres jours, ... tout comme DATEDIFF
ne reconnaît que les limites qui ont été franchies. Par exemple, ils renvoient tous deux 1, même si certaines personnes se plaignent qu'il devrait y avoir une certaine logique intégrée pour arrondir à l'unité supérieure ou inférieure :
SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');
Pour répondre à comment obtenir un dimanche :
Si vous voulez un dimanche, choisissez une date de base qui n'est pas un lundi mais plutôt un dimanche. Par exemple :
DECLARE @dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);
Cela ne se brisera pas si vous changez votre DATEFIRST
(ou votre code est exécuté pour un utilisateur avec un paramètre différent) - à condition que vous vouliez toujours un dimanche, quel que soit le paramètre actuel. Si vous voulez que ces deux réponses concordent, vous devez utiliser une fonction qui fait dépendent de la DATEFIRST
le cadre, par exemple
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);
Donc si vous changez votre DATEFIRST
à lundi, mardi, etc., le comportement changera. En fonction du comportement que vous souhaitez, vous pouvez utiliser l'une de ces fonctions :
CREATE FUNCTION dbo.StartOfWeek1 -- always a Sunday
(
@d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19050101', @d), '19050101'));
END
GO
...ou...
CREATE FUNCTION dbo.StartOfWeek2 -- always the DATEFIRST weekday
(
@d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, @d), @d));
END
GO
Vous avez maintenant de nombreuses alternatives, mais laquelle est la plus performante ? Je serais surpris qu'il y ait des différences majeures, mais j'ai rassemblé toutes les réponses fournies jusqu'à présent et je les ai soumises à deux séries de tests - l'une bon marché et l'autre coûteuse. J'ai mesuré les statistiques du client car je ne pense pas que les entrées/sorties ou la mémoire jouent un rôle dans les performances (bien qu'elles puissent entrer en jeu selon la façon dont la fonction est utilisée). Dans mes tests, les résultats sont les suivants :
Demande d'affectation "bon marché" :
Function - client processing time / wait time on server replies / total exec time
Gandarez - 330/2029/2359 - 0:23.6
me datefirst - 329/2123/2452 - 0:24.5
me Sunday - 357/2158/2515 - 0:25.2
trailmax - 364/2160/2524 - 0:25.2
Curt - 424/2202/2626 - 0:26.3
Demande d'affectation "coûteuse" :
Function - client processing time / wait time on server replies / total exec time
Curt - 1003/134158/135054 - 2:15
Gandarez - 957/142919/143876 - 2:24
me Sunday - 932/166817/165885 - 2:47
me datefirst - 939/171698/172637 - 2:53
trailmax - 958/173174/174132 - 2:54
Je peux vous communiquer les détails de mes tests si vous le souhaitez - je m'arrête ici car je suis déjà très long. J'ai été un peu surpris de voir que Curt est le plus rapide à l'extrémité supérieure, étant donné le nombre de calculs et de code en ligne. Peut-être que je vais faire des tests plus approfondis et en faire un blog... si vous n'avez pas d'objection à ce que je publie vos fonctions ailleurs.
10 votes
(@@DATEFIRST + DATEPART(DW, @SomeDate)) % 7
reste constant indépendamment de@@datefirst
réglage je pense. Avec lundi = 2.