#Variatus Ref the macro you have been working on, for a Friday production the shift will still start at 05:30 but end at 18:30 and if Saturday production the shift will start at 07:00 and finish at 14:00. am I correct in thinking I need to add another Enum called Day 5 Nsh with the start and end time and then same again for day 6 calling it Day 6 Nsh. If this is correct then in the sub Setcompletion how would I call this. would it need to be referenced any where else in the macro also?
Enum Nws ' Worksheet navigation
NwsFirstDataRow = 2
NwsQty = 1 ' Columns (not necessarily contiguous):
NwsTime ' time to produce one unit
NwsStart ' date/time
NwsEnd ' date/time
End Enum
Enum Nsh ' Shift (use 24h format)
NshStart = 530 ' read as 05:30 (on current day)
NshEnd = 2430 ' read as 00:30 (on next day)
End Enum
next
Sub SetCompletion(ws As Worksheet, R As Long)
' 25 Mar 2017
Dim Qty As Long
Dim ShiftQty As Long, DayQty As Long
Dim UnitTime As Double, StartTime As Double
Dim ComplDate As Double
Dim Days As Integer
With Rows(R)
Qty = .Cells(NwsQty).Value
UnitTime = .Cells(NwsTime).Value
StartTime = .Cells(NwsStart).Value
If Qty And (UnitTime > 0) And (StartTime > 0) Then
ComplDate = (UnitTime * Qty) + StartTime
ShiftQty = QtyTillShiftEnd(StartTime, UnitTime)
If ShiftQty < Qty Then
Qty = Qty - ShiftQty
DayQty = DailyProduction(UnitTime)
ComplDate = Int(StartTime) + 1 + NshToDays(NshStart) + Int(Qty / DayQty)
ComplDate = ComplDate + UnitTime * (Qty Mod DayQty)
End If
.Cells(NwsEnd).Value = ComplDate
End If
End With
End Sub
next
Private Function QtyTillShiftEnd(ByVal StartTime As Double, _
ByVal UnitTime As Double) As Double
' 20 Mar 2017
Dim ProdTime As Double
ProdTime = (Int(StartTime) + NshToDays(NshEnd) - StartTime)
QtyTillShiftEnd = (ProdTime + 0.0001) / UnitTime
End Function
next
Private Function DailyProduction(UnitTime As Double) As Integer
' 19 Mar 2017
DailyProduction = Int((NshToDays(NshEnd) - NshToDays(NshStart) + 0.000001) / UnitTime)
End Function
next
Private Function NshToDays(TimeCode As Nsh) As Double
' 19 Mar 2017
Dim H As Double, M As Double
H = Int(TimeCode / 100)
M = TimeCode Mod 100
NshToDays = (1 / 24 * H) + (1 / 24 / 60 * M)
End Function
next
Function AdjustedStartTime(ByVal StartTime As Double) As Double
' 19 Mar 2017
' return new StartTime or 0
Dim Fun As Double
Dim StartDate As Long
Dim ShiftStart As Double, ShiftEnd As Double
ShiftStart = NshToDays(NshStart)
ShiftEnd = NshToDays(NshEnd)
StartDate = Int(StartTime)
StartTime = StartTime - StartDate
Fun = StartTime
If ShiftEnd > 1 Then
If StartTime < (ShiftStart - Int(ShiftStart)) Then
If StartTime > (ShiftEnd - Int(ShiftEnd)) Then Fun = ShiftStart
End If
Else
If (StartTime - Int(StartTime)) < ShiftStart Then
Fun = ShiftStart
Else
If StartTime > ShiftEnd Then Fun = ShiftStart + 1
End If
End If
AdjustedStartTime = Fun + StartDate
End Function
Plese set up a named range in your workbook and call it "SpecialDays". I suggest you create a dedicated worksheet to house it and make it accessible throughout the workbook. The picture below illustrates and explains.
The program's logic will be like this:-
There will be no production on any day marked as Holiday
There will be a short shift on any day marked as "Half shift"
There will be a full shift on any day marked as "full shift"
There will be no work on weekends unless the days are marked as Special Days
There will be a full shift on all other days
The important part of this list is in the sequence: whichever condition applies first is the condition that prevails. For example, there will be a full shift on Sunday Dec 31 because the condition for "full shift" is met before that of the day being a Sunday, but if it were also listed as a holiday (in a second row, anywhere in the list) there would be no work because holidays are filtered out first.
In order to connect the range to your code, please add these three lines above the enums on your code sheet.
' a named range of this name must exist:
' it must have 2 columns, first with a date, 2nd with a number as Nsh
Const SpecialDays As String = "SpecialDays"
You can change the name of the range here, but must make sure that you use the same name here and on the worksheet where you name the range.
Now, as you already suggested, the Enum Nsh needs to be extended. Here it is. Just replace the existing with the new, in its entirety (meaning form the declaration to "End Enum".
Enum Nsh ' Shift
' 28 Mar 2017
NshFullShift = 0
NshHalfShift
NshNoShift
NshStart = 530 ' read as 05:30 (on current day)
NshEnd = 2430 ' read as 00:30 (on next day)
NshHalfStart = 700 ' (use 24h format)
NshHalfEnd = 1400
End Enum
The first three enumeration correspond to the numbers you may enter in the "SpecialDays" range's 2nd column.
Of course, the SetCompletion procedure must be modified. It now calculates each day's production individually instead of presuming that every day's output is the same.
Sub SetCompletion(Ws As Worksheet, R As Long)
' 28 Mar 2017
Dim Qty As Long, ShiftQty As Long
Dim CommenceTime As Double, UnitTime As Double
Dim ComplTime As Double
With Rows(R)
Qty = .Cells(NwsQty).Value
UnitTime = .Cells(NwsTime).Value
CommenceTime = .Cells(NwsStart).Value
If Qty And (UnitTime > 0) And (CommenceTime > 0) Then
ComplTime = CommenceTime + (UnitTime * Qty)
Qty = Qty - QtyTillShiftEnd(CommenceTime, UnitTime)
If Qty > 0 Then
Do While Qty > 0
ComplTime = Int(ComplTime) + 1
ShiftQty = DailyProduction(ComplTime, UnitTime)
If Qty > ShiftQty Then
Qty = Qty - ShiftQty
Else
ComplTime = ComplTime + StartTime(ShiftType(ComplTime)) + (Qty * UnitTime)
Exit Do
End If
Loop
End If
.Cells(NwsEnd).Value = ComplTime
End If
End With
End Sub
The daily production is different on different days. The new function therefore receives the date as an argument and calculates the production according to what kind of day it is: Holiday, half-shift or full-shift day. Of course, the same holds true for the calculation on the first day of production which starts at the CommenceTime, not the start of the shift.
Private Function QtyTillShiftEnd(ByVal CommenceTime As Double, _
ByVal UnitTime As Double) As Double
' 28 Mar 2017
Dim ProdTime As Double
Dim ShType As Nsh
ShType = ShiftType(CommenceTime)
ProdTime = Int(CommenceTime) + EndTime(ShType) - CommenceTime
QtyTillShiftEnd = Int((ProdTime + 0.0001) / UnitTime)
End Function
Private Function DailyProduction(ShiftDay As Double, _
UnitTime As Double) As Integer
' 28 Mar 2017
Dim ShType As Nsh
ShType = ShiftType(ShiftDay)
DailyProduction = Int((EndTime(ShType) - StartTime(ShType) + 0.0001) / UnitTime)
End Function
The NshToDays function remains unchanged in principle, but I modified the method by which the parameter is received (ByVal instead of the previous default ByRef).
Private Function NshToDays(ByVal TimeCode As Nsh) As Double
' 28 Mar 2017
Dim H As Double, M As Double
H = Int(TimeCode / 100)
M = TimeCode Mod 100
NshToDays = (1 / 24 * H) + (1 / 24 / 60 * M)
End Function
The next function has undergone a complete overhaul. It will now find the start of the next shift even if the entered start time is several days from where it should be.
Function AdjustedStartTime(ByVal CommenceTime As Double) As Double
' 28 Mar 2017
' return new CommenceTime or 0
Dim StartDate As Long
Dim ShType As Nsh
StartDate = Int(CommenceTime)
' if StartDate isn't a workday, then loop for a workday
Do
ShType = ShiftType(StartDate)
If ShType <> NshNoShift Then Exit Do
StartDate = StartDate + 1
Loop
If StartDate < CommenceTime Then
' StartDate is a workday:
If CommenceTime > (StartDate + EndTime(ShType)) Then
StartDate = StartDate + 1
End If
End If
If StartDate < CommenceTime Then
CommenceTime = CommenceTime - StartDate
CommenceTime = Application.Max(CommenceTime, StartTime(ShType))
Else
CommenceTime = StartTime(ShType)
End If
AdjustedStartTime = CommenceTime + StartDate
End Function
The FormatCells procedure is the sole survivor from March 25. I believe you have taken complete charge of it and know how to modify it to do what you want if it doesn't do so on its own.
There are three more new procedures which you can paste at the bottom of your code sheet (not the one with the even procedure). ShiftType is the function which refers to the SpecialDays and determines which, if any, are the start and end times for the daily shift.
Private Function ShiftType(ByVal ShiftDate As Double) As Nsh
' 28 Mar 2017
Dim Fun As Nsh
Dim Rng As Range, Fnd As Range
Dim Fmt As String
ShiftDate = Int(ShiftDate)
Set Rng = ThisWorkbook.Names(SpecialDays).RefersToRange.Columns(1)
With Rng
Fmt = .Cells(1).NumberFormat
.NumberFormat = "General"
Set Fnd = .Find(What:=ShiftDate, LookIn:=xlFormulas)
.NumberFormat = Fmt
End With
If Fnd Is Nothing Then
Fun = Application.Weekday(ShiftDate)
If (Fun = vbSaturday) Or (Fun = vbSunday) Then
Fun = NshNoShift
Else
Fun = NshFullShift
End If
Else
Fun = CLng(Val(Fnd.Offset(0, 1).Value))
Fun = Application.Min(Fun, NshNoShift)
Fun = Application.Max(Fun, NshFullShift)
End If
ShiftType = Fun
End Function
The last two functions return the StartTime and EndTime depending upon the ShiftType. Note that they return 0 (zero) for off-days.
Private Function StartTime(ShType As Nsh) As Double
' 28 Mar 2017
On Error Resume Next
StartTime = NshToDays(Array(NshStart, NshHalfStart, 0)(ShType))
Err.Clear
End Function
Private Function EndTime(ShType As Nsh) As Double
' 28 Mar 2017
On Error Resume Next
EndTime = NshToDays(Array(NshEnd, NshHalfEnd, 0)(ShType))
Err.Clear
End Function
Basically, your code works as before but it has become a lot more complex, meaning it has a lot more points where something may have gone without sufficient attention. My hope is that you will be able to find the procedure responsible for any fault you might discover and either can fix it yourself. After all, each procedure is rather simple in itself. Good luck!
Related
I need to automatically calculate a Start Date (aka QRT_START) which is 5 years of Quarters back. A Quarter is 3 months. For example, there are 4 Quarters in a Year: March 31st, June 30th, September 30th and December 31st.
Since we are currently in November 16th 2022, the Start Date would be December 31st 2017. So depending on whatever the current date is, the Start Date needs to go back 5 years worth of Quarters.
I also need to automatically calculate the most recent End Date (aka QRT_END). So since, we are in November 16th 2022, the End Date would be the previous quarter end before today which is September 30th 2022. I have the VBA code written below, please help me fix.
Private Function getQRT_END() As String
Dim endmonth As Variant
Dim endyear As Variant
Dim Day As Variant
endmonth = Month(Date) - 1
If endmonth = 0 Then
endyear = Year(Date) - 1
endmonth = 12
day = 31
Else
endyear = Year(Date)
If endmonth = 3 Then
day = 31
Else
day = 30
End if
endmonth = “0” & endmonth
End If
getQRT_END = endyear & endmonth & day
End Function
Private Function getQRT_START() As String
Dim startmonth As Variant
Dim startyear As Variant
Dim Day As Variant
startyear = Year(Date) - 5
startmonth = Month(Date) + 2
If startmonth <10 Then
If startmonth = 3 Then
day = 31
Else
day = 30
End if
startmonth = “0” & startmonth
Else
day = 30
End If
getQRT_START = startyear & startmonth & day
End Function
Function GetQuartal(years, data)
d = DateAdd("yyyy", years, data)
q = (Month(d) + 2) \ 3
qstart = DateSerial(Year(d), (q - 1) * 3 + 1, 1)
qend = DateSerial(Year(d), q * 3 + 1, 1) - 1
GetQuartal = Array(data, d, qstart, qend)
End Function
Sub test()
Debug.Print "Date", "Date-5Y", "QY-5 Start", "QY-5 End"
For Each d In Array(Date, #2/29/2000#, #12/1/2021#, #5/5/1992#)
q = GetQuartal(-5, d)
Debug.Print q(0), q(1), q(2), q(3)
Next
End Sub
Date Date-5Y QY-5 Start QY-5 End
17.11.2022 17.11.2017 01.10.2017 31.12.2017
29.02.2000 28.02.1995 01.01.1995 31.03.1995
01.12.2021 01.12.2016 01.10.2016 31.12.2016
05.05.1992 05.05.1987 01.04.1987 30.06.1987
You can use two functions found in my library at GitHub: VBA.Date.
? DateThisQuarterUltimo(DateAdd("yyyy", -5, Date))
2017-12-31
? DatePreviousQuarterUltimo(DateAdd("yyyy", -5, Date))
2017-09-30
They are simple high-level functions:
' Returns the ultimo date of the quarter of the date passed.
'
' 2016-01-13. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function DateThisQuarterUltimo( _
ByVal DateThisQuarter As Date) _
As Date
Dim Interval As String
Dim Number As Double
Dim ResultDate As Date
Number = 0
Interval = IntervalSetting(DtInterval.dtQuarter)
ResultDate = DateIntervalUltimo(Interval, Number, DateThisQuarter)
DateThisQuarterUltimo = ResultDate
End Function
' Returns the ultimo date of the quarter preceding the quarter of the date passed.
'
' 2016-01-13. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function DatePreviousQuarterUltimo( _
ByVal DateThisQuarter As Date) _
As Date
Dim Interval As String
Dim Number As Double
Dim ResultDate As Date
Number = -1
Interval = IntervalSetting(DtInterval.dtQuarter)
ResultDate = DateIntervalUltimo(Interval, Number, DateThisQuarter)
DatePreviousQuarterUltimo = ResultDate
End Function
Haven't tested it completely
You can use DateSerial, DateAdd and DatePart to achieve what you want...
Option Explicit
Sub Sample()
Dim D As Date
Dim prevD As Date
D = DateSerial(2022, 11, 16)
'~~> Date 5 years years ago
prevD = DateAdd("q", -(4 * 5), D)
'~~> Last date of the quarter for a specific date
Debug.Print DateAdd("q", DatePart("q", prevD), DateSerial(Year(prevD), 1, 1)) - 1
'OUTPUT : 31-12-2017
'~~> Last date of previous quarter for a specific date
Debug.Print DateAdd("q", DatePart("q", D) - 1, DateSerial(Year(D), 1, 1)) - 1
'OUTPUT : 30-09-2022
End Sub
Changed string part to a proper date.
I am aware that this question has been asked in many different forms, but I would like to show my case as I have not found the perfect solution for it.
So, what I need to do is divide every month in 4 or 5 weeks, and type it into the corresponding cells.
Example :
I have tried this sample code written by User : danieltakeshi in this thread :
https://stackoverflow.com/a/47393516/11969596
But it has a flaw in it, for example if you type a date from October 2021 the result outputs 6 weeks which is impossible :
Sub WeeksInMonth()
Dim MonthYear As String, txt As String
Dim InputDate As Date, MonthYearDay As Date
Dim i As Long, intDaysInMonth As Long, j As Long
Dim MyArray As Variant
Dim arr As New Collection, a
ReDim MyArray(0 To 31)
j = 0
InputDate = ("1 / 10 / 2021") ' Date from October
MonthYear = Month(InputDate) & "/" & Year(InputDate)
intDaysInMonth = Day(DateSerial(Year(MonthYear), Month(MonthYear) + 1, 0))
For i = 1 To intDaysInMonth
MonthYearDay = DateSerial(Year(InputDate), Month(InputDate), i)
MyArray(j) = Application.WorksheetFunction.WeekNum(MonthYearDay)
j = j + 1
Next i
ReDim Preserve MyArray(0 To j - 1)
On Error Resume Next
For Each a In MyArray
arr.Add a, CStr(a)
Next
For i = 1 To arr.Count
Debug.Print arr(i)
Next
End Sub
Please help me find a solution, or tell me how I can adapt it to my current situation.
Cordially,
This routine checks for the first and last workingday (monday to friday) and then gives the calendar weeks for that date range
Option Explicit
Public Sub test_getWeeknumbersForMonth()
Dim arr As Variant
arr = getWeekNumbersForMonth("1.10.2021")
Debug.Print "1.10.2021: ", Join(arr, " - ")
arr = getWeekNumbersForMonth("1.1.2022")
Debug.Print "1.1.2022: ", Join(arr, " - ")
End Sub
Public Function getWeekNumbersForMonth(inputDate As Date) As Variant
Dim datStart As Date
datStart = getFirstWorkingDayOfMonth(inputDate)
Dim datEnd As Date
datEnd = getLastWorkingDayOfMonth(inputDate)
Dim arrWeekNumbers As Variant
ReDim arrWeekNumbers(1 To 6) 'max 6 weeks can be returned
Dim i As Long: i = 1
Dim dat As Date
dat = datStart
While dat <= datEnd
arrWeekNumbers(i) = getCalendarWeek(dat)
i = i + 1
dat = DateAdd("ww", 1, dat)
Wend
ReDim Preserve arrWeekNumbers(i - 1)
getWeekNumbersForMonth = arrWeekNumbers
End Function
Private Function getFirstWorkingDayOfMonth(inputDate As Date) As Date
Dim datToCheck As Date: datToCheck = DateSerial(Year(inputDate), Month(inputDate), 1) - 1
Dim isWorkingday As Boolean
Do
datToCheck = datToCheck + 1
isWorkingday = Weekday(datToCheck, vbMonday) <= 5
Loop Until isWorkingday = True
getFirstWorkingDayOfMonth = datToCheck
End Function
Private Function getLastWorkingDayOfMonth(inputDate As Date) As Date
Dim datToCheck As Date: datToCheck = DateSerial(Year(inputDate), Month(inputDate) + 1, 1)
Dim isWorkingday As Boolean
Do
datToCheck = datToCheck - 1
isWorkingday = Weekday(datToCheck, vbMonday) <= 5
Loop Until isWorkingday = True
getLastWorkingDayOfMonth = datToCheck
End Function
Private Function getCalendarWeek(inputDate As Date) As Long
'european iso week - CW 1 = week with first thursday
getCalendarWeek = Application.WorksheetFunction.IsoWeekNum(inputDate)
'use weeknum-function -adjust second parameter to your needs
'https://support.microsoft.com/en-us/office/weeknum-function-e5c43a03-b4ab-426c-b411-b18c13c75340
'getCalendarWeek = Application.WorksheetFunction.WeekNum(inputDate, 2)
End Function
First, some months have dates in six weeks.
Next, VBA natively can't return the correct ISO 8601 weeknumbers:
How to get correct week number in Access
Finally, week numbers don't care about workdays or weekends. If you wish to exclude weeks that don't include specific weekdays, filter on the dates of these.
I would like to create a date column formatted via "mmm-yyyy" but starting with next year's date, i.e.
Jan-2020
Feb-2020
Mar-2020
Apr-2020
May-2020
Jun-2020
Jul-2020
Aug-2020
Sep-2020
Oct-2020
Nov-2020
Dec-2020
My code only created the same month for 12 times. Can any one help me with this?
My current code
Sub demo()
'month recurring till dec
Dim x As Integer
Dim i As Integer
For x = 1 To 12
For i = 1 To 12
StartDate = (month(x + 1)) & "-" & (Year(Now())) + 1
Cells(i, 1).Value = StartDate
Cells(i, 1).NumberFormat = "mmm-yyyy"
Next i
Next x
End Sub
Write month dates into column
You have several issues here. Basically you aren't incrementing the year (correct: Year(Now) + increment) and you are overwriting each target cell 12-times with the last calculated value.
Working example procedure
Option Explicit ' declaration head of your code module
Sub demo()
With Sheet1 ' << Reference the sheet's CodeName, e.g. Sheet1
Dim repetition As Long ' << Long, provide for counters greater than ~65K
For repetition = 1 To 10 ' << change to ..= 1 to 1 if only one column :-)
Dim mon As Long
For mon = 1 To 12
' calculate month date via DateSerial function (arguments year,month,day)
Dim StartDate As Date
StartDate = DateSerial(Year(Now) + repetition, mon, 1)
' write to fully referenced range - note the prefixed "." referring to the sheet object
.Cells((repetition - 1) * 12 + mon, 1).Value = StartDate
.Cells((repetition - 1) * 12 + mon, 1).NumberFormat = "mmm-yyyy"
Next mon
Next repetition
End With
End Sub
Problem
The following [mcve] will output an array of arrays of week numbers between two dates. It works when both dates are on the same year, however, some years have 52 weeks and start within the last days of the last year. And others have 53 weeks.
An example of 52 weeks is the 2020 calendar:
Where the first week begins on Dec 30.
And the example of 53 weeks is the 2016 calendar:
That begins only on Jan 4th.
Code
The following code is commented and outputs an array of arrays with the week numbers.
Sub w_test()
Dim Arr() As Variant, ArrDateW() As Variant
'Initial Date
DateI = DateSerial(2015, 5, 5)
'Final Date
DateF = DateSerial(2017, 9, 20)
'Difference in weeks between DateI and DateF
weekDif = DateDiff("ww", DateI, DateF) + k - 1
i = Weekday(DateI)
d = DateI
'If not Sunday, go back to last week, to start the loop
If i <> 1 Then
d = DateAdd("d", -(i - 1), d)
End If
ReDim ArrDateW(weekDif)
ReDim Arr(2)
'Loop on all weeks between two dates to populate array of arrays
For i = 0 To weekDif
'Date
Arr(0) = d
'Trying to solve problem with New Year
If Application.WorksheetFunction.WeekNum(d) = 53 Then
flag = True
End If
If flag = False Then
Arr(1) = Application.WorksheetFunction.WeekNum(d)
Else
Arr(1) = Application.WorksheetFunction.WeekNum(DateSerial(Year(d) + 1, 1, 1))
flag = False
End If
'Year
Arr(2) = Year(d)
'Populate array of arrays
ArrDateW(i) = Arr
'Next Week Number
d = DateAdd("ww", 1, d)
Next i
'To stop with Ctrl+F8
Debug.Print d
End Sub
Question
2015 had 53 weeks, however the program outputs the following:
And between 2016 and 2017, the output is a mess:
How to fix the program to output these week numbers correctly?
I went about it somewhat differently, relying on built-in VBA functions to correctly calculate the week numbers. Read about ISO week numbers is this answer and see how I'm using the DataPart function -- though you can substitute your own version of Ron de Bruin's ISO week number function if you feel it's warranted.
A couple of quick side notes:
Always use Option Explicit
Try to use more descriptive variable names. YOU know what you're talking about NOW. In a few months, you'll struggle to remember what d and Arr mean (even if it seems obvious now). It's just a good habit and makes the code self-documenting.
My example below breaks the logic into a separate function with an optional parameter (just for fun) that would allow the caller to change the start of the week to a different day.
Code module:
Option Explicit
Sub w_test()
Dim initialDate As Date
Dim finaldate As Date
initialDate = #5/5/2015#
finaldate = #9/29/2017#
Dim weeks As Variant
weeks = WeekNumbers(initialDate, finaldate)
Debug.Print "There are " & UBound(weeks, 1) & " weeks between " & _
Format(initialDate, "dd-mmm-yyyy") & " and " & _
Format(finaldate, "dd-mmm-yyyy")
End Sub
Private Function WeekNumbers(ByVal initialDate As Date, _
ByVal finaldate As Date, _
Optional ByVal weekStart As VbDayOfWeek = vbSunday) As Variant
Dim numberOfWeeks As Long
numberOfWeeks = DateDiff("ww", initialDate, finaldate, weekStart, vbFirstFullWeek)
Dim startOfWeek As Date
If Weekday(initialDate) <> vbSunday Then
Dim adjustBy As Long
If Weekday(initialDate) > weekStart Then
adjustBy = Weekday(initialDate) - weekStart
Else
adjustBy = (Weekday(initialDate) + 7) - weekStart
End If
startOfWeek = DateAdd("d", -adjustBy, initialDate)
End If
Dim allTheWeeks As Variant
ReDim allTheWeeks(1 To numberOfWeeks)
Dim weekInfo As Variant
ReDim weekInfo(1 To 3)
Dim i As Long
For i = 1 To numberOfWeeks
weekInfo(1) = startOfWeek
weekInfo(2) = DatePart("ww", startOfWeek, weekStart, vbFirstFourDays)
weekInfo(3) = Year(startOfWeek)
allTheWeeks(i) = weekInfo
startOfWeek = DateAdd("ww", 1, startOfWeek)
Next i
WeekNumbers = allTheWeeks
End Function
When planning projects we give a approximate duration in weeks. A project starts on the next Monday from today.
Public Function NextMonday() As Date
Dim D As Integer
Dim N As Date
D = Weekday(Now)
N = Now() + (9 - D)
NextMonday = N
End Function
With this code I can assign the right date to a cell (Next Monday). Now i need to get the next Friday 12 weeks from that date. (84 Days)
For this i used the previous code and adjusted it a little.
Public Function NextFriday(AproxDate As Date) As Date
Dim E As Integer
Dim M As Date
E = Weekday(Now)
M = AproxDate + (14 - E)
NextFriday = M
End Function
Now for the main module the code looks like;
Private Sub Worksheet_Activate()
Dim wbCurrent As Workbook
Dim wsCurrent As Worksheet
Dim StartDate As Range
Dim AproxDate As Date
Dim EndDate As Range
Set wbCurrent = ThisWorkbook
Set wsCurrent = wbCurrent.Sheets("Sheet1")
Set StartDate = wsCurrent.Range("C15")
Set EndDate = wsCurrent.Range("C16")
Call NextMonday
StartDate.Value = NextMonday
'Setting Monday 12 weeks from StartDate
AproxDate = NextMonday + 84
Call NextFriday(AproxDate)
EndDate.Value = NextFriday
End Sub
The NextMonday part works fine, but when running the NextFriday i get an "Argument Not Optional" When trying to set the EndDate.Value = NextFriday.
I cant seem to find the problem with this code. Any thoughts?
This is not how you get a value from a function:
Call NextFriday(AproxDate)
EndDate.Value = NextFriday
If you want the value that function NextFriday returns based on (AproxDate) and you want that value in cell EndDate then (instead of both lines above) you would use:
EndDate.Value = NextFriday(AproxDate)
You only use Call with a function if you do not want a value to be returned from it.
Simplified Procedures:
Your procedure are needlessly overcomplicated.
Believe it or not, this is exactly the same as your procedures:
Public Function NextMonday() As Date
NextMonday = Now() + (9 - Weekday(Now))
End Function
Public Function NextFriday(AproxDate As Date) As Date
NextFriday = AproxDate + (14 - Weekday(Now))
End Function
Private Sub Worksheet_Activate()
.Range("C15")= NextMonday
ThisWorkbook.Sheets("Sheet1").Range("C16")= NextFriday(NextMonday + 84)
End Sub
Simplified even further:
Going a step further, this is 1 sub is exactly the same as the 3 procedures above:
Private Sub Worksheet_Activate()
With Sheets("Sheet1")
.Range("C15") = Now() + (9 - Weekday(Now))
.Range("C16") = (.Range("C15") + 84) + (14 - Weekday(Now))
End With
End Sub
One more thing to note, function Now returns the current date+time. Id it's only the date you're interested in, use function Date.
You have 2 mistakes in your Next Friday function.
1) from Monday to Friday in Weekdays is +4 and not +5 (so you get Next Monday = +9 and next Friday = +(9+4) )
2) You took the now() instead of aproxdate in the next friday code
Your code for next friday should be:
Public Function NextFriday(AproxDate As Date) As Date
Dim E As Integer
Dim M As Date
E = Weekday(AproxDate)
M = AproxDate + (13 - E)
NextFriday = M
End Function
Then you can call the function as in the other answer
var d = new Date();
d.setDate(d.getDate() + (5+7 - d.getDay()) % 7);
document.write(d);
This is a Javascript code which will result you next friday, the only condition where it fails if it is a friday.