Globalization in a C# WinForms Appointment Scheduler

Felix Berinde,c#desktopwinforms

One of my favorite desktop projects is an Appointment Scheduler built with C# WinForms and MySQL. The core challenge was not CRUD operations — those are straightforward — but handling time zones correctly so that appointments entered in the user's local time are stored consistently in the database as UTC.

This post explains the problem, the approach I took, and why timezone handling matters even in small applications.

The Problem

Users schedule appointments in their local time. The MySQL server stores timestamps in UTC (specifically 00:00:00 UTC format). If you save local time directly to the database without conversion, appointments display incorrectly for users in different time zones and break when daylight saving time changes.

The requirements for this project were:

Application Structure

The app follows a layered structure common in WinForms projects:

The main form shows a list of upcoming appointments. A separate form handles create and edit operations with date/time pickers for start and end times.

Time Zone Conversion on Save

When the user clicks Save, the application reads the DateTime values from the date/time pickers. These values are in the local time zone of the machine running the app.

Before inserting or updating the database record, the local times are converted to UTC:

DateTime localStart = startDateTimePicker.Value;
DateTime utcStart = TimeZoneInfo.ConvertTimeToUtc(localStart);

The UTC values are what get written to the MySQL columns. Using parameterized queries ensures the values are passed safely:

command.Parameters.AddWithValue("@start", utcStart);
command.Parameters.AddWithValue("@end", utcEnd);

Time Zone Conversion on Load

When appointments are retrieved from the database, the UTC timestamps are converted back to local time before populating the UI:

DateTime utcStart = reader.GetDateTime("start");
DateTime localStart = TimeZoneInfo.ConvertTimeFromUtc(utcStart, TimeZoneInfo.Local);

This ensures the user always sees times that make sense for their location, regardless of where the server is hosted.

Why Not Just Store Local Time?

Storing local time feels simpler, but it creates problems:

  1. Ambiguity during DST transitions — A local time of 2:30 AM may not exist or may exist twice when clocks change
  2. Multi-user scenarios — If the app ever supports users in different regions, local storage breaks down immediately
  3. Reporting and sorting — UTC provides a single consistent timeline for queries like "all appointments this week"

Even for a single-user desktop app, practicing UTC storage builds habits that transfer directly to web APIs and distributed systems.

Additional Features

Beyond timezone handling, the scheduler includes:

UI Considerations in WinForms

WinForms date/time pickers default to the system's local time zone, which aligns well with this approach. A few UI decisions that improved usability:

WinForms is an older framework, but it remains excellent for learning desktop development concepts without the complexity of XAML or MAUI.

Lessons Learned

  1. Always store UTC, display local — This is the standard pattern across web and desktop development
  2. Use TimeZoneInfo from the BCL — Do not manually calculate offsets; the .NET base class library handles DST rules
  3. Test around DST boundaries — Create appointments on the days clocks change to verify conversions
  4. Parameterized queries are non-negotiable — Even in a school project, building safe SQL habits matters

Source Code

The full project is on GitHub (opens in a new tab). There is also a walkthrough video (opens in a new tab) demonstrating the application in action.

If you are working on a scheduling application — desktop or web — getting timezone handling right early will save significant debugging time later.

© Felix Berinde.ContactPrivacyTermsRSS