此例程将于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
答案 0 :(得分:1)
假设输入p_selection.date_from
是12/01/2015 ...
IF date_month = 12
返回TRUE,因此date_thru
计算为01/01/2016
但是第二个IF
语句也会返回TRUE,再添加一年到p_selection.date_thru
(01/01/2017),然后将其减少一天到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
换句话说,找到所选月份的第一天,添加一个月并减去一天。它简单而强大,适用于年界和闰日。
答案 1 :(得分:0)
这里有一些旧的代码,偶尔没有见到,但仍然是有效的I4GL。
{
@(#)$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}
{
@(#)$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}
这里有一些基于上述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};
-- @(#)$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计算的一个令人难以置信的混合。
答案 2 :(得分: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,那么我们应该考虑将它们包含在语言中,而不是让每个人重新发明轮子。作为讨论的一部分,我学到的是在他的回答中使用的+ 1个单位月,就像他说闰年安全一样。出于某种原因,我认为它不是,并且倾向于避免它,并以JLefflers的答案写出来。看看我见过的其他4GL / Genero客户库代码,我怀疑其他开发人员也有同样的想法。