เปลี่ยนปีเป็น พ.ศ และคำนวน

   
ขอรบกวนหน่อยนะค่ะ พอดีพึ่งเรียนโปรแกรมนี้เมื่อเดือนที่แล้วนะค่ะ อยากจะทราบว่าหนูมี table อยู่อันหนึ่ง มีfiled วันเกิด(birthday) เป็นdate และมี filed อายุ(age) วัน(day) เดือน(month) เป็น numberic
และหนูก็สร้างฟอร์มขึ้นมาหนึ่งอัน ลากข้อมูลที่อยู่ใน dataenvironment ออกมาแสดงบนฟอร์ม ชื่อ txtbirthday และก็สร้า text ขึ้นมาอีก 3 อัน ชื่อว่า txtage txtmonth txtday และมีปุ่ม command ที่ใช้คำนวนอายุจากวันเกิด ว่ามีอายุกี่ปี กีเดือน กี่วัน
PROC NOWAGE
* FORMAT var=NOWAGE(date)
* ใช้สำหรับหาอายุปัจจุบันโดยการส่งค่าวันเดือนปีเกิดมาให้ แล้วจะเทียบกับวันที่ขณะนี้
PARA _age,_derive
IF ! EMPTY(_age)
PRIVATE _mage
_mage=DATE()-_age
IF PARAMETERS() > 1
IF _derive='2' .AND. _mage >=365
RETU LTRIM(STR(YEAR(DATE())-YEAR(_age)))+' ปี '
ENDI
ENDI
DO CASE
CASE _mage<=30
RETU STR(_mage,2)+' วัน '
CASE _mage<=365
RETU STR(INT(_mage/31),2)+' เดือน '
OTHER
_mage = INT(_mage/365)
RETU IIF( _mage>99, '99', STR(_mage,2) ) +' ปี '
ENDC
ELSE
RETU SPACE(11)
ENDIF
หนูก็เปลี่ยนมาเป็นตามที่คุณ joe แนะนำ ที่ให้เขียนโค้ดใน .prg หนูเขียนแล้วพอรันฟอร์ม คลิกcommand ให้คำนวณ ใน txtage มันกลายเป็น **วัน
แล้วช่วยบอกวิธีที่จะเปลี่ยนจาก ค.ศ. มาเป็น พ.ศ.หน่อยสิค่ะ
(ส่งวันที่ 27 มีนา วันเริ่ม้รียน summerนะค่ะกรุณาวยหนูด้วยนะค่ะ)
tri
24 มี.ค. 49 เวลา 21:59:20 น. --> 58.136.224.56,
   
   
ดูแล้วไม่รู้เรื่อง เอา ค.ศ.+543 ได้ไม๊ครับ ทำไมเขียนโปรแกรมวนอ้อมโลก ที่จริงการเขียนโปรแกรมหาอายุโดยนับจากวันเกิดถึงปัจจุบัน เขียนแค่บรรทัดเดียวแค่นั้นเองนี่นา
nn
24 มี.ค. 49 เวลา 22:31:24 น. --> 61.7.139.99, ww
  
   

<<ที่จริงการเขียนโปรแกรมหาอายุโดยนับจากวันเกิดถึงปัจจุบัน เขียนแค่บรรทัดเดียวแค่นั้นเองนี่นา>>
ว้าว!!

. .
25 มี.ค. 49 เวลา 9:08:34 น. --> 203.155.94.129,
  
   
ถ้าคุณ tri ลอง post code ที่คุณเขียนมาให้ช่วยกันดู อาจจะมีคนช่วยตอบ
ถ้าคุณตัดแปะ code ที่คนตอบกระทู้ให้มาทั้งดุ้น
และ/หรืออ้างถึงวิธีที่คุณ joe แนะนำ .. txtage มันกลายเป็น ** วัน
โดยไม่มีรายละเอียดว่าคุณเขียนอย่างไร แบบนี้ยากครับ

25 มี.ค. 49 เวลา 21:23:18 น. --> 124.120.145.241
  
   
ขออนุญาตนิดนึง
code PROC NOWAGE ข้างบนมีปัญหาหลายอย่างนะครับ

