How to Use Protobuf Well-Known Types: Any, Timestamp, and Duration

Use google.protobuf.Any to wrap arbitrary messages with type URLs, google.protobuf.Timestamp for absolute UTC timestamps, and google.protobuf.Duration for signed time spans.

Protobuf well-known types provide standardized, cross-language message definitions for common data patterns. Defined in the protocolbuffers/protobuf repository, these types ensure consistent binary wire format and JSON mapping across all supported languages.

Understanding Protobuf Well-Known Types

What Are Well-Known Types?

Well-known types are a set of protocol buffer message definitions maintained by Google in the src/google/protobuf/ directory. Unlike custom messages, these types ship with pre-generated code for every supported language and follow strict JSON mapping rules defined in the protobuf specification.

Core Types Overview

The three most frequently used well-known types are:

  • google.protobuf.Any – A container that holds an arbitrary serialized message as bytes along with a URL that identifies the message type. Defined in src/google/protobuf/any.proto.
  • google.protobuf.Timestamp – Represents a point in time independent of time zone or calendar, stored as seconds and nanoseconds since the Unix epoch. Defined in src/google/protobuf/timestamp.proto.
  • google.protobuf.Duration – Represents a signed span of time, also using seconds and nanoseconds components. Defined in src/google/protobuf/duration.proto.

Working with google.protobuf.Any

The Any type enables dynamic typing by storing the raw bytes of any message alongside a type URL that identifies the message's fully qualified name (e.g., type.googleapis.com/my.package.User).

Packing and Unpacking Messages

When using Any, you must pack a message before serialization and unpack it after deserialization. The type URL format follows type.googleapis.com/{fully.qualified.message.name}.

Go Example:

import (
    "google.golang.org/protobuf/types/known/anypb"
    "google.golang.org/protobuf/proto"
)

