How can I get a week number in access - ms-access

I've tried this but it returns text15 = 09/12/2020 Result = 2eek, I actually need week 2.
=Format(DatePart("ww",[Text15])-DatePart("ww",DateSerial(Year([Text15]),Month([Text15]),1))+1,"Week ")

you are almost there, try this:
= "Week " & (DatePart("ww",[Text15])-DatePart("ww",DateSerial(Year([Text15]),Month([Text15]),1))) + 1
or this:
="Week " & Abs(Int(-DatePart("d",[Text15])/7))

You can use a method similar to the ISO 8601 numbering of weeks:
' Calculates the "weeknumber of the month" for a date.
' The value will be between 1 and 5.
'
' Numbering is similar to the ISO 8601 numbering having Monday
' as the first day of the week and the first week beginning
' with Thursday or later as week number 1.
' Thus, the first day of a month may belong to the last week
' of the previous month, having a week number of 4 or 5.
'
' 2020-09-23. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function WeekOfMonth( _
ByVal Date1 As Date) _
As Integer
Dim ThursdayInWeek As Date
Dim FirstThursday As Date
Dim WeekNumber As Integer
ThursdayInWeek = DateWeekdayInWeek(Date1, vbThursday, vbMonday)
FirstThursday = DateWeekdayInMonth(ThursdayInWeek, 1, vbThursday)
WeekNumber = 1 + DateDiff("ww", FirstThursday, Date1, vbMonday)
WeekOfMonth = WeekNumber
End Function
As you can see, a supporting function is used:
Option Explicit
Public Const DaysPerWeek As Long = 7
Public Const MaxWeekdayCountInMonth As Integer = 5
' Calculates the "weeknumber of the month" for a date.
' The value will be between 1 and 5.
'
' Numbering is similar to the ISO 8601 numbering having Monday
' as the first day of the week and the first week beginning
' with Thursday or later as week number 1.
' Thus, the first day of a month may belong to the last week
' of the previous month, having a week number of 4 or 5.
'
' 2020-09-23. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function WeekOfMonth( _
ByVal Date1 As Date) _
As Integer
Dim ThursdayInWeek As Date
Dim FirstThursday As Date
Dim WeekNumber As Integer
ThursdayInWeek = DateWeekdayInWeek(Date1, vbThursday)
FirstThursday = DateWeekdayInMonth(ThursdayInWeek, 1, vbThursday)
WeekNumber = 1 + DateDiff("ww", FirstThursday, Date1, vbMonday)
WeekOfMonth = WeekNumber
End Function
' Calculates the date of DayOfWeek in the week of DateInWeek.
' By default, the returned date is the first day in the week
' as defined by the current Windows settings.
'
' Optionally, parameter DayOfWeek can be specified to return
' any other weekday of the week.
' Further, parameter FirstDayOfWeek can be specified to select
' any other weekday as the first weekday of a week.
'
' Limitation:
' For the first and the last week of the range of Date, some
' combinations of DayOfWeek and FirstDayOfWeek that would result
' in dates outside the range of Date, will raise an overflow error.
'
' 2017-05-03. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function DateWeekdayInWeek( _
ByVal DateInWeek As Date, _
Optional ByVal DayOfWeek As VbDayOfWeek = VbDayOfWeek.vbUseSystemDayOfWeek, _
Optional ByVal FirstDayOfWeek As VbDayOfWeek = VbDayOfWeek.vbUseSystemDayOfWeek) _
As Date
Dim DayInWeek As VbDayOfWeek
Dim OffsetZero As Integer
Dim OffsetFind As Integer
Dim ResultDate As Date
' Find the date of DayOfWeek.
DayInWeek = Weekday(DateInWeek)
' Find the offset of the weekday of DateInWeek from the first day of the week.
' Will always be <= 0.
OffsetZero = (FirstDayOfWeek - DayInWeek - DaysPerWeek) Mod DaysPerWeek
' Find the offset of DayOfWeek from the first day of the week.
' Will always be >= 0.
OffsetFind = (DayOfWeek - FirstDayOfWeek + DaysPerWeek) Mod DaysPerWeek
' Calculate result date using the sum of the offset parts.
ResultDate = DateAdd("d", OffsetZero + OffsetFind, DateInWeek)
DateWeekdayInWeek = ResultDate
End Function
' Calculates the date of the occurrence of Weekday in the month of DateInMonth.
'
' If Occurrence is 0 or negative, the first occurrence of Weekday in the month is assumed.
' If Occurrence is 5 or larger, the last occurrence of Weekday in the month is assumed.
'
' If Weekday is invalid or not specified, the weekday of DateInMonth is used.
'
' 2019-12-08. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function DateWeekdayInMonth( _
ByVal DateInMonth As Date, _
Optional ByVal Occurrence As Integer, _
Optional ByVal Weekday As VbDayOfWeek = vbUseSystemDayOfWeek) _
As Date
Dim Offset As Integer
Dim Month As Integer
Dim Year As Integer
Dim ResultDate As Date
' Validate Weekday.
Select Case Weekday
Case _
vbMonday, _
vbTuesday, _
vbWednesday, _
vbThursday, _
vbFriday, _
vbSaturday, _
vbSunday
Case Else
' vbUseSystemDayOfWeek, zero, none or invalid value for VbDayOfWeek.
Weekday = VBA.Weekday(DateInMonth)
End Select
' Validate Occurence.
If Occurrence < 1 Then
' Find first occurrence.
Occurrence = 1
ElseIf Occurrence > MaxWeekdayCountInMonth Then
' Find last occurrence.
Occurrence = MaxWeekdayCountInMonth
End If
' Start date.
Month = VBA.Month(DateInMonth)
Year = VBA.Year(DateInMonth)
ResultDate = DateSerial(Year, Month, 1)
' Find offset of Weekday from first day of month.
Offset = DaysPerWeek * (Occurrence - 1) + (Weekday - VBA.Weekday(ResultDate) + DaysPerWeek) Mod DaysPerWeek
' Calculate result date.
ResultDate = DateAdd("d", Offset, ResultDate)
If Occurrence = MaxWeekdayCountInMonth Then
' The latest occurrency of Weekday is requested.
' Check if there really is a fifth occurrence of Weekday in this month.
If VBA.Month(ResultDate) <> Month Then
' There are only four occurrencies of Weekday in this month.
' Return the fourth as the latest.
ResultDate = DateAdd("d", -DaysPerWeek, ResultDate)
End If
End If
DateWeekdayInMonth = ResultDate
End Function
Watch an example output here.

