Skip to content
Developer Tools8 min readPublished: September 14, 2026

How to Decode UUIDv7 Timestamp Natively: Zero-Dependency CLI Guide

Extract the 48-bit millisecond Unix timestamp from UUIDv7 identifiers using native Linux Bash and Windows PowerShell commands without third-party dependencies. This guide breaks down RFC 9562 big-endian memory layout, hexadecimal bit shifting, and minimal runtime parsing.

Written by WasyTech Engineering Β· Core Engineering Team
Share:𝕏RedditLinkedIn

Quick Answer: Decode UUIDv7 in One Command

To extract the embedded timestamp from a UUIDv7, isolate the first 48 bits (the first 12 hexadecimal characters, skipping the first hyphen) and convert that big-endian value into a Unix epoch millisecond timestamp.

Linux (Bash + GNU Coreutils)

bash
UUID="018f43a8-b647-7000-811c-6d9b4b9b00e9"

# 1. Strip the hyphen and extract the first 12 hex characters (48 bits)
HEX_MS="${UUID:0:8}${UUID:9:4}"

# 2. Convert hex to decimal milliseconds
MS_DEC=$((16#$HEX_MS))

# 3. Format using GNU date via seconds and remaining milliseconds
SEC=$((MS_DEC / 1000))
MILLI=$((MS_DEC % 1000))
date -d "@$SEC" -u +"%Y-%m-%d %H:%M:%S.${MILLI} UTC"

Windows (PowerShell CLI)

powershell
$uuid = "018f43a8-b647-7000-811c-6d9b4b9b00e9"

# Extract 48-bit hex prefix, parse to Int64, and map to DateTimeOffset
$hexMs = ($uuid.Substring(0, 8) + $uuid.Substring(9, 4))
$ms = [System.Convert]::ToInt64($hexMs, 16)
[System.DateTimeOffset]::FromUnixTimeMilliseconds($ms).UtcDateTime.ToString("yyyy-MM-dd HH:mm:ss.fff 'UTC'")

---

128-Bit Memory Layout of UUIDv7 (RFC 9562)

The IETF RFC 9562 defines the bit allocation for UUID version 7. Unlike legacy UUIDv4 identifiers that rely entirely on pseudo-random entropy, UUIDv7 provides time-ordered locality by dedicating its most significant bits to an absolute Unix timestamp.

bash
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           unix_ts_ms                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          unix_ts_ms           |  ver  |       rand_a          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var|                        rand_b                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            rand_b                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Field Breakdown * **`unix_ts_ms` (Bits 0–47 / Bytes 0–5)**: A 48-bit unsigned integer representing the number of milliseconds elapsed since the Unix epoch (`1970-01-01T00:00:00Z`). It is encoded in **big-endian (network byte order)**. * **`ver` (Bits 48–51 / Nibble 12)**: The 4-bit version identifier, set to `0111` binary (`0x7`). * **`rand_a` (Bits 52–63 / Nibbles 13–15)**: 12 bits of pseudo-random data or sub-millisecond precision extensions. * **`var` (Bits 64–65)**: The 2-bit variant field defined by RFC 4122/9562, fixed to `10` binary. * **`rand_b` (Bits 66–127)**: The remaining 62 bits of entropy to guarantee uniqueness across distributed nodes.

Because the first 48 bits map sequentially from left to right, decoding does not require parsing complex record structures. You only need to extract the first 6 bytes.

---

Native Linux Parsing via Bash and GNU Coreutils

Modern Linux environments provide the tools required to parse 48-bit integers without installing external utilities like Node.js, Python, or Ruby.

String Slicing and Base-16 Arithmetic A formatted UUID string contains hyphens at positions 8, 13, 18, and 23:

text
018f43a8-b647-7000-811c-6d9b4b9b00e9
^^^^^^^^ ^^^^
8 chars  4 chars -> Total 12 hex chars (48 bits / 6 bytes)

In Bash, extract the high-order bits using parameter expansion:

bash
UUID="018f43a8-b647-7000-811c-6d9b4b9b00e9"
HEX="${UUID:0:8}${UUID:9:4}"

Bash natively supports arbitrary-base integer arithmetic using the $((base#value)) syntax. Convert the 48-bit hexadecimal value to base-10:

bash
MS=$((16#$HEX))

Timestamp Transformation via GNU Coreutils The GNU Coreutils `date` implementation accepts Unix epoch seconds using the `@` prefix.

Because date -d expects seconds rather than milliseconds, divide the base value by 1000 and append the remainder:

bash
#!/usr/bin/env bash
set -euo pipefail

decode_uuidv7() {
    local uuid="$1"
    local clean_uuid="${uuid//-/}"
    local hex_ts="${clean_uuid:0:12}"
    
    # Base-16 arithmetic expansion
    local epoch_ms=$((16#$hex_ts))
    local epoch_sec=$((epoch_ms / 1000))
    local millis=$((epoch_ms % 1000))
    
    # Format directly to ISO-8601 UTC
    printf "UUID: %s\n" "$uuid"
    printf "Epoch Milliseconds: %d\n" "$epoch_ms"
    printf "Timestamp UTC: %s.%03dZ\n" \
        "$(date -u -d "@$epoch_sec" +'%Y-%m-%dT%H:%M:%S')" \
        "$millis"
}

decode_uuidv7 "018f43a8-b647-7000-811c-6d9b4b9b00e9"

---

Native Windows Parsing via PowerShell and the .NET Runtime

Windows PowerShell and PowerShell Core have direct access to the Base Class Library (BCL), allowing native, high-performance byte manipulation without third-party modules.

The Endianness Problem with `System.Guid` A common pitfall on Windows is passing the UUID directly to `[System.Guid]::Parse()`.

The internal storage of Microsoft's Guid structure reflects legacy Mixed-Endian (Little-Endian for Data1, Data2, and Data3 fields) layouts for compatibility with COM/RPC interfaces.

powershell
# CAUTION: [System.Guid]::ToByteArray() swaps bytes in Data1, Data2, Data3
$guid = [System.Guid]::Parse("018f43a8-b647-7000-811c-6d9b4b9b00e9")
$bytes = $guid.ToByteArray()
# $bytes[0..3] will be reversed relative to the RFC 9562 big-endian text representation!

To avoid endianness corruption when processing raw byte buffers, parse the string directly or handle the explicit big-endian byte array via System.Convert and [Microsoft's System.BitConverter](https://learn.microsoft.com/en-us/dotnet/api/system.bitconverter).

Direct Bitwise and BCL Implementation

The most direct, allocation-light method in PowerShell uses [System.Convert] combined with [Microsoft's System.DateTimeOffset](https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset):

powershell
function Get-UUIDv7Timestamp {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [ValidatePattern('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$')]
        [string]$Guid
    )

    process {
        # Extract the 12 hex characters containing the 48-bit timestamp
        $hexTimestamp = $Guid.Substring(0, 8) + $Guid.Substring(9, 4)
        
        # Parse base-16 directly into a 64-bit signed integer
        $epochMilliseconds = [System.Convert]::ToInt64($hexTimestamp, 16)
        
        # Instantiate UTC DateTimeOffset directly from epoch ms
        $dto = [System.DateTimeOffset]::FromUnixTimeMilliseconds($epochMilliseconds)
        
        [PSCustomObject]@{
            UUID               = $Guid
            EpochMilliseconds  = $epochMilliseconds
            TimestampUtc       = $dto.UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ")
        }
    }
}

Get-UUIDv7Timestamp -Guid "018f43a8-b647-7000-811c-6d9b4b9b00e9"

Parsing Raw 16-Byte Buffers with `System.BitConverter` If your PowerShell pipeline ingests raw 16-byte binary files (e.g., database dumps, stream sockets), use bitwise shifting with `System.BitConverter` while accounting for system architecture endianness:

powershell
# Example: 16-byte raw UUIDv7 binary array
[byte[]]$rawUuid = @(
    0x01, 0x8F, 0x43, 0xA8, 0xB6, 0x47, 0x70, 0x00, 
    0x81, 0x1C, 0x6D, 0x9B, 0x4B, 0x9B, 0x00, 0xE9
)

# Extract first 6 bytes and pad to 8 bytes for Int64 conversion
[byte[]]$paddedBytes = @(0, 0) + $rawUuid[0..5]

# System.BitConverter expects Little-Endian on modern x64 hardware
if ([System.BitConverter]::IsLittleEndian) {
    [System.Array]::Reverse($paddedBytes)
}

$epochMs = [System.BitConverter]::ToInt64($paddedBytes, 0)
$date = [System.DateTimeOffset]::FromUnixTimeMilliseconds($epochMs).UtcDateTime
Write-Output "Extracted UTC Date: $($date.ToString('o'))"

---

Binary Memory Representation and Bitwise Extraction

Understanding the binary mechanics helps diagnose corrupted IDs or incorrect offset alignment.

text
UUIDv7: 018f43a8-b647-7000-811c-6d9b4b9b00e9

1. Hex to Binary Breakdown (First 64 Bits)

Byte IndexHex ValueBinary RepresentationField Assignment
**Byte 0**`01``00000001``unix_ts_ms [47:40]`
**Byte 1**`8f``10001111``unix_ts_ms [39:32]`
**Byte 2**`43``01000011``unix_ts_ms [31:24]`
**Byte 3**`a8``10101000``unix_ts_ms [23:16]`
**Byte 4**`b6``10110110``unix_ts_ms [15:8]`
**Byte 5**`47``01000111``unix_ts_ms [7:0]`
**Byte 6**`70``0111 0000``ver (0111)` \`rand_a (0000)`
**Byte 7**`00``00000000``rand_a [7:0]`

2. Hex Value Reconstruction Combine the first 6 bytes into a 48-bit hex string: $$\text{0x018F43A8B647} = 1,714,727,466,567 \text{ ms}$$

3. Unix Millisecond Conversion Divide by 1000 to extract seconds and milliseconds: $$\text{Seconds} = \lfloor 1714727466567 / 1000 \rfloor = 1714727466 \implies \text{2024-05-03 09:11:06 UTC}$$ $$\text{Milliseconds} = 1714727466567 \pmod{1000} = 567 \text{ ms}$$

Resulting Timestamp: 2024-05-03T09:11:06.567Z

---

Critical Edge Cases: Monotonicity and Distributed Clocks

While UUIDv7 provides natural time-ordering capabilities, production systems introduce constraints defined by hardware limitations and distributed network conditions.

bash
Node A (NTP +15ms)  ---> [ 018f43a8-b647... (ms: 567) ]
Node B (NTP -20ms)  ---> [ 018f43a8-b630... (ms: 544) ]  <-- Generated *after* Node A

1. Millisecond Precision Limits According to **RFC 9562 Section 5.7**, the core `unix_ts_ms` field is limited strictly to millisecond precision.

  • Sub-millisecond accuracy cannot be guaranteed from the first 48 bits alone.
  • While implementations *may* pack fractional sub-millisecond bins into the 12-bit rand_a field, this behavior is optional and varies across language libraries.
  • Do not rely on the unix_ts_ms field for microsecond-accurate event sequencing or distributed race-condition arbitration.

2. NTP Desynchronization and Clock Drift Because the primary sort key is generated by the local machine's system clock: * Sorting UUIDv7 values across independent servers depends entirely on the accuracy of the local **Network Time Protocol (NTP)** daemons. * If Node A's clock leads Node B's clock by 50ms, a UUIDv7 generated on Node A will sort *after* a UUIDv7 generated on Node B, even if Node B generated its record later in absolute physical time. * Database systems relying on UUIDv7 for B-Tree indexing preserve index locality, but cross-node ingestion may experience slight out-of-order writes during clock drift.

---

Eliminating Dependency Bloat in Core Tooling

Inspecting data structures shouldn't require pulling heavy runtimes into your toolchain. A simple 48-bit bitmask and timestamp extraction can be handled directly by standard operating system tools.

bash
Bloated Approach:
[npm install uuid-tool] -> [12 packages] -> [Node Runtime ~40MB] -> Parse 6 Bytes

Minimalist Approach:
[Bash Parameter Expansion] -> [$((16#HEX))] -> [GNU date] -> Parse 6 Bytes

Overhead Comparison

Pipeline ComponentRuntime DependencyMemory FootprintExternal Packages Required
**Node.js Script**Node.js V8 Engine (`node`)~35 MB – 50 MB`uuid` or custom parsing module
**Web-Based Decoders**Browser Engine (Chromium/Gecko)~150 MB – 500 MBJavaScript tracking + remote network roundtrip
**Native Bash / GNU**GNU Coreutils (`date`, `bash`)< 2 MB**Zero** (Built into OS)
**PowerShell / .NET**.NET CLR Engine (`pwsh`)Embedded within OS**Zero** (Native BCL)

Relying on built-in utilities like Bash arithmetic and the .NET Base Class Library minimizes supply chain exposure, ensures scripts run reliably in locked-down production servers, and eliminates runtime overhead for basic systems tasks.

Frequently Asked Technical Questions

Per RFC 9562, the timestamp occupies the first 48 bits (6 bytes) of the 128-bit structure, stored as an unsigned big-endian integer representing milliseconds since the Unix epoch (1970-01-01T00:00:00Z). In standard 36-character hyphenated UUID string notation, this corresponds directly to the first 12 hexadecimal characters: the entire 8-character first group and the first 4 characters of the second group.

WasyTech Engineering

Core Engineering Team

The collective engineering minds behind WasyTech's zero-bloat utility architecture.

Focus:Systems ProgrammingPerformance DiagnosticsWindows InternalsNetwork Protocols

Related Systems Guides

View all guides β†’
System & Hardware9 min readSeptember 9, 2026

Why Is System Interrupts High CPU Usage? Kernel-Level ISR and DPC Diagnostics

High System Interrupts CPU usage indicates low-level driver or ACPI hardware latency preempting the Windows kernel scheduler via prolonged Interrupt Service Routines (ISRs) and Deferred Procedure Calls (DPCs). Learn to trace the exact offending .sys driver or firmware conflict using Event Tracing for Windows (ETW) and Windows Performance Analyzer without third-party driver bloatware.