NodaTime C# (.NET): Complete Guide with Examples
Working with dates and times is one of the most complex and error-prone tasks in software development. .NET's built-in DateTime and DateTimeOffset types have fundamental issues: confusion between local and UTC time, lack of clear separation between "a moment in time" and "a calendar date," and ambiguity when dealing with time zones and daylight saving time. The NodaTime library was created to solve these problems, offering developers a safe, expressive, and type-safe API for time handling.
NodaTime is an alternative date and time library for .NET, inspired by the Joda-Time library for Java. It provides a clear separation between different time concepts: Instant (a moment in time), LocalDateTime (date and time without a time zone), ZonedDateTime (date and time with a time zone), Duration (a time interval in nanoseconds), and Period (a time interval in calendar units). The library uses IANA time zone data (tzdata database), making it more accurate and up-to-date than built-in Windows mechanisms.
The main goal of NodaTime is to make invalid time operations impossible at compile time. For example, you cannot accidentally add a LocalDateTime to a Duration (because it doesn't make sense without a time zone), or compare an Instant with a LocalDate. The library also provides powerful formatting, parsing, time zone handling, and calendar system support (including Julian, Islamic, and Hebrew calendars).
Installation
To install NodaTime in your .NET project, use the NuGet Package Manager. Run one of the following commands:
# Via .NET CLI (recommended)
dotnet add package NodaTime
# Via Package Manager Console (Visual Studio)
Install-Package NodaTime
# Or via NuGet Package Manager UI: search for "NodaTime"
After installation, add the using NodaTime; directive at the top of your file. For time zone operations, you may also need using NodaTime.TimeZones;.
Quick Start
A minimal working example demonstrating NodaTime's core features:
using NodaTime;
using NodaTime.Text;
// 1. Current moment in UTC
Instant now = SystemClock.Instance.GetCurrentInstant();
Console.WriteLine($"Current moment (UTC): {now}");
// 2. Convert to local time (Moscow)
DateTimeZone moscowZone = DateTimeZoneProviders.Tzdb["Europe/Moscow"];
ZonedDateTime moscowTime = now.InZone(moscowZone);
Console.WriteLine($"Time in Moscow: {moscowTime}");
// 3. Create a specific date and time
LocalDateTime localDate = new LocalDateTime(2024, 12, 25, 10, 30, 0);
Console.WriteLine($"Local date: {localDate}");
// 4. Parse a string
var pattern = LocalDateTimePattern.CreateWithInvariantCulture("yyyy-MM-dd HH:mm:ss");
LocalDateTime parsed = pattern.Parse("2024-12-25 10:30:00").Value;
Console.WriteLine($"Parsed: {parsed}");
// 5. Work with durations
Duration duration = Duration.FromHours(2.5);
Instant future = now + duration;
Console.WriteLine($"In 2.5 hours: {future.InZone(moscowZone)}");
Key Classes and Methods
1. Instant — A Moment in Time
Signature: public readonly struct Instant : IEquatable<Instant>, IComparable<Instant>
What it does: Represents a point on the timeline, measured in nanoseconds from the Unix epoch (January 1, 1970, 00:00:00 UTC). Independent of time zones.
Instant epoch = Instant.FromUnixTimeTicks(0); // Unix epoch
Instant now = Sy