I have a list of ascending dates. I am using the following formula to return the cell reference:
=CELL("address",INDEX(A2:A14,MATCH(D1,A2:A14,1)))
This formula gives me the result I what e.g. a search for 1/2/2017 returns the cell reference of $A$6. While a search for 12/30/2016 returns the cell reference of $A$4.
How would I accomplish the same result using VBA, while returning the next date value in the list if the search date is greater than the previous date in the list and another date that is greater than the search date exist?
Dates 1/2/2017
12/27/2016 $A$6
12/28/2016
12/29/2016
1/1/2017
1/2/2017
1/3/2017
...
If i anderstood your question i have an alternative for you.
I have tested this code and works fine.
I have a list of ascending dates from A2 to A14
I use cells(1,4) [in the sheet is D1] as input data to compare into list.
The result of comparison is into cells(2,4) [in the sheet is D2]
i.e.
my list from A2 to A14
12/27/2016
12/28/2016
12/29/2016
01/01/2017
01/02/2017
01/03/2017
01/04/2017
01/05/2017
01/06/2017
01/07/2017
01/08/2017
01/09/2017
01/10/2017
into cells(1,4) i wrote 01/05/2017
output macro is into cells(2,4) and is :$A$9
If i write 01/11/2017 the result is $A$14
Sub test()
Dim i, start, finish As Integer
Dim myDate,output As Date
i = 0
start = 2
finish = 14
myDate = Cells(1, 4) ' my input - cells(2,4) is output
For i = finish To start Step -1
If (i = start) Then
Cells(i, 1).Activate 'cell where is "my date"
Cells(2, 4) = ActiveCell.Address ' get the address -output
'Exit For
End If
If myDate >= Cells(i, 1) Then
Cells(i, 1).Activate 'cell where is "my date"
Cells(2, 4) = ActiveCell.Address ' get the address -output
Exit For
End If
Next i
End Sub
Related
Guys my primary objective is to avoid invalid days.
In sheet 1 i have:
A1 data validation with years (from 1900-2019)
B1 data validation with all months
C1 i use change event (if both fields A1 & A2 are not empty) calculate how many days the selected month has based on the selected year and create a data validation includes all available days.
For days calculation i use:
Option Explicit
Sub test()
Dim ndays As Long
With ThisWorkbook.Worksheets("Sheet1")
ndays = Day(DateSerial(.Range("A1").Value, .Range("B1").Value + 1, 1) - 1)
End With
End Sub
Sheet Structure:
Is there a batter way to calculate days?
you could use:
DateValue() function to build a date out of a string you compose with your year and month values and adding any valid day number (I chose "1" to be sure...)
EOMONTH() worksheet function to get the last day of the resulting date month:
like follows:
With someSheet
...
nb_days = Day(WorksheetFunction.EoMonth(DateValue(.Range("A1").Value & " " & .Range("B1").Value & " 1"), 0))
...
End With
I suggest to use the UDF (User Defined Function) below.
Function MonthDays(Rng As Range) As Integer
Const Y As Integer = 1
Const M As Integer = 2
Dim Arr As Variant
Application.Volatile ' recalculates on every change
If Application.WorksheetFunction.Count(Rng) = 2 Then
Arr = Rng.Value
MonthDays = DateDiff("d", DateSerial(Arr(Y, 1), Arr(M, 1), 1), _
DateSerial(Arr(Y, 1), Arr(M, 1) + 1, 1))
End If
End Function
You can call it directly from the worksheet with a function call like =MonthDays(A1:A2) where A1 holds the year and A2 holds the month. If either is missing the function returns 0. The function accepts impossible numbers for both year and month and will return a logical result, such as the 14th month of a year being the following year's February. However, you can limit the entries by data validation.
All UDFs can be called as normal functions from your code. Cells(3, 1).Value = MonthDays(Range("A1:A2")) would have the same effect as entering the function call as described in the preceding paragraph in A3. However, if the function is called from VBA the line Application.Volatile would be not required (ineffective).
how to write EXCEL VBA to make my date from 04/JUNE > 04/JUNE 23:59. i cannot use the '= date + 5/6' as i have to run the VBA many times a day and it will add my dates to tomorrow/ the day after tomorrow. i just wanna make the date to end of date. please help.
The example will be like
CELL A1 : 12/June
CELL B1 : 15/June
CELL C1 : 15/June 12:00 HRS
CELL D1 : =IF C1B2, “OUT OF RANGE”, “Okay !”)
in this case D1 will still display OUT OF RANGE.
I have loads of such to change so I was thinking of writing a VBA to automatically convert C1 from 15/JUNE -> 15/JUNE 23:59 , so that D1 will display Okay !
I tried Cdate(Range(“D1”)) + 5/6 in vba to make it 23:00 hrs and I run this macro a few times in a day and it will keep adding 23hrs to the date and made it change to another date.
About what you are talking?
About:
- "Excel Formula" or
- "EXCEL VBA"
?
About:
- "Comparing Range of Date" or
- "to make my date"
?
Assume, that VBA is...
The Date type in VBA is Double, where:
- Integer part as quantity of days from... (look F1), and
- Fractional part of day.
So, your desired "04/JUNE > 04/JUNE 23:59" will:
? DateSerial(2018, 06, 4) + ((23& * 60& * 60&) + (59& * 60&)) / 86400&
18-06-04 23:59:00
Yeah, sure, you can use TimeSerialinstead of above, but ... it didn't give you right understanding of VBA dates.
.
----------
ADD:
Sorry but will this code only work for one cell because I have lots of
cells with dates and I need VBA to extract them out and convert to
23:59 for eg I run a for loop to change like 20 cells in a row with
multiple range. And I will run the macro a few times in a day will it
add 23hrs to that date every time and cause it to change dates ?
Public Sub sp_Test_Date()
Dim rSel As Range
Dim i&
Const H23M59 As Double = 1 - 60 / 86400
Set rSel = Selection
With rSel
For i = 1 To .Cells.Count
With .Cells(i)
If IsDate(.Value) Then
.Offset(0, 1).Value = CDate(Int(.Value) + H23M59)
End If
End With ' .Cells(i)
Next
End With ' rSel
End Sub
i tried modifying it to below and it failed me :(
`
Dim x As Integer
Dim test1 As Date
Dim schdWS, compWS As Worksheet
Const H23M59 As Double = 1 - 60 / 86400
Set schdWS = Sheet1
Set compWS = Sheet11
lastrow = schdWS.Cells(Rows.Count, 8).End(xlUp).Row
For x = 20 To lastrow
If IsDate(schdWS.Cells(x, 3).Value) Then
Cells(x, 3).Value = CDate(Int(Cells(x, 3).Value + H23M59))
End If
'test1.NumberFormat = "dd/mm/yyyy"
'schdWS.Cells(x, 3).FormulaR1C1 = test1 & " 23:59"
Next x
End Sub
`
I have a cell value, for example
A1 = 17/06/2016 19:00:46
i want to change it to 17/06/2016 19:00:00
so basically the seconds have to be 0 but i can not seem to be able to achieve that with the formatting. I did the format as dd/mm/yyyy hh:mm, but the seconds is still retaining.
i will be using these values to match the values in a different sheet using Application.Match in vba. the different sheet has the seconds as 0, hence, to match it i need to be convert these to 0 seconds.
Thank you.
The easier way to achieve this:
Function DateWithZeroSeconds(MyDate As Date)
DateWithZeroSeconds = Format(MyDate, "dd/mm/yyyy h:m") & ":00"
End Function
Select the cells you wish to convert and run this short macro:
Sub SecondKiller()
Dim d As Date, d2 As Date
For Each r In Selection
d = r.Value
r.Value = DateSerial(Year(d), Month(d), Day(d)) + TimeSerial(Hour(d), Minute(d), 0)
Next r
End Sub
An other way, format the Excel cell, and then show the seconds as 00's:
Sub FormatRange_AsDate(ByVal Rg As Range)
With Rg
.NumberFormat = "d/m/yyyy h:mm:ss;#" 'give the format to the cell , showing seconds
.Value = Format(.Value, "d/m/yyyy h:m") & ":00" 'changing the seconds to "00", don't use .value2
End With
End Sub
In the following picture of an Excel sheet, the heading of the first column, and then of every 7th column after that, contains a month and a year.
I am trying to think of some code which would make entering complete dates under these headings faster. Since the month and the year are already present, I'm thinking there must be a way to enter just the day, and get the whole thing. For example, if "21" were entered in cell A26, "2/21/2015" would result.
Anyone have an idea for how I might get this output?
Edit: Thanks to the helpful replies on this forum, I figured out exactly how to do this. Here is the code for my finished product, in case anyone wants to do something similar:
Private Sub Worksheet_change(ByVal Selection As Range)
Set Sel = Selection
If Sel.Count > 1 Then
Exit Sub
End If
If (Sel.Column - 1) Mod 7 = 0 Or Sel.Column = 1 Then
'In my case, date columns always follow the pattern of 1, 8, 15...
If Sel.Value > 31 Or Sel.Value = "" Then
Exit Sub
Else
Sel.NumberFormat = "General"
Sel.Value = Left(Cells(1, Sel.Column), InStr(Cells(1, Sel.Column), ",") - 1) & " " & _
Sel.Value & Right(Cells(1, Sel.Column), 6)
Selection.NumberFormat = "m/d/yyyy"
End If
End If
End Sub
How about entering the day numbers, selecting the range where these day numbers are entered, and running the below:
Sub Add_month_year()
Dim c As Range
For Each c In Selection
c = Left(Cells(1, c.Column), InStr(Cells(1, c.Column), ",") - 1) & " " & _
c.Value & Right(Cells(1, c.Column), 6)
Next
End Sub
This should return the full dates in date code, which you can then format as you see fit.
I am trying to create dates for each month individually. I have done my bit of work but looking for optimised code.
Steps
Create a Spreadsheet and change the name from "Sheet1" to "Year"
Column A ColumnB
2014 January
February
March
April
May
June
July
August
September
October
November
December
Now copy the below to VBA module
Sub GenerateDate()
Dim amonth As String
Dim col, cola As String
Dim ayear As Integer
For x = 1 To 12
Worksheets("Year").Select
Worksheets("Year").Activate
'//this will add every month worksheet
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = Cells(x, 2)
Worksheets("Year").Activate
'//get month name to string called amonth//
amonth = Cells(x, 2).Value
'//get year to variable type int called ayear//
ayear = Cells(1, 1).Value
'//activate month sheet
Worksheets(amonth).Activate
'//insert date 1st day of each month in cell A1
Cells(1, 1).Value = DateSerial(ayear, x, 1)
'//select 'A1' cell values
Cells(1, 1).Select
'// pass A1 value to a my_date
my_date = Cells(1, 1).Value
'//change the format of the date in A1 cell
Selection.NumberFormat = "d/mm/yyyy;#"
'//count number of days in month for the date in A1
numof_days = Day(DateSerial(Year(my_date), Month(my_date) + 1, 1) - 1)
'// col a and cola are two strings holds sting values "A" and "A1" respectively
col = "A"
cola = "A1"
'//Final value is range to be used to fill the dates
Final = col & numof_days
'//fill dates from A1 to Final cell values
With Range("A1")
.AutoFill Destination:=Range(cola, Final), Type:=xlFillDays
End With
'//auto fit the entire "A" column
Columns("A:A").EntireColumn.AutoFit
Next x
End Sub
My output
Creates new sheet for each month and generates dates for that month only.
As a first step you may find it more effective to add application.screenupdating = false at the beginning of your code and then application.screenupdating = true at the end. This will speed up your code. You may also consider doing the same for application.displayalerts.