View Full Version : [SOLVED:] Date Entry Not Being Correctly Interpreted
HTSCF Fareha
01-30-2021, 02:14 PM
I’m trying to find a solution to a problem with date input interpretation. The dates that are being handled are UK format (dd/mm/yyyy) and are being input into a UK setup of Excel. There are two issues that are affecting accurate and correctly interpreted results.
 The leap year issue (this I have read has something to do with Lotus 123 and enabling their spreadsheet formats to be imported into MS Excel)
 Any date entered after 01/01/1900, is not input correctly. Although it would appear that only dates where the day is equal to or less than a month value (12) are affected. For example, 05/03/1901 (dd/mm/yyyy) will be shown as 03/05/1901, whereas 14/03/1901 (dd/mm/yyyy) will be shown correctly. The only way to get say 05/03/1901 to be input correctly is to enter it as 03/05/1901.
This is the current section of code (courtesy of Dave) which is being used to control date input.
Private Sub cmbEnter_Click()
    ' Input known soldier's number and enlistment date to add to selected Regiment / Battalion
    Dim LastRow As Integer, LastCol As Integer, Cnt As Integer, Cnt2 As Integer
    Dim Sht As Worksheet, SortRange As Range
    If frmEnlistment.lboRegiment.ListIndex = -1 Then
        MsgBox "Select Regiment!", vbExclamation + vbOKOnly, "Soldier Enlistment"
        Exit Sub
    End If
    If frmEnlistment.lboBattalion.ListIndex = -1 Then
        MsgBox "Select Battalion!", vbExclamation + vbOKOnly, "Soldier Enlistment"
        Exit Sub
    End If
    If Not IsNumeric(frmEnlistment.txtSoldierNumber.Value) Or _
       frmEnlistment.txtSoldierNumber.Text = vbNullString Then
        MsgBox "Enter Soldier Number!", vbExclamation + vbOKOnly, "Soldier Enlistment"
        Exit Sub
    End If
    If Not IsDate(frmEnlistment.txtEnlistmentDate.Text) Or _
       frmEnlistment.txtEnlistmentDate.Text = vbNullString Then
        MsgBox "Enter date in Day-Month-Year format!", vbExclamation + vbOKOnly, "Soldier Enlistment"
        Exit Sub
    End If
    
    For Each Sht In ThisWorkbook.Sheets
    If frmEnlistment.lboRegiment.List(frmEnlistment.lboRegiment.ListIndex) = Sht.Name Then
    With Sheets(Sht.Name)
    LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
    For Cnt = 1 To LastCol
    If Sheets(Sht.Name).Cells(1, Cnt) = frmEnlistment.lboBattalion.List(frmEnlistment.lboBattalion.ListIndex) Then
    LastRow = .Cells(.Rows.Count, Cnt).End(xlUp).Row
    For Cnt2 = 3 To LastRow
    If CInt(Sheets(Sht.Name).Cells(Cnt2, Cnt)) = CInt(frmEnlistment.txtSoldierNumber.Value) Then
    frmEnlistment.txtEnlistmentDate.Text = vbNullString
    MsgBox "Soldier number already exists!", vbExclamation + vbOKOnly, "Soldier Enlistment"
    frmEnlistment.txtEnlistmentDate.Text = Format(Sheets(Sht.Name).Cells(Cnt2, Cnt + 1), "dd/mm/yyyy")
    Exit Sub
    End If
    Next Cnt2
    .Cells(LastRow + 1, Cnt) = frmEnlistment.txtSoldierNumber.Value
    .Cells(LastRow + 1, Cnt + 1) = Format(frmEnlistment.txtEnlistmentDate.Value, "dd/mm/yyyy")
           
             
    ' Sort out 1900 date issue
    If Left(CDate(Sheets(Sht.Name).Cells(Cnt2, Cnt + 1)), 4) <> 1900 Then
    frmEnlistment.txtEnlistmentDate.Text = Format(Sheets(Sht.Name).Cells(Cnt2, Cnt + 1), "dd/mm/yyyy")
    Else
    frmEnlistment.txtEnlistmentDate.Text = CStr(Sheets(Sht.Name).Cells(Cnt2, Cnt + 1))
    End If
    Exit For
    End If
    Next Cnt
    Exit For
    End With
    End If
    Next Sht
    
    With Sheets(Sht.Name)
        Set SortRange = .Range(.Cells(3, Cnt), .Cells(LastRow + 1, Cnt + 1))
    End With
    With SortRange
        .Sort Key1:=Cells(3, Cnt), Order1:=xlAscending, _
              Header:=xlNo, OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom
              
    ' Count total number of records
    
              
    End With
    
    frmEnlistment.txtSoldierNumber.Text = vbNullString
    frmEnlistment.txtEnlistmentDate.Text = vbNullString
    frmEnlistment.lboRegiment.ListIndex = -1
    frmEnlistment.lboBattalion.ListIndex = -1
