20260927215912
This commit is contained in:
1 parent
27e49e2e45
commit
f22e67fc85
294 files changed
+29247
-3576
No files matched your search
@@ -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
|
||||
Reference in new issue
Block a user