Why is midnight added to my array instead of the date? - excel

I declare a date array as such:
Dim date_array() as Date
It's goal is to store dates found in a range.
Dim date_range As String
I declare it as a string because I have an input form where a user specifies the range of dates (e.g. A1:A5).
Then I calculate how many cells are in the range and specify the size of the date_array.
ReDim date_array(Range(date_range).Cells.count)
So far so good. I then loop through each element of date_array and add the date from the range.
Dim i As Long
i = 0
For Each r In ThisWorkbook.Worksheets("Name").Range(date_range)
date_array(i) = r.Value
i + i + 1
Next r
However, when I do a MsgBox(date_array(i)) during this loop, I get a value of 12:00:00 AM instead of the date I want (e.g. 2/2/2019) which tells me something is getting lost in translation.
I get the correct result if I do MsgBox(r.Value)... so it seems like something about the way I'm assigning the date to the array is wrong.
Has anyone run into an issue like this before? How can I fix it?
The larger goal is to map data between two files using date + a naming convention as a validation, so I need the array to store the correct date in a date format so it can be compared to a different cell value later.
Thank you,

Related

Can you assign index values to .Currentpage VBA/Excel?

I'm trying to create a Macro that will, among other things, set the .CurrentPage to a specific value. My question is can you use an index value instead of the name of one of the values?
ActiveSheet.PivotTables("PivotTable1").PivotFields("starttime").CurrentPage = "11/19/2018"
Here is an example line that I'm using. The problem is the dates will change every week to represent the new data. However there will always be five options, Monday to Friday. So instead of having to use the date, which I'll have to change every week, can I use an index value instead?
I.e. [0] for Monday and [4] for Friday etc. If this is possible then what is the correct syntax for this? I've looked all over the web and found nothing even remotely related to using index numbers instead of values.
If you know that your field will only contain the relevant items and nothing else, then:
With ActiveSheet.PivotTables("PivotTable1").PivotFields("starttime")
.CurrentPage = .PivotItems(3).Value
End With
However pivot tables may retain items deleted from the data source. If that is how it is set up for you, then you will either need to remove cached items before using this code, or calculate that page value instead of looking it up in the list of available values, which should be not difficult given that it is based on the current week.
Something like this
Public arrDate(4) As Date
Sub CreateDateArray()
Dim i As Integer
For i = 0 To 4
arrDate(i) = DateAdd("d", -Weekday(Date, vbMonday) + (i + 1), Date)
Next i
End Sub
or something like this
Function DateFromIndex(intDay As Integer) As Date
DateFromIndex = DateAdd("d", -Weekday(Date, vbMonday) + (intDay+1), Date)
End Function

How to make time as variable in VBA?

I need to title graphs dynamically in following pattern:
date time symbol
I take these values as variables from certain cells in worksheet and I'm stuck with a time variable. It doesn't read hour as, for example 09:26:51 but as decimal value 0,3..etc
Last thing I came up to is:
Dim tim As Date
tim = TimeValue(Range("b2").Value)
I believe it's an easy one to solve.
You can use the Format() function for example:
MyNewTime = Format(MyTime, "h:m:s") ' Returns "17:4:23".
MyNewtime = Format(MyTime, "hh:mm:ss AMPM") ' Returns "05:04:23 PM".

Excel Substrings

