Saturday, April 26, 2014

GOMONTH() on an End Of Month, Beware!!!

What is GOMONTH() Function?

GOMONTH() gives us the ability to move forward/backward on a specified number of months before or after a given Date or Date/Time expression:

Create Cursor junk (xdate d)
ldBase = Date(2014,1,1)
For lnloop = 1 To 12
      Insert Into junk Values (GOMONTH(m.ldBase,1))
      ldBase = xdate
Next
Browse Normal

I have been comfortably using GOMONTH() without any thought of its known bug which is that it returns empty dates before 09/14/1752 because I definitely won't need to go way back that far for any date requirements.

However, I expect that when I perform GOMONTH() on end of month dates, that it will return the end of months of the succeeding months as well.  A fellow Foxite member Gene Wirchenko mentioned that it does not that if dates fall between 28 to 30 (February 28 & 29 plus months that ends on 30), succeeding dates will show the same day; not the end of month.   I tested now and he is right:



Create Cursor junk (xdate d)
ldBase = Date(2014,2,28)
For lnloop = 1 To 12
      Insert Into junk Values (GOMONTH(m.ldBase,1))
      ldBase = xdate
Next
Browse Normal



Having realized this now,  I created a small function called GoMonthX which I will start using from now on in replacement of this function:

***************
Function GomonthX(dDate,nStep, lForce)
***************
Local ldReturn, ldNewMonth
ldReturn = Gomonth(m.dDate,m.nStep)
If !m.lForce
      ldNewMonth = m.ldReturn
      If Month(m.dDate+1)<> Month(m.dDate)
            Do While Month(m.ldReturn) = Month(m.ldNewMonth)
                  ldReturn = ldReturn + 1
            Enddo
            ldReturn = ldReturn - 1
      Endif
Endif

Return(m.ldReturn)

It is very similar to GOMONTH() except with these:
  1. If base date won't fall on the abovementioned dates, then it will perform pure GOMONTH()
  2. If base date will fall on the abovementioned dates, will perform further steps to ensure it will get the accurate end of month date.
  3. a 3rd parameter that when passed a value of .T. will force retain the day.  Like if you wanted to have the 28th of every month instead of the real end of month date.  May be useful in some cases.
Now I can get the best of both worlds so to speak.  If say base date is February 28, then I can get the end of months of the succeeding months.  Or opt to return the 28th's of each month via that 3rd switch.

The main goal of this blog is to make VFP developers be aware of these results on some of end of month dates.  



No comments:

Post a Comment