type User struct {
    Id   int64  `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
    Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
}

func exampleAny() {
    u := &User{Id: 42, Name: "Alice"}
    
    // Pack the message into Any
    anyMsg, _ := anypb.New(u)
    
    // Unpacking requires checking type first
    var unpacked User
    if anypb.UnmarshalTo(anyMsg, &unpacked, proto.UnmarshalOptions{}) == nil {
        // Successfully unpacked
    }
}

Python Example:

from google.protobuf import any_pb2
from google.protobuf.message import Message

# Assuming User is a generated message class

user = User(id=99, name="Bob")

any_msg = any_pb2.Any()
any_msg.Pack(user)

# Type checking before unpacking

if any_msg.Is(User.DESCRIPTOR):
    unpacked_user = User()
    any_msg.Unpack(unpacked_user)

Java Example:

import com.google.protobuf.Any;
import com.google.protobuf.Message;

public class AnyExample {
    public static void packAndUnpack(UserProto.User user) {
        // Pack
        Any any = Any.pack(user);
        
        // Unpack with type check
        if (any.is(UserProto.User.class)) {
            UserProto.User unpacked = any.unpack(UserProto.User.class);
        }
    }
}

Handling Timestamps with google.protobuf.Timestamp

Timestamp represents time as two fields: seconds (int64) since the Unix epoch and nanos (int32) for the fractional second component. The valid range spans from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.

Go Example:

import (
    "time"
    "google.golang.org/protobuf/types/known/timestamppb"
)

func timestampOps() {
    // Current time
    now := timestamppb.Now()
    
    // From time.Time
    t := time.Date(2024, 3, 2, 12, 0, 0, 0, time.UTC)
    ts := timestamppb.New(t)
    
    // Convert back to time.Time
    goTime := ts.AsTime()
}

Python Example:

from google.protobuf import timestamp_pb2
from datetime import datetime, timezone

ts = timestamp_pb2.Timestamp()
ts.FromDatetime(datetime.now(timezone.utc))

# Convert back

dt = ts.ToDatetime()

Java Example:

import com.google.protobuf.Timestamp;
import com.google.protobuf.util.Timestamps;
import java.time.Instant;

public class TimestampExample {
    public static void main() {
        // From milliseconds
        Timestamp now = Timestamps.fromMillis(System.currentTimeMillis());
        
        // To Java Instant
        Instant instant = Timestamps.toInstant(now);
        
        // Add duration
        Timestamp later = Timestamps.add(now, Durations.fromSeconds(3600));
    }
}

Managing Durations with google.protobuf.Duration

Duration represents a signed span of time using the same seconds + nanos structure as Timestamp. Negative durations are valid. The JSON representation uses a string ending with the letter s (e.g., "300s" or "1.500s").

Go Example:

import (
    "time"
    "google.golang.org/protobuf/types/known/durationpb"
)

func durationOps() {
    // Create from time.Duration
    d := durationpb.New(5 * time.Second)
    
    // Convert to time.Duration
    goDuration := d.AsDuration()
    
    // Arithmetic with timestamps
    future := timestamppb.New(time.Now().Add(d.AsDuration()))
}

Python Example:

from google.protobuf import duration_pb2
from datetime import timedelta

dur = duration_pb2.Duration()
dur.FromTimedelta(timedelta(hours=2, minutes=30))

# Convert back

td = dur.ToTimedelta()

Java Example:

import com.google.protobuf.Duration;
import com.google.protobuf.util.Durations;

public class DurationExample {
    public static void main() {
        // From seconds
        Duration hour = Durations.fromSeconds(3600);
        
        // Parse from string
        Duration parsed = Durations.parse("1.5s");
        
        // Add to timestamp
        Timestamp later = Timestamps.add(now, hour);
    }
}

Key Source Files and Implementation Details

The well-known types are defined in the main protobuf repository under src/google/protobuf/. These proto files contain extensive comments explaining JSON mapping, valid ranges, and security considerations.

File Definition Key Implementation Details
src/google/protobuf/any.proto Any message with type_url and value fields Lines 78-101 detail type URL format (type.googleapis.com/{msg}) and security considerations for unpacking. Lines 59-68 explain JSON encoding with @type field.
src/google/protobuf/timestamp.proto Timestamp with seconds and nanos Lines 8-15 specify valid range (0001-01-01 to 9999-12-31). Lines 59-99 provide language-agnostic construction examples. JSON maps to RFC 3339 strings.
src/google/protobuf/duration.proto Duration with seconds and nanos Lines 50-84 demonstrate arithmetic examples. JSON representation requires string suffix s (e.g., "3.000001s"). Valid range is -315,576,000,000 to +315,576,000,000 seconds.

All three types follow standard protobuf wire encoding: field 1 is always seconds or type_url, field 2 is nanos or value.

Summary

  • Protobuf well-known types provide standardized, cross-language implementations for Any, Timestamp, and Duration in the protocolbuffers/protobuf repository.
  • google.protobuf.Any enables dynamic typing by storing arbitrary messages with a type URL; use Pack and Unpack methods with type safety checks.
  • google.protobuf.Timestamp represents absolute time as seconds and nanoseconds since Unix epoch; JSON serializes to RFC 3339 format.
  • google.protobuf.Duration represents signed time spans; JSON requires the s suffix and supports negative values.
  • Source definitions in src/google/protobuf/any.proto, timestamp.proto, and duration.proto guarantee binary compatibility and consistent JSON mapping across all languages.

Frequently Asked Questions

What is the difference between Timestamp and Duration in protobuf?

google.protobuf.Timestamp represents an absolute point in time relative to the Unix epoch (January 1, 1970), while google.protobuf.Duration represents a signed length of time independent of any starting point. In the source definitions (timestamp.proto and duration.proto), both use seconds and nanos fields, but semantically you add durations to timestamps to produce new timestamps.

How do I safely unpack a message from google.protobuf.Any?

Always verify the type before unpacking to avoid deserialization attacks. In Go, use anypb.UnmarshalTo with error checking; in Python, call any_msg.Is(User.DESCRIPTOR) before Unpack(); in Java, use any.is(User.class) before any.unpack(). The any.proto file (lines 78-101) warns that unpacking arbitrary types can be a security risk if the type URL is not validated.

Can I use well-known types with JSON serialization?

Yes, protobuf well-known types have canonical JSON representations defined in the protobuf specification. Timestamp maps to RFC 3339 strings (e.g., "2024-03-02T12:34:56.123Z"), Duration maps to strings ending with s (e.g., "300s"), and Any maps to a JSON object containing @type and value fields. These mappings are documented in the comments of timestamp.proto (lines 8-15), duration.proto, and any.proto (lines 59-68).

What is the valid range for protobuf Timestamp values?

According to src/google/protobuf/timestamp.proto (lines 8-15), valid timestamps range from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. This represents a range of approximately 10,000 years. The seconds field must be within this range, and nanos must be between 0 and 999,999,999 inclusive (or negative for negative timestamps in the case of Duration).

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →