Question

Convert Unix Timestamp to DateTime in C#

csharpdatetimeunixepochdata-conversion

Question

How can I correctly convert a Unix timestamp to a DateTime in C#, and convert a DateTime back to a Unix timestamp?

I found example code, but it starts discussing millisecond and nanosecond differences, which made the solution unclear.

I also saw a related discussion on MSDN about seconds since the Unix epoch in C#.

Here is the code I currently have:

public double CreatedEpoch
{
    get
    {
        DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime();
        TimeSpan span = this.Created.ToLocalTime() - epoch;
        return span.TotalSeconds;
    }
    set
    {
        DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime();
        this.Created = epoch.AddSeconds(value);
    }
}

Is this the correct approach, especially with regard to time zones and Unix time being measured in seconds since 1970-01-01 UTC?

Short Answer

By the end of this page, you will understand what a Unix timestamp is, how it relates to UTC, how to convert between Unix time and DateTime in C#, and which common mistakes to avoid. You will also see safer modern approaches and practical examples you can use in real code.

Concept

Unix time is the number of seconds that have passed since 1970-01-01 00:00:00 UTC, often called the Unix epoch.

In C#, the main challenge is not the subtraction itself. The real challenge is handling time zones correctly.

A Unix timestamp is always based on UTC, not local time. That means:

  • When converting a DateTime to a Unix timestamp, first make sure the DateTime represents a UTC moment.
  • When converting a Unix timestamp back to a DateTime, the result should usually start as UTC.

This matters because the same instant can look different in different time zones:

  • 2024-01-01 12:00 UTC
  • 2024-01-01 07:00 in UTC-5
  • 2024-01-01 13:00 in UTC+1

These are different clock displays of the same moment.

In real programming, Unix timestamps are widely used in:

  • APIs
  • databases
  • logging systems
  • authentication tokens
  • event tracking
  • distributed systems

If you mix local time and UTC incorrectly, you can create bugs such as:

  • timestamps being off by several hours
  • values changing depending on the server location
  • daylight saving time errors
  • incorrect ordering of events

In modern C#, the best tool for this is often DateTimeOffset, because it represents a point in time more clearly than DateTime. It includes an offset from UTC and has built-in Unix conversion methods.

Mental Model

Think of Unix time as a universal stopwatch that started at midnight on 1970-01-01 UTC.

  • A Unix timestamp is just the stopwatch reading in seconds.
  • A DateTime is like a calendar clock display.
  • A local time zone is like choosing which wall clock you want to look at.

The important idea is this:

  • Unix timestamp = one exact moment
  • Local time = how that moment appears in a specific region

So when converting:

  • Convert the wall-clock time to the universal stopwatch reading.
  • Or take the stopwatch reading and display it as UTC or local time.

If you start mixing stopwatch values with local wall clocks too early, your result can shift unexpectedly.

Take Quiz

Syntax and Examples

The safest modern approach in C# is to use DateTimeOffset.

Convert Unix timestamp to date/time

long unixSeconds = 1704067200;
DateTimeOffset dto = DateTimeOffset.FromUnixTimeSeconds(unixSeconds);
DateTime utcDateTime = dto.UtcDateTime;
DateTime localDateTime = dto.LocalDateTime;

Explanation:

  • FromUnixTimeSeconds creates a DateTimeOffset from Unix seconds.
  • UtcDateTime gives the UTC version.
  • LocalDateTime converts that same moment to the machine's local time zone.

Convert date/time to Unix timestamp

DateTime created = DateTime.UtcNow;
long unixSeconds = new DateTimeOffset(created).ToUnixTimeSeconds();

If your DateTime is local time:

DateTime localTime = DateTime.Now;
long unixSeconds = new DateTimeOffset(localTime).ToUnixTimeSeconds();

If you must use DateTime directly

DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
DateTime utcTime = DateTime.UtcNow;
long unixSeconds = (long)(utcTime - epoch).TotalSeconds;

And converting back:

DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
DateTime utcTime = epoch.AddSeconds(unixSeconds);

Better version of your property

public long CreatedEpoch
{
    get
    {
        return new DateTimeOffset(Created).ToUnixTimeSeconds();
    }
    set
    {
        Created = DateTimeOffset.FromUnixTimeSeconds(value).UtcDateTime;
    }
}

