【问题标题】:How to get week start date & week end date如何获取周开始日期和周结束日期
【发布时间】:2015-12-22 11:34:44
【问题描述】:

我想从每个月的第一天开始计算一个月的周数,而不是从星期一开始。 它必须是第 1 个。到 7 日,8 日。到 14 日、15 日。到 21 日、22 日。到 28 日和 29 日。到月底。

所以如果我将日期传递为 2015-12-30 00:00,那么它应该返回周开始日期为 2015-12-29 00:00 和周结束日期为 2016-01-01 00:00

我尝试了以下脚本,但它让我每周从星期一开始。

【问题讨论】:

标签: sql sql-server-2008 datetime


【解决方案1】:

第一步是确定当月的当前周,由当月的当天除以 7(向上取整)得出,然后您可以通过乘以周来获得当前周的开始日期数字 7 并增加一天。最后,您可以使用当月的第一天和DATEADD(DAY 来获取星期几的开始日期。阶段是:

DECLARE @Date DATE = '2015-12-30';

SELECT  WeekNumberOfMonth = CEILING(DATEPART(DAY, @Date) / 7.0),
        WeekStartDay =  1 + FLOOR((DATEPART(DAY, @Date) - 1) / 7.0) * 7,
        FirstDayOfMonth = DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date), 0),
        WeekStart = DATEADD(DAY, 
                            (CEILING(DATEPART(DAY, @Date) / 7.0) - 1) * 7,
                            DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date), 0));

这给出了:

WeekNumberOfMonth   WeekStartDay    FirstDayOfMonth     WeekStart
--------------------------------------------------------------------
5                   29              2015-12-01          2015-12-29

最后,周末需要一个case语句来检查它是否仍然与一周开始在同一个月:

DECLARE @Date DATE = '2015-12-30';

SELECT  d.WeekStart,
        Weekend = CASE WHEN DATEADD(DAY, 7, WeekStart) > StartOfNextMonth
                            THEN StartOfNextMonth
                        ELSE DATEADD(DAY, 7, WeekStart)
                    END
FROM    (   SELECT  WeekStart = DATEADD(DAY, 
                                        ((DATEPART(DAY, @Date) - 1) / 7.0) * 7, 
                                        DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date), 0)),
                    StartOfNextMonth = DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date) + 1, 0)
        ) AS d;

这给出了:

WeekStart       Weekend
----------------------------
2015-12-29      2016-01-01

进一步测试

SELECT  d.[Date],
        d.WeekStart,
        Weekend = CASE WHEN DATEADD(DAY, 7, WeekStart) > StartOfNextMonth
                            THEN StartOfNextMonth
                        ELSE DATEADD(DAY, 7, WeekStart)
                    END
FROM    (   SELECT  dt.[Date],
                    WeekStart = DATEADD(DAY, 
                                        (CEILING(DATEPART(DAY, dt.[Date]) / 7.0) - 1) * 7, 
                                        DATEADD(MONTH, DATEDIFF(MONTH, 0, dt.[Date]), 0)),
                    StartOfNextMonth = DATEADD(MONTH, DATEDIFF(MONTH, 0, dt.[Date]) + 1, 0)
            FROM    (VALUES 
                        (CONVERT(DATE, '20151106')),
                        (CONVERT(DATE, '20151107')),
                        (CONVERT(DATE, '20151220')),
                        (CONVERT(DATE, '20151228')),
                        (CONVERT(DATE, '20151230')),
                        (CONVERT(DATE, '20160104'))
                    ) dt ([Date])
        ) AS d;

输出

Date            WeekStart       Weekend
-------------------------------------------
2015-11-06      2015-11-01      2015-11-08
2015-11-07      2015-11-01      2015-11-08
2015-12-20      2015-12-15      2015-12-22
2015-12-28      2015-12-22      2015-12-29
2015-12-30      2015-12-29      2016-01-01
2016-01-04      2016-01-01      2016-01-08  

【讨论】:

  • 嗨@GarethD,当我将日期传递为“2015-12-20 00:00”时,它返回 WeekStart : 2015-12-15 00:00:00.000 和 WeekEnd 2015-12-21 00:00 :00.000 。理想的周末应该是 2015-12-22 00:00:00.000
  • 还有一个疑问,当我将 Date 传递为 '2015-11-07 19:07:09.880' 它返回 WeekStart : 2015-11-08 00:00:00.000 和 WeekEnd 2015-11-15 00:00:00.000 。它应该在哪里返回 WeekStart : 2015-11-01 00:00:00.000 和 WeekEnd 2015-11-08 00:00:00.000
  • 是的,抱歉,在计算周数时需要扣除一天,因为它需要一个基于 0 的系统,但工作日基于 1。现在应该可以了。
  • 仍然不正确。现在这是返回 WeekStart : 2015-11-06 00:00:00.000 Weekend : 2015-11-13 00:00:00.000
  • 再次道歉,也为编辑的延迟道歉,我现在已经纠正了这些问题(我认为)并添加了进一步的查询以允许测试多个日期。
【解决方案2】:

您可以在 EOMONTH() 上使用 DATEADD()。例如。从 EOMONTH 减去一天,得到该月的天数。

要计算一个月有多少周,请取 EOMONTH 并将其除以 7。使用 FLOOR() 函数删除余数。

DECLARE @date DATETIME = GETDATE();
SELECT EOMONTH ( @date ) AS 'This Month';
SELECT EOMONTH ( @date, 1 ) AS 'Next Month';
SELECT EOMONTH ( @date, -1 ) AS 'Last Month';
GO

【讨论】:

  • OP 不能使用 EOMONTH,因为它仅在 SQL Server 2012 及更高版本中可用。
【解决方案3】:

有点晚了,但这是我使用的:

DECLARE @now datetime = GETDATE();

-- strip the time part from your date
DECLARE @date datetime = CONVERT(date, @now);

-- do the day of week math
DECLARE @start datetime = DATEADD(d, 1 - DATEPART(w, @date), @date),
        @end   datetime = DATEADD(d, 8 - DATEPART(w, @date), @date);

SELECT @start AS [WeekStart], @now AS [Now], @end AS [WeekEnd];

请记住 BETWEEN 运算符包含一个包含 [@start, @end] 的日期范围,因此从技术上讲,您应该使用 @start <= [Date] AND [Date] < @end 或从 @end 中减去 1 毫秒——除非您可以忍受 1/86,400,000 的机会事件被记录在下周的 0 毫秒!

【讨论】: