Working out core and unsocial shift hours (1 Viewer)

Mattkitch80

New member
Local time
Today, 00:05
Joined
Jan 22, 2019
Messages
8
Hi all (first post so bare with):confused:

Fairly new to access but do know some SQL and have been using this mainly rather then the builder (Just find it easier this way!)

I have a date, as date only, start and end times of shifts as time values only in a table . I have a core start time as 06:00 and unsocial start at 20:00. I need to work out the hours worked between core and unsocial. Just to complicate things, it also needs to calculate the switch between a date in unsocial to a core day.

There is also another table for the core start and Unsocial start times (dependent of type of worker)

Example 1

Normal working day Tuesday 09:00 to 17:00 = 8 core

Example 2

Friday start time 17:00 and end 09:00 (following day), So it need to calculate that there are 3 hours core and 13 hours unsocial as a sat is unsocial all day.

Example 3

Roll over to bank holiday
Thursday night Shift start 20:00 ends 09:00 (following day)
Thursday night is 4 hours then it rolls into a bank holiday (separate table for BH date references) so should calculate that there are 4 hours at unsocial and 9 hours at a Sun/Bank Holiday rate


I am looking to build this as a query but will look at the possibility of needing some VBA (would need help with this as well!:rolleyes:) if a query is just too much of a ball ache!

any Help would be appreciated.

Thanks
Matt
 

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:05
Joined
May 21, 2018
Messages
8,525
If it was me I would do this in vba. I would think this is unlikely to be doable in pure sql (or at least very complicated).

I would probably create a new table.
EmployeeID
StartDateTime
EndDateTime
ChargeType
OriginalRecordID

Then I would loop your current records and split them into multiple records inserting into new table. So your second example, I would create

Code:
Emp1 1/1/2019 17:00  1/1/2019 20:00  Core 2
Emp1 1/1/2019 20:00  1/1/2020 09:00  Social 2

These 2 new records get linked to Employee1 and back to the original table ID of 2.

Can you provide some sample data?
 

Mattkitch80

New member
Local time
Today, 00:05
Joined
Jan 22, 2019
Messages
8
If it was me I would do this in vba. I would think this is unlikely to be doable in pure sql (or at least very complicated).

I would probably create a new table.
EmployeeID
StartDateTime
EndDateTime
ChargeType
OriginalRecordID

Then I would loop your current records and split them into multiple records inserting into new table. So your second example, I would create

Code:
Emp1 1/1/2019 17:00  1/1/2019 20:00  Core 2
Emp1 1/1/2019 20:00  1/1/2020 09:00  Social 2
These 2 new records get linked to Employee1 and back to the original table ID of 2.

Can you provide some sample data?


Hopefully I have replied to this correctly!!:D
Thanks MajP for getting back so quickly

Not sure How I get sample data on here??:banghead:

Code:
Day of Start Date TimeMinute of Start Date TimeMinute of End Date Time11/05/201819:00:0006:00:0029/05/201819:00:0005:00:00
 

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:05
Joined
May 21, 2018
Messages
8,525
Not sure How I get sample data on here??
Using the advanced features you can post attachments. Either a slimmed down db or just some table data in Excel or CSV.
 

Mattkitch80

New member
Local time
Today, 00:05
Joined
Jan 22, 2019
Messages
8
Using the advanced features you can post attachments. Either a slimmed down db or just some table data in Excel or CSV.

I have (hopefully) attached some sample data from the DB as an excel doc.

The DB is looking at linked excel binary files (for periods) and the unique identifier is the Request ID field as there is no record Id number generated from the DB.

Thanks
 

Attachments

  • DB sample data Times - date.xlsx
    12.2 KB · Views: 146

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:05
Joined
May 21, 2018
Messages
8,525
Not too helpful. Need either a table or something that has the rules for the time categories.

Thursday night Shift start 20:00 ends 09:00 (following day)
Thursday night is 4 hours then it rolls into a bank holiday (separate table for BH date references) so should calculate that there are 4 hours at unsocial and 9 hours at a Sun/Bank Holiday rate

