将IBM iSeries DB2十进制日期类型转换为DateTime对象
本文关键字:类型转换 DateTime 对象 日期 十进制 IBM iSeries DB2 | 更新日期: 2023-09-27 18:12:47
我正在编写一个程序,将数据从IBM iSeries服务器导入到MSSQL 2008 R2数据库中。不幸的是,一些开发人员很久以前就决定将日期存储为十进制类型,从而有效地破坏了用于存储日期的CYYMMDD格式。
例如,在该格式中,1995年8月1日将存储为:0950801。但是,实际存储在数据库中的是95081,如果我试图将其转换为System.DateTime,显然会抛出异常。
如果只是缺少前导0的简单问题,我可以在尝试转换字符串之前轻松地将其添加到字符串中。然而,有几个(实际上是数千个)只有3或4位数的日期,我真的不知道该怎么做。例如,有一个存储为1128的日期。我完全不知道这是怎么回事。如果我只是在它后面加上3,然后转换它,它会产生一个明显不正确的日期。
那么,有人知道一种可靠的方法来解析这些日期吗?要么直接通过SQL选择语句,要么在c#中做一些操作?或者我只是假设3位数和4位数的日期从一开始就没有输入正确,然后就抛弃这些日期?
我建议查看插入/更新表的程序(以及特别是任何更改注释[假设它们存在])(查询DB2)。更改注释将有希望告诉您是否更改了日期格式(例如Y2K)及其原因。
同样看一下任何程序读取DB,可能有特殊代码来处理Date。可能有代码来确定日期格式。
95081也可以是序数日期(YYDDD),其中DDD是一年中的一天。参见序数或儒略日期。
我猜DB-Field最初是YYMMDD,没有Century。格式可能为Y2k更改为CYYMMDD。像1128(和221)这样的日期可能是YYMMDD日期,它们是在Y2k更改实现之前创建的(或者在最初的Y2k实现中错过并后来更改的)。
经过反复试验,我想我找到了解决办法。
<>之前选择(int (substr (digits (dtpstd), 1,2))> mod (year(当前日期),100)然后date (concat (concat (concat (substr (digits (dtpstd), 3,2), '/'), concat (substr (digits (dtpstd), 5,2), '/')), concat ('19', substr (digits (dtpstd), 1,2))))Else date (concat (concat (concat (substr (digits (dtpstd), 3,2), '/'), concat (substr (digits (dtpstd), 5,2), '/')), concat ('20', substr (digits (dtpstd), 1,2))))END) AS TransactionDate从TABLE_NAME其中customer_id = 1之前 DTPSTD
为"Date published "
据我所知,这适用于1900年或2000年的任何日期,但不适用于1900年1月1日之前的日期。在我的例子中,这很好,因为我没有存储任何超过1920年左右的日期。
十进制CYYMMDD是一种标准的IBM格式,其中C为0表示1900年,1表示2000年。这可以追溯到S/38(1982年左右)或更早。但我不记得他们在S/38之前使用过它,S/38是AS/400和isseries的前身。
我建议在DB2中创建一个用户定义的函数,将十进制日期转换为ISO日期值。DB2 for i将缓存DETERMINISTIC函数的结果,因此该函数不必在每次看到之前处理过的日期值时都重新计算。
下面是一个示例,我对其进行了修改,将cyymmd或yymmdd格式的打包的十进制(8,0)值转换为DB2 Date:
CREATE OR REPLACE FUNCTION
Cvt_Dec8cymd_to_Date ( dtin dec(8,0) )
returns date
LANGUAGE SQL
CONTAINS SQL
DETERMINISTIC -- caches results
NO EXTERNAL ACTION
RETURNS NULL ON NULL INPUT
NOT FENCED
SET OPTION DBGVIEW = *SOURCE
prc: BEGIN NOT ATOMIC -- don't rollback on error
DECLARE ans date;
DECLARE cymd dec(8,0);
-- add declarations for conditions and handlers here
SET ans = null;
CASE
WHEN dtin > 999999 THEN -- more than 6 digits given
set cymd = dtin;
WHEN dtin < 400000 THEN -- yr < 40 means 2000's
SET cymd = 20000000 + dtin;
ELSE -- yr >= 40 means 1900's
SET cymd = 19000000 + dtin;
END CASE;
--convert to date
SET ans = date( insert(insert(digits(cymd),7,0,'-'),5,0,'-') );
RETURN ans;
END prc
;
这是一个简单的逻辑,没有错误处理无效值。
其他人可能有一个更好的例子,或者可能会改进这个。