Related

Microsoft Access Form using "Date Code" to be autogenerated but is always 1 week behind

I'm not fluent in Access and am trying to figure out why the date code field is not propagating correctly. The field Screenshot of Date Code shows up as YYWWDD (Last two digits of Year, Week number of year, and day of work week (Monday = 1 - Friday = 5), but for the last two years the Week number of year has consistently been 1 week behind. As seen in the screenshot Date Code 20242 this is actually the 25 week since the first week of January.
the code in the property sheet is as follows:
=IIf(IsNull([DaySelected]),IIf(Len(Format(Date(),"ww",2,3))=1,Format(Date(),"yy") & "0" & Format(Date(),"ww w",2,3),Format(Date(),"yywww ",2,3)),IIf(Len(Format(Date(),"ww",2,3))=1,Format(Date(),"yy") & "0" & Format(Date(),"ww",2,3) & [DaySelected],Format(Date(),"yyww",2,3) & [DaySelected]))
Any help would be much appreciated.
Problem is, that the year is the ISO 8601 year, not the calendar year, and a custom function is needed to obtain the true ISO 8601 week number:
' Returns the ISO 8601 week of a date.
' The related ISO year is returned by ref.
'
' 2016-01-06. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function Week( _
ByVal Date1 As Date, _
Optional ByRef IsoYear As Integer) _
As Integer
Const MaxWeekValue As Integer = 53
Const MinWeekValue As Integer = 1
Const MaxMonthValue As Integer = 12
Const MinMonthValue As Integer = 1
Dim Month As Integer
Dim Interval As String
Dim Result As Integer
Interval = "ww"
Month = VBA.Month(Date1)
' Initially, set the ISO year to the calendar year.
IsoYear = VBA.Year(Date1)
Result = DatePart(Interval, Date1, vbMonday, vbFirstFourDays)
If Result = MaxWeekValue Then
If DatePart(Interval, DateAdd(Interval, 1, Date1), vbMonday, vbFirstFourDays) = MinWeekValue Then
' OK. The next week is the first week of the following year.
Else
' This is really the first week of the next ISO year.
' Correct for DatePart bug.
Result = MinWeekValue
End If
End If
' Adjust year where week number belongs to next or previous year.
If Month = MinMonthValue Then
If Result >= MaxWeekValue - 1 Then
' This is an early date of January belonging to the last week of the previous ISO year.
IsoYear = IsoYear - 1
End If
ElseIf Month = MaxMonthValue Then
If Result = MinWeekValue Then
' This is a late date of December belonging to the first week of the next ISO year.
IsoYear = IsoYear + 1
End If
End If
' IsoYear is returned by reference.
Week = Result
End Function
Then, build a simple custom function to generate your year-week-day number:
Public Function FormatWeekDayIso8601(ByVal DaySelected As Integer) As String
Dim Result As String
Dim IsoYear As Integer
Dim IsoWeek As Integer
IsoWeek = Week(Date, IsoYear)
Result = _
CStr(IsoYear Mod 100) & _
VBA.Format(IsoWeek, String(2, "0")) & _
CStr(DaySelected)
FormatWeekDayIso8601 = Result
End Function
Now, use it like this:
=FormatWeekDayIso8601(Nz([DaySelected],1))

