There is an updated version of the online timecard calculator here
It has some new features, includes bug fixes, and provides a variety of integrated sanity checks.
If you have a moment, I'd love your feedback.
Having been converted from a salaried to an hourly employee, I found myself wanting to make midweek evaluations
to determine if I was ahead or behind in my accumulation of hours for the week. Having been ruined by forms and calculators,
I find it difficult to do the calculations in my head particularly when it gets down to exact minutes.
I'd share this with anyone interested. Let me know if you run into any problems or if you have suggestions for
improving this... I can't make any promises, but I'd love your input.
Let's get started
What I basically want to do is walk through the process of calculating a single day, then possibly
expand that code to cover multiple days (a week, or two week period for example).
Breaking down the overall problem of calculating a timesheet, I came up with this series of steps
that will need to happen.
- Get user input for start and stop times and a lunch adjustment.
- Convert the start and stop hours into 24 hour format.
- Convert the minutes from 60 to 100ths.
- Subtract the converted start time from the converted stop time.
- Subtract the lunch adjustment.
- Display the total hours in 100ths.
Again, I'm going to start by calculating a single day's time card related hours in order to simplify this.
The functional example -- Try Me!
Source Code for Example
Dirty Object Relationships
Because there is a relationship between all of the form elements on a given row we have to create
script that is aware of the relationship, but it's not as intuitive as perhaps it could be.
My example builds those relationships each time a change requiring a refactoring of those relationships
occurs. It does so by having the "changed" object (form element) call a function passing itself as
an argument. The function assumes the caller ends with a number which it obtains using a regular expression.
It further assumes it can use that number combined with an expected set of names to attach to and evaluate
all of the related form elements for that row. Some part of me cringes to have to use that instead
of some more graceful mechanism, but a more efficient mechanism didn't materialize, so there it is.
Testing to Validate or Invalidate your logic
It's important to define test cases to validate (or invalidate) your approach to solving the problem.
Here are the cases I used:
- 8AM - 5PM (best case scenario)
- 8:30AM - 5:30PM (test minutes)
- 10AM - 11AM (doesn't cross AM/PM boundary)
- 11AM - 10AM (error case? or does this imply an 23 hour stint... unsure.)
- 12PM - 12AM (12 hour boundary case A)
- 12AM - 12PM (12 hour boundary case B)
- 11AM - 11PM (sanity check)
- 11PM - 11AM (sanity check)
- 9PM - 6AM (graveyard outlyer)
Don't Pull Your Hair Out
Programming is like puzzle building in a lot of ways. It's often tedious and aggravating.
I went through numerous iterations trying to get the calculations generated by all the related items on
a row to match all of the test cases I outlined. My strategy over time has become to hibernate the computer
(sorry, I use Windows... at least until true Linux migration is feasible -- including all the apps)
and walk away to let my brain relax. It's very easy to program yourself into a corner. While it's happening,
your mind latches onto what it believes is a solution, and then you start trying to force the other pieces
into play around that solution... whether they really fit or not.
If you allow this process to continue your mind cramps up like a clenched muscle and you begin to inject
code into the process which you will kick yourself for doing later. So, when you first recognize that you
are banging your head on the wall, put down the computer and walk away. You'll discover that when your
mind is really tuned to programming, it just attracts and organizes the answers like a magnet.
Here are some of the things I'd like to add (unless I've already added them and just forgot to pull the item...er, oops.)
- Use ajax and a cgi to persist the user's data instead of making them type it each time. Incremental changes
might be faster and easier than starting from scratch each time.