Textbox converts date into number - excel

Private Sub TextBox1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
If Mid(TextBox1.Value, 4, 2) > 12 Then
MsgBox "Invalid date, please re-enter", vbCritical
TextBox1.Value = vbNullString
TextBox1.SetFocus
Exit Sub
End If
StartDate = DateSerial(Year(Date), Month(Date), Day(Date))
TextBox1.Value = Format(TextBox1.Value, "dd.mm.yyyy")
StartDate = TextBox1.Value
End Sub
This code works well for me and my colleagues to make sure the value entered in the textbox is a date. However, a colleague from a different country (but also with the dd.mm.yyyy date-format) gets weird results.
For example: If he enters 01.10.2017 the TextBox automatically format the date into 20.03.4917.
I suspect that in this case the entered value is not recognized as a date but as a number because 01102017 will transform into 20.03.4917 in Excel if you convert it as a date.
Does anyone have a suggestion or a guess how to work around this problem?
Thanks and best regards

You could split the date by . into an array ArrInput and then use DateSerial to make it a real date, that you can format.
Dim ArrInput As Variant
ArrInput = Split(TextBox1.Value, ".")
'StartDate = DateSerial(Year(Date), Month(Date), Day(Date)) 'I see no use in this at all
TextBox1.Value = Format$(DateSerial(ArrInput(2), ArrInput(1), ArrInput(0)), "dd.mm.yyyy")
StartDate = TextBox1.Value
The issue with Format(TextBox1.Value, "dd.mm.yyyy") is that here you let Excel guess which date format the string in TextBox1.Value is. It automatically casts into a number which is then converted into a string again.
To avoid date misunderstandings I recommend always to use the YYYY-MM-DD format according to ISO 8601. This is the only date format that is human readable and cannot be misunderstood. It also has benefits when sorting by dates that are actually strings.
To make your validation even more solid use something like:
Dim ArrInput As Variant
ArrInput = Split(TextBox1.Value, ".")
Dim ValidDate As Boolean
If UBound(ArrInput) = 2 Then 'make sure there are exactly two dots in the date
If ArrInput(1) > 0 And ArrInput(1) <= 12 And _ 'month <= 12
ArrInput(0) > 0 And ArrInput(0) <= 31 Then 'day <= 31
ValidDate = True
End If
Else
ValidDate = False
End If
If Not ValidDate Then
MsgBox "Invalid date, please re-enter in format dd.mm.yyyy", vbCritical
TextBox1.Value = vbNullString
TextBox1.SetFocus
Exit Sub
End If
TextBox1.Value = Format$(DateSerial(ArrInput(2), ArrInput(1), ArrInput(0)), "dd.mm.yyyy")
StartDate = TextBox1.Value

I do believe that your colleague enters the text string "01102017" without dots.
You might want to convert such kind of entries into a valid date:
' "01102017" => 01.10.2017 - 8 chars variant
' "011017" => 01.10.2017 - 6 chars variant
This needs to be done of cause prior to a date conversion.
Add a log of the input value to a free cell range and
have the workbook sent back to you:
...
Private Sub TextBox1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
Range("Z1").value = "'" & TextBox1.Value
If Mid(TextBox1.Value, 4, 2) > 12 Then
...
Check if only numbers are used:
How to check if a string contains only numbers?
and check the length of the string (6 or 8 chars variant) and check if the year part is within a valid range => try to convert to a date and offer it to the user.

Related

CDATE VBA gives out 12:00:00 AM instead of date

I am trying to convert the date format of my cells as the csv format they are delivered in shows a date but excel doesn't recognize it as a date (it shows "Standard" as format and the dates are aligned on the left, hence not dates in excel).
Dim lr11 As Integer
Dim dates11 As Date
lr11 = WS1.Cells(WS1.Rows.Count, "C").End(xlUp).row
For dates11 = 2 To lr11
WS1.Cells(dates11, 3).Value = CDate(Cells(dates11, 3).Value)
Next dates11
The above code sometimes works in a Test Sub() but when used in my main Sub, I always get "12:00:00 AM" in all cells instead of dates.
What am I doing wrong?
Thanks!
If you have strings that look like dates in the format DD.MM.YYYY you can split them and create a numeric date using DateSerial like below:
Option Explicit
Public Function ConvertStringDDMMYYYYtoDate(ByVal InputString As String) As Date
Dim RetVal As Date
Dim Parts() As String
Parts = Split(InputString, ".")
If UBound(Parts) = 2 Then
RetVal = DateSerial(Parts(2), Parts(1), Parts(0))
If Not Format$(RetVal, "DD.MM.YYYY") = InputString Then
MsgBox "Input String is not a real date", vbCritical
RetVal = 0
End If
End If
ConvertStringDDMMYYYYtoDate = RetVal
End Function
Then use it like
For dates11 = 2 To lr11
WS1.Cells(dates11, 3).Value = ConvertStringDDMMYYYYtoDate(WS1.Cells(dates11, 3).Value)
WS1.Cells(dates11, 3).NumberFormat = "DD.MM.YYYY" ' format it however you like it to look like
Next dates11

