The Day I Discovered My Clock-In System Was Living in Yesterday

When Time Travel Breaks Your Clock-In UI

It was early. Too early. One of those mornings where the coffee machine feels passive-aggressive and your inbox is already judging you.

I opened a WhatsApp message from one of our night shift staff:

Adeen: “I can’t clock out. The system thinks I never clocked in.”

My response?

“That’s weird. Wait… actually… oh no.”

Because I knew immediately what had happened: my clock-in system, the one I built from scratch, had never learned to think across the date boundary.

The Great Midnight Betrayal

Here’s what was happening:

  • Staff clocked in at 11 PM on June 7.

  • Came back to clock out at 7 AM on June 8.

  • The system looked at June 8 records and confidently said: “Nothing to see here. You should clock in now!”

The SQL query I had written in /attendance/status was the culprit:

// Old logic: completely blind to yesterday
SELECT * FROM attendance
WHERE user_id = ? AND DATE(clock_in_time) = ?

My system was acting like a bouncer who checks today’s guest list and refuses to acknowledge anyone still partying from the night before.

Operation: Remember Yesterday

I rewired the logic to handle reality better—by making it check both today and yesterday:

// New logic: with actual awareness of how night shifts work
const yesterday = moment(date).subtract(1, 'day').format('YYYY-MM-DD');

const [records] = await pool.execute(
`SELECT * FROM attendance
WHERE user_id = ? AND (DATE(clock_in_time) = ? OR DATE(clock_in_time) = ?)
ORDER BY clock_in_time DESC`,
[userId, date, yesterday]
);

It was one small OR for SQL, one giant leap for night shift workers everywhere.

Preventing Accidental Double Clock-Ins

Next up: the /attendance/clock-in endpoint.

It used to only check if you’d clocked in today, which meant people still clocked in from yesterday could double dip.

Now, it checks if you’re clocked in—period:

const [activeClockInCheck] = await pool.execute(
`SELECT id, status, clock_in_time FROM attendance
WHERE user_id = ? AND status = 'clocked_in'
ORDER BY clock_in_time DESC LIMIT 1`
);

if (activeClockInCheck.length > 0) {
const clockInDate = moment(activeClockInCheck[0].clock_in_time).format('YYYY-MM-DD');

return res.status(400).json({
success: false,
message: clockInDate === today
? 'You are already clocked in for today'
: `You are still clocked in from ${clockInDate}. Please clock out first.`
});
}

Now the system gently but firmly stops people from creating quantum duplicates of themselves.

Long Shifts? I See You (And I’m Concerned)

Some folks work long hours—really long. So I added a friendly panic button:

if (hoursWorked > 16) {
console.warn(`WARNING: User ${userId} has been clocked in for ${hoursWorked.toFixed(2)} hours since ${activeRecord.clock_in_time}`);
}

It’s not a hard block, but it logs a big red flag in the console—because no one should be clocked in longer than an international flight.

The Today-Shift Endpoint Gets a Brain

Previously, the /attendance/today-shift endpoint was totally confused if your shift started yesterday. I gave it a moment of clarity:

if (clockInDate === yesterday) {
relevantDate = yesterday;
isActiveNightShift = true;
}

Now it understands: if your clock-in started yesterday and you’re still clocked in, it should show you yesterday’s shift details—not today’s blank slate.

Testing Time Travel Scenarios

I ran through every twisted timeline imaginable:

  • Clocking in yesterday, clocking out today? ✅ Works.

  • Trying to double clock-in while still clocked in? ✅ Blocked.

  • Shifts longer than 16 hours? ✅ Logs a warning.

  • Regular day shift? ✅ Still works like before.

Testing it felt like building a temporal simulator. But hey—no paradoxes. So I’ll call that a win.

The Deployment: Surprisingly Smooth (?!?)

Pushed to production during a quiet hour. Held my breath.

Then came the magic moment: a security staff member clocked out after a night shift—and the button actually appeared. No drama. No confusion.

They messaged me with a single word:

“Finally.”

Yes. Finally.

Lessons From Debugging Time

  1. Your system needs to understand “yesterday” just as much as “today.”

  2. Night shifts aren’t an edge case—they’re half your operations.

  3. Always test shifts that span two days. Or three. Or more.

  4. Logging saves your sanity.

  5. Even time-travel bugs can be squashed—with a well-placed SQL OR.

 

In case you missed my previous post where i began this system development: Building a Web-Based Clocking System: A 48-Hour Sprint (and a Latte or Two)

Previous Article

The Night I Fixed Night Shifts and Made WhatsApp Shut Up

Next Article

How I Became the Digital Bouncer Nobody Asked For

Write a Comment

Leave a Comment

Subscribe to our Newsletter

Subscribe to our email newsletter to get the latest posts delivered right to your email.
Pure inspiration, zero spam ✨