หากมีคำถาม ขอให้ไปโพสต์ลง เว็บบอร์ดจีทูจีเน็ตดอตคอม ตัวใหม่แทนน่ะครับ

หรือติดต่อเข้ามาทาง Inbox ที่ เฟซบุ๊ค ผมครับ

หน้าหลัก
ข่าวสาร - บทความ ทั้งหมด
VB 6/VB.Net
ASP/ASP.Net
จับฉ่ายคอมพิวเตอร์
เรียนรู้ผ่าน Flash Movie
บทความที่มีผู้ตอบล่าสุด  
 RSS Feeds
 ดาวน์โหลดโปรแกรม RSS Reader ได้ที่นี่ ...   Download โปรแกรม RSS Reader

Forum - www.g2gnet.com
Webmaster - www.g2gnet.com
Visitors - Session views
 5 5 9 1 7 7 6

7 ธันวาคม พ.ศ.2549
137 Users On-Line.
Visitors - Page views
 8 9 4 6 8 2 6
1 กุมภาพันธ์ พ.ศ.2551

Google   
เว็บ g2gnet.com
ขนาดตัวอักษร:  

ทำการอ่านค่ารูปแบบวันที่ของระบบเพื่อนำไปประยุกต์ใช้งานกับ MS Access

Category »  VB 6/VB.Net
โดย : Webmaster เมื่อ 28/4/2551 3:31:00
(อ่าน : 17080) 
ออกบทความเรื่องของ Time Attendance ไปแล้ว ผมหวลกลับมาอ่านดูอีกครั้งก็มีความรู้สึกตะหงิดใจเล็กๆ น้อยๆ อันเนื่องจากเขียนหรือบอกพี่น้องไป แบบไม่ครบถ้วนกระบวนความสักเท่าไหร่ อันเรื่องปัญหาเรื่องวันที่ใน MS Access มันมีมาหลายยุคสมัยแล้ว ซึ่งก็ไปเกี่ยวข้องกับการตั้งค่าจาก Control Panel --> Regional and Language Options โดยปกติทั่วไปที่พบเจอ ก็มักจะถูกตั้งค่าอยู่ใน 2 รูปแบบดังนี้ คือ
  • dd/mm/yyyy
  • mm/dd/yyyy
    พอเราไปใช้งาน VB6 กะเรื่องของวันที่ปั๊บ ปัญหาก็จะเกิดขึ้นทันทีเลย เพราะบางทีก็จะค้นหาข้อมูลเจอ (หรือ อาจจะไม่เจอเลย) หรือเจอแล้วแต่ได้ข้อมูลออกมาไม่ครบตามที่ต้องการ ซึ่งในลักษณะนี้โปรแกรมของเราก็ขาดความถูกต้อง แม่นยำ และแน่นอนไป ดังนั้นบทความนี้ผมก็จะใช้ ฟังค์ชั่น (Function) เพื่อช่วยในการทดสอบ ว่าระบบวันที่มันอยู่ในรูปแบบไหนกันแน่ แล้วค่อยเอารูปแบบที่ได้มานี้ไปใช้ในการค้นหาข้อมูลในช่วงระหว่างวันที่

    Design Time

    Run Program
    ดาวน์โหลด Source Code สำหรับ MS Visual Basic 6.0 - Service Pack 6
     ดาวน์โหลด Visual Basic 6.0 SP5: Run-Time Redistribution Pack
     ดาวน์โหลด Microsoft Data Access Object (MDAC) และ Jet 4.0 Update
     ดาวน์โหลด Microsoft Visual Basic Service Pack 6
    
    Option Explicit
    Dim Conn As New ADODB.Connection
    Dim RS As New ADODB.Recordset
    Dim SQLStmt As String
    ' ใช้เพื่อนำไปเป็นเงื่อนไขในการกำหนดรูปแบบของวันที่ เช่น
    ' 1 = dd/mm/yyyy
    ' 2 = mm/dd/yyyy
    Private blnDate As Byte
    
    ' กำหนดค่าคงที่ (Constant) รูปแบบเลขฐาน 16 น่ะครับ
    ' เราสามารถหาค่าเหล่านี้ได้จากเครื่องมือตัวหนึ่ง คือ API Text Viewer
    Private Const LOCALE_SSHORTDATE = &H1F
    Private Const LOCALE_USER_DEFAULT = &H400
    Private Const LOCALE_SYSTEM_DEFAULT = &H800
    
    ' ต้องใช้ WinAPI ฟังค์ชั่น GetLocaleInfo เข้ามาช่วยในการค้นหารูปแบบวันที่ด้วยน่ะครับ
    Private Declare Function GetLocaleInfo Lib "kernel32" Alias "GetLocaleInfoA" _
                (ByVal Locale As Long, ByVal LCType As Long, ByVal lpLCData As String, ByVal cchData _
                As Long) As Long
    
    ' ฟังค์ชั่นที่ใช้ในการตรวจสอบรูปแบบวันที่ของระบบ
    Function GetSystemDate() As String
    Dim sBuff As String
    Dim x As Long
        ' ประกาศจับจองพื้นที่ในหน่วยความจำไว้ 16 ไบต์
        ' เพื่อใช้ในการรับค่ารูปแบบวันที่ เช่น dd/mm/yyyy
        sBuff = Space$(16)
        x = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, sBuff, Len(sBuff))
        
        ' หาก Return ค่า 0 กลับมาแสดงว่าเกิด Error ขึ้น
        ' GetSystemDate จะ Return ค่าแบบ String กลับเพื่อนำไปใช้ในการทดสอบ
        If x > 0 Then GetSystemDate = Left$(sBuff, x - 1)
    
    x = 11 ทำให้ต้อง Return ค่ากลับ Left$(sBuff, x - 1) จะได้ "dd/mm/yyyy"
    End Function

    การเรียกใช้งาน API Text Viewer

    อ่านข้อมูล (Text) เข้ามา

    เลือก WIN32API

    พิมพ์ชื่อตัวแปรที่ต้องการ
    
    Private Sub Form_Load()
        Dim strDate As String
        Me.Move (Screen.Width - Me.Width) \ 2, (Screen.Height - Me.Height) \ 2
        
        ' กำหนดค่าเริ่มต้น
        dtpDateBegin.Value = Format(Now(), "dd/mm/yyyy")
        dtpDateEnd.Value = Format(Now(), "dd/mm/yyyy")
        
        ' =================================================
        ' อันที่จริงในส่วนนี้นำไปไว้ในฟังค์ชั่น GetSystemDate ไปเลยก็ได้น่ะครับ ... แต่ผมอยากเขียนแบบแยกไว้ให้ดูมากกว่าน่ะ
        ' ตรวจสอบรูปแบบของวันที่
        strDate = GetSystemDate
        ' ปรับรูปแบบเพื่อใช้ในการตรวจสอบ เช่น strDate = "dd/mm/yyyy"
        ' ทำการอ่านค่าจากตัวแรกของ strDate ไปจนกว่าจะเจอเครื่องหมาย "/" เช่น "dd/" --> มาจาก InStr(1, strDate,"/")
        ' จากนั้นให้ลดค่าความยาวลงอีก 1 ก็จะได้ dd (ตัด / ออกนั่นเอง) --> Mid$(strDate, 1, InStr(1, strDate,"/") - 1)
        ' แล้วแปลงให้กลายเป็นอักษรตัวเล็ก (LCase) เพื่อไม่ให้เกิดความยุ่งยากในการทดสอบ
        Select Case LCase$(Mid$(strDate, 1, InStr(1, strDate, "/") - 1))
            ' แสดงว่าเป็นแบบ d/mm/yyyy หรือ dd/mm/yyyy
            Case "d", "dd"
                blnDate = 1
            ' แสดงว่าเป็นแบบ m/d/yyyy หรือ mm/dd/yyyy
            Case "m", "mm"
                blnDate = 2
        End Select
        ' =================================================
        
    End Sub
    
    Private Sub cmdSearch_Click()
    Dim sRow As Integer, sCol As Integer
        Set Conn = New Connection
        Set RS = New Recordset
        ' *************************************************************
        Conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & App.Path & "\Member.mdb"
        ' *************************************************************
        ' ส่งค่า dtpDateBegin และ dtpDateEnd ไปจัดรูปแบบใหม่ใน GetFormatDate
        SQLStmt = "SELECT * FROM tblMember WHERE DateRegistered BETWEEN " & _
                            "#" & GetFormatDate(dtpDateBegin.Value) & "#" & _
                            " AND " & _
                            "#" & GetFormatDate(dtpDateEnd.Value) & "#" & _
                            " ORDER BY [DateRegistered]  ASC "
        RS.CursorLocation = adUseClient
        RS.Open SQLStmt, Conn, adOpenForwardOnly, adLockReadOnly, adCmdText
        ' กำหนดแบบ Run Time
        ' กำหนด Colume Header เพื่อแสดงชื่อฟิลด์
        fg.FixedRows = 1
        ' ไม่ต้องมี Row Header ที่อยู่ทางด้านซ้าย
        fg.FixedCols = 0
        fg.SelectionMode = flexSelectionByRow
        fg.AllowUserResizing = flexResizeColumns
        
        If Not RS.EOF Then
            fg.Rows = RS.RecordCount + 1
            fg.Cols = RS.Fields.Count
            For sRow = 0 To RS.Fields.Count - 1
                fg.TextMatrix(0, sRow) = RS.Fields(sRow).Name
            Next
            
            sRow = 1
            Do Until RS.EOF
                For sCol = 0 To RS.Fields.Count - 1
                    If Not IsNull(RS.Fields(sCol).Value) Then
                        If IsDate(RS.Fields(sCol).Value) Then
                            fg.TextMatrix(sRow, sCol) = Format(CDate(RS.Fields(sCol).Value), "dd-mm-yyyy")
                        Else
                            fg.TextMatrix(sRow, sCol) = RS.Fields(sCol).Value
                        End If
                    End If
                Next
            ' เลื่อนแถวของ FlexGrid ขึ้นอีก 1
            sRow = sRow + 1
            ' เลื่อนตัวชี้ตำแหน่งข้อมูลขึ้นอีก ... รายการต่อไป
            RS.MoveNext
            ' วนรอบจนกว่าจะหมดข้อมูล
            Loop
        
        ' แจ้งรายการ
        MsgBox "จำนวนรายชื่อสมาชิกทั้งสิ้น: " & sRow - 1 & " รายการ."
        End If
    RS.Close:   Set RS = Nothing
    End Sub
    
    ' เลือกรูปแบบวันที่ ที่ต้องนำไปใช้ในการค้นหา
    ' จากนั้นจะ Return ค่ากลับไปตามรูปแบบที่เราต้องนำไปใช้ในการค้นหา
    Function GetFormatDate(sDate As Date) As Date
        Select Case blnDate
            ' รูปแบบวันที่มาก่อน เช่น dd/mm/yyyy
            Case 1
                GetFormatDate = Left$(Format(sDate, "dd/mm/yyyy"), 2) & _
                                                    "/" & Mid$(Format(sDate, "dd/mm/yyyy"), 4, 2) & _
                                                    "/" & Right$(Format(sDate, "dd/mm/yyyy"), 4) - 543
            ' รูปแบบเดือนมาก่อน เช่น mm/dd/yyyy
            Case 2
                GetFormatDate = Left$(Format(sDate, "mm/dd/yyyy"), 2) & _
                                                    "/" & Mid$(Format(sDate, "mm/dd/yyyy"), 4, 2) & _
                                                    "/" & Right$(Format(sDate, "mm/dd/yyyy"), 4) - 543
    
        End Select
    End Function
    
    
    Conclusion:
    บทความนี้ต้องตัดตอนแยกเป็นส่วนๆ เพื่อให้ง่ายต่อการอธิบาย (ของผม) เมื่อเวลาที่พี่น้องจะนำไปใช้งานจริงๆแล้ว ก็ควรที่จะต้องใส่ไอเดีย ความคิด ของตัวเอง เพื่อดัดแปลงนำไปใช้งานเองต่างหากน่ะครับ (แหมเล่นมุขแบบมีกั๊ก ... ไม่เล่นเป็นขวดกลมไปซ่ะเลยล่ะ) โดยเฉพาะหลายคนชอบมาถามผมซ่ะเหลือเกินว่าโปรแกรมย่อยอย่าง Sub Program หรือ Function มันมีไว้ทำไม แล้วตอนไหนที่ต้องใช้มัน ????? (แป่วๆๆๆๆ) หากเรื่องแบบนี้พี่น้องยังไม่เข้าใจแล้วล่ะก็ อย่าพึ่งไปฝันถึง .Net เลยครับ เพราะเจ้าเนี่ยมันมีแต่ Class ซ่ะเต็มพรึบ ในทัศนะส่วนตัวของผม ใครอยากเก่ง .Net ให้ลองมาศึกษา VB6 ให้เข้าใจอย่างถ่องแท้ซ่ะก่อนครับ เอาแบบไม่ต้องขั้น Expert หรอก จากนั้นแล้วค่อยขยับไป .Net ... เชื่อกระผมเหอะ ... เหอๆๆๆๆ

  • จี ทู จี เน็ต ดอต คอม - g2gNet Dot Com
    เลขทะเบียนพาณิชย์อิเล็กทรอนิกส์ 0407314800231
    CopyLeft © 2004 - 2099 g2gNet.Com All rights reserved.
    Email: [email protected] หรือ โทร. 08-6862-6560