Understanding Message Timestamps
1. Understanding Timestamp Types
| Type | Source | Detail |
|---|---|---|
| CreateTime | Set by producer | Event time |
| LogAppendTime | Set by broker on write | Ingestion time |
| message.timestamp.type | Topic config selects | CreateTime default |
Example: Read record timestamp
long ts = record.timestamp();
TimestampType type = record.timestampType(); // CREATE_TIME or LOG_APPEND_TIME
2. Using Create Time
| Aspect | Description | Detail |
|---|---|---|
| CreateTime | When event occurred | Producer-supplied |
| Default | Current time if unset | System.currentTimeMillis |
| Streams | Drives event-time windows | Preferred |
Example: Explicit create time
// topic, partition, timestamp, key, value
producer.send(new ProducerRecord<>("events", null, eventTimeMs, key, value));
3. Using Log Append Time
| Aspect | Description | Detail |
|---|---|---|
| LogAppendTime | Broker write moment | Overwrites producer ts |
| Monotonic | Roughly increasing per partition | Server clock |
| Use Case | Retention by arrival | Deterministic |
Example: Set log append time
kafka-configs.sh --alter --entity-type topics --entity-name events \
--add-config message.timestamp.type=LogAppendTime \
--bootstrap-server localhost:9092
4. Configuring Timestamp Type
| Config | Values | Default |
|---|---|---|
| message.timestamp.type | CreateTime / LogAppendTime | CreateTime |
| Scope | Broker default + topic override | Per topic |
| log.message. timestamp.type |
Broker-level default | CreateTime |
5. Setting Producer Timestamp
| Aspect | Description | Detail |
|---|---|---|
| Timestamp arg | Explicit in ProducerRecord | ms epoch |
| null | Defaults to send time | Auto |
| Ignored if | Topic uses LogAppendTime | Broker overwrites |
Example: Backdated event
long original = parseEventTime(json);
producer.send(new ProducerRecord<>("events", null, original, key, json));
6. Understanding Timestamp Ordering
| Aspect | Description | Detail |
|---|---|---|
| Not Guaranteed | CreateTime may be unordered | Out-of-order events |
| Offset Order | Offsets always increase | Storage order |
| Streams | Handles via grace period | Late events |
Example: Detect out-of-order
if (record.timestamp() < lastSeenTs) outOfOrderCount++;
lastSeenTs = Math.max(lastSeenTs, record.timestamp());
7. Using Timestamps for Retention
| Aspect | Description | Detail |
|---|---|---|
| Retention Basis | Segment max timestamp vs retention.ms | Per segment |
| CreateTime risk | Backdated data deleted early | Watch clocks |
| LogAppendTime | Predictable expiry | Arrival-based |
Warning: With CreateTime, future-dated timestamps can keep segments alive far beyond retention.ms.
8. Filtering by Timestamp
| Method | Purpose | Detail |
|---|---|---|
| offsetsForTimes | Find offset at/after time | Per partition |
| seek | Jump to that offset | Then poll |
| In-loop | Skip records below time | Post-filter |
Example: Seek by timestamp
Map<TopicPartition, Long> query = Map.of(tp, sinceMs);
var offsets = consumer.offsetsForTimes(query);
consumer.seek(tp, offsets.get(tp).offset());
9. Configuring Timestamp Difference
| Config | Description | Default |
|---|---|---|
| message.timestamp. difference.max.ms |
Max allowed skew vs broker time | Long.MAX |
| Reject | Records beyond skew refused | CreateTime only |
| Use Case | Block bad clocks | Data hygiene |
10. Resetting Offsets by Timestamp
| Method | Description | Detail |
|---|---|---|
| --to-datetime | CLI reset to time | Group offline |
| offsetsForTimes | API equivalent | In-app |
| Use Case | Replay from incident | Recovery |