在 Delphi 中复制 SQL Server DATEPART(wk, ...) 函数

Posted

技术标签:

【中文标题】在 Delphi 中复制 SQL Server DATEPART(wk, ...) 函数【英文标题】:Replicate SQL Server DATEPART(wk, ...) function in Delphi 【发布时间】:2017-11-02 22:54:43 【问题描述】:

Delphi 的 WeekOfTheYear 函数使用 ISO 8601 方法,其中一周从星期一开始,一年的第一周定义为该年有四天或更多天的第一周。

要在 Microsoft SQL Server 中获取一年中的第几周,您可以使用 DATEPART(wk, ...) 函数,但这使用了不同的机制,因为美国英语的默认设置从星期日开始一周,而year 是一年中的第一个星期日,除非该星期日是 1 月 1 日,否则第 2 周从一年中的第 2 个星期日开始,运行此示例可以看出:

SELECT '2010-1-3', DATEPART(wk, '2010-1-3'), DATENAME(dw, '2010-1-3')
SELECT '2011-1-2', DATEPART(wk, '2011-1-2'), DATENAME(dw, '2011-1-2')
SELECT '2012-1-1', DATEPART(wk, '2012-1-1'), DATENAME(dw, '2012-1-1')
SELECT '2013-1-6', DATEPART(wk, '2013-1-6'), DATENAME(dw, '2013-1-6')
SELECT '2014-1-5', DATEPART(wk, '2014-1-5'), DATENAME(dw, '2014-1-5')
SELECT '2015-1-4', DATEPART(wk, '2015-1-4'), DATENAME(dw, '2015-1-4')
SELECT '2016-1-3', DATEPART(wk, '2016-1-3'), DATENAME(dw, '2016-1-3')
SELECT '2017-1-1', DATEPART(wk, '2017-1-1'), DATENAME(dw, '2017-1-1')
SELECT '2018-1-7', DATEPART(wk, '2018-1-7'), DATENAME(dw, '2018-1-7')
SELECT '2019-1-6', DATEPART(wk, '2019-1-6'), DATENAME(dw, '2019-1-6')
SELECT '2020-1-5', DATEPART(wk, '2020-1-5'), DATENAME(dw, '2020-1-5')

上面的结果显示每个星期日是一年中的第 2 周,除了 2 是 1 月 1 日,它显示一年中的第 1 周。

我查看了以下问题的答案,这似乎表明它将根据一周的开始日期返回一年中的一周,

Delphi week number function based on system start of week

但这也是基于使用 Delphi 函数,并且不会返回与 SQL Server 相同的结果。

SQL Server 目前在 2018 年 1 月 1 日至 2018 年 1 月 8 日期间显示的内容是:

1/1/2018 = 1
2/1/2018 = 1
3/1/2018 = 1
4/1/2018 = 1
5/1/2018 = 1
6/1/2018 = 1
7/1/2018 = 2
8/1/2018 = 2

Delphi 确实有一个 DayOfWeek 函数使用星期日作为一周的第一天,与使用星期一的 DayofTheWeek 函数相比,但我似乎无法计算出获取所需的逻辑与 SQL Server 相同的结果。至少必须有一个条件来处理 1 月 1 日星期日是第 1 周,但其他第一个星期日是第 2 周。

有没有人有任何 Delphi 源代码在使用美国英语默认值 DATEFIRST 7 时返回一年中的星期与 SQL Server 完全相同?

【问题讨论】:

你会发现这个post很有趣 @Sami。我做到了。那是我在我的问题中包含的那个。我通过WeeksSince01Jan 函数运行了相同的 1 月 8 天,将sdSun 作为第二个参数传递,它们都返回 0。实际上,该函数一直返回 0,直到 2018 年 1 月 13 日。直到 2018 年 1 月 14 日才返回 1。 【参考方案1】:

代码看似简单,但逻辑有点难。关于第一个星期日的规则意味着,在所有情况下,第一个星期六都在第 1 周。所以我们的想法是我们去下一个星期六并计算从年初开始的星期六数。

function SQLWeekOfYear(const pDate: TDate): integer;
var
  iYear, iMonth, iDay : word;
  iDOW : integer;
  iDays : integer;
begin
  // this is based on First Sunday in year being in week 2
  // unless it is the first of Jan, which is equivalent of saying that the
  // first saturday is always in week 1.
  //
  // This means that we count the number of saturdays prior to this date and add one,
  // which is equivalent to finding the next saturday
  DecodeDate( pDate, iYear, iMonth, iDay );
  iDOW := DayOfWeek( pDate );
  // Find how many days so far since 1st jan
  iDays := Trunc(pDate - EncodeDate( iYear, 1, 1 )) + 1;
  // now adjust for day of week to get to next saturday
  iDays := iDays + (7-iDOW);
  // add 6 and divide by 7 to find actual number saturdays
  Result := (iDays + 6) div 7;
end;

【讨论】:

谢谢。我已经通过我的问题中的日期组合运行了你的函数,它给了我与 SQL Server 相同的结果。我还尝试了其他一些,例如闰年的 2 月 29 日等,它仍然匹配。第一个星期六总是第一周。

以上是关于在 Delphi 中复制 SQL Server DATEPART(wk, ...) 函数的主要内容,如果未能解决你的问题,请参考以下文章

Query (SQL Server 2008 Express) 在 SQL Server Management Studio 中有效,但在 Delphi 中使用 ADODB 无效

Delphi连接SQL Server 2000

Delphi动态配置ODBC数据源--SQL Server版本

delphi怎样发布基于Microsoft SQL Server的程序

SQL Server / Delphi:如何使用表变量类型将整数列表作为参数传输?

delphi怎样在ADO里用ADOproc调用数据库sql server存储过程?,用ADODATASET或者ADOQUERY又怎样调用存储过程?