将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位数的日期从一开始就没有输入正确,然后就抛弃这些日期?

将IBM iSeries DB2十进制日期类型转换为DateTime对象

我建议查看插入/更新表的程序(以及特别是任何更改注释[假设它们存在])(查询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                                                          
;

这是一个简单的逻辑,没有错误处理无效值。

其他人可能有一个更好的例子,或者可能会改进这个。

相关文章: