Inconsistent behaviour of CDate() - vba

Regional settings in Windows are MM/DD/YYYY
Now look at these two lines, and the change in the MONTH:
Sub DateBug()
Debug.Print Format(CDate("11/4/1999"), "MMMM D, YYYY")
Debug.Print Format(CDate("30/4/1999"), "MMMM D, YYYY")
End Sub
OUTPUT:
November 4, 1999
April 30, 1999
Great, huh? What is going on?
In the 2nd line, I want an error, not "guessing".
Is this a bug? Any idea how this can be circumvented ?
Same in Excel 2007, 2010, 2013

Not a bug. VB will convert strings to date literals using the default regional settings, if it can. Which it did in the first date. But on the second date, that would have given an invalid date, so it tried DD/MM/YYYY and that worked. Solution, put use date literals instead of strings. Put # signs around both date literals (ex: '#4/30/1999#') to ignore regional setting and force use of the MM/DD/YYYY format. '#30/4/1999#' would have given you the error you want. This will make your code independent of the regional setting of the computer - ie, it will work regardless. Or else use DateTime(1999, 4, 30, 0, 0, 0). Look here... Date Data Type (Visual Basic)
In Excel, you would use the literal without the single quotes:
Sub Macro1()
Range("D2").Select
ActiveCell.FormulaR1C1 = CDate(#4/30/1999#)
End Sub

This is not a bug, its a "feature"
CDate() will interpret the string according to fixed rules. If the date is valid as m/d/y, that will be returned. If the date is not valid as m/d/y, but is valid as d/m/y, then that will be returned. If the date is not valid as either m/d/y or d/m/y, then an error will be returned.
Sub dural()
Dim st As String
st = CStr(CDate("12/4/2012")) & vbCrLf & CStr(CDate("13/4/2012"))
MsgBox st
End Sub

Related

VBA - Get the day before when a date is specified

I'm currently trying to write a piece of code where the user is giving a text box to enter a date in the format dd/mm/yyyy and once that has been specified, I want to get the day before that date.
For example, the user enters 14/12/2018 and I would like VBA to store 13/12/2018 to another variable.
Probably a stupid query, but would be handy to know if this is possible.
Nevermind, I figured it out!
Here's what I did in case anyone wants to know:
Dim FirstRun as Date
Dim FirstRunBefore as Date
FirstRun = InputBox("Enter date")
FirstRunBefore = Format(DateAdd("d", -1, FirstRun), "dd mmmm yyyy")

VBA: reading date from a string of a specific format

I'm looking for a way to convert strings to Date data type in VBA. I can use CDate() function for this purpose, but it uses its own implicit algorithm for parsing strings and I would like to specify my own format to differentiate between "DD/MM/YY" and "MM/DD/YY", for example.
Please notice that unlike Visual Basic, VBA has no DateTime.TryParseExact function.
ADD: As some answers suggest, I can write my own parser. If there is no built-in solution, it will be my choice.
Do something like this...
strDate = Split(strDate,"/")
newstrDate = strDate(1) & "/" & strDate(0) & "/" & strDate(2)
strDate = CDate(newstrDate)
In this case I would avoid CDate alltogether and instead split the date string into year, month and day and use DateSerial(year, month, day). This way you have full control.
Can you use the below code
Msgbox Format("24/01/2017","MMM, DD, YYYY")
This will give you output as Jan, 24, 2017 . You can use other format which is easily available when you click on the Format cells. Thanks

Excel vba error with dates on sheet and textbox

I live in Australia and we use the d/mm/yyyy date format. I am trying to make a userform with VBA in excel that will read the a cell (A1), display it in a textbox. The user can then enter a date in another textbox and set that date back to cell(A1). The problem I have is that when I am reading the date from Cell(A1) is changes from d/mm/yyyy to m/dd/yyyy in the textbox. I have used the
" = Format(DateCurrent_Tbx.Value, "d/mmm/yy")" but it makes no difference. I am using Excel 2010 32bit, on a Windows 7 SP1 64Bit Computer, and have the computer set to English (Australian) time format. Cell(A1) is set to custom formatting "d/mm/yyyy"
As the VBA code for the file I'm using is very long, I've replicated the error in a smaller userform (attached excel file).
Sample of Excel file with Error
Private Sub LockInput_Cmd_Click()
SetDate_Cmd.Caption = InputDate_Tbx.Value
SetDate_Cmd.Caption = Format(SetDate_Cmd.Caption, "d/mmm/yy")
End Sub
Private Sub SetDate_Cmd_Click()
ThisWorkbook.Sheets(1).Range("A1").Value = SetDate_Cmd.Caption
DateCurrent_Tbx.Value = ThisWorkbook.Sheets(1).Range("A1").Value
DateCurrent_Tbx.Value = Format(DateCurrent_Tbx.Value, "d/mmm/yy")
End Sub
Private Sub UserForm_Initialize()
DateCurrent_Tbx.Value = ThisWorkbook.Sheets(1).Range("A1").Value
DateCurrent_Tbx.Value = Format(DateCurrent_Tbx.Value, "d/mmm/yy")
End Sub
I have been racking my head and searching the web for days to no avail. I hope I have explained things clearly enough.
There is some confusion with strings that look like dates and actual dates and the EN-US-centric VBA default MDY locale is doing nothing to alleviate that.
First off, the date in A1 is a number between 0 and 42,225 (Aug 9, 2015 is 42,225); nothing more or less. You can dress it up as d/mm/yyyy regardless of what locale your computer system is running under. Mine runs under EN-US and I have no trouble displaying a date as 9/08/2015 if I use a number format mask of d/mm/yyyy. To get the displayed date from A1 back into the textbox AS A STRING use the Range.Text property. This is the displayed text that is in a cell. It is read-only so you cannot stuff a "9/08/2015" string back into it.
Private Sub UserForm_Initialize()
DateCurrent_Tbx.Value = ThisWorkbook.Sheets(1).Range("A1").TEXT
End Sub
As far as user input of a 'string-that-looks-like-a-date' is concerned, you may have to trust your users a bit to do the right thing. If they can be relied upon to input in a DMY format, you can split the pieces and put them together properly using the DateSerial function.
Private Sub LockInput_Cmd_Click()
dim dt as date, vDT as variant
vDT = split(InputDate_Tbx.Value, chr(47)) 'split the string-date on the forward slash
dt = DateSerial(vDT(2), vDT(1), vDT(0)) 'create a real date
SetDate_Cmd.Caption = Format(dt, "d/mmm/yy") 'use any format mask you want to create another string-date
End Sub
Private Sub SetDate_Cmd_Click()
dim dt as date, vDT as variant
vDT = split(SetDate_Cmd.Caption, chr(47)) 'split the string-date on the forward slash
dt = DateSerial(vDT(2), vDT(1), vDT(0)) 'create a real date
ThisWorkbook.Sheets(1).Range("A1").Value = dt 'put the actual date back into A1
End Sub
As far as the CDate function is concerned, I would avoid its use. If you stuff "19/08/2015" into CDate (try it in the VBE's Immediate window as ?CDate("19/08/2015")) it will correctly interpret it as 19-Aug-2015 but that is only because IT HAS NO OTHER CHOICE! If you try the same with ?CDate("9/08/2015") you end up with 08-Sep-2015 because whenever there is a choice, CDate opts for the EN-US locale of MDY. Best not to rely on this one. I believe the DateValue function is at least as unreliable.

How to change mm/dd/yyyy to dd/mm/yyyy using VBA

I have a problem in converting mm/dd/yyyy to dd/mm/yyyy date format using VBA.
I have a table like this:
fyi, the table is auto generated from a reporting tool.
Can "string manipulation" or any excel function help? Hope anyone who know how to solve this problem can give me some idea.
Well, from the way you've worded your question I'm not convinced you actually want or need VBA.
Looking at the image you posted it would appear the first cell contains the string 05/06/2013 - 05/10/2013 not the date 05/06/2013. So the first thing you need to do is split out the parts so the built in Excel or VBA functions can convert it.
By Excel Formulas
So we could use SEARCH or FIND to find the "-" and do things dynamically. But I'm feeling lazy so I'll just assume the first 10 characters of the string are the first date and the last 10 characters are the second date. A TRIM function on the source string should make this a bit safer in case of extra spaces before or after.
So if our string 05/06/2013 - 05/10/2013 is in cell A2, we can put =LEFT(TRIM(A2),10) in B2 and =RIGHT(TRIM(A2),10) in C2.
Now these are still strings. Normally I'd use DATEVALUE to convert the strings to dates, but my copy of Excel doesn't like those crazy nonsense* date formats. So we will parse the dates into the DATE function. Putting =DATE(RIGHT(B2,4),LEFT(B2,2),MID(B2,4,2)) and =DATE(RIGHT(C2,4),LEFT(C2,2),MID(C2,4,2)) into cells C2 and D2 respectively.
From here we can recombine them using the TEXT function (much like the format function in VBA) and some string concatenation into your original single-cell date range format. Assuming that's the desired result.
So our final cell, F2, would be =TEXT(D2,"dd/MM/yyyy") & " - " & TEXT(E2,"dd/MM/yyyy"). We could of course combine all those formulas into one big mess like so:
=TEXT(DATE(RIGHT(LEFT(A2,10),4),LEFT(LEFT(A2,10),2),MID(LEFT(A2,10),4,2)),"dd/MM/yyyy") & " - " & TEXT(DATE(RIGHT(RIGHT(TRIM(A2),10),4),LEFT(RIGHT(TRIM(A2),10),2),MID(RIGHT(TRIM(A2),10),4,2)),"dd/MM/yyyy")
By Visual Basic for Applications
It's the same process here, just using VBA functions and syntax instead of Excel formulas.
Now for whatever reason the VBA version of DateValue will accept those dates in my copy of Excel. So I'll use it.
Public Function ChangeDateFormat(inputString As String) As String
Dim firstDate As Date
Dim secondDate As Date
Dim trimmedInput As String
trimmedInput = Trim$(inputString)
firstDate = DateValue(Left$(trimmedInput, 10))
secondDate = DateValue(Right$(trimmedInput, 10))
ChangeDateFormat = Format(firstDate, "dd\/MM\/yyyy") & " - " & Format(secondDate, "dd\/MM\/yyyy")
End Function
Public Sub Test()
Sheet1.[B2] = ChangeDateFormat(Sheet1.[A2])
End Sub
This can be tested either by running the provided Test sub, or ChangeDateFormat can be used as a user defined function in an excel formula =ChangeDateFormat(A2).
Note, in the date formats passed to Format, I escaped the date separator \/ instead of just putting / in. This is because the Format function will automatically replace / with the date separator from your Windows settings. And since I use a modern computer friendly date format, my seperators are dashes...
Footnote
* Life would be so much easier if people would just use ISO 8601. It exists for a reason, a good reason.

datediff help in vb.net

Hey all i have 2 dates that i need to see the days that are different.
Problem being is that the server date is not in the normal MM/DD/YYYY format. It is in the format YYYYMMDD.
I've tried the following:
Dim curDate As Date = Format(Now, "yyyyMMdd")
Dim srDate As Date = dr(6)
Dim M As Long = DateDiff(DateInterval.Weekday, curDate, srDate)
The curDate has the error of:
Conversion from string "20110325" to type 'Date' is not valid.
Any help would be great! :o)
David
Try not to hammer a square string peg into a round date hole, that just has way too many ways to break your mallet. The Now function already returns a date:
Dim curDate As Date = Now.Date
Option Strict On at the top of the source code file helps you find these kinds of mistakes.
If you get the string from the server (pray you don't) then use ParseExact() to convert the date:
Dim curDate As Date = Date.ParseExact(serverValue, "yyyyMMdd", Nothing)
Why are you formatting Now like that? You could just do this:
Dim curDate As Date = DateTime.Now.Date
As the other posters have said, you don't need to format DateTime.Now.
But there's something else going wrong here: Format returns a string, and you're trying to assign that to a Date. It's trying to implicitly convert a string, and failing.
In future, when you do have a date-string like "yyyyMMdd" to turn into a DateTime type, use DateTime.Parse
Your problem is the first line; it seems you have Option Strict off in your project (FOR SHAME!), as it would otherwise not compile at all.
Format(Now, "yyyyMMdd") will produce the current date formatted in that manner as a string. The trouble is that you're attempting to assign that output (the string) to a Date variable. Because you have Option Strict off, the compiler indicates this conversion implicitly, and the runtime is attempting to convert your non-standard date string back into a date. This is what's failing.
Changing as little as possible about your code, it should read:
Dim curDate As Date = Now.Date
Dim srDate As Date = DateTime.ParseExact(dr(6).ToString(), "yyyyMMDD", CultureInfo.InvariantCulture).Date
Dim M As Long = DateDiff(DateInterval.Weekday, curDate, srDate)
Step 0: TURN OPTION STRICT ON
There's no reason that new code should be written with this option turned off. There's too much potential for runtime errors that are easily caught at compile time (like this one) with it off. It's a feature that should be banished from the language entirely.
Step 1: Adopt standard .NET types and functions
While this isn't required, it will make your code more readable to other developers and other developers' code more readable to you. Things like Format, DateDiff, Now, etc. are all VB-specific functions that exist primarily to make it easier for classic VB6 applications to be ported over to .NET. Unless there's a particular reason to use the language-specific versions, it's a good idea to use standard .NET functions instead.
Firstly:
"MM/DD/YYYY" is not normal in most of the world, only North America.
China uses "YYYY-MM-DD".
Europe uses "DD/MM/YYYY"
Secondly, if you are parsing a known date format, you can pass a format string to DateTime.Parse. In your case that is what you need to do.
Try
Dim curDate As Date = Now
Dim srDate As Date = mid(dr(6),5,2) & "/" & right(dr(6),2) & "/" & left(dr(6),4)