I have two unordered sets of data here:
blah blah:2020:50::7.1:45
movie blah:blahbah, The:1914:54:
I want to extract all the data to the left of the year (aka, 1915 and 1914).
What excel formula would I use for this?
I tried this formula
=IF(ISNUMBER(SEARCH(":",A1)),MID(A1,SEARCH(":",A1),300),A1)
these were the results below:
: blahblah, The:1914:54::7
:1915:50::7.1:45:
This is because there is a colon in the movie title.
The results I need consistently are:
:1914:54::7.9:17::
:1915:50::7.1:45::
Can someone help with this?
You can use Regular Expressions, make sure you include a reference for it in your VBA editor. The following UDF will do the job.
Function ExtractNumber(cell As Range) As String
ExtractNumber = ""
Dim rex As New RegExp
rex.Pattern = "(:\d{4}:\d{2}::\d\.\d:\d{2}::\d:\d:\d:\d:\d:\d:\d)"
rex.Global = True
Dim mtch As Object, sbmtch As Object
For Each mtch In rex.Execute(cell.Value)
ExtractNumber = ExtractNumber & mtch.SubMatches(0)
Next mtch
End Function
Without VBA:
In reality you don't want to find the : You want to find either :1 or :2 since the year will either start with 1 or 2This formula should do it:
=MID(A1,MIN(IFERROR(FIND(":1",A1,1),9999),IFERROR(FIND(":2",A1),9999)),9999)
Look for a four digit string, in a certain range, bounded by colons.
For example:
=MID(A1,MIN(FIND(":" &ROW(INDIRECT("1900:2100"))&":",A1 &":" &ROW(INDIRECT("1900:2100"))&":")),99)
entered as an array formula by holding down ctrl-shift while hitting Enter would ensure years in the range 1900 to 2100. Change those values as appropriate for your data. The 99 at the end represents the longest possible string. Again, that can be increased as required.
You can use the same approach to return just the left hand part, up to the colon preceding the year:
=LEFT(A1,-1+MIN(FIND(":" &ROW(INDIRECT("1900:2100"))&":",A1 &":" &ROW(INDIRECT("1900:2100"))&":")))
Here is a screen shot, showing the original data in B1:B2, with the results of the first part in B4:B5, and the formula for B4 showing in the formula bar.
The results for the 2nd part are in B7:B9

How to make match() work with date in excel vba?

I'm having problem making the match() work in excel VBA. The code is:
x = Application.Match("Sep 2008", Range("F1:F1"), 0)
The value in cell F1 is 9/1/2008.
Even if I changed Sep 2008 to 9/1/2008, it still doesn't return any value.
Any idea how to fix it?
The reason why Even if I changed Sep 2008 to 9/1/2008, it still doesn't return any value.
Is because when there is a Date in excel, Excel automatically converts that date to a numeric value, What you really want to search for is:
39692
This number is the number of days between 9/1/2008 and excel default of 1/1/1900
every date in excel is stored with a value like this. So the easiest way to handle this would be to convert what you see as a date to what excel sees as a date using CDate().
This by itself will give you an unuseful error that vba can't get the property.
That is because the Lookup_value can be a value (number, text, or logical value) or a cell reference to a number, text, or logical value. Not a date so simply convert the now date value to a number to search for the matching number in the list using CLng()
Give this a shot it will also be much faster then using the Find alternative:
x = WorksheetFunction.Match(CLng(CDate("Sep 2008")), Range("F1:F1"), 0)
This should give you the result expected
To handle when no match is found try this Sub:
Sub MatchDate()
Dim myvalue As Double
Dim LastRow As Long
LastRow = Cells(Rows.Count, "F").End(xlUp)
On Error GoTo NotFound
myvalue = WorksheetFunction.Match(CLng(CDate("Sep 2008")), Range("F1:F" & LastRow), 0)
MsgBox (myvalue)
End
NotFound:
MsgBox ("No Match Was Found")
End
End:
End Sub
Your best bet is to use .Find(). This will return a range if found or nothing if not.
Set x = Range("F1:F1").Find(CDate("Sept 2008"), , , xlWhole)
If you wanted the column number:
x = Range("F1:F1").Find(CDate("Sept 2008"), , , xlWhole).Column
With capture of not found
Sub test()
Dim y As Date, x As Variant, c As Long
y = CDate("Sep 2008")
Set x = Range("1:1").Find(y, , , xlWhole)
If Not x Is Nothing Then
c = x.Column '<~~found
Else
Exit Sub 'not found
End If
End Sub
Bottom line:
use WorksheetFunction.Match(CDbl(date), range, 0)
Alternatively, use a Date cell's Value2 property (which will also be a Double) instead of Value for the search key.
CLng suggested in other answers would discard the time part of the date.
The same problem exists for the Currency data type but you can't use CDbl for it (see below for options).
Range.Value2 Property (Excel) article suggests that Date and Currency types are "special" in that they have an "internal representation" that's in stark contrast with displayed value. Indeed:
Date is internally represented as IEEE 64-bit (8-byte) floating-point numbers where the integer part is the date and fractional part is the time
Currency is also 8-byte but is treated as a fixed-point number with 4 fractional digits (an integer scaled by 10'000)
Apparently, Match compares these internal values for performance reasons. So, we must ensure that they, rather than the readable representations, match exactly.
Since Date is already floating-point internally, CDbl(date) doesn't actually change the data.
For the Currency type, CDbl does change data, so it's out of question. So either
use the exact representation of the key (to 4 fractional digits) this way or another if you require exact match, or
make the cells in the range actually be formulas with Round) if the value to compare with comes from elsewhere and/or you only require equality to 2 fractional digits
This way it works using this method:
Nbr,L, C as Integer
Datedeb as date
nbr = WorksheetFunction.Match(CLng(CDate(Datedeb)), Range(Cells(L, C), Cells(L + 100, C)), 0)
I think I can safely assume that the value in F1 is a date. In you code "Sep 2008" is a string. You will never be able to get a successful match as long as your datatypes are inconsistent.
If you are looking for a date, then make sure that the first parameter is a date.
Dim dSearchSDate As Date
dSearchSDate = "01/Sept/2008"
x = Application.Match(dSearchSDate, Range("F1:F1"), 0)
Here is another possible approach.
Sub temp()
Dim x
Dim dSearchSDate As Date
dSearchSDate = "01/Sept/2008"
If ThisWorkbook.Worksheets(1).Range("F1:F1").Value = dSearchSDate Then
Debug.Print "Found it!"
Else
Debug.Print "Doh!!"
End If
End Sub
I know this post is old, but I had the same issue, and did find the answer.
To make it work, you first need to make VBA see the same data formatting as it appears in your excel spreadsheet :
YourVar = Format("YourDate","mmm-yyyy")
YourResult = Application.match(Clng(Cdate(YourVar)), YourRange, 0)
Regards
Gilles