This avoids manually calculating from a local-time epoch and better matches how Unix time actually works.

Step by Step Execution

Consider this example:

DateTime utcTime = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc);
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
long unixSeconds = (long)(utcTime - epoch).TotalSeconds;

Step by step:

  1. epoch is set to 1970-01-01 00:00:00 UTC.
  2. utcTime is set to 2024-01-01 00:00:00 UTC.
  3. utcTime - epoch produces a TimeSpan.
  4. That TimeSpan contains the total elapsed time between the two UTC moments.
  5. TotalSeconds returns the difference in seconds.
  6. Casting to long removes the fractional part.

Now convert it back:

long unixSeconds = 1704067200;
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
DateTime utcTime = epoch.AddSeconds(unixSeconds);

Step by step:

  1. Start with a Unix timestamp in seconds.
  2. Start from the Unix epoch in UTC.
  3. Add the number of seconds to the epoch.
  4. The result is the UTC date and time for that timestamp.

If you need local time for display:

DateTime localTime = utcTime.ToLocalTime();

This last conversion should usually happen only when showing the value to users.

Real World Use Cases

APIs

Many APIs send timestamps as Unix seconds or milliseconds because the format is compact and language-independent.

{ "createdAt": 1704067200 }

Logging and event tracking

Logs often use Unix timestamps so events can be compared consistently across servers in different time zones.

Authentication and security

JWT tokens and other auth systems often use Unix timestamps for expiration fields like exp.

Databases and storage

Some systems store timestamps as integers for easier sorting and transport.

Scheduled jobs

Background tasks may compare the current Unix timestamp with a stored timestamp to decide whether a job should run.

Take Quiz

Real Codebase Usage

In real projects, developers usually avoid scattering manual epoch math throughout the codebase.

Common patterns include:

Using DateTimeOffset for serialization

public class EventRecord
{
    public DateTimeOffset CreatedAt { get; set; }

    public long CreatedAtUnix => CreatedAt.ToUnixTimeSeconds();
}

This keeps the main value as a proper date/time type and only converts when needed.

Guarding against ambiguous DateTime values

DateTime can have these Kind values:

  • Utc
  • Local
  • Unspecified

Unspecified is risky because C# cannot always know how to interpret it.

Example guard clause:

public static long ToUnixSeconds(DateTime dateTime)
{
    if (dateTime.Kind == DateTimeKind.Unspecified)
        throw new ArgumentException("DateTimeKind.Unspecified is ambiguous.");

    return new DateTimeOffset(dateTime).ToUnixTimeSeconds();
}

Converting only at system boundaries

A common pattern is:

  • keep DateTimeOffset or UTC DateTime inside the application
  • convert to Unix timestamps when sending to APIs or storing compact values
  • convert back when reading external data

Early return for validation

public static DateTimeOffset FromUnixSeconds(long seconds)
{
    return DateTimeOffset.FromUnixTimeSeconds(seconds);
}

The framework method already validates the range, which reduces custom error-prone code.

Common Mistakes

1. Using local time for the Unix epoch

Broken example:

DateTime epoch = new DateTime(1970, 1, 1).ToLocalTime();

Why it is a problem:

  • Unix time is defined from a UTC epoch.
  • Converting the epoch to local time changes the reference point.

Correct:

DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

2. Mixing local and UTC values

Broken example:

DateTime now = DateTime.Now;
long unixSeconds = (long)(now - epoch).TotalSeconds;

Why it is a problem:

  • DateTime.Now is local time.
  • epoch may be UTC.
  • Mixing them can lead to offset errors.

Correct:

DateTime now = DateTime.UtcNow;
long unixSeconds = (long)(now - epoch).TotalSeconds;

3. Confusing seconds and milliseconds

Some systems use:

  • seconds: 1704067200
  • milliseconds: 1704067200000

Broken example:

DateTimeOffset.FromUnixTimeSeconds(1704067200000);

Correct:

DateTimeOffset.FromUnixTimeMilliseconds(1704067200000);

4. Using double when whole seconds are expected

Your property uses double. That works, but whole-second Unix timestamps are usually integers.

Prefer:

