当我知道 ISO 8601 中的周数时如何获得一周的第一天
How to get first day of week when i know week number in ISO 8601
例如我知道年份和周数
year = 2016
week = 1
如何根据 ISO 8601 从中获取 一周的第一天 ?
我在 table datetime2[0]
日期类型中生成默认值 2015-12-28
但一周的第一天应该是 2016-01-04
有什么想法吗?
我认为处理业务数据的最佳方式是将其存储在 table 中。 ISO 周是业务数据。如果你有一个看起来像这样的 table
calendar_date iso_year iso_week
--
2016-01-01 2015 53
2016-01-02 2015 53
2016-01-03 2015 53
2016-01-04 2016 1
2016-01-05 2016 1
2016-01-06 2016 1
2016-01-07 2016 1
然后回答问题 "Whats the first date of ISO week 1 in 2016?" 简化为这个。
select min(calendar_date)
from calendar
where iso_year = 2016;
and iso_week = 1;
下面是创建这样一个 table 的方法。 (未经严格测试。)
create table calendar (
calendar_date date primary key,
iso_year integer not null,
iso_week integer not null,
check (iso_week = datepart(iso_week, calendar_date)),
check (iso_year = year(dateadd(wk, datediff(d, 0, calendar_date) / 7, 3)))
);
此代码将填充它。
declare @start_date date;
select @start_date = '2016-01-01';
declare @end_date date;
select @end_date = '2050-12-31';
declare @next_date date;
select @next_date = (select coalesce(max(calendar_date), @start_date) from calendar);
while @next_date <= @end_date
begin
begin transaction;
insert into calendar values (@next_date , year(dateadd(wk, datediff(d, 0, @next_date) / 7, 3)), datepart(iso_week, @next_date));
commit;
select @next_date = dateadd(d, 1, @next_date);
end
谨慎控制权限。很少有人应该有插入、更新或删除权限。
CLR 函数也是可能的
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Globalization;
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static DateTime fnFirstDateOfWeekISO8601(int year, int weekOfYear)
{
DateTime jan1 = new DateTime(year, 1, 1);
int daysOffset = DayOfWeek.Thursday - jan1.DayOfWeek;
DateTime firstThursday = jan1.AddDays(daysOffset);
var cal = CultureInfo.CurrentCulture.Calendar;
int firstWeek = cal.GetWeekOfYear(firstThursday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
var weekNum = weekOfYear;
if (firstWeek <= 1)
{
weekNum -= 1;
}
var result = firstThursday.AddDays(weekNum * 7);
return result.AddDays(-3);
}
}
#更新 2020-09-13
Microsoft 已经 class 为此
https://docs.microsoft.com/en-us/dotnet/api/system.globalization.isoweek?view=netcore-3.1
所以 CLR 函数可能看起来更简单
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Globalization;
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static DateTime fnFirstDateOfWeekISO8601(int year, int weekOfYear)
{
return System.Globalization.ISOWeek.ToDateTime(year, weekOfYear, DayOfWeek.Monday);
}
}
给定任何日期,此 SQL 将 return ISO-week:SELECT DATEPART(ISO_WEEK, @date)
。下面是一个丑陋的(但非常有效)one-liner 来计算第一个日期 ISO-week:
DECLARE @date DATETIME = '2012-09-16'
SELECT (
CASE DATEPART(ISO_WEEK, @date)
WHEN DATEPART(ISO_WEEK, DATEADD(DAY,-6,@date)) THEN DATEADD(DAY,-6,@date)
WHEN DATEPART(ISO_WEEK, DATEADD(DAY,-5,@date)) THEN DATEADD(DAY,-5,@date)
WHEN DATEPART(ISO_WEEK, DATEADD(DAY,-4,@date)) THEN DATEADD(DAY,-4,@date)
WHEN DATEPART(ISO_WEEK, DATEADD(DAY,-3,@date)) THEN DATEADD(DAY,-3,@date)
WHEN DATEPART(ISO_WEEK, DATEADD(DAY,-2,@date)) THEN DATEADD(DAY,-2,@date)
WHEN DATEPART(ISO_WEEK, DATEADD(DAY,-1,@date)) THEN DATEADD(DAY,-1,@date)
ELSE DATEADD(DAY,0,@date)
END
) FirstDayOfISOWeek
现在,这不是我最漂亮的作品,但它通过反复试验工作 - 测试多少天前 ISO-week 仍然相同,然后 return 那天。
例如我知道年份和周数
year = 2016
week = 1
如何根据 ISO 8601 从中获取 一周的第一天 ?
我在 table datetime2[0]
日期类型中生成默认值 2015-12-28
但一周的第一天应该是 2016-01-04
有什么想法吗?
我认为处理业务数据的最佳方式是将其存储在 table 中。 ISO 周是业务数据。如果你有一个看起来像这样的 table
calendar_date iso_year iso_week -- 2016-01-01 2015 53 2016-01-02 2015 53 2016-01-03 2015 53 2016-01-04 2016 1 2016-01-05 2016 1 2016-01-06 2016 1 2016-01-07 2016 1
然后回答问题 "Whats the first date of ISO week 1 in 2016?" 简化为这个。
select min(calendar_date)
from calendar
where iso_year = 2016;
and iso_week = 1;
下面是创建这样一个 table 的方法。 (未经严格测试。)
create table calendar (
calendar_date date primary key,
iso_year integer not null,
iso_week integer not null,
check (iso_week = datepart(iso_week, calendar_date)),
check (iso_year = year(dateadd(wk, datediff(d, 0, calendar_date) / 7, 3)))
);
此代码将填充它。
declare @start_date date;
select @start_date = '2016-01-01';
declare @end_date date;
select @end_date = '2050-12-31';
declare @next_date date;
select @next_date = (select coalesce(max(calendar_date), @start_date) from calendar);
while @next_date <= @end_date
begin
begin transaction;
insert into calendar values (@next_date , year(dateadd(wk, datediff(d, 0, @next_date) / 7, 3)), datepart(iso_week, @next_date));
commit;
select @next_date = dateadd(d, 1, @next_date);
end
谨慎控制权限。很少有人应该有插入、更新或删除权限。
CLR 函数也是可能的
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Globalization;
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static DateTime fnFirstDateOfWeekISO8601(int year, int weekOfYear)
{
DateTime jan1 = new DateTime(year, 1, 1);
int daysOffset = DayOfWeek.Thursday - jan1.DayOfWeek;
DateTime firstThursday = jan1.AddDays(daysOffset);
var cal = CultureInfo.CurrentCulture.Calendar;
int firstWeek = cal.GetWeekOfYear(firstThursday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
var weekNum = weekOfYear;
if (firstWeek <= 1)
{
weekNum -= 1;
}
var result = firstThursday.AddDays(weekNum * 7);
return result.AddDays(-3);
}
}
#更新 2020-09-13
Microsoft 已经 class 为此 https://docs.microsoft.com/en-us/dotnet/api/system.globalization.isoweek?view=netcore-3.1 所以 CLR 函数可能看起来更简单
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Globalization;
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static DateTime fnFirstDateOfWeekISO8601(int year, int weekOfYear)
{
return System.Globalization.ISOWeek.ToDateTime(year, weekOfYear, DayOfWeek.Monday);
}
}
给定任何日期,此 SQL 将 return ISO-week:SELECT DATEPART(ISO_WEEK, @date)
。下面是一个丑陋的(但非常有效)one-liner 来计算第一个日期 ISO-week:
DECLARE @date DATETIME = '2012-09-16'
SELECT (
CASE DATEPART(ISO_WEEK, @date)
WHEN DATEPART(ISO_WEEK, DATEADD(DAY,-6,@date)) THEN DATEADD(DAY,-6,@date)
WHEN DATEPART(ISO_WEEK, DATEADD(DAY,-5,@date)) THEN DATEADD(DAY,-5,@date)
WHEN DATEPART(ISO_WEEK, DATEADD(DAY,-4,@date)) THEN DATEADD(DAY,-4,@date)
WHEN DATEPART(ISO_WEEK, DATEADD(DAY,-3,@date)) THEN DATEADD(DAY,-3,@date)
WHEN DATEPART(ISO_WEEK, DATEADD(DAY,-2,@date)) THEN DATEADD(DAY,-2,@date)
WHEN DATEPART(ISO_WEEK, DATEADD(DAY,-1,@date)) THEN DATEADD(DAY,-1,@date)
ELSE DATEADD(DAY,0,@date)
END
) FirstDayOfISOWeek
现在,这不是我最漂亮的作品,但它通过反复试验工作 - 测试多少天前 ISO-week 仍然相同,然后 return 那天。