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

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

谢谢

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

 dataAdapter.ReturnProviderSpecificTypes = true; 

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

也许以下链接可以帮助?

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

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