IF _derive='2' .AND. _mage >=365
RETU LTRIM(STR(YEAR(DATE())-YEAR(_age)))+' ปี '

เดาว่า _derive แปลว่าเป็น วันเกิดที่อนุมาณมา(เพราะเจ้าตัวรู้แค่ปีเกิดเป็นต้น)
อย่างนี้จะใช้ได้กับ _age ที่ต้องเท่ากับ 1/1/yyyy เท่านั้นจึงจะได้ค่าถูก

CASE _mage<=30
อันนี้คร่าวมากๆ หลายเดือนมี 31 วัน และ ก.พ. มี 28/29 เท่านั้น

RETU STR(INT(_mage/31),2)+' เดือน '
ข้างบนใช้1 เดือน =30 พอมาตรงนั้กลับใช้ 31 มาหาร ซึ่งก็ไม่ปม่นอีก

_mage = INT(_mage/365)
ไม่จริงนะครับ หนึ่งปีมีทั้ง 365 และ366 เฉลี่ยแล้ว 365.2524 วัน/ปี
แต่ก็ใช้คำนวณดุ่ยๆ ด้วย 365.2524 ไม่ได้ คุณลองกับ การคำนวณวันเกิด
ในปีที่เป็นปีที่ ก.พ. มี 29 วันดู

25 มี.ค. 49 เวลา 21:44:38 น. --> 124.120.145.241
  
   
เรื่องวันเวลานี่เป็นปัญหาจริงๆ
ขนาดเรื่องแค่นี้ผมยังไม่เข้าใจเลยครับ

จากวันนี้ ถึง วันพรุ่งนี้ = 1 วัน หรือ 2 วัน
จากวันนี้ ถึง วันมะรืน = 2 วัน หรือ 3 วัน
จากวันที่ 1 ถึงวันที่ 3 = 2 วัน หรือ 3 วัน

ไอ้เรื่องอายุก็เหมือนกัน
สุดสวย เกิดวันที่ 29 กุมภาพันธ์ พ.ศ 2543 อยากทราบว่า ณ. วันที่ 2 มีนาคม พ.ศ. 2543
สุดสวยอายุได้กี่วัน (ลูกสาวผมเองครับ น่ารักมาก)
เบื่อวันเวลา
26 มี.ค. 49 เวลา 14:50:12 น. --> 203.113.16.241,
  
   
ผมเคยเขียนโปรแกรมเช่าวีดีโอ,หนังสือ จะคิดค่าปรับเมื่อผู้เช่าส่งคืนช้ากว่ากำหนด
โดยไฟล์หนังสือจะมีรหัสหนังสือ ชื่อหนังสือ จำนวนวันที่ให้ยืม ราคาเช่า ปรับวันละ ฯลฯ
ไฟล์สมาชิกก็มีรหัส ชื่อ ที่อยู่ จำนวนสูงสุดที่ให้เช่า
เวลามาเช่าก็บันทึกวันที่เช่า รหัสผู้เช่า รหัสหนัง เข้าไฟล์การเช่า
เวลามาคืน โปรแกรมก็จะเอาวันที่มาคืนไปลบวันที่เช่า ได้กี่วันก็เอาไปเทียบว่าเกินจำนวนวันกี่วัน*ค่าปรับ
ถ้าคืนก่อนก็ลดให้ การเช่า,การคืนทั้งหมดใช้สแกนเนอร์ยิงเอาเลย
การคิดจำนวนวัน ผมคิดแบบนี้ครับ
จากวันนี้ ถึง วันพรุ่งนี้ = 2 วัน
จากวันนี้ ถึง วันมะรืน = 3 วัน
จากวันที่ 1 ถึงวันที่ 3 = 3 วัน
แต่ถ้าเจอวันอาทิตย์ซึ่งทางร้านปิด ก็ลดไป1วัน บางทียืมไปเป็นเดือนก็มีวันอาทิตย์หลายวัน
โปรแกรมก็ต้องคำนวณให้ทันทีเลยว่ามีวันอาทิตย์กี่วันแล้วลดเงินให้

