คำนวนหาวันที่ที่ต้องการไม่นับเสาร์อาิทิตย์วันหยุดน
กระทู้เก่าบอร์ด อ.Yeadram

 9,269   13
URL.หัวข้อ / URL
คำนวนหาวันที่ที่ต้องการไม่นับเสาร์อาิทิตย์วันหยุดน

คำนวนหาวันที่ที่ต้องการโดยไม่นับเสาร์,อาทิตย์, วันหยุดนักขัตฤกษ์ต่าง ๆ ครับ, มือใหม่ไม?ชำนาญเรื่อง VBA, อ่านจากหลายๆ กระทู้แล้วก็ยังไม่เหมือนกับปัญหาของตนเองเท่าใดนักครับ, พอคลำทางได้บ้างแต่ก็คิดไม่ออก, เ้รียนท่านอาจารย์หลาย ๆ ท่าน (อ.YeadRam, อ.แดน ฯลฯ) โปรดชี้แนะครับ,
ข้อมูลของผมเป็นดังนี้ (ตามความรู้ที่ตนเองมี)

Table - WorkDate ประกอบด้วยฟิลด์
           ID(ลำดับที่),
           StartDate(วันที่เริ่มต้น),   [ เมื่อระบุ เช่น 03/12/2553 ]
           Days (จำนวนวันทำงาน) [ เมื่อระบุ เช่น 15 ]

Table - HolidayDate (ตารางเก็บวันที่วันหยุดนักขัตฤกษ์ต่าง ๆ)
           HDate (วันที่ที่เป็นวันหยุดนักขัตฤกษ์), type เป็น Date แน่นอน
           Description (อธิบายว่าเป็นวันหยุดอะไร เช่น วันรัฐธรรมนูญ)       
           ตามตัวอย่างนี้เป็นเดือนธันวาคม 53 จะมีวันหยุดคือ จันทร์ที่6, ศุกร์ที่ 10
           ศุกร์ที่ 31.....

Module1 - ฟังก์ชั่นสำหรับให้วันนับข้ามเสาร์,อาทิตย์,วันหยุดนักขัตฤกษ์ (เขียนไม่
               เป็นครับ) โดยกำหนดชื่อ function - NonCountDay

Query - ดึงจาก Table WorkDate และเพิ่มฟิลด์คำนวนดังนี้
             ID
             StartDate วันที่ 03/12/2553
             Days       จำนวนวัน 15
             WorkDate [ฟิลด์คำนวนผลลัพท์คือนำวันที่ 03/12/2553 บวกไป
             15 วัน,โดยไม่นับวันเสาร์, ไม่นับอาทิตย์, ไม่นับวันหยุดตามตาราง
              HolidayDate....ผลที่ออกมาต้องเป็นวันที่ 27/12/2553 ].....ในช่องนี้
             จะต้องระุบุคำสั่งเป็นแบบนี้หรือไม่ครับ
              WorkDate : DateAdd ("d",StartDate,Days) ...เอ..แล้ว function
              NonCountDay จะเข้ามาเกี่ยวข้องกับฟิลด์นี้ตอนไหนครับ

ขอบพระคุณล่วงหน้าครับ
            

13 Reply in this Topic. Dispaly 1 pages and you are on page number 1

1 @R07266
ไม่มีใครตอบเลย
2 @R07267
Public Function WorkingDays(StartDate As Date, EndDate As Date) As Integer
'....................................................................
' Name:     WorkingDays
' Inputs:   StartDate As Date
'   EndDate As Date
' Returns: Integer
' Author: Arvin Meyer ผู้เขียน code ครับ
' Date:     February 19, 1997
' Comment: Accepts two dates and returns the number of weekdays between them
' Note that this function does not account for holidays.
'....................................................................
On Error GoTo Err_WorkingDays

Dim intCount As Integer
              
                            
               intCount = 0
                 
               If Weekday(StartDate) = 1 Then
              
                     intCount = intCount + 1
              
               End If
              
               Do While StartDate <= EndDate
               'Make the above < and not <= to not count the EndDate
              
                    Select Case Weekday(StartDate)
                    Case Is = 1, 7     'ตรงนี้บอกว่า 1คือวันอาทิตย์ 7 คือ วันเสาร์ที่เราจะไม่นับ
                        intCount = intCount
                    Case Is = 2, 3, 4, 5, 6
                        intCount = intCount + 1
                    End Select
                    
                    StartDate = StartDate + 1
                    
                    If Weekday(EndDate) = 1 Then
                        If EndDate > StartDate Then
                            intCount = intCount + 1
                         End If
                    End If
                    
               Loop
              
               WorkingDays = intCount

Exit_WorkingDays:
    Exit Function