Number of business days dynamic month

I need to make a report in Access about how many overtime every employee has. Because some workes work from Mo-Th 10h and Fr 0h i cant say
Count everything above 8h .
Therefore I need all business days a month * 8h and compare it with actual working time which I Sum by month ( already working! )
Solution approach:
SELECT Format([TaetigkeitsDatum],"mmmm yy") AS Monat,
tbl_Taetigkeitserfassung.TaetigkeitsPersonalID,
Sum(tbl_Taetigkeitserfassung.TaetigkeitsStundenAnzeigen) AS SummevonTaetigkeitsStundenAnzeigen
FROM tbl_Taetigkeitserfassung
GROUP BY Format([TaetigkeitsDatum],"mmmm yy"),
tbl_Taetigkeitserfassung.TaetigkeitsPersonalID;
This shows me the formatted Month(TaetigkeitsDatum), the Employee(TaetigkeitsPersonalID) and the Sum of the Working Hours ( TaetigkeitsStundenAnzeigen).
But I dont know how to display the hours of Business days that month so I can compare and display overtime...
Expected Solution:
January 19: 23Days (without Weekend, holidays dont matter) * 8h = 184h
Working Time of Mr.X = 186h -> 2h Overtime
DateDiff isnt working, because I need 2 Dates for it to work and than there is the "only count business days" problem.
You can use this expression:
WorkDays: ISO_WorkdayDiff(DateSerial(Year([TaetigkeitsDatum]), Month([TaetigkeitsDatum]), 1), DateSerial(Year([TaetigkeitsDatum]), Month([TaetigkeitsDatum]) + 1, 1))
and a function like this:
Public Function ISO_WorkdayDiff( _
ByVal datDateFrom As Date, _
ByVal datDateTo As Date, _
Optional ByVal booExcludeHolidays As Boolean) _
As Long
' Purpose: Calculate number of working days between dates datDateFrom and datDateTo.
' Assumes: 5 or 6 working days per week. Weekend is (Saturday and) Sunday.
' May be freely used and distributed.
' 1999-04-23. Gustav Brock, Cactus Data ApS, Copenhagen
' 2000-10-03. Constants added.
' Option for 5 or 6 working days per week added.
' 2008-06-12. Option to exclude holidays from the count of workdays.
Const cbytWorkdaysOfWeek As Byte = 5
' Name of table with holidays.
Const cstrTableHoliday As String = "tblHoliday"
' Name of date field in holiday table.
Const cstrFieldHoliday As String = "HolidayDate"
Dim bytSunday As Byte
Dim intWeekdayDateFrom As Integer
Dim intWeekdayDateTo As Integer
Dim lngDays As Long
Dim datDateTemp As Date
Dim strDateFrom As String
Dim strDateTo As String
Dim lngHolidays As Long
Dim strFilter As String
' Reverse dates if these have been input reversed.
If datDateFrom > datDateTo Then
datDateTemp = datDateFrom
datDateFrom = datDateTo
datDateTo = datDateTemp
End If
' Find ISO weekday for Sunday.
bytSunday = Weekday(vbSunday, vbMonday)
' Find weekdays for the dates.
intWeekdayDateFrom = Weekday(datDateFrom, vbMonday)
intWeekdayDateTo = Weekday(datDateTo, vbMonday)
' Compensate weekdays' value for non-working days (weekends).
intWeekdayDateFrom = intWeekdayDateFrom + (intWeekdayDateFrom = bytSunday)
intWeekdayDateTo = intWeekdayDateTo + (intWeekdayDateTo = bytSunday)
' Calculate number of working days between the two weekdays, ignoring number of weeks.
lngDays = intWeekdayDateTo - intWeekdayDateFrom - (cbytWorkdaysOfWeek * (intWeekdayDateTo < intWeekdayDateFrom))
' Add number of working days between the weeks of the two dates.
lngDays = lngDays + (cbytWorkdaysOfWeek * DateDiff("w", datDateFrom, datDateTo, vbMonday, vbFirstFourDays))
If booExcludeHolidays And lngDays > 0 Then
strDateFrom = Format(datDateFrom, "yyyy\/mm\/dd")
strDateTo = Format(datDateTo, "yyyy\/mm\/dd")
strFilter = cstrFieldHoliday & " Between #" & strDateFrom & "# And #" & strDateTo & "# And Weekday(" & cstrFieldHoliday & ", 2) <= " & cbytWorkdaysOfWeek & ""
lngHolidays = DCount("*", cstrTableHoliday, strFilter)
End If
ISO_WorkdayDiff = lngDays - lngHolidays
End Function

