1

我正在开发一个将数据从 IBM iSeries 服务器导入 MSSQL 2008 R2 数据库的程序。不幸的是,一些开发人员很久以前就决定将日期存储为十进制类型,从而有效地打破了用于存储日期的 CYYMMDD 格式。

例如,在该格式中,1995 年 8 月 1 日将存储为:0950801。但是,实际存储在数据库中的是 95081,如果我尝试将其转换为 System.DateTime,显然会引发异常。

如果缺少前导 0 是一件简单的事情,我可以在尝试转换之前轻松地将其添加到字符串中。但是,有几个(实际上是数千个)只有 3 或 4 位数字的日期,我真的不知道该怎么做。例如,有一个日期存储为 1128。我完全不知道该怎么做。如果我只是添加 3 个前导 0 并将其转换,它会产生一个明显不正确的日期。

那么,有人知道解析这些日期的可靠方法吗?是直接通过 SQL 选择语句,还是在 C# 中进行一些操作?还是我只是假设一开始就没有正确输入 3 位和 4 位日期,而只是丢弃这些日期?

4

3 回答 3

0

经过大量的反复试验,我想我已经找到了解决方案。

选择
(INT(SUBSTR(DIGITS(DTPSTD),1,2))> MOD(年份(当前日期),100时的情况)
            那么日期(CONCAT(CONCAT(CONCAT(SUBSTR(DIGITS(DTPSTD),3,2),'/'),CONCAT(SUBSTR(DIGITS(DTPSTD),5,2),'/')),CONCAT('19 ', SUBSTR(DIGITS(DTPSTD), 1,2))))
        其他日期(CONCAT(CONCAT(CONCAT(SUBSTR(DIGITS(DTPSTD),3,2),'/'),CONCAT(SUBSTR(DIGITS(DTPSTD),5,2),'/')),CONCAT('20 ', SUBSTR(DIGITS(DTPSTD), 1,2))))
        END) 作为交易日期
FROM TABLE_NAME
WHERE CUSTOMER_ID = 1

DTPSTD是“发布日期”

据我所知,这适用于 1900 年或 2000 年的任何日期,但不适用于 1900 年 1 月 1 日之前的日期。就我而言,这很好,因为我没有存储任何早于 1920 年左右的日期。

于 2013-05-08T15:29:18.597 回答
0

十进制 CYYMMDD 是一种标准的 IBM 格式,其中 C 在 1900 年代为 0,在 2000 年代为 1。这可以追溯到 S/38(大约 1982 年)或更早。但我不记得他们在 S/38 之前使用过它,S/38 是 AS/400 和 iSeries 的前身。

我建议在 DB2 中创建一个用户定义的函数来将十进制日期转换为 ISO 日期值。DB2 for i 将缓存 DETERMINISTIC 函数的结果,因此不必在每次看到之前处理过的日期值时重新计算该函数。

更新

这是一个示例,我将 ccyymmd 或 yymmdd 格式的压缩十进制 (8,0) 值转换为 DB2 日期:

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                                                          
;

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

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

于 2013-05-07T23:39:52.510 回答
0

我建议查看插入/更新表的程序(尤其是任何更改注释[假设它们存在])(为此查询 DB2)。更改评论有望告诉您日期格式是否已更改(例如Y2K)以及原因。

还要查看读取 DB的任何程序,可能有特殊代码来处理日期。可能有代码来确定日期格式。

95081 也可以是序数日期 (YYDDD),其中 DDD 是一年中的某一天。请参阅Ordinal 或 Julian-Date。这些日期在一个阶段流行。

我猜 DB-Field 最初是没有 Century 的YYMMDD。Y2k 的格式可能已更改为 CYYMMDD。像 1128(和 221)这样的日期可能是 YYMMDD 日期,这些日期在 Y2k 更改之前创建的地方已实现(或在原始 y2k 实现中错过并稍后更改)。

于 2013-05-07T23:44:57.363 回答