20260927215912

This commit is contained in:
oneao committed 2026-09-27 21:59:13 +08:00
1 parent 27e49e2e45
commit f22e67fc85
294 files changed
+29247 -3576

No files matched your search

+123
View File
@@ -0,0 +1,123 @@
/* ============================================================================
时间口径迁移:本地墙钟(服务器时间)→ UTC 墙钟
----------------------------------------------------------------------------
背景:本项目原先全链路使用「服务器本地墙钟值」(库端 getdate() / sysdatetime(),
应用层 LocalDateTime.now(Asia/Shanghai))。现统一为 UTC 口径(见后端 TimeUtils):
· 库中 datetime 列一律存 UTC 墙钟值,新写入默认值走 sysutcdatetime();
· 接口出口发带 Z 的 ISO 串("2026-09-26T02:00:00Z"),前端按浏览器时区展示;
· 提交时前端带 Z / ±HH:mm,后端折回 UTC 墙钟值落库。
本脚本做两件事:
1. 默认值约束:getdate() / sysdatetime() → sysutcdatetime();
2. 存量数据:把每个 datetime 列的旧值从「来源时区墙钟」折成 UTC。
幂等:执行成功后在 dbo.s_time_utc_migrated 留标记,重复执行直接跳过
(校正类脚本重复执行会二次偏移,必须防重)。
执行范围:每个机构库各执行一次(后端按机构切换连接库)。
时区前提:旧数据是「中国标准时间(UTC+8)」的墙钟值 —— 现网服务器与使用方均在中国。
若某机构库的旧值来自别的时区,把 @source_zone 换成对应 Windows 时区名即可。
依赖:AT TIME ZONE 需要 SQL Server 2016+;建议在维护窗口执行(全表更新会持有行锁)。
============================================================================ */
set nocount on;
go
/* ---------------------------------------------------------------------------
0. 防重标记表(首次执行时创建)
--------------------------------------------------------------------------- */
if object_id(N'dbo.s_time_utc_migrated', N'U') is null
begin
create table dbo.s_time_utc_migrated (
b_id varchar(50) not null primary key, -- 迁移标识
b_source_zone sysname not null, -- 旧值的来源时区
b_migrated_at datetime2 not null, -- 执行时间(UTC)
b_column_count int not null -- 校正的列数
);
end
go
declare @source_zone sysname = N'China Standard Time';
declare @already int = (select count(*) from dbo.s_time_utc_migrated where b_id = 'time-utc');
if @already > 0
begin
print N'[跳过] 时间口径迁移已执行过(见 dbo.s_time_utc_migrated 的 time-utc 标记)。';
end
else
begin
declare @table sysname, @column sysname, @type sysname, @sql nvarchar(max);
/* -----------------------------------------------------------------------
1. 默认值约束:getdate() / sysdatetime() → sysutcdatetime()
----------------------------------------------------------------------- */
declare @constraint sysname;
declare defaults_cursor cursor local fast_forward for
select dc.name, t.name, c.name
from sys.default_constraints dc
join sys.tables t on t.object_id = dc.parent_object_id
join sys.columns c on c.object_id = dc.parent_object_id and c.column_id = dc.parent_column_id
where t.is_ms_shipped = 0
and (dc.definition like '%getdate()%' or dc.definition like '%sysdatetime()%')
and dc.definition not like '%sysutcdatetime%';
open defaults_cursor;
fetch next from defaults_cursor into @constraint, @table, @column;
while @@fetch_status = 0
begin
set @sql = N'alter table dbo.' + quotename(@table)
+ N' drop constraint ' + quotename(@constraint) + N';'
+ N'alter table dbo.' + quotename(@table)
+ N' add constraint ' + quotename(@constraint)
+ N' default sysutcdatetime() for ' + quotename(@column) + N';';
execute sp_executesql @sql;
print N'[默认值] ' + @table + N'.' + @column + N' → sysutcdatetime()';
fetch next from defaults_cursor into @constraint, @table, @column;
end
close defaults_cursor;
deallocate defaults_cursor;
/* -----------------------------------------------------------------------
2. 存量数据:每个 datetime 列从「@source_zone 墙钟」折成 UTC
AT TIME ZONE 先给旧值贴上来源时区,再换算到 UTC —— 不写死 -8,
将来某个库的旧值来自其他时区时改 @source_zone 即可。
----------------------------------------------------------------------- */
declare @column_count int = 0;
declare time_columns cursor local fast_forward for
select t.name, c.name, ty.name
from sys.columns c
join sys.tables t on t.object_id = c.object_id
join sys.schemas s on s.schema_id = t.schema_id
join sys.types ty on ty.user_type_id = c.user_type_id
where s.name = 'dbo'
and t.is_ms_shipped = 0
and c.is_computed = 0
and t.name <> 's_time_utc_migrated'
and ty.name in ('datetime', 'datetime2', 'smalldatetime')
order by t.name, c.column_id;
open time_columns;
fetch next from time_columns into @table, @column, @type;
while @@fetch_status = 0
begin
set @sql = N'update dbo.' + quotename(@table)
+ N' set ' + quotename(@column)
+ N' = cast(((' + quotename(@column) + N' at time zone @zone) at time zone ''UTC'') as '
+ @type + N')'
+ N' where ' + quotename(@column) + N' is not null;';
execute sp_executesql @sql, N'@zone sysname', @zone = @source_zone;
set @column_count = @column_count + 1;
fetch next from time_columns into @table, @column, @type;
end
close time_columns;
deallocate time_columns;
/* -----------------------------------------------------------------------
3. 留痕
----------------------------------------------------------------------- */
insert into dbo.s_time_utc_migrated (b_id, b_source_zone, b_migrated_at, b_column_count)
values ('time-utc', @source_zone, sysutcdatetime(), @column_count);
print N'[完成] 已按 ' + @source_zone + N' 校正 ' + cast(@column_count as varchar(10))
+ N' 个时间列;抽查 b_created_at / b_occurdatetime 与界面展示是否一致。';
end
go