End Sub
Enter the dates as "MMM d, yyyy"
Lotus, therefore Excel, adds a Feb 29 day to 1900. In Excel, but not in VBA, all DateSerials after Feb 28, 1900 are off by 1. Excel and VBA correctly handles this to display dates in Excel.
Date Functions in VBA are correct even for dates before 1900.
VBA: Cell = Format(Cdate("Mar 9, 1989"), "dd/mm/yyyy")) will only return 09/03/1899, not 03/09/1899.
Do this: In A1 enter "Jan 1, 1900". Format Range("A1:C3") as a date. In B2 enter "=A1+365"
Run this Sub
Sub t4()
Cells(2, 2) = CDate(DateAdd("d", 365, Range("A1")))
Cells(3, 2) = CDate(DateAdd("d", 365, "1/1/1900"))
End Sub
Also see
Enter "Feb 29, 1900" in C1
Sub t()
MsgBox "IsDate  Feb 29, 1900? " & IsDate("Feb 29, 1900")
MsgBox "IsDate Range C1? " & IsDate(Range("C1"))
End Sub
Moral is "Don't mix Excel Dates and VBA Dates." Good news is that User Form Control Values are Strings, not Excel Dates
Paul_Hossler
02-01-2021, 09:31 AM
SamT -- 
Date Functions in VBA are correct even for dates before 1900.
Moral is "Don't mix Excel Dates and VBA Dates."
I didn't know this. For some weird reason I'd thought that Excel was consistent
HTSCF Fareha
02-01-2021, 12:53 PM
Thanks for the explanation, Sam.
I tried the examples you gave.
Am I correct in assuming that there is no easy way to avoid a user entering dates as described (i.e. Mar 9, 1889)?
This is done via a Userform and the date is input into a TextBox, so having to type the first three letters of the month will become tedious and doesn't feel natural to us in the UK. Is there a way that the MMM d, yyyy format can be changed "behind the scenes" after the date is typed into the userform in dd/mm/yyyy format?
Paul, the only wrong date I was able to create was by adding numbers to a date in a cell, but only if the cell'sdate was between 1/1/1900 and 2/28//1900 and the new date was after 2/29/1900. VBA's DateAdd worked fine in that case
Fareha,
Yes, in fact it is a good way to visually insure the correctly formatted date was entered
txtEnlistmentDate_Exit()
    With Me
      .txtEnlistmentDate = Format(CDate(.txtEnlistmentDate), "MMM dd, yyyy")
         'I would use a Form level Variable to store the Date As a DateSerial and use that Variable in the rest of the code
         'EnlistmentDateSerial = DateSerial(Year(.txtEnlistmentDate), Month(.txtEnlistmentDate), Day(.txtEnlistmentDate))
    End With
