Keeping Track of Time

Sign in to queue


  In this article, we will learn to create a basic time tracking tool which sits quietly in the system tray
Arian Kulp's Blog

Difficulty: Easy
Time Required: Less than 1 hour
Cost: Free
Software: Visual Studio Express Editions


Time and how we use it is a matter of great importance to many people. I am certainly no exception, frequently working on two to five projects at a given time. Whether it's just being curious about how much time you are spending on various classes at school, or billable projects, time tracking can be tedious. Do you use a paper notebook (remember those)? Do you create a spreadsheet in Excel? What about a custom time accounting software package? For this installment of In the Box, I decided it would be good to create a basic time tracking tool to sit quietly in the system tray.

As always, the code for this project is included in a downloadable archive in both C# and Visual Basic versions. The code shown in the article is in C#, though both versions are identical other than syntax differences dictated by language. You will need either the C# or Visual Basic version of Visual Studio 2005 Express Editions. No additional products or tools are required.

The goal of this project was to create a simple application with an uncluttered interface. There are no advanced reporting capabilities, though nothing precludes one from adding them. The first step was to create the notification icon and context menu. Both were dragged from the Toolbox onto the default form (created with the solution). The context menu is attached to the notification icon using the ContextMenuStrip property. Visual Studio automatically offers any context menu strip objects in the drop-down box when setting the property.

The menu was created to offer the least number of options to get the job done. In addition to being able to exit (seemed like a good idea...), it allows you to set which project you are working on. The projects themselves are displayed in a sub-menu, along with an option to add a new project. Clicking a project causes it to be checked, and the Punch In option enabled. Clicking Punch In toggles it between Punch In and Punch Out, either creating or closing time entries. Finally, the View Time Details option displays the main form showing time entry details in various groupings.

Generic Episode Image

Figure 1: The ContextMenuStrip editor

For simplicity of deployment, no database is used to maintain the project and time entries. Instead, a basic DataSet was created with a Projects and TimeEntries table. This DataSet is no different than if it had been created from a database schema, and it supports primary keys, foreign keys, null constraints, and even auto-incrementing fields. Right-click the project, click Add Item, then select DataSet to use the designer. Instead of persisting to a database, the DataSet is serialized as XML to a file.

Generic Episode Image

Figure 2: The DataSet designer

When you punch in (start a time entry) for a project, the application creates a new time entry row, associates it with the current project, sets the start time to the current time, then adds the row to the TimeEntries table. Because of the foreign key relationship between the Projects and TimeEntries table, the Projects row can be set directly in the TimeEntries row, even though the underlying relationship is a numeric type. The ProjectID, in this case, is set automatically. It preserves a better object relationship this way, and reduces potential errors from lookup codes. Notice that the currently selected project is saved to the Tag property of the Change Project menu.

Visual C#

currentTimeEntryRow = ds.TimeEntries.NewTimeEntriesRow();
currentTimeEntryRow.StartTime = DateTime.Now;
currentTimeEntryRow.ProjectsRow =               

Visual Basic

currentTimeEntryRow = ds.TimeEntries.NewTimeEntriesRow()
currentTimeEntryRow.ProjectsRow = CType( _
    currentProjectMenuItem.Tag, TimeTracker.TimeTrackerDataSet.ProjectsRow)
currentTimeEntryRow.StartTime = DateTime.Now

Adding a new project follows a similar flow of logic for creating and adding the DataSet row. It takes advantage of a string editor dialog created for the project, since .NET has no built-in string prompt. As with any form, it can be displayed modally using the ShowDialog method, and can even return a DialogResult object as like the MessageBox object. Simply set the DialogResult property of buttons on your form to allow them to return OK, Cancel, Yes, No, etc.

Visual C#

StringInputForm input =
    new StringInputForm("Please enter a name for the new project");

if (input.ShowDialog() == DialogResult.OK)
    TimeTracker.TimeTrackerDataSet.ProjectsRow newProjectRow = 
    newProjectRow.ProjectName = input.Response;



Visual Basic

Dim input As _
    New StringInputForm("Please enter a name for the new project")
If input.ShowDialog() = Windows.Forms.DialogResult.OK Then
    Dim newProjectRow As TimeTracker.TimeTrackerDataSet.ProjectsRow = _
    newProjectRow.ProjectName = input.Response
End If