MS Access Query - Total Week Hours Worked

looking for some access query help.
Im trying to make a total hours worked in a week query.
TotalHours: (([FinishAM]-[StartAM]+[FinishPM]-[StartPM])*24 & " Hours")
Here's the query for the daily hours worked..
Im quite new to access.
cheers.
You can use:
' Specify begin and end time of daily working hours.
Const cdatWorkTimeStart As Date = #8:00:00 AM#
Const cdatWorkTimeStop As Date = #4:00:00 PM#
Const cbytWorkdaysOfWeek As Byte = 5
Dim TotalHours As Integer
TotalHours = DateDiff("h", cdatWorkTimeStart, cdatWorkTimeStop) * cbytWorkdaysOfWeek
For an extended count of hours for any count of days, you can use the full function here:
Public Function ISO_WorkTimeDiff( _
ByVal datDateTimeFrom As Date, _
ByVal datDateTimeTo As Date, _
Optional ByVal booNoHours As Boolean) _
As Long
' Purpose: Calculate number of working minutes between date/times datDateTimeFrom and datDateTimeTo.
' Assumes: 5 or 6 working days per week. Weekend is (Saturday and) Sunday.
' Returns: "Working minutes". Divide by 60 to obtain working hours.
' Limitation: Does not count for public holidays.
'
' May be freely used and distributed.
' 2001-06-26. Gustav Brock, Cactus Data ApS, Copenhagen
'
' If booNoHours is True, time values are ignored.
' Specify begin and end time of daily working hours.
Const cdatWorkTimeStart As Date = #8:00:00 AM#
Const cdatWorkTimeStop As Date = #4:00:00 PM#
Const cbytWorkdaysOfWeek As Byte = 5
Dim bytSunday As Byte
Dim intWeekdayDateFrom As Integer
Dim intWeekdayDateTo As Integer
Dim datTimeFrom As Date
Dim datTimeTo As Date
Dim lngDays As Long
Dim lngMinutes As Long
Dim lngWorkMinutesDaily As Long
' No special error handling.
On Error Resume Next
If DateDiff("n", datDateTimeFrom, datDateTimeTo) <= 0 Then
' Nothing to do. Return zero.
Else
' Calculate number of daily "working minutes".
lngWorkMinutesDaily = DateDiff("n", cdatWorkTimeStart, cdatWorkTimeStop)
' Find ISO weekday for Sunday.
bytSunday = Weekday(vbSunday, vbMonday)
' Find weekdays for the dates.
intWeekdayDateFrom = Weekday(datDateTimeFrom, vbMonday)
intWeekdayDateTo = Weekday(datDateTimeTo, vbMonday)
' Compensate weekdays' value for non-working days (weekends).
intWeekdayDateFrom = intWeekdayDateFrom + (intWeekdayDateFrom = bytSunday)
intWeekdayDateTo = intWeekdayDateTo + (intWeekdayDateTo = bytSunday)
' Calculate number of working days between the weeks of the two dates.
lngDays = (cbytWorkdaysOfWeek * DateDiff("w", datDateTimeFrom, datDateTimeTo, vbMonday, vbFirstFourDays))
' Add number of working days between the two weekdays, ignoring number of weeks.
lngDays = lngDays + intWeekdayDateTo - intWeekdayDateFrom - (cbytWorkdaysOfWeek * (intWeekdayDateTo < intWeekdayDateFrom))
If Not booNoHours = True Then
' Extract begin and stop hour (time) for the working period.
datTimeFrom = TimeSerial(Hour(datDateTimeFrom), Minute(datDateTimeFrom), Second(datDateTimeFrom))
datTimeTo = TimeSerial(Hour(datDateTimeTo), Minute(datDateTimeTo), Second(datDateTimeTo))
' Adjust times before or after daily working hours to boundaries of working hours.
If DateDiff("n", datTimeFrom, cdatWorkTimeStart) > 0 Then
datTimeFrom = cdatWorkTimeStart
ElseIf DateDiff("n", datTimeFrom, cdatWorkTimeStop) < 0 Then
datTimeFrom = cdatWorkTimeStop
End If
If DateDiff("n", datTimeTo, cdatWorkTimeStart) > 0 Then
datTimeTo = cdatWorkTimeStart
ElseIf DateDiff("n", datTimeTo, cdatWorkTimeStop) < 0 Then
datTimeTo = cdatWorkTimeStop
End If
' Calculate number of working minutes between the two days, ignoring number of days.
lngMinutes = DateDiff("n", datTimeFrom, datTimeTo)
End If
' Calculate number of working minutes between the two days using the workday count.
lngMinutes = lngMinutes + (lngDays * lngWorkMinutesDaily)
End If
ISO_WorkTimeDiff = lngMinutes
End Function