Excel VBA - remove weekends from automatic timesheet print

I slightly amended some code I found online.
Purpose:
Click on a 'Print with Dates' button, then enter start date, and have Excel automatically generate/print a months worth of timesheets (much better than the previous spreadsheet having 6 weeks of pages to print, and you had to edit every date manually).
Issues:
It prints weekends, which wastes paper. Is there a way it can refer to a list of dates (weekends, public holidays), and not generate those for printing?
You'll see the date format is m/d/yyyy in the code, which strangely prints as dd/mm/yyyy (which is what I wanted). When the code was dd/mm/yyyy it was printing correctly (20/03/2019), but if it goes to the following month it was switching to American format m/d/yyyy (04/20/2019). I know it doesn't seem to make sense, but having it as m/d/yyyy actually prints as dd/mm/yyyy across any start/end dates. I'd like to know why, and also have dd/mm/yyyy in the code correctly printing across any date range.
CODE:
Sub PrintSheet()
Dim s As String
Dim d As Date
s = InputBox(Prompt:="Please enter the start date")
If Not IsDate(s) Then
MsgBox "Incorrect date", vbExclamation
Exit Sub
End If
For d = CDate(s) To DateAdd("m", 1, CDate(s)) - 1
Range("F2").Value = Format(d, "dddd")
Range("I2").Value = "" & Format(d, "m/d/yyyy")
ActiveSheet.PrintOut
Next d
End Sub
Cheers in advance :)
You can use the weekday function. It returns a number from 1 to 7. You can filter for 1-5 only for weekdays.
Sub PrintSheet()
Dim s As String
Dim d As Date
s = InputBox(Prompt:="Please enter the start date")
If Not IsDate(s) Then
MsgBox "Incorrect date", vbExclamation
Exit Sub
End If
For d = CDate(s) To DateAdd("m", 1, CDate(s)) - 1
If Weekday(d, vbMonday) < 6 Then
Range("F2").Value = Format(d, "dddd")
Range("I2").Value = "" & Format(d, "m/d/yyyy")
'MsgBox ("printing ") 'for testing
ActiveSheet.PrintOut
End If
Next d
End Sub

VBA Date Format For Variable

I need to turn content in a spreadsheet column from text to a date.
The cell format is text and the inputters were instructed to input a date as "ddmmyyyy".
Accidents happened and I found some content that would not parse as a date, including entries like "Unknown".
So I used a variable declared as a date and wrote an error handler to deal with content that would not parse.
Now for the bit I cannot work out.
If the date was 3rd March 2000 and someone input that as "03332000" that will not parse because "33" cannot be a month or a day; it is caught by the error handler as I wanted.
But if it was input as "03132000" I can't think of a way of preventing VBA converting that to a valid date as "13/03/2000".
Declaring a format for the date variable will not prevent VBA parsing the date.
I can write something that tests number range of the day and month part of the string but that is extra lines of code and I was hoping to do it just by the error handler.
I'd approach it a little differently and let Excel do the work.
Public Function ValidateDate(ByVal strDate As String) As Boolean
Dim intDay As Integer, intMonth As Integer, intYear As Integer, dtDate As Date
ValidateDate = True
On Error GoTo IsInValid
If Len(strDate) <> 8 Then GoTo IsInValid
If Not IsNumeric(strDate) Then GoTo IsInValid
intDay = Left(strDate, 2)
intMonth = Mid(strDate, 3, 2)
intYear = Right(strDate, 4)
dtDate = DateSerial(intYear, intMonth, intDay)
If DatePart("d", dtDate) <> intDay Then GoTo IsInValid
If DatePart("m", dtDate) <> intMonth Then GoTo IsInValid
If DatePart("yyyy", dtDate) <> intYear Then GoTo IsInValid
Exit Function
IsInValid:
ValidateDate = False
End Function
... this will ensure that anything related to leap years etc. will still work correctly and it will ensure that all entries are validated correctly.
If you place:
03332000
in cell A1 and run:
Sub CheckDate()
Dim s As String, d As Date
s = Range("A1").Text
d = DateSerial(CInt(Right(s, 4)), CInt(Mid(s, 3, 2)), CInt(Left(s, 2)))
MsgBox s & vbCrLf & d
End Sub
You will get:
So even though a valid month can only be in the range [1-12], Excel is trying to "help" you by interpreting the 33 as a projection of future date. For example, if the month was entered as 13, Excel will treat it as December of the following year!
You can't rely on error-handling for this. You need checks like:
Sub CheckDate2()
Dim s As String, d As Date
Dim dd As Integer, mm As Integer, yr As Integer
s = Range("A1").Text
yr = CInt(Right(s, 4))
mm = CInt(Mid(s, 3, 2))
dd = CInt(Left(s, 2))
If yr = 0 Or yr < 1900 Then
MsgBox "year is bad"
Exit Sub
End If
If dd = o Or dd > 31 Then
MsgBox "day is bad"
Exit Sub
End If
If mm = 0 Or mm > 12 Then
MsgBox "month is bad"
Exit Sub
End If
d = DateSerial(yr, mm, dd)
MsgBox s & vbCrLf & d
End Sub
You can also do other checks like looking at the length of the field, etc.