End sub
When a DateSerial is entered into an Excel Cell, it will be displayed in the Format you select for that cell.
It should be known that the world standard for Date recording is becoming Year Month Day and any format of such ("yy/mm/dd")("yyyy.mm.dd")("yy m d") and even ("yymmdd"). Date viewing remains regional. Computers, still and probably will always, store dates internally as DateSerial.
p45cal
02-02-2021, 10:27 AM
re;
The dates that are being handled are UK format (dd/mm/yyyy) and are being input into a UK setup of Excel.
and:
Although it would appear that only dates where the day is equal to or less than a month value (12) are affected. For example, 05/03/1901 (dd/mm/yyyy) will be shown as 03/05/1901, whereas 14/03/1901 (dd/mm/yyyy) will be shown correctly. The only way to get say 05/03/1901 to be input correctly is to enter it as 03/05/1901.
I live in the UK and have Excel setup with the UK locale, and the above is not my experience at all; if I enter 05/03/1901 I get 5th March.
HTSCF Fareha, could you try something for me, start with a newly created sheet, enter 05/03/1901 into a cell and press Enter.
1. What do you see?
2. Select that cell, right-click and choose Format Cells…, you should get a dialogue box like so:
27838
Without changing anything, what do you see in the circled field (I've blanked it out in the picture)?
HTSCF Fareha
02-02-2021, 11:49 AM
Hi p45cal,
The results I get are as follows (not sure why they upload in revers order :doh:) :-
Thanks,
Steve
p45cal
02-02-2021, 12:28 PM
That looks like what I get here.
Now if you select the the option *14 March 2012 and press OK do you get 5th March or 3rd May?
HTSCF Fareha
02-02-2021, 12:34 PM
I get 5th March.
Steve
p45cal
02-02-2021, 12:56 PM
So this:
The only way to get say 05/03/1901 to be input correctly is to enter it as 03/05/1901.
no longer happens?
HTSCF Fareha
02-02-2021, 01:06 PM
No, it doesn't.
Here is the link to the form that is being used. You will see the date problem.
http://www.vbaexpress.com/forum/showthread.php?68187-Predict-Date-of-Enlistment
 (http://www.vbaexpress.com/forum/showthread.php?68187-Predict-Date-of-Enlistment)
p45cal
02-02-2021, 03:00 PM
What version of Excel are you using? Is it 32 or 64 bit?
I have an idea that a date/time picker might solve a lot of your problems - be it an MS one or a third party one.
Paul_Hossler
02-02-2021, 03:41 PM
From http://www.vbaexpress.com/forum/showthread.php?68187-Predict-Date-of-Enlistment
This might be OBE, but
I set PC to UK English formats, and entered 1234 as 25/12/1950. Col B is formatted as "Short Date"
27850
The commented line makes it into a string
Try the DateSerial()
                        Dim Y As Long, M As Long, D As Long
                        Y = Right(frmEnlistment.txtEnlistmentDate.Value, 4)
                        M = Mid(frmEnlistment.txtEnlistmentDate.Value, 4, 2)
                        D = Left(frmEnlistment.txtEnlistmentDate.Value, 2)
                        .Cells(LastRow + 1, Cnt + 1) = DateSerial(Y, M, D)
'                        .Cells(LastRow + 1, Cnt + 1) = Format(frmEnlistment.txtEnlistmentDate.Value, "dd/mm/yyyy")
Also more thoughts:
1. I always use DateSerial to put dates into worksheet
range("A1").Value = dateserial (2020,12,25)
2. To use the Regional Settings, you need to Format the cell as
27856
and not as Custom "dd-mm-yyyy". This way it stays a date, and if you send the spreadsheet to another location with different regional settings, it will automatically adjust
HTSCF Fareha
02-04-2021, 01:34 AM
Thanks p45cal for taking the time to look at this.
p45cal
02-04-2021, 01:44 AM
So: '1. What version of Excel are you using? 
2. Is it 32 or 64 bit?'
HTSCF Fareha
02-04-2021, 01:56 AM
The commented line makes it into a string
Try the DateSerial()
                        Dim Y As Long, M As Long, D As Long
                        Y = Right(frmEnlistment.txtEnlistmentDate.Value, 4)
                        M = Mid(frmEnlistment.txtEnlistmentDate.Value, 4, 2)
                        D = Left(frmEnlistment.txtEnlistmentDate.Value, 2)
                        .Cells(LastRow + 1, Cnt + 1) = DateSerial(Y, M, D)
'                        .Cells(LastRow + 1, Cnt + 1) = Format(frmEnlistment.txtEnlistmentDate.Value, "dd/mm/yyyy")
Also more thoughts:
1. I always use DateSerial to put dates into worksheet
range("A1").Value = dateserial (2020,12,25)
2. To use the Regional Settings, you need to Format the cell as
27856
and not as Custom "dd-mm-yyyy". This way it stays a date, and if you send the spreadsheet to another location with different regional settings, it will automatically adjust
Thanks for this input and advice. I can see how using the serial format for the date should be viewed as best practice.
I'm going to need some help in utilising this in my code. My thinking is that this will remove some of my existing code.
Will this mess up my previously entered data?
HTSCF Fareha
02-04-2021, 01:56 AM
Sorry p45cal, forgot to answer this bit.
Office Professional Plus 2019, 32 bit.
p45cal
02-04-2021, 04:56 AM
Office Professional Plus 2019, 32 bit.…and will this be just on one computer, or do you expect it to be run on other computers too?
[Sorry, should've asked this before (there are several date picker controls out there, including one from MS that I've used quite a lot and is quite good and handles dates before 1900, but is no longer available by default in more rescent versions of Excel (including your) but could be pressed into service (this might have the advantage that if soon MS decides to reintroduce a newer DT picker there might be little code change - (people have been crying out for MS to reinstate some  kind of DT picker for quite a while now)). Anyway I need to make sure it's a suitable one.]
Paul_Hossler
02-04-2021, 07:42 AM
Thanks for this input and advice. I can see how using the serial format for the date should be viewed as best practice.
I'm going to need some help in utilising this in my code. My thinking is that this will remove some of my existing code.
Will this mess up my previously entered data?
27863
Somewhat I believe
I think the major issue will be the fact that pre-1900 dates on the worksheet are formatted as strings, even if .NumberFormat = "Short Date" , while VBA can handle pre-1900 dates 99.9% OK (1900 is NOT a leap year)
27864
I like to separate the 'Presentation' from the 'Calculation' layer
That said, a possible path forward "might be" to leave the dates presented in the worksheet as strings (dd/mm/yyyy) but have (for ex) 'ToWorksheet' and 'FromWorksheet' functions so that VBA always has 'real dates' (at least after 100 CE):
SyntaxDateSerial(year, month, day)
The DateSerial function syntax has these named arguments (https://docs.microsoft.com/en-us/office/vba/language/glossary/vbe-glossary#named-argument):
Part
Description
year
Required; Integer. Number between 100 and 9999, inclusive, or a numeric expression (https://docs.microsoft.com/en-us/office/vba/language/glossary/vbe-glossary#numeric-expression).
month
Required; Integer. Any numeric expression.
day
Required; Integer. Any numeric expression.
All calculations, estimating, interpolation, etc. would require that the WS 'look like dates' be converted to 'VBA dates', crunched, and reformatted back
Even simple things like MATCH require different approaches depending on if the date is pre-1900 or post-1900
27865
Do-able. Let me and others think on it. Maybe they have a better way
Paul_Hossler
02-04-2021, 09:09 AM
I'd do all calculating / estimating / guessing within VBA
Bring in the data from the WS, process, reformat and return to WS
That way I would know that all my dates are consistent and are real dates.
Option Explicit
Function WS2VBA(s As String) As Variant
    Dim Y As Long, M As Long, D As Long
    Dim v As Variant
    
    On Error GoTo ReturnBlank
    'dd/mm/yyyy or d/m/yyyy
    
    v = Split(s, "/")
    D = Right("00" & v(0), 2)
    M = Right("00" & v(1), 2)
    Y = Right("0000" & v(2), 4)
    
    WS2VBA = DateSerial(Y, M, D)
    Exit Function
    
ReturnBlank:
    WS2VBA = vbNullString
End Function
Function VBA2WS(D As Date) As String
    
    On Error GoTo ReturnBlank
    VBA2WS = "'" & Format(D, "dd/mm/yyyy")
    Exit Function
ReturnBlank:
    VBA2WS = vbNullString
End Function
Function WS2Array(r As Range) As Variant
    Dim rFirst As Range, rLast As Range
    Dim i As Long
    Dim v As Variant
        
    With r.Columns(1).EntireColumn
        Set rFirst = r.Columns(1).EntireColumn.Cells(1, 1)
        Set rLast = .Cells(.Rows.Count, 1).End(xlUp)
    End With
    
    v = Application.WorksheetFunction.Transpose(Range(rFirst, rLast).Value)
    
    For i = LBound(v) To UBound(v)
        v(i) = WS2VBA(CStr(v(i)))
    Next i
    WS2Array = v
End Function
'return 1 dim column range
Sub Array2WS(A As Variant, r As Range)
    Dim rFirst As Range, rLast As Range
    Dim i As Long
    Dim v As Variant
    
    ReDim v(LBound(A) To UBound(A))
    
    For i = LBound(A) To UBound(A)
        If IsDate(A(i)) Then v(i) = VBA2WS(CDate(A(i)))
    Next i
    
    r.Cells(1, 1).Resize(UBound(v), 1).Value = Application.WorksheetFunction.Transpose(v)
End Sub
Sub test()
    Dim A As Variant
    Dim i As Long
    'A contains Dates that work with VBA
    A = WS2Array(Worksheets("Hampshire Regiment").Columns(2))
    'simple return of Dates formatted as strings dd/mm/yyyy
    Call Array2WS(A, Worksheets("Hampshire Regiment").Range("H1"))
    
    'simple processing example of adding one month
    For i = LBound(A) To UBound(A)
        If IsDate(A(i)) Then A(i) = DateAdd("m", 1, A(i))
    Next i
        
    Call Array2WS(A, Worksheets("Hampshire Regiment").Range("J1"))
End Sub
HTSCF Fareha
02-05-2021, 01:39 AM
Thanks to all who looked into this. I'll close this thread as solved at this time as the "main" project is here.
http://www.vbaexpress.com/forum/showthread.php?68187-Predict-Date-of-Enlistment
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.