I think there are 4 hours of social and 9 hours of bank holiday? What are the rules and time periods? Need to provide detail logic. Is core monday to Friday 0600-2000. Holiday? Weekends? What holidays?

That table does not look promising. You have a start date, but you talk in your examples of rolling into the next day. No way to save that. It really should be two fields

DtmStart and DtmEnd . These fields have both a date and time component.
 

Mattkitch80

New member
Local time
Today, 00:05
Joined
Jan 22, 2019
Messages
8
Not too helpful. Need either a table or something that has the rules for the time categories.

I think there are 4 hours of social and 9 hours of bank holiday? What are the rules and time periods? Need to provide detail logic. Is core monday to Friday 0600-2000. Holiday? Weekends? What holidays?

That table does not look promising. You have a start date, but you talk in your examples of rolling into the next day. No way to save that. It really should be two fields

DtmStart and DtmEnd . These fields have both a date and time component.

Sorry, new to this. The sample was a dulled down version of table which holds a lot more fields. but those are the fields that I thought would be the only requirement at this time?

Rules are

Mon to Friday are core between times

06:00 & 20:00 (Day)

Saturday all day is Unsocial (Sat/Night)
Sunday is a Sunday rate all day (Sun/BH)

So there are 3 categorised shifts essentially.

Day
Sat/night
Sun/BH

BH= Bank holiday

The data held is raw data held from a linked file (No date time field) which is mapped to add more details (staff groups Month names etc..). I could look at adding a "Date start / time" column as well as an "Date end / time" if that would help?

There are 2 tables (Manually created), 1 with the start of core time and start of unsocial time and the other with bank holidays again created / updated manually.

Also on the 3rd sheet is the data after mapping with some dummy data, First line shows the formatting of all the rows.

I hope this helps?

Thanks for the replies so far MajP:)
 

Attachments

  • Table examples DB times.xlsx
    22.4 KB · Views: 104

Mattkitch80

New member
Local time
Today, 00:05
Joined
Jan 22, 2019
Messages
8
MajP.