Need a Warning pop up message in Access

I want to use a VBA code to pop up a warning message in the start of my database and tell me the name of people that their ages passed 50 just for once the last i could reach is that
For i = 1 To 4
If [Forms]![1]![years] >=50 Then
MsgBox "employees:" & Me.name
End If
Next i
You can use my simple function:
Public Function AgeSimple( _
ByVal datDateOfBirth As Date) _
As Integer
' Returns the difference in full years from datDateOfBirth to current date.
'
' Calculates correctly for:
' leap years
' dates of 29. February
' date/time values with embedded time values
'
' DateAdd() is used for check for month end of February as it correctly
' returns Feb. 28. when adding a count of years to dates of Feb. 29.
' when the resulting year is a common year.
' After an idea of Markus G. Fischer.
'
' 2007-06-26. Cactus Data ApS, CPH.
Dim datToday As Date
Dim intAge As Integer
Dim intYears As Integer
datToday = Date
' Find difference in calendar years.
intYears = DateDiff("yyyy", datDateOfBirth, datToday)
If intYears > 0 Then
' Decrease by 1 if current date is earlier than birthday of current year
' using DateDiff to ignore a time portion of datDateOfBirth.
intAge = intYears - Abs(DateDiff("d", datToday, DateAdd("yyyy", intYears, datDateOfBirth)) > 0)
End If
AgeSimple = intAge
End Function
And a loop in the click event of a button on your form (example):
Dim rs As DAO.Recordset
Set rs = Me.RecordsetClone
If rs.RecordCount > 0 Then
rs.MoveFirst
End If
While Not rs.EOF
If AgeSimple(Nz(rs!DOB.Value, Date)) >= 50 Then
MsgBox "Employee: " & rs![Name].Value, vbInformation + vbOKOnly, "50+"
End If
rs.MoveNext
Wend
Set rs = Nothing
Of course, replace the field/control names here with those of your actual form.
Edit
A demo is here