As noted, the notification icon context menu dynamically adds project entries to the menu itself. This seemed a better solution than popping up a ListBox to display projects, even though the effort would have been slightly less. Adding items to a menu at runtime is fairly easy, as I hope this demonstrates, and provides a better integrated experience. Start by instantiating the ToolStripMenuItem class, set the Name property to a unique value, set the Text property to a descriptive value, and set a Click event handler. In this case, the event handler is shared among all project menu items. Notice that the event handler isn't created at this point. The event handler creation occurs when the form object is initialized. This simplifies the code, as the basic action to take is identical regardless of which object is selected. The projectMenuItems object is a generic List object I'm using to hold onto references to the menu items so they don't go out of scope.

Visual C#

ToolStripMenuItem newMenuItem = new ToolStripMenuItem();

newMenuItem.Name =
    "Project-" + changeProjectToolStripMenuItem.DropDownItems.Count;
newMenuItem.Text = newProjectRow.ProjectName;
newMenuItem.Click += projectSelectEventHandler;

newMenuItem.Tag = newProjectRow;

    new System.Windows.Forms.ToolStripItem[] {


Visual Basic

Dim newMenuItem As New ToolStripMenuItem()
newMenuItem.Name = _
    "Project-" & changeProjectToolStripMenuItem.DropDownItems.Count
newMenuItem.Text = newProjectRow.ProjectName
AddHandler newMenuItem.Click, projectSelectEventHandler
newMenuItem.Tag = newProjectRow
changeProjectToolStripMenuItem.DropDownItems.AddRange( _
    New System.Windows.Forms.ToolStripItem() { _

The block of code that probably requires the most explanation is the PopulateProjectList method. This is used to display the time entries in the main form. The top-level entries show projects and total time tracked. If any time entries exist for the project, a sub-item exists for each day, and within each day the individual Punch In/Out times can be seen. Every level is totaled separately for easier tracking. The TimeSpan object is used to keep track of the difference between start times and end times at various levels. Adding or subtracting two DateTime objects yields a TimeSpan object. TimeSpan objects can also be added, greatly simplifying the process. The method first iterates over projects, then for each project iterates over the children time entries. Each time a new day is encountered for a time entry, a new day sub-item is created for a project, and then the corresponding time entry is added as a child of the day sub-item.

What's left?

The functionality of the Time Tracker is admittedly simple, but provides a sound foundation for enhancements. The ability to tweak time entries would be a nice addition. If you forget to punch out and don't notice for a few hours, you may not want to hand-edit the XML file to adjust the timestamp. The ability to close out projects might also be handy to unclutter the project menu. Finally, the ability to report hours based on date ranges or to organize by date rather than by project would also be useful.


Using notification icons, hierarchical lists, and typed DataSet objects require some studying, but can be mastered fairly quickly. They are well worth the effort to speed up development of your applications. Get started by downloading your choice of Visual Studio 2005 Express Editions for C# or Visual Basic at The Time Tracker project can be run as-is, or extend it to make it just right for you. Most of all, have fun!

The Discussion

  • User profile image

    Great quick time tracker. Takes up no desktop space and is always available.

  • User profile image

    Very nice, just the thing i was looking for, maybe i'll change it to my liking, but for now, ill use it like this!

  • User profile image

    I just asked two questions about extending the time tracker to a web-version of itself, but forgot to leave an email address!

  • User profile image

    This is really cool. Seems like you crank this stuff out really easily. Is there a web-version of this time-tracker anywhere???

    Or how easy would it be for me to extent the time tracker to a webversion of what you did???


  • User profile image

    I couldn't download the application . Can anyboby help me for updated url.

  • User profile image

    @Sims: both links worked for me

  • User profile image

    You have the concepts, with ASP.Net Ajax, I think most of the code should remain the same.

  • User profile image

    @csharp error:  email me through the contact page and I'll follow up with you.

    - clint

  • User profile image
    csharp error

    throws an exception @

    currentTimeEntryRow.ProjectsRow = (TimeTracker.TimeTrackerDataSet.ProjectsRow)


  • User profile image
    Arian Kulp's Blog

    This project is a basic time tracking tool which sits quietly in the system tray until needed. Originally published in a Coding 4 Fun article (like most of my projects!), this has evolved somewhat over time as I've used it for my own day-to-day time tracking

  • User profile image
    Ondrej Paulicek

    exactly thing I was looking for. Great arcticle as well. Thanks!!

Add Your 2 Cents