0

此例程返回 2016 年 12 月 31 日而不是 2015 年 12 月 31 日,并弄乱了报告。知道哪里出错了吗?

    LET date_month = MONTH(p_selection.date_from)
IF  date_month = 12 THEN 
    LET date_month = 1
    LET p_selection.date_from = p_selection.date_from + 1 UNITS YEAR
    LET date_thru = date_month,"/01/",YEAR(p_selection.date_from)
    LET p_selection.date_from = p_selection.date_from - 1 UNITS YEAR
ELSE 
    LET date_month = date_month + 1
    LET date_thru = date_month,"/01/",YEAR(p_selection.date_from)
END IF

LET p_selection.date_thru = date_thru CLIPPED

IF YEAR(p_selection.date_thru) <> YEAR(p_selection.date_from) THEN 
    LET p_selection.date_thru = p_selection.date_thru + 1 UNITS YEAR
END IF 
    LET p_selection.date_thru = p_selection.date_thru - 1
4

3 回答 3

1

假设输入p_selection.date_from是 12/01/2015 ...

IF date_month = 12返回 TRUE,因此date_thru计算为 01/01/2016

但随后第二IF条语句也返回 TRUE,在 (01/01/2017) 中再增加一年p_selection.date_thru,然后再减少一天到 2016 年 12 月 31 日。

在我看来,有人曾多次尝试计算该月最后一天的日期,并且需要一种或另一种方法,而不是两者兼而有之。DBDATE在您的代码中首先出现的那个特别可疑 -当它在 DATE 和 CHAR 之间转换时,假设是美国格式,这是完全没有必要的。

一个更简单的解决方案是简单地计算:

LET p_selection.date_thru = 
    MDY(MONTH(p_selection.date_from), 1, YEAR(p_selection.date_from))
    + 1 UNITS MONTH - 1 UNITS DAY

换句话说,找到所选月份的第一天,加一个月,减一天。简单而强大,它适用于年份边界和闰日。

于 2016-01-07T23:01:34.930 回答
0

我有

FUNCTION last_of_month(m,y)
DEFINE m,y SMALLINT
    RETURN MDY(m,days_in_month(m,y),y)
END FUNCTION

使用适当的函数 days_in_month() 根据月份和年份返回 28,29,30,31

对于 OP,您应该创建一个函数并重新使用它,而不是像您正在做的那样潜在地重复逻辑。

我真正想评论的是,在 Genero,我们正在讨论是否添加内置函数来执行这些类型的计算。如果每个人都有自己的 first_of_month、last_of_month、add_months,那么我们的想法是我们应该将它们包含在语言中,而不是让每个人都重新发明轮子。作为讨论的一部分,我了解到 RET 在他的回答中使用的 + 1 UNITS MONTH 正如他所说的闰年安全。出于某种原因,我认为它不是并且倾向于避免它,并以 JLefflers 回答的风格写作。查看我见过的其他 4GL/Genero 客户库代码,我怀疑其他开发人员也有同样的想法。

于 2016-01-11T22:13:10.953 回答
0

这里有一些旧代码有一段时间没有出现,但仍然是有效的 I4GL。

ltmonth.4gl

{
    @(#)$Id: ltmonth.4gl,v 1.4 1990/04/05 11:02:05 john Exp $
    @(#)Sphinx Informix Tools: General Library
    @(#)Find last day of this month
    @(#)Author: JL
}

FUNCTION last_of_this_month(edate)

    DEFINE
        edate   DATE        { Effective date (frequently TODAY) }

    IF edate IS NULL THEN
        RETURN edate
    END IF

    RETURN first_of_next_month(edate) - 1

END FUNCTION {last_of_this_month}

fnmonth.4gl

{
    @(#)$Id: fnmonth.4gl,v 1.4 1990/04/05 11:02:03 john Exp $
    @(#)Sphinx Informix Tools: General Library
    @(#)Find 1st of next month
    @(#)Author: JL
}

FUNCTION first_of_next_month(edate)

    DEFINE
        edate   DATE,       { Effective date (frequently TODAY) }
        mm      INTEGER,    { Month number }
        yy      INTEGER     { Year }

    IF edate IS NULL THEN
        RETURN edate
    END IF

    LET mm = MONTH(edate) + 1
    LET yy = YEAR(edate)
    IF mm > 12 THEN
        LET mm = 1
        LET yy = yy + 1
    END IF

    RETURN MDY(mm, 1, yy)

END FUNCTION {first_of_next_month}

lastthismonth.spl

下面是一些基于上述 I4GL 的 SPL:

-- @(#)$Id: lastthismonth.spl,v 1.2 2008/07/20 02:54:37 jleffler Exp $
--
-- @(#)Create last_of_this_month Stored Procedure
--
-- @(#)Version: ltmonth.4gl,v 1.4 1990/04/05 11:02:05 john
-- @(#)Sphinx Informix Tools: General Library
-- @(#)Find last day of this month
-- @(#)Author: JL
--
-- Alternative expression: 
-- (MDY(MONTH(dateval), 1, YEAR(dateval)) + 1 UNITS MONTH) - 1 UNITS DAY

CREATE PROCEDURE last_of_this_month(edate DATE DEFAULT TODAY)
    RETURNING DATE AS last_of_this_month;

    IF edate IS NULL THEN
        RETURN edate;
    END IF

    RETURN first_of_next_month(edate) - 1;

END PROCEDURE {last_of_this_month};

firstnextmonth.spl

-- @(#)$Id: firstnextmonth.spl,v 1.1 2008/07/20 02:21:13 jleffler Exp $
--
-- @(#)Create first_of_next_month Stored Procedure
--
-- @(#)Version: fnmonth.4gl,v 1.4 1990/04/05 11:02:03 john
-- @(#)Sphinx Informix Tools: General Library
-- @(#)Find 1st of next month
-- @(#)Author: JL

CREATE PROCEDURE first_of_next_month(edate DATE DEFAULT TODAY)
    RETURNING INTEGER AS first_of_next_month;

    DEFINE mm   INTEGER;    { Month number }
    DEFINE yy   INTEGER;    { Year }

    IF edate IS NULL THEN
        RETURN edate;
    END IF

    LET mm = MONTH(edate) + 1;
    LET yy = YEAR(edate);
    IF mm > 12 THEN
        LET mm = 1;
        LET yy = yy + 1;
    END IF

    RETURN MDY(mm, 1, yy);

END PROCEDURE {first_of_next_month};

注意替代表达式。它有效,但它是 DATE 和 DATETIME 计算的令人难以置信的混合。

于 2016-01-08T08:15:46.960 回答