C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
113: Working with TimeSpan
A few years ago, I was reviewing a PR from a junior dev who was building a session timeout feature. They had stored the "timeout limit" as a simple integer in the configuration file—30—and then scattered DateTime.Now.AddMinutes(timeoutLimit) all over the codebase. The problem started when the product manager asked for the timeout to be 90 seconds instead of 30 minutes. Suddenly, that integer 30 didn't make sense anymore, and the developer had to hunt down every instance of AddMinutes and change it to AddSeconds, while also updating the config value to 90. It was a mess of "magic numbers" and guesswork.
This is exactly why TimeSpan exists. In C#, DateTime represents a specific point in time (a date and a clock reading), but TimeSpan represents a duration—the amount of time that passes between two points. When you start thinking in terms of durations rather than just adding numbers to dates, your code becomes much more intentional and far less prone to these kinds of bugs.
Defining Durations without the Math Headaches
You can create a TimeSpan in a few ways, but I always recommend the From... static methods. They are explicit and readable. If you see TimeSpan.FromMinutes(30), you know exactly what's happening. If you see new TimeSpan(0, 30, 0), you have to remember the order of the constructor arguments (hours, minutes, seconds), which is a waste of your mental energy.
// The clear way to do it
TimeSpan sessionTimeout = TimeSpan.FromMinutes(30);
TimeSpan gracePeriod = TimeSpan.FromSeconds(45);
TimeSpan longTermStorage = TimeSpan.FromDays(7);
// You can also use the static constants for common durations
TimeSpan zero = TimeSpan.Zero;
TimeSpan infinity = TimeSpan.MaxValue;
I've found that using these methods makes the code self-documenting. You aren't just passing an integer; you're passing a type that explicitly says "I am a length of time."
The Trap of TotalSeconds vs Seconds
This is the part that trips up almost everyone at first. TimeSpan has two types of properties: the component properties and the "Total" properties. This distinction is critical.
- Component Properties (e.g.,
.Seconds): These return the remaining part of the time slice. If yourTimeSpanis 1 minute and 10 seconds,.Secondswill return10. - Total Properties (e.g.,
.TotalSeconds): These return the entire duration expressed in that unit. For that same 1 minute and 10 seconds,.TotalSecondswill return70.
TimeSpan interval = TimeSpan.FromSeconds(70);
Console.WriteLine(interval.Seconds); // Output: 10
Console.WriteLine(interval.TotalSeconds); // Output: 70
If you're calculating a timeout or a countdown for a UI, you almost always want TotalSeconds or TotalMilliseconds. Using .Seconds in a calculation is a classic bug that usually results in a timer that resets every 60 seconds.
Calculating the Gap Between Events
The most common way you'll encounter TimeSpan is as the result of subtracting one DateTime from another. In C#, the subtraction operator for DateTime is overloaded to return a TimeSpan automatically.
DateTime startTime = DateTime.Now;
// ... some heavy processing happens here ...
DateTime endTime = DateTime.Now;
TimeSpan elapsed = endTime - startTime;
if (elapsed.TotalMilliseconds > 500)
{
Console.WriteLine($"Warning: Operation took too long! {elapsed.TotalMilliseconds}ms");
}
You can also go the other way: adding a TimeSpan to a DateTime gives you a new DateTime. This is much cleaner than calling AddDays() or AddHours() repeatedly when you already have a duration object defined in your settings.
📋 Practical Task
Exercise: Building a Server Response Latency Tracker
Create a small program that simulates tracking the response time of several API calls. Your goal is to determine if the "average latency" of these calls exceeds a specific threshold.
Requirements:
- Define a
TimeSpanvariable calledlatencyThresholdset to 200 milliseconds. - Create a list of
DateTimeobjects representing the "start time" and "end time" of three simulated API calls (you can just hardcode these asDateTime.Now.AddMilliseconds(...)to simulate different durations). - Calculate the
TimeSpanfor each call by subtracting the start from the end. - Calculate the average total milliseconds across all three calls.
- Print whether the average latency was "Acceptable" or "Too Slow" based on your
latencyThreshold.
There are no comments for now.