I have responded to your last message but has been held by a moderator to look at first for some reason!:(
 

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:05
Joined
May 21, 2018
Messages
8,525
The dummy data, may not be the best example. I was hoping to see something were I could read the data and then have to split records based on the "shift". Those records all appear to start and end on a single sunday 1 Apr. So they would all simply get tagged against Sun/BH.

Do you have an example of some data where the period spans from Core to Unsocial or Unsocial to Sun/BH? Also what is the category for 20:00 - 07:00 during the week? Is that Unsocial?

You may need to zip and post your db with real tables to make sense of what you start with and what you would like to end with. You can strip out the non relevant fields.

You can either split the records into seperate records for each time category (that would provide more flexibility) as previously stated, or simply tag each record with three Fields TotalMinutesCore, TotalMinutesUnsocial, TotalMinutesSunBH. Then divide the portion accordingly.
 

Mattkitch80

New member
Local time
Today, 00:05
Joined
Jan 22, 2019
Messages
8
The dummy data, may not be the best example. I was hoping to see something were I could read the data and then have to split records based on the "shift". Those records all appear to start and end on a single sunday 1 Apr. So they would all simply get tagged against Sun/BH.

Do you have an example of some data where the period spans from Core to Unsocial or Unsocial to Sun/BH? Also what is the category for 20:00 - 07:00 during the week? Is that Unsocial?

You may need to zip and post your db with real tables to make sense of what you start with and what you would like to end with. You can strip out the non relevant fields.

You can either split the records into seperate records for each time category (that would provide more flexibility) as previously stated, or simply tag each record with three Fields TotalMinutesCore, TotalMinutesUnsocial, TotalMinutesSunBH. Then divide the portion accordingly.

Hi again MajP

I cant put my DB up on here due to data protection. I will however (when I get some time!!):( create a copy with some dummy data in it with what you are requesting.

Also, I have tested the creating date time fields into one field so will add that to the data set.


Thanks again for your time
 

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:05
Joined
May 21, 2018
Messages
8,525
You could export your real data into excel and delete all fields except fields related to the following

IDField (some way to ID that Record)
StartDate
StartTime (Or if the above two are combined StartDateTime)
EndDate
EndTime (or if the above two fields are combined EndDateTime)
StaffGroupID

StaffGroupID is needed because if the time is split need to know if the core starts at 0600 or 0700.

Would like to have your real field names and real table names for this data.
None of that would be protected, since it is basically nothing but a list of dates.
 

Mattkitch80

New member
Local time
Today, 00:05
Joined
Jan 22, 2019
Messages
8
You could export your real data into excel and delete all fields except fields related to the following

IDField (some way to ID that Record)
StartDate
StartTime (Or if the above two are combined StartDateTime)
EndDate
EndTime (or if the above two fields are combined EndDateTime)
StaffGroupID

StaffGroupID is needed because if the time is split need to know if the core starts at 0600 or 0700.

Would like to have your real field names and real table names for this data.
None of that would be protected, since it is basically nothing but a list of dates.

Hi MajP

Sorry for the delay, first chance I have had to get back to this!

I have now attached what you are looking for. The data attached is in excel but the sheet names are table names and the data attached is how formatted within the DB and field names are the header names in the columns.

So just to recap....

I need two columns. One for Core hors worked and the other for Unsocial hours worked. All hours on a Weekend or Bank holiday is Unsocial and needs to also work out the overlaps between normal working day into Bank holiday or bank holiday into normal working day as well as Normal working days into weekend (depending on times worked would denote core or unsocial).

The other part is referring back to the shift category. Day,Sat/Night or Sun/BH.

Thanks
 

Attachments

  • Core unsocial dummy data - tables.xlsx
    321.1 KB · Views: 100

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:05
Joined
May 21, 2018
Messages
8,525
Matt,
I have been gone for a while and not sure if you are still interested. I think I got it done, but you will have to look at the data. I ended up modifying the tables so if you want to use this it may take some work to modify the names. I wanted some clear names, because this can get real confusing. I read through the table apply the rules and write child records to a new table. So each requestID will have one or many child records depending on how many time groups the shift covers.

For example
Code:
RequestDate	RequestID	  ShiftStart	ShiftEnd	StaffGroup
1-Apr-18	        8	          8:00:00 PM	 8:00:00 AM	 Staff group 5

I read that record and if it rolls over into another day I break it first into two records. One going from 8:00pm to 11:59:59 and one that goes from 12:00 AM the next day to 8:00 AM the next morning. Then break these up based on the core, holiday, and unsocial

for this one you get 3 records (Sunday, Daily Unsocial, and Core)
Code:
StartStatus	EndStatus	Status
4/1/2018 8:00:00 PM	       4/1/2018 11:59:59 PM	Sunday
4/2/2018 12:00:01 AM	4/2/2018 5:59:59 AM	        DailyUnsocial
4/2/2018 6:00:00 AM	        4/2/2018 8:00:00 AM	        DailyCore

Once you break this down into the child records it is easy to do different aggregate queries to get core and unsocial by day and staff.

The code is actually pretty lengthy to do this.

Code:
Public Enum TimeType
  CoreStart = 1
  CoreEnd = 2
  UnsocialStart = 3
  UnsocialEnd = 4
End Enum

Public Function GetTime(staffGroup As String, dtmDate As Date, WhatTime As TimeType)
  Dim fieldName As String
  Dim strSql As String
  Dim rs As DAO.Recordset
  Select Case WhatTime
    Case CoreStart
      fieldName = "StartCoreTime"
    Case CoreEnd
      fieldName = "EndCoreTime"
    Case UnsocialStart
      fieldName = "StartUnsocialTime"
    Case UnsocialEnd
      fieldName = "EndUnsocialTime"
  End Select
  'Need to account for the effective date
  strSql = "Select TOP 1 * from tblTimeStatus WHERE StaffGroup = '" & staffGroup & "' AND AppliedDate <= #" & Format(dtmDate, "mm/dd/yyyy") & "#"
  strSql = strSql & " ORDER BY AppliedDate DESC"
  Set rs = CurrentDb.OpenRecordset(strSql)
  GetTime = rs.Fields(fieldName)
End Function
Public Function isHoliday(dtmDate As Date) As Boolean
  If DCount("*", "tblBankHolidays", "HolidayDate = #" & Format(dtmDate, "mm/dd/yyyy") & "#") > 0 Then isHoliday = True
End Function

Public Sub CreateShiftDetails()
  Dim rs As DAO.Recordset
  Dim strSql As String
  Dim RequestID As Long
  Dim requestDate As Date
  Dim ShiftStart As Date
  Dim shiftEnd As Date
  Dim shift2Start As Date
  Dim shift2End As Date
  Dim staffGroup As String
  Dim CoreStart As Date
  Dim CoreEnd As Date
  Dim UnsocialStart As Date
  Dim UnsocialEnd As Date
  Dim ShiftID1 As String
  Dim shiftID2 As String
  Dim CheckHoliday As Boolean
  Dim rollover As Boolean
  Set rs = CurrentDb.OpenRecordset("tblShiftRequests")
  
  Do While Not rs.EOF
    RequestID = rs!RequestID
    requestDate = rs!requestDate
    ShiftStart = rs!ShiftStart
    shiftEnd = rs!shiftEnd
    staffGroup = rs!staffGroup
    rollover = shiftEnd < ShiftStart  'moves into next day
    'check the first day
    CoreStart = GetTime(staffGroup, requestDate, TimeType.CoreStart)
    CoreEnd = GetTime(staffGroup, requestDate, TimeType.CoreEnd)
    UnsocialStart = GetTime(staffGroup, requestDate, TimeType.UnsocialStart)
    UnsocialEnd = GetTime(staffGroup, requestDate, TimeType.UnsocialEnd)
    
    If isHoliday(requestDate) Then
      ShiftID1 = "BankHoliday"
    ElseIf Weekday(requestDate) = vbSaturday Then
      ShiftID1 = "Saturday"
    ElseIf Weekday(requestDate) = vbSunday Then
      ShiftID1 = "Sunday"
    Else
      ShiftID1 = "Daily"
    End If
    
    If rollover Then
      'if roll over break up into two dates
      shift2End = shiftEnd
      shiftEnd = #11:59:59 PM#
      shift2Start = #12:00:01 AM#
      If isHoliday(requestDate + 1) Then
        shiftID2 = "BankHoliday"
      ElseIf Weekday(requestDate + 1) = vbSaturday Then
        shiftID2 = "Saturday"
      ElseIf Weekday(requestDate + 1) = vbSunday Then
        shiftID2 = "Sunday"
      Else
        shiftID2 = "Daily"
      End If
      InsertShifts RequestID, requestDate, CoreStart, CoreEnd, UnsocialStart, UnsocialEnd, ShiftStart, shiftEnd, ShiftID1
      'break up the rollover and treat as a second day
      InsertShifts RequestID, requestDate + 1, CoreStart, CoreEnd, UnsocialStart, UnsocialEnd, shift2Start, shift2End, shiftID2
    Else
      'does not rollover
      InsertShifts RequestID, requestDate, CoreStart, CoreEnd, UnsocialStart, UnsocialEnd, ShiftStart, shiftEnd, ShiftID1
    End If
    
    rs.MoveNext
  Loop
End Sub
Public Sub InsertShifts(RequestID As Long, requestDate As Date, CoreStart As Date, CoreEnd As Date, UnsocialStart As Date, UnsocialEnd As Date, ShiftStart As Date, shiftEnd As Date, ShiftID As String)
      Dim strSql As String
      If Not ShiftID = "Daily" Then
        strSql = "Insert into TblShiftDetails (ParentRequestID, StartStatus, EndStatus,Status) values (" & RequestID & ", #" & requestDate + ShiftStart & "#, #" & requestDate + shiftEnd & "#, '" & ShiftID & "')"
        CurrentDb.Execute strSql
      Else
        'case 1 all time inside core
        If ShiftStart >= CoreStart And shiftEnd <= CoreEnd Then
           strSql = "Insert into TblShiftDetails (ParentRequestID, StartStatus, EndStatus,Status) values (" & RequestID & ", #" & requestDate + ShiftStart & "#, #" & requestDate + shiftEnd & "#, 'DailyCore')"
           'Debug.Print strSql
           CurrentDb.Execute strSql
        'case 2 starts in core and goes into unsocial
        ElseIf ShiftStart >= CoreStart And ShiftStart <= CoreEnd And shiftEnd > CoreEnd Then
           strSql = "Insert into TblShiftDetails (ParentRequestID, StartStatus, EndStatus,Status) values (" & RequestID & ", #" & requestDate + ShiftStart & "#, #" & requestDate + CoreEnd & "#, 'DailyCore')"
           'Debug.Print strSql
           CurrentDb.Execute strSql
           strSql = "Insert into TblShiftDetails (ParentRequestID, StartStatus, EndStatus,Status) values (" & RequestID & ", #" & requestDate + UnsocialStart & "#, #" & requestDate + shiftEnd & "#, 'DailyUnsocial')"
           'Debug.Print strSql
           CurrentDb.Execute strSql
        'case 3 starts before core and ends in core
        ElseIf ShiftStart < CoreStart And shiftEnd > CoreStart And shiftEnd < CoreEnd Then
           strSql = "Insert into TblShiftDetails (ParentRequestID, StartStatus, EndStatus,Status) values (" & RequestID & ", #" & requestDate + ShiftStart & "#, #" & requestDate + UnsocialEnd & "#, 'DailyUnsocial')"
           'Debug.Print strSql
           CurrentDb.Execute strSql
           strSql = "Insert into TblShiftDetails (ParentRequestID, StartStatus, EndStatus,Status) values (" & RequestID & ", #" & requestDate + CoreStart & "#, #" & requestDate + shiftEnd & "#, 'DailyCore')"
           'Debug.Print strSql
           CurrentDb.Execute strSql
        'Case 4 starts before core and ends after core
        ElseIf ShiftStart < CoreStart And shiftEnd > CoreEnd Then
           strSql = "Insert into TblShiftDetails (ParentRequestID, StartStatus, EndStatus,Status) values (" & RequestID & ", #" & requestDate + ShiftStart & "#, #" & requestDate + UnsocialEnd & "#, 'DailyUnsocial')"
           'Debug.Print strSql
           CurrentDb.Execute strSql
           strSql = "Insert into TblShiftDetails (ParentRequestID, StartStatus, EndStatus,Status) values (" & RequestID & ", #" & requestDate + CoreStart & "#, #" & requestDate + CoreEnd & "#, 'DailyCore')"
           'Debug.Print strSql
           CurrentDb.Execute strSql
           strSql = "Insert into TblShiftDetails (ParentRequestID, StartStatus, EndStatus,Status) values (" & RequestID & ", #" & requestDate + UnsocialStart & "#, #" & requestDate + shiftEnd & "#, 'DailyUnsocial')"
           'Debug.Print strSql
           CurrentDb.Execute strSql
        End If
     End If
End Sub
 

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:05
Joined
May 21, 2018
Messages
8,525
Here is the working DB. I created the table with 15k of records breaking it into all time categories.

Here is the trick in doing something like this. There are six cases you have to check, people often miss a couple, usually it is case 6.
Assume this is the core time period
Code:
                        |-----core--------|
|--------| case 1 it starts and end before core start
            |-------------| Case 2. Starts before and ends inside
                            |-------| Case 3. Starts inside and ends inside
                                       |----------| case 4 starts inside and ends outside
                                                        |-----------------| starts and ends outside
                   |------------------------------| case 6 starts before and ends after
 

Attachments

  • Core_Unsocial.zip
    551.4 KB · Views: 108

Users who are viewing this thread

Top Bottom