public long CreatedEpoch { get; set; }

Use fractional values only when you truly need sub-second precision.

5. Ignoring DateTimeKind

Broken example:

DateTime dt = new DateTime(2024, 1, 1, 0, 0, 0);

Why it is risky:

  • The Kind is Unspecified.
  • Later conversions may interpret it differently than you expect.

Better:

DateTime dt = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc);

Comparisons

ApproachBest forProsCons
DateTimeOffset.FromUnixTimeSeconds() / ToUnixTimeSeconds()Most application codeClear, built-in, handles offsets wellRequires newer .NET versions
Manual DateTime + epoch subtractionLearning or legacy codeSimple to understandEasier to get UTC handling wrong
DateTime.NowDisplaying local current timeUseful for UINot good as a basis for Unix time calculations
DateTime.UtcNowTimestamps and storageConsistent across systemsMust convert to local time for display if needed

DateTime vs DateTimeOffset

TypeWhat it representsGood choice for Unix time?
DateTimeA date/time value with a KindSometimes, but can be ambiguous
DateTimeOffsetA date/time plus UTC offsetYes, usually the better choice

Seconds vs Milliseconds

UnitExampleMethod
Seconds1704067200FromUnixTimeSeconds()
Milliseconds1704067200000FromUnixTimeMilliseconds()
Take Quiz

Cheat Sheet

// Unix timestamp -> DateTimeOffset
DateTimeOffset dto = DateTimeOffset.FromUnixTimeSeconds(unixSeconds);

// Unix timestamp -> UTC DateTime
DateTime utc = DateTimeOffset.FromUnixTimeSeconds(unixSeconds).UtcDateTime;

// Unix timestamp -> Local DateTime
DateTime local = DateTimeOffset.FromUnixTimeSeconds(unixSeconds).LocalDateTime;

// DateTime -> Unix timestamp
long unix = new DateTimeOffset(dateTime).ToUnixTimeSeconds();

// Current Unix timestamp
long nowUnix = DateTimeOffset.UtcNow.ToUnixTimeSeconds();

Rules:

  • Unix epoch is 1970-01-01 00:00:00 UTC
  • Prefer DateTimeOffset over manual math
  • Use UtcNow for current timestamps
  • Convert to local time only for display
  • Watch out for seconds vs milliseconds
  • Avoid DateTimeKind.Unspecified when possible

Manual UTC conversion:

DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
long unix = (long)(DateTime.UtcNow - epoch).TotalSeconds;
DateTime utc = epoch.AddSeconds(unix);

FAQ

How do I convert a Unix timestamp to a DateTime in C#?

Use DateTimeOffset.FromUnixTimeSeconds() or FromUnixTimeMilliseconds(), then read UtcDateTime or LocalDateTime.

Should I use DateTime or DateTimeOffset for Unix timestamps?

DateTimeOffset is usually better because it represents an exact point in time more clearly and has built-in Unix conversion methods.

Why is my converted time off by a few hours?

This usually happens because local time and UTC were mixed incorrectly during conversion.

What is the Unix epoch in C#?

It is 1970-01-01 00:00:00 UTC, the starting point for Unix timestamps.

Are Unix timestamps in seconds or milliseconds?

They can be either. Always check the source system. A 10-digit value is often seconds, while a 13-digit value is often milliseconds.

Can I store a Unix timestamp in a double?

You can, but long is usually better for whole-second or whole-millisecond timestamps because it avoids floating-point issues.

When should I convert UTC to local time?

Usually only when displaying the date/time to a user or formatting output for a specific region.

Take Quiz

Mini Project

Description

Build a small C# utility that converts values both ways: from Unix timestamp to human-readable time, and from DateTime to Unix timestamp. This demonstrates the most important rule of time handling in real applications: keep the internal value in UTC and only convert to local time when needed.

Goal

Create a console program that reads a Unix timestamp, prints its UTC and local values, and also prints the current Unix timestamp.

Requirements

  • Read a Unix timestamp in seconds and convert it to UTC time.
  • Show the same moment in local time.
  • Print the current Unix timestamp.
  • Convert the current UTC time back into Unix seconds.
  • Use DateTimeOffset for the conversions.
Take Quiz

Keep learning

Related questions

View more