I have the following code:
minDate = CDate(Table.Cell(i, 4).Range.Text)
But I get a "Type mismatch error".
Table.Cell(i, 4) is in a "dd.mm.yy" format.
I wrote a macro to test this and the date format dd.mm.yyyy is invalid, it seems you must use dd/mm/yyyy (using slashes instead of period) or dd-mm-yyyy (using hyphens instead of periods):
Sub Macro1()
Dim minDate As Date
Dim DateStr As String
' with slashes, ok
DateStr = "27/12/2013"
minDate = CDate(DateStr)
' replace periods w/ slashes, ok
DateStr = "27.12.2013"
minDate = CDate(Replace(DateStr, ".", "/"))
' replace periods w/ hyphens, ok
DateStr = "27.12.2013"
minDate = CDate(Replace(DateStr, ".", "-"))
' type mismatch
DateStr = "27.12.2013"
minDate = CDate(DateStr)
End Sub
So, to solve your problem, you just need to replace all periods in your date to either hyphen or slash:
minDate = CDate(Replace(Table.Cell(i, 4).Range.Text, ".", "/"))
Try
minDate = CDate(Table.Cell(i, 4))
The date conversion performance depends on the date format settings in Region and Language.
The following function ensures a successful conversion:
Function TextToDate(vstrText) As Variant
' Description: Convert Text Date to Date
'--
Dim d As Variant
Dim sDate As String
sDate = Replace(vstrText, ".", "-")
If Right(sDate, 1) = "-" Then
sDate = Left(sDate, Len(sDate) - 1)
End If
If IsDate(sDate) Then
d = CDate(sDate)
Else
d = ""
End If
TextToDate = d
End Function
Related
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
I have vba function to split date/time on my worksheet
but when it find 0:00AM it will stop and I don't know how to fix this
code
Function extractDateTime(strTime As Date) As Variant
Dim arrD, d As String, t As Date
arrD = Split(strTime, " ")
d = arrD(0)
t = CDate(arrD(1) & " " & arrD(2))
extractDateTime = Array(d, t)
End Function
pic when it find date/time at 12:00:00 AM
function not return value arrD(1) and arrD(2)
cell value
pic when function normally working
Always handle date/time as Date, not text, not numbers, no exceptions. So:
Public Function ExtractDateTime(Value As Date) As Variant
Dim d As Date
Dim t As Date
d = DateValue(Value)
t = TimeValue(Value)
ExtractDateTime = Array(d, t)
End Function
Parsing the Date for spaces is not a great way to go about it.
Instead, you can use Format to just get the pieces you want.
Function extractDateTime(dt As Date) As Variant
Dim d As String, t As String
d = Format(dt, "dd/mm/yyyy")
t = Format(dt, "hh:mm:ss AMPM")
extractDateTime = Array(d, t)
Debug.Print d
Debug.Print t
Debug.Print Format(dt, "mmm dd, yyyy")
Debug.Print Format(dt, "mmmm")
Debug.Print WeekdayName(Weekday(dt))
End Function
Kinda seems like a waste of a function tho when you can just do this:
Result = Array(Format(dt, "dd/mm/yyyy"), Format(dt, "hh:mm:ss AMPM"))
In consequence of a new installation of windows (different language) some log files now have a different DateTime format.
To make my Excel/VBA scripts work again I have to convert DateTime strings to the old (German) time format of constant length.
To make it clear: I want to manipulate a string (not getting another datatype).
Problematic Format => Wanted Format
"12/28/2019 9:37:49 PM" => "28.12.2019 21:37:49"
"1/2/2020 10:15:20 AM" => "02.01.2020 10:15:20"
"2/1/2020 7:10:15 AM" => "01.02.2020 07:10:15"
"2/13/2020 7:10:15 AM" => "13.02.2020 07:10:15"
One problem I face is that the "Problematic format" has a variable string length. That means I am not able to extract specific positions inside this string using LEFT / MID / RIGHT.
Is there any easy possibility to convert this string into the old format without loops?
The following Code is not working because of a strange/inconsistent behavior of Excel:
ProblematicFormat$ = "2/1/2020 7:10:15 AM"
MyDate = CDate(ProblematicFormat$)
NewDateTime$ = Format(MyDate, "dd.MM.yyyy H:nn:ss")
MsgBox NewDateTime$
The result of that code mixes up day and month:
"2/1/2020 7:10:15 AM" => "02.01.2020 07:10:15" (wrong)
"2/13/2020 7:10:15 AM" => "13.02.2020 07:10:15" (correct)
Being a matter of string manipulation, try this code, please:
Sub testDateFormatLocale()
Dim ProblematicFormat$, replacement$, toReplace$, MyDate As Date, NewDateTime$, CorrectDateTime$
'Debug.Print Now, Format(Now, "dd\/mm\/yyyy hh:nn:ss")
ProblematicFormat$ = "2/13/2020 7:10:15 AM"
MyDate = CDate(ProblematicFormat$) 'm/dd/yyyy
NewDateTime$ = Format(MyDate, "dd.MM.yyyy H:nn:ss")
Debug.Print NewDateTime$
replacement = Split(NewDateTime, ".", 3)(1) & "." & Split(NewDateTime, ".", 3)(0)
toReplace = Split(NewDateTime, ".", 3)(0) & "." & Split(NewDateTime, ".", 3)(1)
CorrectDateTime$ = Replace(NewDateTime$, toReplace, replacement)
Debug.Print CorrectDateTime$
End Sub
You can apply the above solution only for German localization. It can be done using:
Debug.Print Application.International(xlCountrySetting)
The solution is in the region and language setting. In the formats tab, change the format to US (mm/dd/yyyy). In case you do not want to change regional settings then you will have to handle the above date using Split/Dateserial and then you will get what you want. Something like this...
Option Explicit
Sub Sample()
Dim oldDateString As String
Dim newDateString As String
Dim d As Integer
Dim m As Integer
Dim y As Integer
Dim MyDate As Date
oldDateString = "2/1/2020 7:10:15 AM"
oldDateString = Split(oldDateString)(0)
d = Val(Split(oldDateString, "/")(1))
m = Val(Split(oldDateString, "/")(0))
y = Val(Split(oldDateString, "/")(2))
MyDate = DateSerial(y, m, d)
Debug.Print MyDate
newDateString = Format(MyDate, "dd.MM.yyyy H:nn:ss")
Debug.Print newDateString
End Sub
Or you can use this? This checks the regional settigns and then decides what to do...
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
Private Const LOCALE_USER_DEFAULT = &H400
Private Const LOCALE_SSHORTDATE = &H1F
Private Sub Sample()
Dim LocaleValue As String
Dim RetValue As Long
LocaleValue = Space(255)
RetValue = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, _
LocaleValue, Len(LocaleValue))
'~~> Get short date format
LocaleValue = Ucase(Trim(Left(LocaleValue, RetValue - 1)))
If Left(LocaleValue, 1) = "M" Then 'M/d/yyyy ???
'~~> Use your original code
ElseIf Left(LocaleValue, 1) = "D" Then
'~~> Use the code that I gave
End If
End Sub
Note: There are different formats that you may come across. The above code will help you handle all those formats, with a little tweak of course.
You can use this function which "eats" even quite weird US formatted strings:
' Converts a US formatted date/time string to a date value.
'
' Examples:
' 7/6/2016 7:00 PM -> 2016-07-06 19:00:00
' 7/6 7:00 PM -> 2018-07-06 19:00:00 ' Current year is 2018.
' 7/6/46 7:00 PM -> 1946-07-06 19:00:00
' 8/9-1982 9:33 -> 1982-08-09 09:33:00
' 2/29 14:21:56 -> 2039-02-01 14:21:56 ' Month/year.
' 2/39 14:21:56 -> 1939-02-01 14:21:56 ' Month/year.
' 7/6/46 7 -> 1946-07-06 00:00:00 ' Cannot read time.
' 7:32 -> 1899-12-30 07:32:00 ' Time value only.
' 7:32 PM -> 1899-12-30 19:32:00 ' Time value only.
' 7.32 PM -> 1899-12-30 19:32:00 ' Time value only.
' 14:21:56 -> 1899-12-30 14:21:56 ' Time value only.
'
' 2018-03-31. Gustav Brock. Cactus Data ApS, CPH.
'
Public Function CDateUs( _
ByVal Expression As String) _
As Date
Const PartSeparator As String = " "
Const DateSeparator As String = "/"
Const DashSeparator As String = "-"
Const MaxPartCount As Integer = 2
Dim Parts As Variant
Dim DateParts As Variant
Dim DatePart As Date
Dim TimePart As Date
Dim Result As Date
' Split expression into maximum two parts.
Parts = Split(Expression, PartSeparator, MaxPartCount)
If IsDate(Parts(0)) Then
' A date or time part is found.
' Replace dashes with slashes.
Parts(0) = Replace(Parts(0), DashSeparator, DateSeparator)
If InStr(1, Parts(0), DateSeparator) > 1 Then
' A date part is found.
DateParts = Split(Parts(0), DateSeparator)
If UBound(DateParts) = 2 Then
' The date includes year.
DatePart = DateSerial(DateParts(2), DateParts(0), DateParts(1))
Else
If IsDate(CStr(Year(Date)) & DateSeparator & Join(DateParts, DateSeparator)) Then
' Use current year.
DatePart = DateSerial(Year(Date), DateParts(0), DateParts(1))
Else
' Expression contains month/year.
DatePart = CDate(Join(DateParts, DateSeparator))
End If
End If
If UBound(Parts) = 1 Then
If IsDate(Parts(1)) Then
' A time part is found.
TimePart = CDate(Parts(1))
End If
End If
Else
' A time part it must be.
' Concatenate an AM/PM part if present.
TimePart = CDate(Join(Parts, PartSeparator))
End If
End If
Result = DatePart + TimePart
CDateUs = Result
End Function
Then apply your format, for example:
? Format(CDateUS("1/2/2020 10:15:20 AM"), "dd.mm.yyyy hh:nn:ss")
02.01.2020 10:15:20
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
I am trying to get the Date as a string formatted yyyy-mm-dd.
I have tried various things with strange results:
Dim mydate As String
mydate = Date
mydate = Year(Date)
mydate = Month(Date)
mydate = Day(Date)
The first one gives 11/02/ without the year.
I can try to concatenate the data but:
The second gives the year OK
However the third gives month as 2 instead of 02
Similar for fourth.
Any clarification or an example would be very welcome.
Use the Format function from the VBA.Strings built-in module:
Debug.Print Format(Now, "YYYY-MM-DD")
Dim sToday As String
sToday = CStr(Date)
That gives sToday value, e.g. "2020-12-31", in the format of my system's date.
In some VBA, the Format() function is not available. In this case, you can do it the old fashion:
y = cstr(year(now))
m = right("0" + cstr(month(now)),2)
d = right("0" + cstr(day(now)),2)
mydate = y + "-"+ m + "-" + d