Created
January 19, 2024 17:59
-
-
Save MarkPflug/af84393127141e04ef0aa22ff156cda8 to your computer and use it in GitHub Desktop.
SQL TZ Convert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Data.SqlClient; | |
internal class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var dbStr = args[0]; | |
var srcTz = args[1]; | |
var dstTz = args[2]; | |
string srv, db; | |
if (dbStr.Contains(':')) | |
{ | |
srv = dbStr.Substring(0, dbStr.IndexOf(':')); | |
db = dbStr.Substring(dbStr.IndexOf(':')+1); | |
} | |
else | |
{ | |
srv = "."; | |
db = dbStr; | |
} | |
var csb = new SqlConnectionStringBuilder() | |
{ | |
DataSource = srv, | |
InitialCatalog = db, | |
IntegratedSecurity = true, | |
TrustServerCertificate = true, | |
}; | |
var conn = new SqlConnection(csb.ConnectionString); | |
conn.Open(); | |
DatabaseTimeZoneUpdate.UpdateTimeZone(conn, srcTz, dstTz); | |
} | |
} | |
// a process to update all datetime values to be in a given timezone | |
public static class DatabaseTimeZoneUpdate | |
{ | |
public static void ValidateTimeZone(SqlConnection conn, string tzId) | |
{ | |
using var cmd = conn.CreateCommand(); | |
cmd.CommandText = "select count(1) from sys.time_zone_info where name = @id"; | |
cmd.Parameters.AddWithValue("id", tzId); | |
if (cmd.ExecuteScalar() is not 1) | |
{ | |
throw new ArgumentOutOfRangeException(nameof(tzId), $"Timezone {tzId} is not known by SqlServer"); | |
} | |
} | |
public static void UpdateTimeZone(SqlConnection conn, string srcTzId, string dstTzId) | |
{ | |
// Validate that the timezone names are correct. | |
ValidateTimeZone(conn, srcTzId); | |
ValidateTimeZone(conn, dstTzId); | |
var cmd = conn.CreateCommand(); | |
// get all the datetime and datetime2 columns in the database. | |
cmd.CommandText = | |
""" | |
select | |
s.name as schemaName, | |
ta.name as tableName, | |
c.name as columnName, | |
t.name as typeName | |
from sys.columns c | |
join sys.tables ta | |
on c.object_id = ta.object_id | |
join sys.schemas s | |
on ta.schema_id = s.schema_id | |
join sys.types t | |
on c.system_type_id = t.system_type_id | |
where | |
t.name in ('datetime', 'datetime2') | |
order by | |
s.name, ta.name, c.name | |
"""; | |
var sw = new StringWriter(); | |
using (var reader = cmd.ExecuteReader()) | |
{ | |
sw.WriteLine($"declare @SrcTzId varchar(128) = '{srcTzId}'"); | |
sw.WriteLine($"declare @DstTzId varchar(128) = '{dstTzId}'"); | |
string? table = null; | |
while (reader.Read()) | |
{ | |
var schemaName = reader.GetString(0); | |
var tableName = reader.GetString(1); | |
var columnName = reader.GetString(2); | |
var typeName = reader.GetString(3); | |
if (tableName != table) | |
{ | |
if (table != null) | |
{ | |
sw.WriteLine(";"); | |
} | |
sw.WriteLine($"update [{schemaName}].[{tableName}] set "); | |
table = tableName; | |
} | |
else | |
{ | |
sw.Write(","); | |
} | |
sw.WriteLine($"{columnName} = {columnName} at time zone @SrcTzId at time zone @DstTzId"); | |
} | |
} | |
cmd.CommandText = sw.ToString(); | |
// this command can take a while. | |
cmd.CommandTimeout = (int)TimeSpan.FromHours(1).TotalSeconds; | |
cmd.ExecuteNonQuery(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment