This library is a C# library that provides a Ulid type in .NET (C#, VB.NET tested by DEV)
A ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier that is designed to be unique and time-ordered. It is similar to a UUID (Universally Unique Identifier) but has the additional property of being sortable by time. A ULID consists of two components: a 48-bit timestamp and a 80-bit random value. The timestamp is encoded in Crockford's Base32 format, which allows the ULID to be lexicographically sortable. The random value provides uniqueness and helps prevent collisions between ULIDs generated at the same time.
Posseth.UlidFactory library provides the following features:
- ULID generation with current or custom timestamps
- Parsing and validation of ULID strings
- DateTime, Epoch, and UnixTime conversion from ULIDs
- Handle new ULIDs or existing ULIDs read from databases
- High-performance implementation with minimal allocations
- SQL Server CLR integration support
The library has been fully modernized to leverage the latest C# 14 and .NET 10 features:
- Record Type: Converted to a
recordfor built-in immutability, equality, and hashing support - File-Scoped Namespaces: Adopted file-scoped namespaces to reduce indentation and improve readability
- Span and ReadOnlySpan: Utilized with
stackallocto minimize heap allocations and enhance performance - Expression-Bodied Members: Simplified method implementations for better readability
- Pattern Matching: Used
orpatterns andwhenclauses for cleaner conditional logic - var Keyword: Improved code readability throughout the codebase
- ArgumentOutOfRangeException.ThrowIfNegative: Modern validation for timestamp parameters
- ArgumentException.ThrowIfNullOrEmpty: Cleaner null/empty checks
- RandomNumberGenerator.Fill: Direct span filling for better performance
- Collection Expressions: Used
[]syntax for empty arrays
- Updated to xUnit 2.9.3: Latest test framework version
- Microsoft.NET.Test.Sdk 18.0.1: Modern test SDK
- Removed obsolete packages: Cleaned up Microsoft.CodeAnalysis.Testing dependencies
These changes maintain full backward compatibility while aligning with C# 14 and .NET 10 best practices, resulting in better performance and maintainability.
Install-Package Posseth.UlidFactoryOr via .NET CLI:
dotnet add package Posseth.UlidFactoryAdd the following using statement to your C# file:
using Posseth.UlidFactory;You can generate a new ULID using the NewUlid method. This can be done with the current timestamp or with a specified timestamp.
using Posseth.UlidFactory;
// Generate a new ULID with the current timestamp
var newUlid = Ulid.NewUlid();
Console.WriteLine($"New ULID: {newUlid}");
// Generate a new ULID with a specified DateTime
var specifiedTime = new DateTime(2023, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var ulidWithTime = Ulid.NewUlid(specifiedTime);
Console.WriteLine($"ULID with specified time: {ulidWithTime}");
// Generate a new ULID with a specified Unix timestamp
const long unixTimestamp = 1672444800000; // Unix timestamp for 2023-01-01 00:00:00 UTC
var ulidWithUnixTime = Ulid.NewUlid(unixTimestamp);
Console.WriteLine($"ULID with specified Unix timestamp: {ulidWithUnixTime}");You can parse an existing ULID string using the Parse method. If the ULID string is invalid, an exception will be thrown.
Alternatively, you can use the TryParse method to avoid exceptions and handle invalid ULIDs more gracefully.
using Posseth.UlidFactory;
// Parse a valid ULID string
const string ulidString = "01BX5ZZKBKACTAV9WEVGEMMVRZ";
try
{
var parsedUlid = Ulid.Parse(ulidString);
Console.WriteLine($"Parsed ULID: {parsedUlid}");
}
catch (ArgumentException ex)
{
Console.WriteLine($"Invalid ULID string: {ex.Message}");
}
// Try to parse a ULID string and handle invalid ULID gracefully
var success = Ulid.TryParse(ulidString, out var ulid);
if (success)
{
Console.WriteLine($"Successfully parsed ULID: {ulid}");
}
else
{
Console.WriteLine("Failed to parse ULID.");
}You can extract the timestamp from a ULID and convert it to a DateTime or Unix timestamp using the ToDateTime, ToEpoch, or ToUnixTime methods.
using Posseth.UlidFactory;
// Generate a new ULID
var newUlid = Ulid.NewUlid();
Console.WriteLine($"New ULID: {newUlid}");
// Get the timestamp as a DateTime
var timestamp = newUlid.ToDateTime();
Console.WriteLine($"Timestamp as DateTime: {timestamp}");
// Get the Unix timestamp in milliseconds
var unixTimestamp = newUlid.ToUnixTime();
Console.WriteLine($"Timestamp as Unix time: {unixTimestamp}");
// Extract timestamp using static method
var extractedTimestamp = Ulid.GetTimestampFromUlid(newUlid);
Console.WriteLine($"Extracted timestamp: {extractedTimestamp}");NewUlid()- Generate a ULID with current timestampNewUlid(DateTimeOffset timestamp)- Generate a ULID with specified DateTimeOffsetNewUlid(DateTime timestamp)- Generate a ULID with specified DateTimeNewUlid(long timestamp)- Generate a ULID with Unix timestamp (milliseconds)Parse(string ulidString)- Parse a ULID string (throws on invalid input)TryParse(string ulidString, out Ulid? ulid)- Try to parse a ULID string (returns bool)GetTimestampFromUlid(Ulid ulid)- Extract DateTime from a ULID
ToDateTime()- Convert ULID to DateTimeToEpoch()- Convert ULID to Unix timestamp (milliseconds)ToUnixTime()- Convert ULID to Unix timestamp (milliseconds) - alias for ToEpochHasValue()- Check if ULID has a valid valueToString()- Get string representation of ULID
SQL Server CLR integration for ULID generation and manipulation.
- SQL Server 2016 or higher
- CLR integration enabled
- .NET Framework 4.8.1
First, you need to enable CLR integration on your SQL Server instance:
sp_configure 'clr enabled', 1;
RECONFIGURE;Build the project and create a file hash of the assembly:
certutil -hashfile "C:\path\to\your\Posseth.Global.UlidFactory.MSSQL.dll" SHA512The result should look like:
b424f44500e83e72c8b4b60528250a40a4eabfddbb6b9c0e93208e6ddc63815e80180f26814f85bdad5ba2c88209d732397c7599e809da6df5146cc94daa250e
Before adding the assembly to the database, you need to tell SQL Server that you trust it:
-- Step 1: Declare a variable and convert the hash to a binary value
DECLARE @binaryHash varbinary(64);
SET @binaryHash = CONVERT(varbinary(64), 0xB424F44500E83E72C8B4B60528250A40A4EABFDDBB6B9C0E93208E6DDC63815E80180F26814F85BDAD5BA2C88209D732397C7599E809DA6DF5146CC94DAA250E, 1);
-- Step 2: Use the variable as parameter in the stored procedure
EXEC sp_add_trusted_assembly @hash = @binaryHash;Now you can add the assembly to the database:
CREATE ASSEMBLY UlidFactoryMSSQL
FROM 'C:\path\to\your\Posseth.Global.UlidFactory.MSSQL.dll'
WITH PERMISSION_SET = SAFE;You should see: 'Commands completed successfully.'
Create the CLR functions in your database:
CREATE FUNCTION dbo.GenerateUlid()
RETURNS NVARCHAR(100)
AS EXTERNAL NAME [UlidFactoryMSSQL].[Posseth.Global.UlidFactory.MSSQL.CLR.UlidFunctionsHelpers].[GenerateUlid];
GO
CREATE FUNCTION dbo.GenerateUlidWithTimestamp(@timestamp DATETIME)
RETURNS NVARCHAR(100)
AS EXTERNAL NAME [UlidFactoryMSSQL].[Posseth.Global.UlidFactory.MSSQL.CLR.UlidFunctionsHelpers].[GenerateUlidWithTimestamp];
GO
CREATE FUNCTION dbo.ExtractDateFromUlid(@ulidString NVARCHAR(100))
RETURNS DATETIME
AS EXTERNAL NAME [UlidFactoryMSSQL].[Posseth.Global.UlidFactory.MSSQL.CLR.UlidFunctionsHelpers].[ExtractDateFromUlid];
GOYou should see: 'Commands completed successfully.'
-- Generate a new ULID with current timestamp
SELECT dbo.GenerateUlid();
-- Result: 01BX5ZZKBKACTAV9WEVGEMMVRZ
-- Generate a ULID with specific timestamp
SELECT dbo.GenerateUlidWithTimestamp(GETDATE());
SELECT dbo.GenerateUlidWithTimestamp('2023-01-01 00:00:00');
-- Extract DateTime from ULID
SELECT dbo.ExtractDateFromUlid('01F8MECHZX3TBDSZ7FBJ4H7FJ6');
-- Result: 1982-11-13 14:32:34.560-- Use ULID as primary key in table
CREATE TABLE Orders (
OrderId NVARCHAR(26) PRIMARY KEY DEFAULT (dbo.GenerateUlid()),
CustomerName NVARCHAR(100),
OrderDate DATETIME DEFAULT GETDATE()
);
-- Insert records with auto-generated ULID
INSERT INTO Orders (CustomerName) VALUES ('John Doe');
INSERT INTO Orders (CustomerName) VALUES ('Jane Smith');
-- Query with timestamp extraction
SELECT
OrderId,
CustomerName,
dbo.ExtractDateFromUlid(OrderId) AS UlidTimestamp,
OrderDate
FROM Orders;For your convenience, a compiled DLL is included in the repository. You can use the above commands to add the assembly to your database without building the project yourself.
If you find this library useful, please consider supporting the development:
Your support helps maintain and improve this project. Thank you! 🙏
The Ulid class provides methods for generating, parsing, and extracting timestamps from ULIDs. By following the examples above, you can incorporate ULID generation and handling in your C# and SQL Server applications. The class ensures that the ULIDs generated are unique and time-ordered, providing a robust solution for use cases requiring such identifiers.
This project is licensed under the MIT License - see the LICENSE.txt file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
Michel Posseth - MPCoreDeveloper
- Based on the ULID specification
- Built with modern C# 14 and .NET 10 features
- Tested on Visual Studio 2026
