Last updated
Twitter Snowflake ID C# Implementation
Complete C# implementation for working with Twitter Snowflake IDs. Includes production-ready code for decoding existing IDs and generating new ones with thread-safety using lock statements.
Key Features
Thread-Safe
Lock statements prevent race conditions
Twitter Snowflake ID in C# — Examples
This page provides C# code for decoding Twitter Snowflake IDs and extracting their embedded timestamps. All examples are production-ready and use idiomatic modern C# (.NET 6+).
Basic Decoder
// C# — basic Twitter Snowflake ID decoder
using System;
public static class TwitterSnowflake
{
// Twitter's custom epoch: November 4, 2010 01:42:54.657 UTC
private const long TwitterEpochMs = 1288834974657L;
public static DateTimeOffset Decode(long id)
{
long timestampMs = (id >> 22) + TwitterEpochMs;
return DateTimeOffset.FromUnixTimeMilliseconds(timestampMs);
}
public static int GetDatacenterId(long id) => (int)((id >> 17) & 0x1F);
public static int GetWorkerId(long id) => (int)((id >> 12) & 0x1F);
public static int GetSequence(long id) => (int)(id & 0xFFF);
}
// Usage
long tweetId = 1529877576591609861L;
DateTimeOffset date = TwitterSnowflake.Decode(tweetId);
Console.WriteLine($"Date (UTC): {date.UtcDateTime:yyyy-MM-dd HH:mm:ss}");
Console.WriteLine($"ISO 8601: {date:O}");
Console.WriteLine($"Unix (s): {date.ToUnixTimeSeconds()}");
Console.WriteLine($"Datacenter: {TwitterSnowflake.GetDatacenterId(tweetId)}");
Console.WriteLine($"Worker: {TwitterSnowflake.GetWorkerId(tweetId)}");
Console.WriteLine($"Sequence: {TwitterSnowflake.GetSequence(tweetId)}");
Full Decoder Class with Record Return Type
// C# — decoder returning a structured result
using System;
public record SnowflakeComponents(
long Id,
DateTimeOffset CreatedAt,
long TimestampMs,
int DatacenterId,
int WorkerId,
int Sequence
);
public static class TwitterSnowflake
{
private const long TwitterEpochMs = 1288834974657L;
public static SnowflakeComponents Decode(long id)
{
long timestampMs = (id >> 22) + TwitterEpochMs;
return new SnowflakeComponents(
Id: id,
CreatedAt: DateTimeOffset.FromUnixTimeMilliseconds(timestampMs),
TimestampMs: timestampMs,
DatacenterId: (int)((id >> 17) & 0x1F),
WorkerId: (int)((id >> 12) & 0x1F),
Sequence: (int)(id & 0xFFF)
);
}
// Reverse: convert a DateTimeOffset to the minimum Snowflake ID for that moment
public static long DateToMinId(DateTimeOffset date)
{
long tsMs = date.ToUnixTimeMilliseconds() - TwitterEpochMs;
if (tsMs < 0)
throw new ArgumentException("Date is before Twitter's Snowflake epoch");
return tsMs << 22;
}
}
// Usage
var components = TwitterSnowflake.Decode(1529877576591609861L);
Console.WriteLine(components);
Extension Methods
// C# — extension methods for clean syntax
using System;
public static class SnowflakeExtensions
{
private const long TwitterEpochMs = 1288834974657L;
public static DateTimeOffset ToTwitterDate(this long id)
{
long timestampMs = (id >> 22) + TwitterEpochMs;
return DateTimeOffset.FromUnixTimeMilliseconds(timestampMs);
}
public static bool IsSnowflakeId(this long id)
{
// Snowflake IDs are larger than ~27 billion
return id > 27_000_000_000L;
}
}
// Usage
long tweetId = 1529877576591609861L;
DateTimeOffset date = tweetId.ToTwitterDate();
Console.WriteLine($"Created: {date:yyyy-MM-dd HH:mm:ss} UTC");
Console.WriteLine($"Is Snowflake: {tweetId.IsSnowflakeId()}");
Batch Processing with LINQ
// C# — batch decode a collection of tweet IDs
using System;
using System.Collections.Generic;
using System.Linq;
var tweetIds = new List<long>
{
1529877576591609861L,
1700000000000000000L,
1800000000000000000L,
1900000000000000000L,
};
var decoded = tweetIds
.Select(id => new
{
Id = id,
Date = TwitterSnowflake.Decode(id).CreatedAt,
Sequence = TwitterSnowflake.GetSequence(id)
})
.OrderBy(x => x.Id) // Sort chronologically
.ToList();
foreach (var item in decoded)
{
Console.WriteLine($"{item.Id} → {item.Date:yyyy-MM-dd HH:mm:ss} UTC (seq: {item.Sequence})");
}
Filtering Tweets by Date Range
// C# — filter tweets by decoded date range
using System;
using System.Collections.Generic;
using System.Linq;
var tweets = new List<(long Id, string Text)>
{
(1529877576591609861L, "Tweet from May 2022"),
(1700000000000000000L, "Tweet from milestone"),
(1800000000000000000L, "Another milestone tweet"),
};
var start = new DateTimeOffset(2022, 1, 1, 0, 0, 0, TimeSpan.Zero);
var end = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero);
var filtered = tweets
.Where(t => {
var date = TwitterSnowflake.Decode(t.Id).CreatedAt;
return date >= start && date < end;
})
.ToList();
Console.WriteLine($"Tweets in 2022: {filtered.Count}");
Unit Tests (xUnit)
// C# — xUnit tests for the Snowflake decoder
using Xunit;
using System;
public class TwitterSnowflakeTests
{
[Fact]
public void Decode_KnownId_ReturnsCorrectYear()
{
long id = 1529877576591609861L;
var result = TwitterSnowflake.Decode(id);
Assert.Equal(2022, result.CreatedAt.Year);
}
[Fact]
public void Decode_ExtractsCorrectComponents()
{
long id = 1529877576591609861L;
var result = TwitterSnowflake.Decode(id);
Assert.True(result.DatacenterId >= 0 && result.DatacenterId <= 31);
Assert.True(result.WorkerId >= 0 && result.WorkerId <= 31);
Assert.True(result.Sequence >= 0 && result.Sequence <= 4095);
}
[Fact]
public void DateToMinId_RoundTrip_IsConsistent()
{
var date = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero);
long minId = TwitterSnowflake.DateToMinId(date);
var decoded = TwitterSnowflake.Decode(minId);
// Decoded date should be within 1ms of the input date
Assert.True(Math.Abs((decoded.CreatedAt - date).TotalMilliseconds) < 1);
}
}
Parallel Processing for Large Datasets
// C# — parallel batch decode for high throughput
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public static Dictionary<long, DateTimeOffset> BatchDecodeParallel(IEnumerable<long> ids)
{
var results = new ConcurrentDictionary<long, DateTimeOffset>();
Parallel.ForEach(ids, id =>
{
var date = TwitterSnowflake.Decode(id).CreatedAt;
results[id] = date;
});
return new Dictionary<long, DateTimeOffset>(results);
}
// Usage
var ids = Enumerable.Range(0, 10000)
.Select(i => 1529877576591609861L + i)
.ToList();
var decoded = BatchDecodeParallel(ids);
Console.WriteLine($"Decoded {decoded.Count} IDs");
These C# examples cover all common use cases for working with Twitter Snowflake IDs in .NET applications. The decoder is fast, accurate, and handles all valid Snowflake IDs correctly.
Production Ready
Error handling and validation included
High Performance
Efficient bit operations for speed
Modern C#
Uses latest C# features and patterns
NuGet Packages
Best Practices
- Use
longdata type for Snowflake IDs (notint) - Always use lock statements for ID generation
- Handle clock backwards scenarios with exceptions
- Use unique worker and process IDs in distributed systems
- Consider using dependency injection for generator instances
- Add logging with ILogger for production environments
Common Use Cases
- Decoding Twitter API responses in .NET applications
- Building Twitter integration services with ASP.NET
- Implementing custom Snowflake ID systems
- Analyzing Twitter data in C# applications
- Creating distributed ID generators for microservices
Frequently Asked Questions
Use bit shifting to extract components: timestamp = (id >> 22) + TWITTER_EPOCH, workerId = (id >> 17) & 0x1F, processId = (id >> 12) & 0x1F, sequence = id & 0xFFF. Twitter's epoch is 1288834974657L milliseconds. Convert to DateTime using DateTimeOffset.FromUnixTimeMilliseconds(timestamp).
Use C#'s long data type for Twitter Snowflake IDs. Snowflake IDs are 64-bit integers that fit perfectly in C#'s long (System.Int64). Avoid using int (32-bit) as it's too small for Snowflake IDs.
Generate Snowflake IDs by combining: timestamp minus TWITTER_EPOCH shifted left 22 bits, workerId shifted left 17 bits, processId shifted left 12 bits, then OR with sequence. Use lock statements for thread-safety and increment sequence for IDs generated in the same millisecond.
You must implement thread-safety manually using lock statements or System.Threading.Interlocked. Track the last timestamp and sequence number to ensure uniqueness across threads in multi-threaded applications.