nn
26 มี.ค. 49 เวลา 18:38:26 น. --> 202.47.247.116,
  
   
field วันที่ผมใช้character แบบนี้ครับ
พอผู้เช่ามาคืน ก็เอาสแกนยิงหนังที่เช่า ก็พรึ่บขึ้นหน้าจอ
โปรแกรมจะรู้ว่าเช่าไปวันไหน ค่าปรับวันละเท่าไหร่ ก็คำนวณได้ทันที
((ctod("วันที่คืน" ) - ctod("วันที่ยืม"))+1) * ค่าปรับต่อวัน


nn
26 มี.ค. 49 เวลา 18:52:39 น. --> 202.47.247.116,
  
   
วิธีการหาให้แม่นยำขึ้นไปอีกในกรณีบางปี เดือนกุมภา มี29วัน บางเดือนมี30วัน บางเดือนมี31วัน
ขอยกตัวอย่างอันเดียวนะครับ
วันที่ที่ผมใช้ สมมุติว่า "01/01/2549"
ผมก็เขียนแบบนี้ครับ ctod("01/01/"+str(val(2549)-val(543),4))
ดีหรือไม่ ถูกต้องหรือไม่ ลองดูนะครับ
nn
26 มี.ค. 49 เวลา 19:05:35 น. --> 202.47.247.116,
  
   
เรื่องว้ันเกิด ไหงกลายเป็น เรื่องเช่าวิดีโอไป ซะแล้ว

แต่ก็ได้ความรู้ดีนะครับ

ผมว่าเรื่องนับวันเกิด กับ วันเช่าวิดีโอ นี่ยังไงก็ไม่เหมือนกันนะครับ

ถ้าไม่นับเรื่องเวลาตกฝากด้วย คนที่เกิด เมื่อวานนี้ นับถึงวันนี้ ก็เป็น 1 วัน เท่านั้นครับ

เรย์
27 มี.ค. 49 เวลา 1:00:48 น. --> 203.121.150.133
  
   
คุณเรย์พูดถูกครับ วันเกิดก็วันเกิด วันเช่าหนังก็วันเช่าหนัง ธนาคารนับวันคิดดอกเบี้ยก็คิดแบบวันเช่าหนัง คือกู้เงินวันที่ 1 พอมาคืนเงินวันที่ 2 ก็คิด 2 วัน แต่เกิดปี 2548 พอปี 2549 ก็นับว่ามีอายุ 1ปี สรุปก็คือแล้วแต่ว่าจะคิดเรื่องอะไร
xx = ctod("วันปัจจุบัน")-ctod("วันเกิด")
เช่น xx=ctod("01/01/2006")-ctod("15/06/2000")
nn
27 มี.ค. 49 เวลา 8:55:26 น. --> 202.47.247.116,
  
   
ฟังก็ชันที่ใช้คำนวณ
FUNCTION fncCalAge
LPARAMETERS tdBthDate, tdCurDate
LOCAL lnY1, lnM1,lnD1, lnY2, lnM2,lnD2, lcY,lcM, lcD

IF tdBthDate >= tdCurDate
RETURN "000Y00M00D"
ELSE
lnY1 = YEAR(tdBthDate)
lnM1 = MONTH(tdBthDate)
lnD1 = DAY(tdBthDate)

lnY2 = YEAR(tdCurDate)
lnM2 = MONTH(tdCurDate)
lnD2 = DAY(tdCurDate)

** Day
IF lnD2 < lnD1
lnD2 = lnD2 + DAY(GOMONTH(GOMONTH(tdCurDate,-1)-DAY(tdCurDate)+1,1)-1)
lnM2 = lnM2 - 1
ENDIF
** Month
IF lnM2 < lnM1
lnM2 = lnM2 + 12
lnY2 = lnY2 - 1
ENDIF

lcY = RIGHT("00"+ALLTRIM(STR(lnY2-lnY1)),3)
lcM = RIGHT("0"+ALLTRIM(STR(lnM2-lnM1)),2)
lcD = RIGHT("0"+ALLTRIM(STR(lnD2-lnD1)),2)