Err_WorkingDays:
    MsgBox Err.Description
    Resume Exit_WorkingDays
   

End Function

ทั้งหมดนั้นจะไม่นับเฉพาะเสาร์อาทิตย์ แต่ถ้าต้องการนับวันอื่นๆเช่นนักขัตฤกษ์หรือวันชดเชย คุณต้องสร้างตารางวันหยุดเหล่านั้นขึ้นมาใหม่แล้วลอก code นี้ไป

Public Function TotalDayoff(StartDate As Date, StopDate As Date) As Integer

    Dim Cnx As ADODB.Connection
    Dim Rst As ADODB.Recordset
    Dim StrCnx As String
    Dim A As Long
    Dim N As Long
    Dim I
    Dim DayCount
        Set Cnx = CurrentProject.Connection
        Set Rst = New ADODB.Recordset
       
        Rst.Open "Holiday", Cnx, 1, 1, 2
        N = Rst.RecordCount
       
        With Rst
            
            
                            .MoveLast
                                Datenow = .Fields!Dateoff.Value
                                    If StartDate = Datenow Then
                                        TotalDayoff = 1
                                    ElseIf StartDate > Datenow Then
                                        TotalDayoff = 0
                                        Exit Function
                                    End If
                                   
                            .MoveFirst
                                Datenow = .Fields!Dateoff.Value
                                    If StopDate = Datenow Then
                                        TotalDayoff = 1
                                        Exit Function
                                    ElseIf StopDate < Datenow Then
                                        TotalDayoff = 0
                                        Exit Function
                                    End If
            
            DayCount = 0
       
                            For I = 1 To N
                                
                                Datenow = .Fields!Dateoff.Value
                                
                                        If Datenow >= StartDate And Datenow <= StopDate Then
                                           DayCount = DayCount + 1
                                        ElseIf Datenow < StopDate Then
                                        Else
                                           Exit For
                                        End If
                                        .MoveNext
                            Next I
       
        End With
       
        TotalDayoff = DayCount
       
        Rst.Close

End Function

Code นี้ไม่ได้ใส่พวก error detection นะครับแต่คิดว่าคุณคงใส่เองได้ไม่ยาก
TotalDayoff=วันหยุดนักขัตฤกษ์หรือวันหยุดชดเชย ซึ่งคุณต้องเอาไปลบออกจาก Workingdays จึงจะได้เป็นจำนวนวันทำงานที่แท้จริง
Code นี้คุณสามารถดัดแปลงได้ตามใจชอบละครับ ไม่ยากอะไร สมัยที่เขียนก็เพิ่งลองเล่น ADODB ใหม่ๆ ช่วง code movelast movefirst นั้นเอาออกก็ได้ ตอนนั้นเขียนเอามัน แต่ไม่จำเป็นต้องใช้ จริงๆแล้ว code Totaldayoff นี้มีวิธีที่ง่ายมากๆคือใช้ query นับเอา แต่ปัญหาใหญ่มากๆคือเรื่องระบบวันที่ใน computer นั่นแหละ แต่เมื่อผมใช้ ADODB ปัญหาเหล่านี้ก็หมดไป ลองดูนะครับ
3 @R07270
ขอบคุณ Nova ผมจะลองไปคิดและดัดแปลงดูน่ะครับ (มือใหม่ไม่เป็นน่ะครับ ไม่รู้จริง ๆ)
4 @R07271
นั่งอ่านดูแล้ว, ต้องคำนวนหาจำนวนวันให้ได้ก่อนหรือไงครับ และถึงจะไปหาว่าวันที่ถึงกำหนดคือวันที่เท่าไร,

(จริงแล้วต้องการว่า หากกำหนดวันนี้ 3/12/2553 + และกำหนด15 วันทำงาน, ไม่นับเสาร์,อาทิตย์, วันหยุดประเพณีต่าง ๆ, ผลที่ออกมาจะเป็นวันที่ 27/12/2553, นั่่นคือระบบจะต้องนับวันเฉพาะวันที่ 3,7.,8,9,13,14,15,16,17,20,21,22,23,24,27 ซึ่งรวมเป็น 15 วันทำการพอดี, โดยไม่นับวันที่ 4,5,6,10,11,12,18,19,25,26)

(อีกตัวอย่างหนึ่งหากกำหนด 8/12/2553 และกำหนด 6 วันทำงาน ผลที่ออกมาคือต้องเป็นวันที่ 16/12/2553, โดยนับเฉพาะวันที่ 8,9,13,14,15,16, และไม่นับวันที่ 10,11,12)

