3

在 IBM iSeries 上运行着上个世纪的许多遗留应用程序仍在使用中。例如 JD 爱德华兹。日期字段通常以多种格式存储,统称为Julian Date。这些格式是年份和日期的组合,现在更准确地称为序数日期

JD Edwards ERP 应用程序数据库中广泛使用的特定 Julian Date 格式是 6 位格式 ( YYYDDD ),由 3 位年份(表示为自 1900 年以来的年数)和 3 位数字(带前导零)组成那一年。 在此处输入图像描述 有一个清晰简洁的方法在 SQL 中在这两种格式之间进行转换是非常有帮助的。

这是 IBM 提供的将 Julian Dates 转换为 Calendar Dates的解决方案:

Select date (days(concat(cast(integer(1900000+"SDIVD") /1000 as Char(4)),'-01-01'))+mod(integer(1900000+" SDIVD"),1000)-1)

哎哟。我头疼...

我希望有一种更简单、更容易的方法来转换任何一种方式,只使用 IBM iSeries DB2 SQL 语法?

4

3 回答 3

4

我不确定您使用什么来显示数据,但限制

包括 1940 年至 2039 年之间的日期

与您的会话设置相关联,不应返回 NULL,而是通常由“++++++++”表示的计算错误。空值通常表示为单个破折号“-”。如果您将会话设置更改为以 ISO 格式而不是 MDY 格式显示日期,则范围之外的日期应正常显示。有关日期时间值的字符串表示的相关 IBM 文章。我不知道为什么这个设置会影响像 DAYOFYEAR 这样的标量函数,但确实如此。(编辑:在向 IBM 提交错误报告后,他们发布了 PTF 来解决 DAYOFYEAR SI77129(7.3)和 SI77130(7.4)的这个特定问题)

我可以跑

SELECT DATE(CHAR(140001 + 1900000)) FROM sysibm.sysdummy1;

并得到

2040-01-01

为了从日期转换为长朱利安并随后转换为您的序数日期,我找到了一个较短的版本:

SELECT INT(TO_CHAR('2019-10-18','YYYYDDD'))-1900000 FROM sysibm.sysdummy1;
于 2020-01-03T21:58:12.963 回答
2

对于 IBM i Db2(版本 7.2),我已经确定了以下两种用于在儒略日期和日历日期之间进行转换的方法:

-- Julian to Db2 Date (Method 1.0)
DATE(CAST(120050 + 1900000 AS CHAR(7)))

-- Db2 Date to Julian (Method 2.0)
1000 * (YEAR(DATE('02/19/2020')) - 1900) + DAYOFYEAR(DATE('02/19/2020'))

更新。我发现第一种方法可以缩短为:

-- Julian to Db2 Date (Method 1.1)
DATE(CHAR(120050 + 1900000))

下面是在 SQL 语句中使用它们的一些示例(以及 IBM 方法):

SELECT
    TEST_DATA."DATE"
    , TEST_DATA."JULIAN"
    , YEAR(TEST_DATA."DATE") AS "YEAR"
    , DAYOFYEAR(TEST_DATA."DATE") AS "DAYOFYEAR"
    , DATE(DAYS(CONCAT(CAST(INTEGER(1900000 + TEST_DATA."JULIAN") / 1000 AS CHAR(4)), '-01-01')) + MOD(INTEGER(1900000 + TEST_DATA."JULIAN"), 1000) - 1) AS "METHOD_IBM"
    , DATE(CAST((TEST_DATA."JULIAN" + 1900000) AS CHAR(7))) AS "METHOD_1.0"
    , DATE(CHAR(TEST_DATA."JULIAN" + 1900000)) AS "METHOD_1.1"
    , 1000 * (YEAR(TEST_DATA."DATE") - 1900) + DAYOFYEAR(TEST_DATA."DATE") AS "METHOD_2.0"
FROM
    TABLE
    (
        VALUES
              (DATE('12/31/1938'), 039365)
            , (DATE('12/31/1939'), 039365)
            , (DATE('01/01/1940'), 040001)
            , (DATE('02/19/2020'), 120050)
            , (DATE('2020-01-01'), 119366)
            , (DATE('2039-01-01'), 139001)
            , (DATE('2039-12-31'), 139365)
            , (DATE('2040-01-01'), 140001)
            , (DATE('2041-01-15'), 141015)
    )
    AS TEST_DATA("DATE", "JULIAN")
;

在此处输入图像描述

另一个答案建议了突出显示的记录:

用 119366 试试 IBM 的版本和你的版本...

我不知道是否有一个“标准”可以说明这个特定值,但我会说 119366 不是有效的儒略日期,因为 2019 年不是闰年,只有 365 天。我认为允许“溢出”到随后的几年是一种不利的方法,我也没有看到任何遗留应用程序以这种方式存储日期。一般来说,我希望我的查询突出数据中的不规则性,而不是掩盖它们。

请注意,至少有一些数据库标量函数只计算 1940 年到 2039 年之间的日期。我已经包含了这个范围之外的一些日期来演示奇怪的行为。我不确定 IBM 在哪里记录了该行为,但在标量 DAYOFYEAR 函数的文档中没有提到任何内容。

于 2019-11-14T22:19:40.913 回答
0

用 119366 试试 IBM 的版本和你的版本...

无论您选择哪种转换方法,我都会将其包装在用户定义函数 (UDF) 中。

这样做打开了自定义错误处理的可能性,例如使用数字字段存储日期。所有的零可能意味着“未设置”并且可以用 null 代替,而所有的 9 应该用 9999-12-31 代替。

使用 UDF 意味着您可以考虑使用不同的语言进行转换,例如 RPG。有一个现有的日期转换 UDF 开源包,称为iDate

要考虑的另一个选项是“日期”/“日历”/“日期维度”表。非常方便,不仅仅是日期转换。谷歌搜索会出现大量适用于任何数据库的信息。

对于 IBM i 特定示例,请查看 Redbook IBM DB2 Web Query for i: The Nuts and Bolts 的第 5 章 (请注意,如果您碰巧安装了 Db2 for i Web Query,则有一个脚本可以创建这样的日期表。)

例如,日期维度表可能包括以下列:
- Julian legacy date,在加入使用 Julian legacy 日期的文件时使用
- Packed decimal(8,0) legacy date,在加入使用 Julian 的文件时使用压缩十进制 (8,0) 旧日期
- 字符 (8) 旧日期,在加入使用 Character(8) 旧日期的文件时使用
- 日期(真正的 DB2 日期字段)
- 会计年度 - 会计季度
- 日期周(周一、周二等)
- 一年中的月份(1 月、2 月等)
- 季节(春季、夏季、秋季和冬季)
- 去年(一周的同一天)
- 一周结束日期
- 一年中的一周
- 超级碗周日旗帜(Y 或 N)
- 假日旗帜前一天(Y 或 N)
- 假日旗帜后一天(Y 或 N)
- 满月旗帜(Y 或 N)

于 2019-11-14T23:50:24.077 回答