oracle odp.net SafeMapping转换,如果有时区的时间戳 - 如何获取偏移而不是区域名称

Ben*_*ehn 6 c# oracle timezone datetime odp.net

从c#开始,使用odp.net,我调用一个返回游标的oracle函数.某些列的类型为"带时区的时间戳"(TSTZ).如果我直接使用OracleDataAdapter,那些列将转换为System.DateTime,并且时区信息将丢失.这是预期的行为,建议似乎是使用SafeMapping强制转换为字符串,如:

dataAdapter.SafeMapping.Add("column_name", typeof(string));
Run Code Online (Sandbox Code Playgroud)

然后我确实将TSTZ作为字符串,但它使用的格式DD-MON-YYYY HH:MI:SS.FF AM TZR如下:

23-NOV-12 08.10.12.057868000 PM ASIA/CALCUTTA
Run Code Online (Sandbox Code Playgroud)

我想要它而不是偏移(例如格式DD-MON-YYYY HH:MI:SS.FF AM TZH:TZD如:

23-NOV-12 08.10.12.057868000 PM +04:30
Run Code Online (Sandbox Code Playgroud)

当我直接查询oracle(比如在Sql Developer中)时,我可以使用

Alter Session Set Nls_Timestamp_Tz_Format='DD-MON-YYYY HH:MI:SS.FF AM TZH:TZM'
Run Code Online (Sandbox Code Playgroud)

获得我想要的格式.使用odp.net我尝试在SetSessionInfo中设置格式:

connection.Open();
OracleGlobalization glob = connection.GetSessionInfo();
glob.TimeStampTZFormat = "DD-MON-YYYY HH:MI:SS.FF AM TZH:TZM";
connection.SetSessionInfo(glob);
Run Code Online (Sandbox Code Playgroud)

以及alter session使用相同的连接执行命令,但都没有任何影响.我认为这是因为转换为字符串发生在稍后阶段,连接设置无效.

有没有其他方法让odp.net直接为我提供偏移量?我无法更改oracle db函数,因此在方法中使用例如tz_offset不是一个选项.

如果这不可能,那么将时区字符串转换为偏移量的最佳方法是什么?我正在考虑执行一个

select TZNAME, TZABBREV, tz_offset(TZNAME) as TZOFFSET
from V$TIMEZONE_NAMES
Run Code Online (Sandbox Code Playgroud)

曾经建立一个查阅表,但如果有更好的选择,会很高兴.

我的数据检索代码,包括我尝试的内容:

using (var connection = new OracleConnection(this.connectionString))
{
connection.Open();
OracleGlobalization glob = connection.GetSessionInfo();
glob.TimeStampTZFormat = "DD-MON-YYYY HH:MI:SS.FF AM TZH:TZM";
connection.SetSessionInfo(glob);
string sql = "ALTER SESSION " +
 "SET NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"'";

using (var cmd = connection.CreateCommand())
{
    cmd.CommandText = sql;
    cmd.ExecuteNonQuery();
}    

using (var cmd = connection.CreateCommand())
{
    cmd.CommandText = "fn_name";
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.BindByName = false;
    var output = cmd.Parameters.Add("return_value", OracleDbType.RefCursor);
    output.Direction = ParameterDirection.ReturnValue;
    cmd.Parameters.Add("id", id).Direction = ParameterDirection.Input;

    using (var dataAdapter = new OracleDataAdapter(cmd))
    {

        dataAdapter.SafeMapping.Add("TZ_COLUMN", typeof(string));
        dataAdapter.TableMappings.Add("Table", "Table");
        OracleGlobalization glob2 = connection.GetSessionInfo();
        glob2.TimeStampTZFormat = "DD-MON-YYYY HH:MI:SS.FF AM TZH:TZM";
        connection.SetSessionInfo(glob2);
        dataAdapter.Fill(dataSet);
    }
    foreach (DataRow row in dataSet.Tables[0].Rows)
    {
  // column is string with timezone name, I want offset
    }
    }
Run Code Online (Sandbox Code Playgroud)

谢谢

Ben*_*ehn 2

看起来一个非常简单的解决方案就是设置

dataAdapter.ReturnProviderSpecificTypes = true;
Run Code Online (Sandbox Code Playgroud)

这似乎使 ODP.net 不会执行到 .net System.DateTime 的有损转换,而是使用它自己的日期类型。