RETURN lcY+"Y"+lcM+"M"+lcD+"D"
ENDIF
ENDFUNC

สมมติจัดเก็บใน program1.prg
เวลาเรียกใช้
SET PROCEDURE TO program1.prg
Age_String = fncCalAge(Birth_date , DATE())

ผลลัพธ์มีรูปแบบเป็น 'aaaYbbMccD' คือ อายุ aaa ปี bb เดือน cc วัน
:-)
AJ
27 มี.ค. 49 เวลา 10:52:57 น. --> 203.170.236.195
  
   
PROC NOWAGE
* FORMAT var=NOWAGE(date)
* ใช้สำหรับหาอายุปัจจุบันโดยการส่งค่าวันเดือนปีเกิดมาให้ แล้วจะเทียบกับวันที่ขณะนี้
PARA _age,_derive
IF ! EMPTY(_age)
PRIVATE _mage
_mage=DATE()-_age
IF PARAMETERS() > 1
IF _derive='2' .AND. _mage >=365
RETU LTRIM(STR(YEAR(DATE())-YEAR(_age)))+' ปี '
ENDI
ENDI
DO CASE
CASE _mage<=30
RETU STR(_mage,2)+' วัน '
CASE _mage<=365
RETU STR(INT(_mage/31),2)+' เดือน '
OTHER
_mage = INT(_mage/365)
RETU IIF( _mage>99, '99', STR(_mage,2) ) +' ปี '
ENDC
ELSE
RETU SPACE(11)
ENDIF
หนูเขียนโค้ดนี้ แล้วช่อง txtage มันกลายเป็น **วันนะค่ะ
tri
28 มี.ค. 49 เวลา 21:44:22 น. --> 58.136.224.41,
  
   
คุณ tri ต้องบอกรายละเอียดมากกว่านี้ครับ
คุณเขียนแค่ code nowage
และช่อง txtage กลายเป็น ** วันนะค่ะ
คนอ่านไม่มีทางรู้ว่าเกิดอะไรขึ้นกับ program/form ของคุณ
ผมขอลองขยายความดูนะครับ

1. code nowage นี้เขียนเป็น prg หรือ เป็น code ของ method ใน form?

2. คุณสั่งเรียก nowage อย่างไร เช่น ถ้าคุณสั่งใน form.command1.click
code ในนี้นเขียนอย่างไร ส่ง parameter 2 ตัวที่มันต้องการอย่างไร? เช่น
cRet =nowage(ctod(thisform.txtBirth.value), .F.) - - *1* หรือ
cRet =Thisform.nowage(thisform.txtBirth.value).F.) - - *2*
แบบ *1* สมมติเอาว่า textbox ชื่อ txtBirth ให้ user ใส่วันเกิดในนั้นมี string
ที่แทนค่าวันที่ dd/mm/yyyy ที่ถูกต้อง
แบบ *2* สมมติว่า txtBirth มีค่าในนั้นเป็น date เรียบร้อยแล้ว
ิbirthday เป็น date ใน table จึงเดาได้ว่าเป็น แบบ *2*

3.คุณใช้ค่า cRet จาก 2 ไปแสดง txtage อย่างไร?

การที่ txtAge ได้ **วัน อนุมานได้ว่า
CASE _mage<=30
RETU STR(_mage,2)+' วัน '
ทำงาน ซึ่งอนุมานได้ว่า
_mage ต้อง < 30 วัน ซึ่งเชื่อต่อได้ว่า
STR(_mage,2) + 'วัน' เป็น **วัน _mage นั้นต้อง < -9 (-10 เป็นต้นไป)

_mage < -9 ได้ เกิดจาก _age ที่ pass มาเป็นวัน"ก่อน"วันนี้มากกว่า 9 วัน
(เช่น date() -10 เป็นต้น) ถ้า _age เป็นปีพ.ศ. เอา date() ที่เป็นค.ศ. มาลบ
ผลคือ _mage จะเป็นตัวเลขติดลบขนาดใหญ่ๆ แน่นอน

