How to apply SET TIME ZONE
to NpgsqlCommand?
Attempt 1. SET TIME ZONE
in CommandText, separated from select with ;
using var cmd = connection.CreateCommand();
cmd.CommandText = "SET TIME ZONE '+02:00'; select "t0"."start_time" from "task"."tasks" "t0" where "t0"."number" = 217";
await connection.OpenAsync();
using var reader = await cmd.ExecuteReaderAsync();
Attempt 2. Use NpgsqlBatch
await connection.OpenAsync();
using var batch = new NpgsqlBatch(connection);
batch.BatchCommands.Add(new NpgsqlBatchCommand("SET TIME ZONE '+02:00'"));
batch.BatchCommands.Add(new NpgsqlBatchCommand("select "t0"."start_time" from "task"."tasks" "t0" where "t0"."number" = 217"));
await batch.PrepareAsync();
using var reader = await batch.ExecuteReaderAsync();
start_time
column is type of timestamptz
In neither attempt did SET TIME ZONE
work. As I understand it: 1 attempt did not work because npgsql
split command text by semicolon ;
into batches. So SET TIME ZONE
is in individual batch and does not apply to select
.
More about batches in npgsql
https://www.infoq.com/news/2022/06/Database-Command-Batching/
When I run query in PgAdmin, SET TIME ZONE
works – I got different result
SET TIME ZONE '+02:00';
select
"t0"."start_time"
from "task"."tasks" "t0"
where "t0"."number" = 217
2
Answers
SET TIME ZONE
has no effect with good reason.NpgSQL returnstimestamp with time zone
as a DateTime value whoseKind
is DateTimeKind.UTC. This is explained in the type mapping docs. PostgreSQL itself storestimestamp with timezone
as a UTC value, without the original offset or timezone name. From the PostgreSQL docs:The value returned by NpgSQL is accurate – a UTC DateTime. This shouldn’t be a problem if the application treats this as a UTC time. Unfortunately, functions like
ToString
ignore theKind
property. In this case a good choice would be to convert the value to a local date in C# with DateTime.ToLocalTime, eg :Another option is to convert the value to a
DateTimeOffset
, ensuring UTC and local are never confused:Another option is to use
AT TIME ZONE
to have PostgreSQL convert the time to a specific timezone. Don’t use the offset though, as this will change based on DST rules. It’s far safer to use the IANA timezone name, eg:Your code above does set the time zone successfully; if you execute
SHOW TIME ZONE
afterwards you should get back the value that you set.However, Npgsql is – very much by design – not sensitive to whatever the time zone is set to. Technically, in PostgreSQL TIME ZONE only has an effect when a
timestamp with time zone
is converted to a textual representation, to atimestamp without time zone
, etc. However, Npgsql does not convert the timestamp to text; it retrieves it from PostgreSQL in its binary encoding, which is simply the UTC timestamp (which is also what is stored on disk).Therefore, changing TIME ZONE simply does not affect what you get from Npgsql.