How do I validate a YYYYMMDD string is a date in Excel VBA?

The date is supplied as a string in the form: 20180503
The function is supposed to validate that the entry is:
in the form YYYYMMDD
a valid date
The following code does not do the trick:
Function formatDateYYYYMMDD(dateStr As String, dateFormat As String) As String
Dim strToDate As Date
strToDate = CDate(dateStr)
If IsDate(strToDate) Then
formatDateYYYYMMDD= format(dateStr, dateFormat)
Else
formatDateYYYYMMDD= "Not a date"
End If
End Function
Perhaps:
edit: original UDF changed as it would not flag certain invalid format dates.
Option Explicit
Function formatDateYYYYMMDD(dateStr As String, dateformat As String) As String
Dim strToDate As Date
On Error GoTo invalidDate
If Len(dateStr) = 8 And _
Left(dateStr, 4) > 1900 And _
Mid(dateStr, 5, 2) <= 12 And _
Right(dateStr, 2) <= 31 Then
formatDateYYYYMMDD = Format(CDate(Format(dateStr, "0000-00-00")), dateformat)
Exit Function
End If
invalidDate: formatDateYYYYMMDD = "Not a date"
End Function
The On Error will pick up invalid dates that otherwise meet the format criteria: eg Sep 31, Feb 30
Interesting idea for a function. I've rewritten your code below to do exactly what you said. Function returns "Not a date" for 2018101a, 20181033, 201810300, otherwise returns date in formatted string. Note that you need to provide a valid string format and I did not handle that error. I assume there are no spaces at the end?
Function formatDateYYYYMMDD(dateStr As String, dateFormat As String) As String
Dim strToDate As Date
Dim day As Integer
Dim month As Integer
Dim year As Integer
On Error Resume Next
year = Left(dateStr, 4)
month = Mid(dateStr, 5, 2)
day = Right(dateStr, 2)
strToDate = DateSerial(year, month, day)
If Err.Number <> 0 Or Len(dateStr) <> 6 Then
formatDateYYYYMMDD = "Not a date"
Err.Clear
On Error GoTo 0
Else
On Error GoTo 0
formatDateYYYYMMDD = Format(strToDate, dateFormat)
End If
End Function
I fiddled with the code getting some directions from the guy's suggestion and it works now. Thanks, guys for all your input.
This is what I did
sValue = frmForm.txtSearch.Value
If IsDate(sValue) Then
'do nothing
Else
sValue = Format(frmForm.txtSearch.Value, "DD-MM-YYYY")
End If
If the input date is always in this format(YYYYMMDD), you can write a custom code to convert it into a string that can be converted to date using CDATE.
Remember to convert month to name of the month, and year to four digit year. In this way you are explicitly defining the month, year and the remaining one as date, if you keep them as two digit numbers they may be interpreted differently on difference systems (when you convert them using CDATE)
I recommend this format DD-MMM-YYYY
In your code instead of
strToDate = CDate(dateStr)
You have to write a custom function
And in place of
formatDateYYYYMMDD= format(dateStr, dateFormat)
Return just the dateStr and set the format of the cell where it is returned to YYYYMMDD

Compare date times chosen with date and time picker in Excel VBA

So i have a multi-page form that uses two "Date and time Picker" controls named StartDate and EndDate. I want to ensure that the user does not enter the StartDate later than the EndDate. I have the following questions. Is the StartDate.value initially "" or is it null? Is what's returned by StartDate a string or a date? Here is what I have so far.
As a side remark I am also somewhat confused by this line of code even after reading the documentation.
emptyRow = Application.WorksheetFunction.CountA(Range("A:A")) + 1
Private Sub StartDate_Change()
Dim emptyRow As Long
'Submits the date in the first empty row immediately since the form does not retain datepicker data after the page changes.
If (EndDate.Value) <> "" And CDate(StartDate.Value) >= CDate(EndDate.Value) Then
MsgBox ("Please enter a valid date")
MultiPage1.Value = 4
Else
Sheet1.Activate
emptyRow = Application.WorksheetFunction.CountA(Range("A:A")) + 1
Cells(emptyRow, 18).Value = StartDate.Value
End If
End Sub
DateTimePickers return Dates.
If you want to test that the EndDate is greater than StartDate, then code such as the following should do the trick:
(StartDate.Value < EndDate.Value)

Resources