将 CYYMMDD (整数) 转换为 DB2 for iSeries 中的日期





4.00/5 (1投票)
将 7 位数字整数日期格式转换为 SQL 日期格式
引言
在 DB2 for iSeries 中,存在一种日期格式 CYYMMDD
。从技术上讲,它是一个整数,因此对日期的比较对于机器来说变得更容易、更快。 这篇文章的目的是演示如何将这种 CYYMMDD
日期转换为 SQL 日期。 这是为了确保日期以用户可以理解的格式呈现,并避免在处理 Java (java.sql.Date
) 等语言时出现类型不匹配。
理解问题
首先,让我们理解这种格式。C YY MM DD
。我们都可以很容易地知道 YY 是年份的后两位数字,MM 是月份,DD 是日期。 那个“C”是什么? 正如你们中的一些人正确猜测的那样,它是世纪。 但什么世纪? 它是从 1900 年开始计算的世纪。 所以 1900-1999 年是 0 世纪,2000-2099 年是 1 世纪,以此类推。 例如,1991 年 12 月 31 日将被写成 '0911231'。 同样,2003 年 1 月 1 日将被写成 '1030101'。 因此,从左边开始的前三位数字加上 1900 将为您提供年份 (1900+103 = 2003)。 接下来两位数字为您提供月份。 后两位数字为您提供日期。 解决此问题的一种简单方法是对传入的 7 个字符长的字符串进行子串操作,并在将世纪年与 1900 相加之前执行必要的类型转换,然后在适当的位置插入连字符 (-),然后再将整个内容转换为 SQL DATE 格式。
注意:可以通过将日期字符串以 YYYY-MM-DD
格式传递给 DATE()
函数来完成 SQL DATE 类型转换。
一些特殊情况
但这里有一个问题。 由于存储在数据库中的值是整数,因此在进行子串操作之前,需要将其预先类型转换为 string
。 好的,让我们假设我们将查询/参数中的整数类型转换为 string
,然后进行子串操作。 它适用于所有情况吗? 因为在将数据保存/处理为整数时,会省略前导零,而 '0911231' 将显示为六位数 '911231'。 在这里,我们可以通过检查位数来避免这个问题。 如果是 7 位数,则对数字 (1,3)、(3,5)、(5,7) 进行子串操作。 否则,对数字 (1,2)、(2,4)、(2,6) 进行子串操作。 问题解决了? 答案是否定的! 1909 年 2 月 23 日呢? 它将显示为 '90223',一个五位数的数字。 另一个“else if
”? 不!!! 如果你是一名程序员,请不要考虑单个案例并编写任何代码。 首先要理解什么是预期的,以及我们可以期望的所有可能的输入。 最佳的起点是边界条件方法。 如上所述,它是一个 7 位整数(仅正数)。 世纪从 1900 年开始计算。 因此,小于 1900 年的日期永远不会出现,即使一些笨蛋传递负值,他们也应该得到错误的结果或错误(随便!)。 最小的可能日期是 1900 年 1 月 1 日,即 '101'(请注意,如果采用并继续使用前面的方法,它只有三个数字,你最终会使用 7、6、5、4 和 3 位数的 if
/else if
/else
,如果 Linus Torvalds 碰巧看到了你所做的事情,你进入天堂的概率是“nolla”。) 现在,可能的最大数字是 2899 年 12 月 31 日 (999+1900)。 由于该格式只允许 7 位数字,因此不能再用 CYYMMDD
格式表示其他日期。
解决方案
因此,无论输入是什么(从 101 到 9991231),我都需要日期。 好的,所以我需要世纪年(即删除最后四位数字后剩下的任何内容)。 所以只需除以 10000。 然后将其与 1900 相加。 如果是 '101',则为 0+1900=1900,如果是 '1010101',则为 101+1900=2001。(整数除法永远不会产生小数结果!) 好的,我们得到了年份。 接下来让我们来算月份。 它在中间(这里有点棘手)。 我发现 DB2 中的 MOD
函数在这里很方便。 MOD(NUMBER, 10000)
将给出最后四位数字,除以 100 将给出最后四位数字的前两位数字。 因此,月份的公式现在是 MOD(NUMBER, 10000)/100
。 如果是 '101',它将是 MOD(101, 10000) = 101
。 然后 101/100 = 1。 这是你的月份。 9991231 呢? MOD(9991231,10000) = 1231
。 然后 1231/100 = 12。 这是你的月份。(同样,整数除法永远不会产生小数结果!) 因此,最后两位数字,即日期,现在单独处理。 再次,我们调用我们值得信赖的盟友 MOD
。 MOD(NUMBER, 100)
将为您提供日期,无论是什么情况。 我认为我可以安全地忽略提供关于 MOD
如何处理各种数字的 100 的示例。 然后我们必须在年、月和日之间放置连字符,并构造一个将被类型转换为日期的 string
。 那样做有用吗?
SELECT DATE(((NUMBER/10000)+1900)|| '-' ||
(MOD(NUMBER,10000) /100)|| '-' ||
MOD(NUMBER,100))
FROM
SYSIBM.SYSDUMMY1;
其中 NUMBER 是你的 CYYMMDD
整数。 如果你经常使用它,为什么不编写你自己的自定义函数来为作为整数传递的任何 CYYMMDD
日期返回 DATE
呢?
-Shenbaga Murugan Paramasivapandian
(DB2 数据库管理员,Java/Web 开发人员,开源爱好者)