【问题标题】:SET DATEFIRST in FUNCTION在 FUNCTION 中设置 DATEFIRST
【发布时间】:2012-09-11 10:46:08
【问题描述】:

我想在我的函数中设置 DATEFIRST,但这是不允许的。

SET DATEFIRST 1

我可以在 SP 中添加代码并从函数中调用 SP,但我并不热衷于这样做。

我可以在调用函数之前设置 DATEFIRST,但我也不热衷于这样做。

还有其他解决方法吗?

编辑

下面是我想在我的 FUNCTION 中使用的代码,用于返回当月的总工作日。但由于我的 DATEFIRST,我无法将此代码添加到 FUNCTION 中

DECLARE @my int
DECLARE @myDeduct int
DECLARE @day INT
DECLARE @mydate DATETIME
DECLARE @TotalDays INT

SET @mydate = GETDATE()

SET @myDeduct = 0
IF (@@DATEFIRST + DATEPART(DW, @mydate)) % 7 not in (0,1)
SET DateFirst 1 -- Set it monday=1 (value)

--Saturday and Sunday on the first and last day of a month will Deduct 1
IF (DATEPART(weekday,(DATEADD(dd,-(DAY(@mydate)-1),@mydate))) > 5)
SET @myDeduct = @myDeduct + 1

IF (DATEPART(weekday,(DATEADD(dd,-(DAY(DATEADD(mm,1,@mydate))),DATEADD(mm,1,@mydate)))) > 5)
SET @myDeduct = @myDeduct + 1

SET @my = day(DATEADD(dd,-(DAY(DATEADD(mm,1,@mydate))),DATEADD(mm,1,@mydate)))

Set @TotalDays = (select (((@my/7) * 5 + (@my%7)) - @myDeduct))

Select @TotalDays

【问题讨论】:

标签: sql-server tsql date


【解决方案1】:

代替

SET DATEFIRST 1

你可以的

SELECT (DATEPART(weekday, GETDATE()) + @@DATEFIRST - 2) % 7 + 1

【讨论】:

  • 这是一个很好的,很好的一个班轮。周一给你 1,周日给你 7。 ISO8601 计算需要这个。如果模数对您来说就像 abracadabra,请参阅 stackoverflow.com/a/41248745/2997016 以获得多行版本
  • @ArieKanarie 但您链接的答案与此答案不同,它没有考虑@@datefirst 的当前值,因此它仅在周日是工作日1 时才有效。也许您可以发布另一个解决该问题的答案。 :P
  • 无论如何,+1,虽然我使用了没有减法和加法的修改版本,因为我只需要数字保持一致,而不是具体。所以0 是星期六,1 是星期天,等等。这意味着我 (A) 可以在函数中容纳 datefirst,并且 (B) 没有与特定 datenames 进行比较的特定区域、较慢的混乱.
【解决方案2】:

我通常的解决方法是使用“已知良好”的日期进行比较。

例如,假设我需要检查日期是否为星期六。我不依赖DATEFIRST 或语言设置(使用DATENAME),而是说:

DATEPART(weekday,DateToCheck) = DATEPART(weekday,'20120714')

我知道 2012 年 7 月 14 日是星期六,所以我在不依赖任何外部设置的情况下执行了检查。


表达式(DATEPART(weekday,DateToCheck) + @@DATEFIRST) % 7 将始终产生值 0 表示周六,1 表示周日,2 表示周一,等等。

所以,我建议你创建一个表:

CREATE TABLE WorkingDays (
    NormalisedDay int not null,
    DaysInMonth int not null,
    WorkingDays int not null
)

填充此表是一次性的练习。 NormalisedDay 将是我上面给出的表达式计算的值。

要计算给定特定日期的DaysInMonth,您可以使用以下表达式:

DATEDIFF(day,
      DATEADD(month,DATEDIFF(month,0,DateToCheck),0),
      DATEADD(month,DATEDIFF(month,'20010101',DateToCheck),'20010201'))

现在您的函数所要做的就是查找表中的值。

(当然,DaysInMonth 为 28 的所有行的结果都是 20。只有 29,30 和 31 的行需要一点工作才能生成)

【讨论】:

  • 请看上面,我添加了我的代码来解释我想如何使用它。
  • @Etienne - 我添加了一些有用的表达式和建议的解决方案。
  • (DATEPART(weekday,DateToCheck) + @@DATEFIRST) % 7+1,非常宝贵!无论如何,肯定比比较工作日名称要好:O
【解决方案3】:

如果您需要星期一作为第一天,请按照此代码 sn-p

declare @MyDate datetime = getdate()
                   select CASE WHEN DATEPART(DW,@MyDate) = 1   
                            THEN 7 
                          WHEN DATEPART(DW,@MyDate) <= 7 
                            THEN DATEPART(DW,@MyDate) - 1                            
                     END 

【讨论】:

  • IMO 这并不是真正的问题,因为它仍然取决于@@datefirst 的当前值。它只是基于此“轮换”工作日,因此如果当前的@@datefirst 是星期天,你只会在星期一得到1。这对一些读者来说可能就足够了,但它不像 Kvasi 的那样是一个全面的答案。另外请注意,&lt;= 7 不是多余的吗,因为一周中不能有 &gt; 7 工作日?
  • @underscore_d 是的,&lt;= 7 也可以是简单的ELSE。至少在我们每周工作 8 天之前 ;-)
【解决方案4】:

另一种方法是明确指定一周的第一天作为参数,避免依赖@@DATEFIRST 设置。您可以使用以下公式在您的函数中实现:

(DATEPART(dw, GETDATE()) + @@DATEFIRST + 6 - @WeekStartDay) % 7 + 1

@WeekStartDay 是您希望系统在一周中的第一天(从 1 到 7 表示从星期一到星期日)。

我已经将它封装到下面的函数中,以便我们可以轻松地重用它:

CREATE FUNCTION [dbo].[GetDayInWeek](@InputDateTime DATETIME, @WeekStartDay INT)
RETURNS INT
AS
BEGIN
    --Note: @WeekStartDay is number from [1 - 7] which is from Monday to Sunday
    RETURN (DATEPART(dw, @InputDateTime) + @@DATEFIRST + 6 - @WeekStartDay) % 7 + 1 
END

示例用法: GetDayInWeek('2019-02-04 00:00:00', 1)

等同于以下(但独立于 DATEFIRST 设置):

SET DATEFIRST 1
DATEPART(dw, '2019-02-04 00:00:00')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2019-07-16
    • 2018-11-21
    • 1970-01-01
    • 2021-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多