How to get correct week number in Access

I get a large data set every week, with Start Date and End Date, Start Date is always Monday and End Date is always Sunday. I want to be able to do a rolling YTD on Sales for different products by week. I am trying to give each week's data a week number. But my first week is 12/28/2015-1/3/2016, it keeps giving me week 53 instead of week 1. I saw another person's post on the same issue and dbDesigner's answer actually works:
Get the week number from a given date
But this gives me 2016-01 in one column. I want two columns with one for correct week number and one for correct year to be able to do a sub query for my rolling YTD sales. For example for my first week 12/28/2015-1/3/2016, it will be week: 1 and year:2016
Thanks.
First, none of the week numbering methods in VBA follows the ISO 8601 standard.
Second, the week number of the week 2015-12-28 to 2016-01-03 is not the first of 2106 but 2015W53.
You can retrieve the correct ISO 8601 week number for any date with a function like this:
Public Function ISO_WeekYearNumber( _
ByVal datDate As Date, _
Optional ByRef intYear As Integer, _
Optional ByRef bytWeek As Byte) _
As String
' Calculates and returns year and week number for date datDate according to the ISO 8601:1988 standard.
' Optionally returns numeric year and week.
' 1998-2007, Gustav Brock, Cactus Data ApS, CPH. Public Function ISO_WeekNumber( _
ByVal datDate As Date) _
As Byte
' Calculates and returns week number for date datDate according to the ISO 8601:1988 standard.
' 1998-2000, Gustav Brock, Cactus Data ApS, CPH.
' May be freely used and distributed.
Const cbytFirstWeekOfAnyYear As Byte = 1
Const cbytLastWeekOfLeapYear As Byte = 53
Dim bytWeek As Byte
Dim bytISOThursday As Byte
Dim datLastDayOfYear As Date
bytWeek = DatePart("ww", datDate, vbMonday, vbFirstFourDays)
If bytWeek = cbytLastWeekOfLeapYear Then
bytISOThursday = Weekday(vbThursday, vbMonday)
datLastDayOfYear = DateSerial(Year(datDate), 12, 31)
If Weekday(datLastDayOfYear, vbMonday) >= bytISOThursday Then
' OK, week count of 53 is caused by leap year.
Else
' Correct for Access97/2000 bug.
bytWeek = cbytFirstWeekOfAnyYear
End If
End If
ISO_WeekNumber = bytWeek
End Function
' May be freely used and distributed.
Const cbytFirstWeekOfAnyYear As Byte = 1
Const cbytLastWeekOfLeapYear As Byte = 53
Const cbytMonthJanuary As Byte = 1
Const cbytMonthDecember As Byte = 12
Const cstrSeparatorYearWeek As String = "W"
Dim bytMonth As Byte
Dim bytISOThursday As Byte
Dim datLastDayOfYear As Date
intYear = Year(datDate)
bytMonth = Month(datDate)
bytWeek = DatePart("ww", datDate, vbMonday, vbFirstFourDays)
If bytWeek = cbytLastWeekOfLeapYear Then
bytISOThursday = Weekday(vbThursday, vbMonday)
datLastDayOfYear = DateSerial(intYear, cbytMonthDecember, 31)
If Weekday(datLastDayOfYear, vbMonday) >= bytISOThursday Then
' OK, week count of 53 is caused by leap year.
Else
' Correct for Access97/2000+ bug.
bytWeek = cbytFirstWeekOfAnyYear
End If
End If
' Adjust year where week number belongs to next or previous year.
If bytMonth = cbytMonthJanuary Then
If bytWeek >= cbytLastWeekOfLeapYear - 1 Then
' This is an early date of January belonging to the last week of the previous year.
intYear = intYear - 1
End If
ElseIf bytMonth = cbytMonthDecember Then
If bytWeek = cbytFirstWeekOfAnyYear Then
' This is a late date of December belonging to the first week of the next year.
intYear = intYear + 1
End If
End If
ISO_WeekYearNumber = CStr(intYear) & cstrSeparatorYearWeek & Format(bytWeek, "00")
End Function
If you just need the week number itself, a function like this can be used:
Do you understand the solution you refer to?
Because if you do, you should notice that year and week are concatinated.
So you should undo concatination.