星期五, 3月 04, 2011

[VFP] GOMONTH() 應用

說明:
GOMONTH(dExpression | tExpression, nNumberOfMonths);
對於給定的日期或日期時間,傳回其指定之前或之後月份數目的日期。

參數說明:
  1. dExpression | tExpression:輸入 Date 或是 DateTime 資料型態
  2. nNumberOfMonths:正數表示加給個月份;負數代表減幾個月。
回傳值:Date 資料型態
備註: GOMONTH() 不支援 1753年01月01日之前的日期
  • 計算月份的最後一天、當月總共有幾天
邏輯:要計算當月份的最後一天,先找到下個月的第一天,再減一天就是當月的最後一天;最後一天同時也代表著當月份的總天數。
LOCAL dDate,dLastDay AS date
LOCAL iTotalDay AS integer 

dDate = DATE() -- 使用者自訂日期

-- 先利用DATE() 來找出自訂日期月份的第一天,
-- 然後利用GOMONTH() 加一個月找到下個月第一天,
-- 再減一天,找到自訂日期月份的最後一天。
dMonthLastDate = GOMONTH(DATE(YEAR(dDate),MONTH(dDate),1),1)-1

-- 邏輯同上,最後再利用DAY()函數把天數抓出來就行
iTotalDay = DAY(dMonthLastDate)

  • 精準計算年紀的年月日(計算兩個日期間的年月日)
為了寫公司計算退休金和資遣費的功能,在計算年齡這個邏輯上打轉了好一陣子,一直都無法很精準的計算出年月日,也因此計算出來的金額總是只能參考用,直到最近才發現自己的盲點。之前因為人事小姐提供給我邏輯參考範例,每次要依比例計算時,總是用 天數 / 365天 ,所以我在計算年齡或是相關變數時,也都是先計算出天數,然後再轉化為年和月,但這個問題是1年又不一定是365天,再加上人事小姐說政府官方是以1年365來計算(其實我也不知道是真是假啦),因次也沒有特別注意這個不準確。

1年並不一定是365天,但是1年一定是12個月吧,因此利用計算月份來計算,就可以精準地計算出年月日。這個邏輯延伸,還可以計算到55歲、65歲、年資15年和年資25年還有多久的年月日資料,其實就是計算兩個日期的年月日資料。
FUNCTION CountYYMMDD(tdStartDate AS date,tdEndDate AS date) AS string 
 
  LOCAL cYYMMDD AS string  
  LOCAL iTotalMonth,iYear,iMonth,iDay AS integer 
  LOCAL dDate AS date 
 
  -- GOMONTH() 函數不支援 17530101 之前的日期
  IF tdStartDate < {^1753/01/01} OR tdEndDate < {^1753/01/01}
    RETURN ""
  ENDIF 
 
  iTotalMonth = 0
  iYear = 0
  iMonth = 0
  iDay = 0
  dDate = tdStartDate -- 迴圈日期;此變數用來跑迴圈,紀錄起始日期
 
  -- 從起始日期計算有幾個月到結束日期
  -- 迴圈日期 小於 結束日期,就一直進入
  DO WHILE dDate < tdEndDate

    dDate = GOMONTH(dDate,1) -- 迴圈日期,一次加一個月
    DO CASE
      CASE dDate <= tdEndDate 
        -- 當迴圈日期小於結束日期,iTotalMonth 加 1
        iTotalMonth = iTotalMonth + 1
      CASE dDate > tdEndDate 
        -- 當迴圈日期大於結束日期,把迴圈日期 減 1 個月,並離開
        -- 此時迴圈日期為最接近結束日期的月份時間
        dDate = GOMONTH(dDate,-1)
        EXIT
    ENDCASE
  
    -- 防呆,避免無限迴圈
    IF iTotalMonth > (999*12) + 11
      RETURN ""
    ENDIF

  ENDDO

  iYear = INT(iTotalMonth/12)
  iMonth = iTotalMonth - (12 * iYear)
  iDay = tdEndDate - dDate -- 結束日期 減 迴圈日期(此時為最接近結束日期的月份時間)
  cYYMMDD = PADL(ALLTRIM(STR(iYear)),3,"0") + PADL(ALLTRIM(STR(iMonth)),2,"0") + PADL(ALLTRIM(STR(iDay)),2,"0")
 
  RETURN cYYMMDD
ENDFUNC
  • 參考資料
  • Age()
  • GOMONTH()、DATE()、DAY() in VFP 9.0 Help

2 則留言:

Robert 提到...

真利害!...加油阿!對於年份日期,怎麼感覺有點怪怪的...邏輯是怎麼去推算?應該說年資是怎麼算的?是以在公司服務的天數來算,還是以在公司服務的月數來算?

TerryTsai 提到...

TO C.C.L ~~
1. 邏輯上面有寫阿,哪裡看不懂嗎?
2. 年月份資料,看你怎麼應用和讓使用者閱讀,我整理好之後,以年資來說,會變成從到職日至欲計算日期(使用者可以自行輸入,預設值是今天),年資為X年X月X日 ~~

張貼留言