Formatting MM/DD/YYYY dates in textbox in VBA

前端 未结 9 1668
故里飘歌
故里飘歌 2020-11-22 10:47

I\'m looking for a way to automatically format the date in a VBA text box to a MM/DD/YYYY format, and I want it to format as the user is typing it in. For instance, once the

相关标签:
9条回答
  • 2020-11-22 11:01
    Private Sub txtBoxBDayHim_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
    If KeyAscii >= 48 And KeyAscii <= 57 Or KeyAscii = 8 Then 'only numbers and backspace
        If KeyAscii = 8 Then 'if backspace, ignores + "/"
        Else
            If txtBoxBDayHim.TextLength = 10 Then 'limit textbox to 10 characters
            KeyAscii = 0
            Else
                If txtBoxBDayHim.TextLength = 2 Or txtBoxBDayHim.TextLength = 5 Then 'adds / automatically
                txtBoxBDayHim.Text = txtBoxBDayHim.Text + "/"
                End If
            End If
        End If
    Else
    KeyAscii = 0
    End If
    End Sub
    

    This works for me. :)

    Your code helped me a lot. Thanks!

    I'm brazilian and my english is poor, sorry for any mistake.

    0 讨论(0)
  • 2020-11-22 11:03

    Just for fun I took Siddharth's suggestion of separate textboxes and did comboboxes. If anybody's interested, add a userform with three comboboxes named cboDay, cboMonth and cboYear and arrange them left to right. Then paste the code below into the UserForm's code module. The required combobox properties are set in UserFormInitialization, so no additional prep should be required.

    The tricky part is changing the day when it becomes invalid because of a change in year or month. This code just resets it to 01 when that happens and highlights cboDay.

    I haven't coded anything like this in a while. Hopefully it will be of interest to somebody, someday. If not it was fun!

    Dim Initializing As Boolean
    
    Private Sub UserForm_Initialize()
    Dim i As Long
    Dim ctl As MSForms.Control
    Dim cbo As MSForms.ComboBox
    
    Initializing = True
    With Me
        With .cboMonth
            '        .AddItem "month"
            For i = 1 To 12
                .AddItem Format(i, "00")
            Next i
            .Tag = "DateControl"
        End With
        With .cboDay
            '        .AddItem "day"
            For i = 1 To 31
                .AddItem Format(i, "00")
            Next i
            .Tag = "DateControl"
        End With
        With .cboYear
            '        .AddItem "year"
            For i = Year(Now()) To Year(Now()) + 12
                .AddItem i
            Next i
            .Tag = "DateControl"
        End With
        DoEvents
        For Each ctl In Me.Controls
            If ctl.Tag = "DateControl" Then
                Set cbo = ctl
                With cbo
                    .ListIndex = 0
                    .MatchRequired = True
                    .MatchEntry = fmMatchEntryComplete
                    .Style = fmStyleDropDownList
                End With
            End If
        Next ctl
    End With
    Initializing = False
    End Sub
    
    Private Sub cboDay_Change()
    If Not Initializing Then
        If Not IsValidDate Then
            ResetMonth
        End If
    End If
    End Sub
    
    Private Sub cboMonth_Change()
    If Not Initializing Then
        ResetDayList
        If Not IsValidDate Then
            ResetMonth
        End If
    End If
    End Sub
    
    Private Sub cboYear_Change()
    If Not Initializing Then
        ResetDayList
        If Not IsValidDate Then
            ResetMonth
        End If
    End If
    End Sub
    
    Function IsValidDate() As Boolean
    With Me
        IsValidDate = IsDate(.cboMonth & "/" & .cboDay & "/" & .cboYear)
    End With
    End Function
    Sub ResetDayList()
    Dim i As Long
    Dim StartDay As String
    
    With Me.cboDay
        StartDay = .Text
        For i = 31 To 29 Step -1
            On Error Resume Next
            .RemoveItem i - 1
            On Error GoTo 0
        Next i
        For i = 29 To 31
            If IsDate(Me.cboMonth & "/" & i & "/" & Me.cboYear) Then
                .AddItem Format(i, "0")
            End If
        Next i
        On Error Resume Next
        .Text = StartDay
        If Err.Number <> 0 Then
            .SetFocus
            .ListIndex = 0
        End If
    End With
    End Sub
    
    Sub ResetMonth()
    Me.cboDay.ListIndex = 0
    End Sub
    
    0 讨论(0)
  • 2020-11-22 11:05

    I never suggest using Textboxes or Inputboxes to accept dates. So many things can go wrong. I cannot even suggest using the Calendar Control or the Date Picker as for that you need to register the mscal.ocx or mscomct2.ocx and that is very painful as they are not freely distributable files.

    Here is what I recommend. You can use this custom made calendar to accept dates from the user

    PROS:

    1. You don't have to worry about user inputting wrong info
    2. You don't have to worry user pasting in the textbox
    3. You don't have to worry about writing any major code
    4. Attractive GUI
    5. Can be easily incorporated in your application
    6. Doesn't use any controls for which you need to reference any libraries like mscal.ocx or mscomct2.ocx

    CONS:

    Ummm...Ummm... Can't think of any...

    HOW TO USE IT (File missing from my dropbox. Please refer to the bottom of the post for an upgraded version of the calendar)

    1. Download the Userform1.frm and Userform1.frx from here.
    2. In your VBA, simply import Userform1.frm as shown in the image below.

    Importing the form

    enter image description here

    RUNNING IT

    You can call it in any procedure. For example

    Sub Sample()
        UserForm1.Show
    End Sub
    

    SCREEN SHOTS IN ACTION

    enter image description here

    NOTE: You may also want to see Taking Calendar to new level

    0 讨论(0)
  • 2020-11-22 11:08

    For a quick solution, I usually do like this.

    This approach will allow the user to enter date in any format they like in the textbox, and finally format in mm/dd/yyyy format when he is done editing. So it is quite flexible:

    Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
        If TextBox1.Text <> "" Then
            If IsDate(TextBox1.Text) Then
                TextBox1.Text = Format(TextBox1.Text, "mm/dd/yyyy")
            Else
                MsgBox "Please enter a valid date!"
                Cancel = True
            End If
        End If
    End Sub
    

    However, I think what Sid developed is a much better approach - a full fledged date picker control.

    0 讨论(0)
  • 2020-11-22 11:11

    I too, one way or another stumbled on the same dilemma, why the heck Excel VBA doesn't have a Date Picker. Thanks to Sid, who made an awesome job to create something for all of us.

    Nonetheless, I came to a point where I need to create my own. And I am posting it here since a lot of people I'm sure lands on this post and benefit from it.

    What I did was very simple as what Sid does except that I do not use a temporary worksheet. I thought the calculations are very simple and straight forward so there's no need to dump it somewhere else. Here's the final output of the calendar:

    enter image description here

    How to set it up:

    • Create 42 Label controls and name it sequentially and arranged left to right, top to bottom (This labels contains greyed 25 up to greyed 5 above). Change the name of the Label controls to Label_01,Label_02 and so on. Set all 42 labels Tag property to dts.
    • Create 7 more Label controls for the header (this will contain Su,Mo,Tu...)
    • Create 2 more Label control, one for the horizontal line (height set to 1) and one for the Month and Year display. Name the Label used for displaying month and year Label_MthYr
    • Insert 2 Image controls, one to contain the left icon to scroll previous months and one to scroll next month (I prefer simple left and right arrow head icon). Name it Image_Left and Image_Right

    The layout should be more or less like this (I leave the creativity to anyone who'll use this).

    enter image description here

    Declaration:
    We need one variable declared at the very top to hold the current month selected.

    Option Explicit
    Private curMonth As Date
    

    Private Procedure and Functions:

    Private Function FirstCalSun(ref_date As Date) As Date
        '/* returns the first Calendar sunday */
        FirstCalSun = DateSerial(Year(ref_date), _
                      Month(ref_date), 1) - (Weekday(ref_date) - 1)
    End Function
    

    Private Sub Build_Calendar(first_sunday As Date)
        '/* This builds the calendar and adds formatting to it */
        Dim lDate As MSForms.Label
        Dim i As Integer, a_date As Date
    
        For i = 1 To 42
            a_date = first_sunday + (i - 1)
            Set lDate = Me.Controls("Label_" & Format(i, "00"))
            lDate.Caption = Day(a_date)
            If Month(a_date) <> Month(curMonth) Then
                lDate.ForeColor = &H80000011
            Else
                If Weekday(a_date) = 1 Then
                    lDate.ForeColor = &HC0&
                Else
                    lDate.ForeColor = &H80000012
                End If
            End If
        Next
    End Sub
    

    Private Sub select_label(msForm_C As MSForms.Control)
        '/* Capture the selected date */
        Dim i As Integer, sel_date As Date
        i = Split(msForm_C.Name, "_")(1) - 1
        sel_date = FirstCalSun(curMonth) + i
    
        '/* Transfer the date where you want it to go */
        MsgBox sel_date
    
    End Sub
    

    Image Events:

    Private Sub Image_Left_Click()
    
        If Month(curMonth) = 1 Then
            curMonth = DateSerial(Year(curMonth) - 1, 12, 1)
        Else
            curMonth = DateSerial(Year(curMonth), Month(curMonth) - 1, 1)
        End If
    
        With Me
            .Label_MthYr.Caption = Format(curMonth, "mmmm, yyyy")
            Build_Calendar FirstCalSun(curMonth)
        End With
    
    End Sub
    

    Private Sub Image_Right_Click()
    
        If Month(curMonth) = 12 Then
            curMonth = DateSerial(Year(curMonth) + 1, 1, 1)
        Else
            curMonth = DateSerial(Year(curMonth), Month(curMonth) + 1, 1)
        End If
    
        With Me
            .Label_MthYr.Caption = Format(curMonth, "mmmm, yyyy")
            Build_Calendar FirstCalSun(curMonth)
        End With
    
    End Sub
    

    I added this to make it look like the user is clicking the label and should be done on the Image_Right control too.

    Private Sub Image_Left_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, _
                                     ByVal X As Single, ByVal Y As Single)
        Me.Image_Left.BorderStyle = fmBorderStyleSingle
    End Sub
    
    Private Sub Image_Left_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, _
                                   ByVal X As Single, ByVal Y As Single)
        Me.Image_Left.BorderStyle = fmBorderStyleNone
    End Sub
    

    Label Events:
    All of this should be done for all 42 labels (Label_01 to Lable_42)
    Tip: Build the first 10 and just use find and replace for the remaining.

    Private Sub Label_01_Click()
        select_label Me.Label_01
    End Sub
    

    This is for hovering over dates and clicking effect.

    Private Sub Label_01_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, _
                                   ByVal X As Single, ByVal Y As Single)
        Me.Label_01.BorderStyle = fmBorderStyleSingle
    End Sub
    
    Private Sub Label_01_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, _
                                   ByVal X As Single, ByVal Y As Single)
        Me.Label_01.BackColor = &H8000000B
    End Sub
    
    Private Sub Label_01_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, _
                                 ByVal X As Single, ByVal Y As Single)
        Me.Label_01.BorderStyle = fmBorderStyleNone
    End Sub
    

    UserForm Events:

    Private Sub UserForm_Initialize()
        '/* This is to initialize everything */
        With Me
            curMonth = DateSerial(Year(Date), Month(Date), 1)
            .Label_MthYr = Format(curMonth, "mmmm, yyyy")
            Build_Calendar FirstCalSun(curMonth)
        End With
    
    End Sub
    

    Again, just for the hovering over dates effect.

    Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, _
                                   ByVal X As Single, ByVal Y As Single)
    
        With Me
            Dim ctl As MSForms.Control, lb As MSForms.Label
    
            For Each ctl In .Controls
                If ctl.Tag = "dts" Then
                    Set lb = ctl: lb.BackColor = &H80000005
                End If
            Next
        End With
    
    End Sub
    

    And that's it. This is raw and you can add your own twist to it.
    I've been using this for awhile and I have no issues (performance and functionality wise).
    No Error Handling yet but can be easily managed I guess.
    Actually, without the effects, the code is too short.
    You can manage where your dates go in the select_label procedure. HTH.

    0 讨论(0)
  • 2020-11-22 11:12

    You could use an input mask on the text box, too. If you set the mask to ##/##/#### it will always be formatted as you type and you don't need to do any coding other than checking to see if what was entered was a true date.

    Which just a few easy lines

    txtUserName.SetFocus
    If IsDate(txtUserName.text) Then
        Debug.Print Format(CDate(txtUserName.text), "MM/DD/YYYY")
    Else
        Debug.Print "Not a real date"
    End If
    
    0 讨论(0)
提交回复
热议问题