VBA convert range to array and format date

I am struggling with a conversion to array in VBA :
Dim list As Range
Set list = Range(series, series.End(xlDown))
list.Select
Dim table() As Variant
Set table = list.value
My understanding is that value returns an array right ? I don't get why VBA tells me that I "can't assign to array".
My list range looks like that in Excel at the Select, and i aim at having that as an array so that I can format my dates using something like Format(table.Rows(i).Columns(1).value, "yyyy-mm-dd"), looping on my table.
02-Sep-09 1.00
18-Sep-09 1.00
16-Oct-09 1.00
20-Nov-09 1.00
18-Dec-09 1.00
19-Mar-10 1.00
18-Jun-10 1.00
By the way, is it possible to modify the table in place ?
Thanks !
There are a number of problem here.
Problem 1
Set table = list.value
table is not an object so you cannot set it. Try:
table = list.value
Problem 2
series is a VBA keyword associated with charts. Please pick a name, such as MyWSTable, which means nothing to VBA.
Problem 3
A worksheet name is not itself a range. Try:
Dim Table() As Variant
Table = Names("MyWSTable").RefersToRange.Value
Note: you do not need variable list nor do you need to select the range.
Answer to formatting question
The following code will reformat your dates:
For inxrow = 1 To UBound(Table, 1)
For inxcol = 1 To UBound(Table, 2)
Table(inxrow, 1) = "ddd d mmm yyyyy"
Table(inxrow, 2) = ""
Next
Next
Names("MyWSTable").RefersToRange.NumberFormat = Table
You can remove your select: list.Select
To be sure you won't get errors when assigning a range to an array, you'd better declare your array as a variant:
Dim table As Variant
table = Range(series, series.End(xlDown)).Value
That error message is popping because you are using SET to fill the array. Drop the SET and it should load.
You can fil directly the array as follows:
Dim table() As Variant
table=Range(series, series.End(xlDown))
Omiting the Select step makes your code safer and faster.
Unfortunately, you can not load the values directly as dates. You will have to loop throu every item of the array and turn them into date.
You are going about this incorrectly. You should use the NumberFormat property of the range to specify the display format. Something like this:
Range("A:A").NumberFormat = "yyyy-mm-dd"

Resources