ดังนั้นคำถามสำคัญคือคุณ pass"วันเกิด"ให้กับ nowage ด้วยวิธีใหน?
และ "วันเกิด" นี้นเป็น type อะไรและ format เป็นแบบใหน?

ถ้า birthday เป็น date ที่บันทึกเป็นปี พ.ศ. โดย"อาศัย" yyyy ที่ต้องเป็น ค.ศ.
แบบนี้ผิดนะครับ ไม่ควรทำเพราะจะบันทึก 29 ก.พ. บางปีไม่ได้ จะมีปัญหากับ
function เกี่ยวกับ date ต่างๆให้ค่าผิดเพราะใช้ ค.ศ. และกรณีนี้เป็นต้น

ถ้าเป็น birthday เป็น date ที่ใช้ปีพ.ศ.ใน yyyy ก็แก้แบบนี้ครับ
ิdBirth = date(year(birthday)-543, month(birthday), day(birthday))

ถ้า birthday เป็น character field
dBirth = ctod(left(birthday,6)+str(val(right(birthday,4))-543,4))

28 มี.ค. 49 เวลา 23:30:23 น. --> 124.120.145.247
  
   
ตุณ AJ ครับ
ผมเข้าใจว่า code ที่ให้มานี้ เป็นแนวทางเดียวกันกับที่มีอยู่ในกระทู้ #5928
ซึ่งที่จริงเสนอโดยคุณสุรชัย ใน #5305 และคุณสองนำไปปรับแก้ต่อ
(และคงต้องอ้างถึง #5829 และ #5892 ประกอบด้วย)

คุณ AJ เลือกใช้วิธีคำนวณแบบเดียวกับ DateDif() ของ Excel
อยากทราบความเห็นคุณ AJ ว่ารุ้สึกอย่างไรกับ จำนวนวันที่ติดลบจากการคำนวณวิธีนี้ครับ
? fncCalAge({^2002-2-1}, {^2003-3-1}) * 001Y01M00D
? fncCalAge({^2002-1-31}, {^2003-3-1}) * 001Y01M-2D
? fncCalAge({^2002-1-30}, {^2003-3-1}) * 001Y01M-1D

ผมไม่ได้ขัดแย้งหรือโต้ว่าวิธีนี้ผิดครับ แต่อยากทราบความเห็นคุณ AJ จริงๆ ครับ

ผมเองชอบแบบ A> (ตามที่คุณสองอธิบาย) มากกว่าแบบ B> (dateDif())
โดยเฉพาะ อายุเป็นวันที่ติดลบได้ เป็นเรื่องที่แปลก รับได้ยาก

*****
ขออนุญาตอีกนิดนะครับ รายละเอียดตรง การขอยืมวันจากเดือนก่อนมาใช้ลบวันที่
** Day
IF lnD2 < lnD1
- - lnD2 = lnD2 + DAY(GOMONTH(GOMONTH(tdCurDate,-1)-DAY(tdCurDate)+1,1)-1)
- - lnM2 = lnM2 - 1
ENDIF

ผมคิดว่าใช้
DAY(tdCurDate - DAY(tdCurDate))
เพื่อหาจำนวณวันของเดือนที่ผ่านมาของ tdCurDate ใดๆ ทำได้กระชับกว่า
DAY(GOMONTH(GOMONTH(tdCurDate,-1)-DAY(tdCurDate)+1,1)-1)
นะครับ

อีกประการ gomonth(...) กับวันที่ 31 จะเจอเดือน *ยน กลายเป็น 30 น้อยไป 1 วัน
ผลคือ กับ tdCurDate
- ที่เป็นวันที่ 31(เดือน *คม)
- - จะได้ 29 วันแทนที่จะเป็น 30
- ที่เป็น (28 สำหรับ leap year) 29 มี.ค. - 31 มี.ค.
- - จะได้ 27 วันแทนที่จะเป็น 28 (หรือ 29)
ในขณะที่ DAY(tdCurDate - DAY(tdCurDate)) ไม่มีปัญหา

แต่เพราะ lnD2 ที่เป็น 31-mm-yy ไม่มีทาง < lnD1 ที่เป็น 31-mm-yy
IF lnD2 < lnD1 ไม่มีทางเป็นจริงได้ จึงไม่เกิดปัญหาในการคำนวณผิดข้างบน
**ยกเว้น**
กรณีพิเศษ lnD1 เป็น 29/30 มีนา จะมีโอกาสเกิด lnD2 < lnD1 กับ lnD1 เป็น 31-mm-yy ได้
ลองดูกับ
? fncCalAge({^2004-1-31}, {^2004-3-30})
ได้ 000Y01M27D แทนที่จะเป็น 000Y01M28D

ก็ต้องขออนุญาตแสดงในส่วนที่ผมเห็นว่ายังเป็นปัญหาอยู่นะครับ :-)
แม้ว่าดูจะเป็นประเด็นปลีกย่อยมากก็ตาม
TS
29 มี.ค. 49 เวลา 11:25:37 น. --> 58.8.167.133, w
  
   
ไม่ทัน 27 แล้วแต่ลงวิธีของผมไว้ให้

