【问题标题】:MySQL function for emulating Java's LocalDate.fromEpochDay()用于模拟 Java 的 LocalDate.fromEpochDay() 的 MySQL 函数
【发布时间】:2020-11-04 19:59:03
【问题描述】:

由于我的 MySQL 数据库中有一些旧值代表 java.time.LocalDate 值,我想创建一个转换函数来取回正确的 MySQL DATE 值。初始值是通过LocalDate.toEpochDay() 生成的。于是我查看了对应的LocalDate.ofEpochDay(long epochDay)方法(见here)并尝试翻译。但是我的翻译产生了我无法解释的负面日子。

有谁知道为什么以下功能不起作用?

create function fromEpochDays(days bigint)
RETURNS date DETERMINISTIC
--RETURNS varchar(50) DETERMINISTIC
BEGIN
    DECLARE dom bigint;
    DECLARE month bigint;
    DECLARE year bigint;
    DECLARE zeroDay bigint;
    DECLARE adjust bigint;
    DECLARE daysPerCycle bigint;
    DECLARE adjustCycles bigint;
    DECLARE yearEst bigint;
    DECLARE doyEst bigint;
    DECLARE marchDoy0 bigint;
    DECLARE marchMonth0 bigint;
    DECLARE dateToParse CHAR(100);
    DECLARE valToCheck CHAR(100);

    SET daysPerCycle = 146097;
    SET adjustCycles = 0;
    SET adjust = 0;

    SET zeroDay = days + 719528 - 60;
    IF zeroDay < 0 THEN
        SET adjustCycles = (zeroDay + 1) / daysPerCycle - 1;
        SET adjust = adjustCycles * 400;
        SET zeroDay = zeroDay + (-adjustCycles * daysPerCycle);
    END IF;

    SET yearEst = (400 * zeroDay + 591) / daysPerCycle;
    SET doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
    IF doyEst < 0 THEN
        SET yearEst = yearEst - 1;
        SET doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
    END IF;
    
    SET yearEst = yearEst + adjust;
    SET marchDoy0 = doyEst;
    SET marchMonth0 = (marchDoy0 * 5 + 2) / 153;
    SET month = MOD((marchMonth0 + 2),12) + 1;
    SET dom = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1;
    SET year = yearEst + marchMonth0 / 10;
    SET dateToParse = concat(cast(dom as char(20)),',',cast(month as char(20)),',',cast(year as char(20)));
    return STR_TO_DATE(dateToParse,'%d,%m,%Y');
END;

如果我将函数更改为仅返回变量 dateToParse 并使用不同的值调用它,我会得到以下结果:

select
 fromEpochDays_AsChar(12),
 fromEpochDays_AsChar(13),
 fromEpochDays_AsChar(14),
 fromEpochDays_AsChar(15),
 fromEpochDays_AsChar(16),
 fromEpochDays_AsChar(29),
 fromEpochDays_AsChar(30),
 fromEpochDays_AsChar(31),
 fromEpochDays_AsChar(32)

fromEpochDays_AsChar(12)    13,1,1970
fromEpochDays_AsChar(13)    14,1,1970
fromEpochDays_AsChar(14)    15,1,1970
fromEpochDays_AsChar(15)    -15,2,1970
fromEpochDays_AsChar(16)    -14,2,1970
fromEpochDays_AsChar(29)    -1,2,1970
fromEpochDays_AsChar(30)    0,2,1970
fromEpochDays_AsChar(31)    1,2,1970
fromEpochDays_AsChar(32)    2,2,1970

从 0 到 14 的值产生正确的值,但以下看起来显然很奇怪......看起来只有前半个月的计算正确。

【问题讨论】:

  • 尝试使用 DECLARE result_date DATE 计算新日期;选择 DATE_ADD("1970-01-01", INTERVAL days DAY) 到 result_date;
  • @BUcorp 感谢您的评论!我现在使用它作为解决方法。但我真的很想知道我在那里做错了什么,因为我花了很多时间在这个功能上。也许这是 MySQL 在计算 bigint 时的限制?
  • 老实说我不知道​​,但我将答案发布为函数 mysql。如果你解决了,请告诉我(记得标记为已回答;))

标签: java mysql datetime


【解决方案1】:

正如我所说,也许尝试像这样简化

CREATE DEFINER=`user`@`%` FUNCTION `fromEpochDays`(days INTEGER) RETURNS date
BEGIN

DECLARE result_date DATE; 
select DATE_ADD("1970-01-01", INTERVAL days DAY) into result_date;

RETURN result_date;
END

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-09
    • 2012-02-24
    • 1970-01-01
    • 2020-01-02
    • 2023-04-04
    • 1970-01-01
    相关资源
    最近更新 更多