เพราะมันมีวัน StartDate สมมุติว่าเป็นวันที่ที่กำหนดเช่น 3/12/2553
และ 15 วันทำงาน หรือ 6 วันทำงาน จะไปอยู่ฟิลด์ไหนครับ, แต่ EndDate เป็นวันที่ใช่ไหมครับ ...
5 @R07273
งั้นผมคงเข้าใจผิด เพราะ code ที่ให้ไป 2 ชุดนั้น ชุดหนึ่งนับวันทำงานจากวันเริ่มต้นถึงวันสิ้นสุดโดยไม่นับเสาร์อาทิตย์ อีกชุดนับเฉพาะวันหยุดพิเศษทั้งหลายแหล่ แต่ถ้าคุณ Twin ต้องการรู้ว่าวันสิ้นสุดจะเป็นวันที่เท่าไหร่ (EndDate) ก็ทำย้อนกลับกันนะครับนั่นคือต้องเปลี่ยนบรรทัด
Do While StartDate <= EndDate
ส่วนจะเปลี่ยนเป็นอะไรนั้นก็มีอยู่ไม่กี่แบบ ต้องเลือกเอาเองแหละครับ ที่แน่ๆคือไม่ต้องใส่ EndDate จะใช้คำสั่ง For... Next ก็ได้
ซึ่งไม่ว่าจะใช้ Do While หรือ For... Next และตรงนี้ก็ต้องกำหนดตัวแปร x ให้เท่ากับจำนวนวันทำงานที่คุณต้องการเช่น
Do While X < จำนวนวันทำงาน
ส่วนใน Loop คุณต้องแก้ไข code เอาเองแหละครับ (ไม่ยากเท่าไหร่หรอก)
คือคุณต้องทำการนับทั้ง X และ IntCount
X จะเพิ่มขึ้นเมื่อ Weekday ไม่ใช่เสาร์หรืออาทิตย์
แต่ IntCount จะเพิ่มขึ้นครั้งละ 1 ทุกรอบ
เมื่อนับ X จนครบตามเงื่อนไข เราก็จะได้ค่า IntCount ออกมาด้วย
ถึงตรงนี้เราก็ใช้ Function ของ Access มาหาวันสิ้นสุดได้ละครับ โดยนำค่า IntCount ไปใช้งาน (ต้องขอโทษด้วยคือผมจำไม่ได้ว่าคำสั่งอะไรแต่มั่นใจว่ามี
ลองดูตรงนี้ก่อนละกันครับ จากนั้นค่อยขยับไปทำวันหยุดพิเศษ ตรงนี้ก็จะซับซ้อนขึ้นอีก
6 @R07274
ขอบคุณครับจะลองทำดูก่อน, หากได้หรือยังไม่ได้ก็จะมาแจ้งน่ะครับ
7 @R07275
พอดีไปดู Code เก่าๆที่เขียนไว้ วิธีหนึ่งที่ได้ผลในการหาวัน EndDate เมื่อรู้ StartDate กับ IntCount ก็คือใช้ Function Convert ครับ
ผมลองเขียนให้ดูเป็นตัวอย่างนะ

EndDate = CDate(CLng(StartDate)+IntCount)

ง่ายๆแค่นี้ครับ

8 @R07277
EndDate คือวันที่ต้องการหา
CDate คือ ฟังก์ชั่นแปลงวันที่
CLng คือฟังก์ชั่นแปลงค่า (ไม่แน่ใจ) ???
StartDate คือวันที่เริ่ม (เราบันทึกกำหนดเข้าไป)
IntCount คือ มาจากฟังก์ชั่นคำนวนนับวัน ???

EndDate = CDate(CLng(StartDate)+IntCount) จะไว้บรรทัดไหนน้ะ

ไม่มีความรู้จริง ๆ จับทางไม่ถูก พยายามจับทางมานานแล้ว
ต้องเริ่มที่ไหนและสิ้นสุดที่อะไร ตามลำดับขั้นตอน
9 @R07279
พอดีผมอาจต้องใช้ด้วย ก็เลยไปคิดมา ผลที่ได้ก็คือโค้ข้างล่างนี้ ยังไงช่วยทดสอบให้ผมอีกทีว่ามีอะไรผิดพลาดหรือไม่

Public Function pfNextWorkDT(pStartDT As Date, pNumOfDay As Long) As Date
'   pStartDT = วันเริ่มต้น
'   pNumOfDy = จำนวนวันทำงาน
'
'   วิธีการคือ หาวันหยุดรวมระหว่างวันเริ่มต้นและวันสุดท้ายที่ได้จากการบวกเข้าไปตรงๆ (pStartDT + pNumOfDay)
'   ถ้าพบว่ามีวันหยุด ก็นำวันหยุดที่หาได้ไปรวมกับจำนวนวันทำงานที่ต้องการ แล้วหาวันสุดท้ายอีกครั้ง (pStartDT + pNumOfDay + wLastTotalHol)
'   นำวันสุดท้ายใหม่นี้ ไปหาวันหยุดรวมจากวันเริ่มต้นอีกครั้ง ทำไปเรื่อยๆจนกว่าจะพบว่า วันหยุดรวมครั้งก่อนหน้า กับครั้งนี้มีจำนวนเท่ากัน
'   ซึ่งหมายความว่า ไม่พบว่ามีวันหยุดเพิ่มเติม ดังนั้นวันสุดท้ายจากครั้งนี้ ก็จะเป็นผลลัพธ์ที่ต้องการ

    Dim wEndDT              As Date     ' วันสุดท้าย
    Dim wDay               As Integer ' จำนวนวันที่ต้องการบวกเข้ากับวันเริ่มต้น เพื่อหาวันสุดท้าย
    Dim wSat               As Integer ' จำนวนวันเสาร์ระหว่างวันเริ่มต้นและวันสุดท้าย
    Dim wSun               As Integer ' จำนวนวันอาทิตย์ระหว่างวันเริ่มต้นและวันสุดท้าย
    Dim wTradHol            As Integer ' จำนวนวันหยุดนักขัตฤกษ์ระหว่างวันเริ่มต้นและวันสุดท้าย
    Dim wTotalHol           As Integer ' จำนวนวันหยุดรวมทั้งหมดระหว่างวันเริ่มต้นและวันสุดท้าย
    Dim wLastTotalHol       As Integer ' จำนวนวันหยุดรวม จากการหาครั้งก่อนหน้า
    
    wTotalHol = 0
    Do
        wLastTotalHol = wTotalHol
        wDay = pNumOfDay + wLastTotalHol
       
        wEndDT = DateAdd("d", wDay - 1, pStartDT)
        wSat = DateDiff("ww", pStartDT - 1, wEndDT, 7)
        wSun = DateDiff("ww", pStartDT - 1, wEndDT, 1)
        wTradHol = DCount("HDATE", "HolidayDate", "HDATE between #" & Format$(pStartDT, "dd-mmm-yyyy") & "# and #" & Format$(wEndDT, "dd-mmm-yyyy") & "#")
       
        wTotalHol = wSat + wSun + wTradHol
    Loop Until wTotalHol = wLastTotalHol
    pfNextWorkDT = wEndDT
End Function
10 @R07280
รออยู่นานครับว่า..บรรดาอาจารย์อื่นๆทั้งหลายจะเข้ามากันบ้าง...อ.สันติสุข...อ.YeadRam....ฯลฯ และอีกหลายท่านที่ไม่เอ่ย ถึง ขอบคุณครับ..จะแกะดู...ไม่ได้จะขออนญาตถามต่อตามประสาคนไม่เป็น
(จริงก็แค่มีความรู้บ้างตรง Table Query Form Report พื้น ๆ น่ะครับ)
ขอบคุณครับ
11 @R07284
เรียน อาจารย์ สันติสุข

แจ้งผลคำนวนหาวันที่, ปรากฎว่าได้แล้วครับ (ผมดึงรูปไม่เป็น หากใครบอกวิธีด้วยขอบคุณ)


(ตอนแรกผมลองแล้วไม่ได้ครับ,ขึ้น run time error 3056 และฟ้องเกี่ยวกับวันที่, ก็คิดไปคิดมา,ไปดูในโค้ดแล้วรูปแบบวันที่, เอะใจรูปแบบวันที่ DD-MMM-YYYY เลยลองเปลี่ยนวันที่ในวินโดว์เป็นภาษาอังกฤษ + ใน access, ฟิลด์ Date เปลี่ยนรูปแบบวันที่เป็น Medium Date, ก็ขึ้นวันที่ที่ต้องการได้แล้วครับ, ถ่อมตัวหรือครับว่ามีอะไรผิดพลาด, ออกมาตรงวันที่ตามรูปแนบครับ)

ขอบคุณครับ

หมายเหตุ ขอบคุณคุณ Nova ด้วยที่ช่วยเป็นการคิดอีกแบบครับ

12 @R07286
ทำรูปได้แล้วครับ, จึงส่งรูปมาให้ดูครับ




13 @R07516
คุณ twin

ขอไฟล์ตัวอย่างบ้างได้ไหมคะ
ส่งมาที่ sec.3810@gmail.com

ขอบคุณค่ะ
@ ประกาศใช้งานเว็บบอร์ดใหม่ => บอร์ดเรียนรู้ Access สำหรับคนไทย
แล้วจะใส่ลิ้งอ้างอิงมาที่โพสต์เก่านี้หรือไม่ก็ตามสะดวกครับ
Time: 0.4011s