Pour expliquer pourquoi vous obtenez un lundi et non un dimanche:
Vous ajoutez un nombre de semaines à la date 0. Qu'est-ce que la date 0? 1900-01-01. Quel était le jour du 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, ajoutez maintenant [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, il s'agit simplement d'ajouter 7 jours, puis d'ajouter 7 jours de plus, ... tout comme DATEDIFF
ne reconnaît que les limites qui ont été franchies. Par exemple, les deux renvoient 1, même si certaines personnes se plaignent qu'il devrait y avoir une logique sensée intégrée pour arrondir vers le haut ou vers le bas:
SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');
Pour savoir 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 cassera pas si vous modifiez votre DATEFIRST
paramètre (ou si votre code est en cours d'exécution pour un utilisateur avec un paramètre différent) - à condition que vous souhaitiez toujours un dimanche quel que soit le paramètre actuel. Si vous voulez que ces deux réponses à jive, vous devez utiliser une fonction qui ne dépend du DATEFIRST
réglage, par exemple
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);
Donc, si vous changez votre DATEFIRST
réglage sur lundi, mardi, qu'as-tu, le comportement changera. Selon le comportement souhaité, 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
Maintenant, vous avez beaucoup d'alternatives, mais laquelle fonctionne le mieux? Je serais surpris qu'il y ait des différences majeures, mais j'ai rassemblé toutes les réponses fournies jusqu'à présent et les ai passées à travers deux séries de tests - un bon marché et un cher. J'ai mesuré les statistiques du client car je ne vois pas les E / S ou la mémoire jouer un rôle dans la performance ici (bien que celles-ci puissent entrer en jeu en fonction de la façon dont la fonction est utilisée). Dans mes tests, les résultats sont:
Requête 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
Requête d'attribution "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 relayer les détails de mes tests si vous le souhaitez - en m'arrêtant ici car cela devient déjà assez long. J'ai été un peu surpris de voir que Curt est le plus rapide du haut de gamme, compte tenu du nombre de calculs et du code en ligne. Peut-être que je vais faire des tests plus approfondis et bloguer à ce sujet ... si vous n'avez aucune objection à ce que je publie vos fonctions ailleurs.
(@@DATEFIRST + DATEPART(DW, @SomeDate)) % 7
reste constant quel que soit le@@datefirst
réglage je pense. With Monday = 2.