6

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

dataAdapter.SafeMapping.Add("column_name", typeof(string));

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

23-NOV-12 08.10.12.057868000 PM ASIA/CALCUTTA

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

23-NOV-12 08.10.12.057868000 PM +04:30

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

Alter Session Set Nls_Timestamp_Tz_Format='DD-MON-YYYY HH:MI:SS.FF AM TZH:TZM'

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

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

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

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

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

select TZNAME, TZABBREV, tz_offset(TZNAME) as TZOFFSET
from V$TIMEZONE_NAMES

一次建立一个查找表,但如果有更好的选择会很高兴。

我的数据检索代码,包括我尝试过的东西:

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
    }
    }

谢谢

4

2 回答 2

2

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

dataAdapter.ReturnProviderSpecificTypes = true;

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

于 2013-01-03T13:55:02.170 回答
1

也许以下链接可以提供帮助?

http://docs.oracle.com/html/A96160_01/oratyp10.htm#1130922

这告诉了 OracleTimeStampTZ 类型,它也可以存储时区信息。timezone 属性返回有关时区的信息。

于 2012-12-27T03:50:24.580 回答