set date ansi
set century on
bd = {^1975.07.26} * field วันเกิด
y = year(date()) - year(bd)
m = month(date()) - month(bd)
d = day(date()) - day(bd)
if d < 0
y1 = year(date())
m1 = month(date())-1
if m1= 0
m1 = 12
y1 = y1 -1
endif
date1 = ctod(tran(y1,'@l 9999')+'.'+tran(m1,'@l 99')+'.'+tran(day(bd),'@l 99'))
d = date() - date1
m = m - 1
endif
if m < 0
m = m+12
y = y - 1
endif
wait window str(y)+str(m)+str(d)
vfp6
29 มี.ค. 49 เวลา 12:10:15 น. --> 61.47.97.214, w
  
   
คุณ vfp6 ครับ

ลองกับวันเกิด(bd) นี้ดูครับ (คำนวณกับ date() วันนี้ 29/03/2006)
{^2004-21-29} wait window แสดง 2 2 0 -> ok
{^2004-21-30} -> 2 1 0 **
{^2004-21-31} -> 2 1 0 **
{^2004-02-01} -> 2 1 28
** ยังไม่ถูกครับ

date1 = ctod(tran(y1,'@l 9999')+'.'+tran(m1,'@l 99')+'.'+tran(day(bd),'@l 99'))
ใช้ไม่ได้ในบางกรณีครับ เช่นตัวอย่างนี้
date1 = empty date

TS
29 มี.ค. 49 เวลา 12:55:47 น. --> 58.8.167.133, w
  
   
ขอโทษครับ พิมพ์เดือนผิดไป 21 ที่ถูกคือ 01

{^2004-01-29} wait window แสดง 2 2 0 -> ok
{^2004-01-30} -> 2 1 0 **
{^2004-01-31} -> 2 1 0 **
{^2004-02-01} -> 2 1 28
TS
29 มี.ค. 49 เวลา 13:34:36 น. --> 58.8.167.133, w
  
   
ผิดจริง ๆ ครับ ขอบคุณคุณ TS งั้นแก้ไขเพิ่มเติม

d1 = day(bd)
do while .t.
* date1 = ctod(tran(y1,'@l 9999')+'.'+tran(m1,'@l 99')+'.'+tran(day(bd),'@l 99'))
date1 = ctod(tran(y1,'@l 9999')+'.'+tran(m1,'@l 99')+'.'+tran(d1,'@l 99'))
if date1 = {}
d1 = d1-1
else
exit
endif
enddo

แทน บรรทัดเดิม
"date1 = ctod(tran(y1,'@l 9999')+'.'+tran(m1,'@l 99')+'.'+tran(day(bd),'@l 99'))"
vfp6
29 มี.ค. 49 เวลา 13:54:20 น. --> 61.47.97.214, w
  
ขอเชิญร่วมตอบคำถามครับ
 
ผู้ตอบ :
รหัสผ่าน :
รูปภาพ :
คำตอบ :