Scenario:
A small business wants a simple program to calculate the total hours worked by employees in a week based on daily logs. Each log contains the employee’s name, date, and hours worked. The goal is to summarize the total hours per employee for the week.
Requirements:
-
Input:
- A list of work logs where each log includes:
employeeName
(string): The name of the employee.date
(string): The date of the work log inYYYY-MM-DD
format.hoursWorked
(number): The hours worked on that day.
- An optional
startDate
andendDate
to define the week (both inYYYY-MM-DD
format).
- A list of work logs where each log includes:
-
Output:
- A summary object where:
- The keys are employee names.
- The values are the total hours worked by that employee during the week.
- A summary object where:
-
Behavior:
- Parse the input data.
- Filter the logs to include only those within the
startDate
andendDate
range (if provided). - Handle edge cases, such as overlapping date ranges or invalid input.
-
Stretch Features:
- Allow tracking overtime by flagging employees who worked more than 40 hours in the week.
Example Input:
typescript
Copy code
const logs = [ { employeeName: "Alice", date: "2024-12-01", hoursWorked: 8 }, { employeeName: "Bob", date: "2024-12-01", hoursWorked: 7.5 }, { employeeName: "Alice", date: "2024-12-02", hoursWorked: 9 }, { employeeName: "Alice", date: "2024-12-03", hoursWorked: 7 }, { employeeName: "Bob", date: "2024-12-03", hoursWorked: 8 }, { employeeName: "Alice", date: "2024-12-05", hoursWorked: 8 }, ]; const startDate = "2024-12-01"; const endDate = "2024-12-07";
Example Output:
typescript
Copy code
{ Alice: 32, // 8 + 9 + 7 + 8 Bob: 15.5 // 7.5 + 8 }
Tips:
- Use libraries like
date-fns
orluxon
for date parsing and filtering if desired. - Use a dictionary (
Record<string, number>
) to store employee totals for efficient lookups. - Test your solution with edge cases like overlapping date ranges, missing fields, or empty logs.
Would you like me to elaborate on how to approach solving this challenge in TypeScript?
My Answer, Attempt #1
I feel great about this! Got it in about 22 minutes:
/* input:
above: name, date, hours worked
optional: start and end
output:
object with name keys and hour values
*/
/*
questions / edge cases
- what if the hours worked is longer than 24 hours
- ignore for now as we don't even know when the shifts start
data structures
- an object that has the name and hours worked
key activities
iterate through all logs
if there's a timerange, check if the range is in the timerange
get name, save it to our employee data structure
If I have time I'll define a
- datematching validation function
*/
interface Log {
employeeName: string,
date: string,
hoursWorked: number
}
interface ParsedLog {
name: string,
date: Date,
hoursWorked: number
}
interface TimeRange {
startDate: string
endDate: string
}
interface Employees {
[key: string]: number
}
const logs = [
{ employeeName: "Alice", date: "2024-12-01", hoursWorked: 8 },
{ employeeName: "Bob", date: "2024-12-01", hoursWorked: 7.5 },
{ employeeName: "Alice", date: "2024-12-02", hoursWorked: 9 },
{ employeeName: "Alice", date: "2024-12-03", hoursWorked: 7 },
{ employeeName: "Bob", date: "2024-12-03", hoursWorked: 8 },
{ employeeName: "Alice", date: "2024-12-05", hoursWorked: 8 },
];
const startDate = "2024-12-01";
const endDate = "2024-12-07";
// console.log(getEmployeeWorkVolume(logs, {startDate, endDate}))
const hours = getEmployeeWorkVolume(logs)
console.log(hours)
function getEmployeeWorkVolume(logs: Log[], timeRange: TimeRange | null = null): Employees {
const employees: Employees = {}
let startDate: Date
let endDate: Date
if (timeRange){
startDate = new Date(timeRange.startDate)
endDate = new Date(timeRange.endDate)
}
// key activities
// iterate through all logs
// if there's a timerange, check if the range is in the timerange
// get name, save it to our employee data structure
const parsedLogs = logs.reduce<ParsedLog[]>((logs, currentLog)=>{
if (timeRange){
const parsedDate = new Date(currentLog.date)
// TODO: I think that same datestrings will be the same timestamps, but it might be good to
// compare on the day level rather than millisecond level, which is what is happening now
if (parsedDate < startDate && parsedDate > endDate){
return logs
}
}
logs.push({
name: currentLog.employeeName,
date: new Date(currentLog.date),
hoursWorked: currentLog.hoursWorked
})
return logs
}, [])
for (const log of parsedLogs){
employees[log.name] = (employees[log.name] ?? 0) + log.hoursWorked
}
return employees
}
What I learned
At the end, when shit is getting crazy and you know you’re running out of time, it doesn’t really help to panic. This just hurts you. I think a little pressure is okay, a bit of speed, but I personally can’t work much faster than I already am. Not because I’m working super fast, just because I already need all the care and introspection I’m putting into these high-pressure programming sessions. I can’t afford to lose any.