在数据库中更新 Oracle TIMESTAMP(0) WITH TIME ZONE 值的正确方法

Proper method to update Oracle TIMESTAMP(0) WITH TIME ZONE value in database

我正在尝试使用 TIMESTAMP(0) WITH TIMEZONE 类型的列更新 table。

我尝试了几种方法都没有成功,因为 TIMESTAMP 写入数据库的方式没有偏移量格式,例如美国东部时间的 -05:00 。它使用 AMERICA/NEW_YORK 作为时区保存,这会导致另一个应用程序无法正确处理此问题。

当前:28-NOV-16 10.51.43.000000000 AM AMERICA/NEW_YORK

期望:28-NOV-16 10.51.43.000000000 AM -05:00

这里的许多贴子主要讲的是从数据库中检索数据时对数据进行格式化;其他示例使用 SqlPlus 而非 C# 进行描述。

Using(OracleConnection conn = new OracleConnection(......))
{
        OracleCommand cmd = new OracleCommand();
        cmd.Connection = conn;
        cmd.BindByName = true;
        cmd.CommandText = "update customer set email_addr = :EMAIL, modified_date= SYSDATE 
    where cust_id = :CUSTID";

        conn.Open();
        cmd.Parameters.Add("EMAIL", OracleDbType.Varchar2).Value = txtEmail.Text;
        cmd.Parameters.Add("MODIFIED_DATE", OracleDbType.Varchar2).Value = OracleDate.GetSysDate().ToOracleTimeStamp();
        cmd.Parameters.Add("CUSTID", OracleDbType.Decimal).Value =Convert.ToDecimal(Session["ID"]);

    cmd.ExecuteNonQuery();
}

我也试过 modified_date=to_timestamp(:modified_date, 'MM/DD/YYYY HH:mi:ss') 但这会产生异常,因为时区格式不正确。

在 C# 中完成此任务的正确方法是什么? date/timestamp 列是否应始终使用字符串转换来编写?

您的代码似乎有错别字。您指定了 2 个绑定变量,但您尝试绑定 3 个值。

OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.BindByName = true;
cmd.CommandText = "update customer set email_addr = :EMAIL, modified_date= :MODIFIED_DATE
where cust_id = :CUSTID";

conn.Open();
cmd.Parameters.Add("EMAIL", OracleDbType.Varchar2).Value = txtEmail.Text;
cmd.Parameters.Add("MODIFIED_DATE", OracleDbType.TimeStampTZ).Value = OracleDate.GetSysDate().ToOracleTimeStamp();
cmd.Parameters.Add("CUSTID", OracleDbType.Decimal).Value =Convert.ToDecimal(Session["ID"]);
cmd.ExecuteNonQuery();

OracleDbType不是Varchar2,一定是TimeStampTZ.

但是,您似乎使用的是 DevArt 的 Oracle Data Provider。当我检查 documentation 时,它们似乎不支持数据类型 TIMESTAMP WITH TIME ZONE.

我看到了几个解决方法。

在 运行 数据库操作之前将 SESSIONTIMEZONE 设置为 -05:00,例如:

cmd.CommandText = "ALTER SESSION SET TIME_ZONE = '-05:00'";
cmd.ExecuteNonQuery();

那么你的C#代码可以是这样的:

OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.BindByName = true;
cmd.CommandText = "update customer set email_addr = :EMAIL, modified_date= CURRENT_TIMESTAMP
where cust_id = :CUSTID";

conn.Open();
cmd.Parameters.Add("EMAIL", OracleDbType.Varchar2).Value = txtEmail.Text;
cmd.Parameters.Add("CUSTID", OracleDbType.Decimal).Value =Convert.ToDecimal(Session["ID"]);
cmd.ExecuteNonQuery();

CURRENT_TIMESTAMP returns 您会话时区中的当前时间作为 TIMESTAMP WITH TIME ZONE 数据类型。

您也可以在SQL中指定时区,例如:

cmd.CommandText = "update customer set email_addr = :EMAIL, 
       modified_date= SYSTIMESTAMP AT TIME ZONE '-05:00'
   where cust_id = :CUSTID";

当您使用 TIMESTAMP 更新 TIMESTAMP WITH TIME ZONE 值时,Oracle 将使用时区 -05:00.

隐式转换为 TIMESTAMP WITH TIME ZONE

注意,America/New_York有夏令时,即你必须使这些命令更动态,并在-05:00-04:00之间切换两次一年(如果您使用像 America/New_York 这样的时区区域,那将是一个很大的好处)。

另一种解决方法是在您的应用程序中使用 运行 ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = 'DD-MON-YY HH.MI:SS.FF AM TZH:TZM',它无法处理 AMERICA/NEW_YORK.

等时区名称