From 890fb08dcf1fae5e060a698b56616efdab43a1d1 Mon Sep 17 00:00:00 2001
From: "sentry-junior[bot]"
<264270552+sentry-junior[bot]@users.noreply.github.com>
Date: Tue, 20 Oct 2026 14:03:20 +0000
Subject: [PATCH 1/6] docs(sdk): Add draft timekeeping spec for span timestamps
---
.../sdk/foundations/timekeeping/index.mdx | 146 ++++++++++++++++++
1 file changed, 146 insertions(+)
create mode 100644 develop-docs/sdk/foundations/timekeeping/index.mdx
diff --git a/develop-docs/sdk/foundations/timekeeping/index.mdx b/develop-docs/sdk/foundations/timekeeping/index.mdx
new file mode 100644
index 0000000000000..419a31a62f04c
--- /dev/null
+++ b/develop-docs/sdk/foundations/timekeeping/index.mdx
@@ -0,0 +1,146 @@
+---
+title: Timekeeping
+description: How SDKs combine wall clocks and monotonic clocks to produce span timestamps and durations.
+spec_id: sdk/foundations/timekeeping
+spec_version: 0.1.0
+spec_status: draft
+spec_depends_on:
+ - id: sdk/telemetry/spans
+ version: ">=1.0.0"
+spec_changelog:
+ - version: 0.1.0
+ date: 2026-10-20
+ summary: Initial draft — anchor model for span timestamps, duration rules, platform notes
+sidebar_order: 30
+---
+
+
+
+
+
+## Overview
+
+Span payloads carry absolute `start_timestamp` and `end_timestamp` values in Unix seconds, and Sentry derives the duration as `end_timestamp − start_timestamp`. If an SDK reads a wall clock for both values, any wall-clock adjustment between them (NTP corrections, the user changing the time, time zone or daylight saving bugs in the clock source) corrupts the duration. That can make a duration negative, push a child span outside its parent, or inflate it by hours.
+
+This spec defines how SDKs combine a wall clock (for absolute position in time) with a monotonic clock (for elapsed time), so that durations stay correct while timestamps remain comparable across services.
+
+Related specs:
+
+- [Spans](/sdk/telemetry/spans/): span payload and timestamp format
+- [Envelopes](/sdk/foundations/envelopes/): `sent_at` header used for server-side clock drift correction
+
+## Requirements Language
+
+The key words "**MUST**", "**MUST NOT**", "**REQUIRED**", "**SHALL**", "**SHALL NOT**", "**SHOULD**", "**SHOULD NOT**", "**RECOMMENDED**", "**NOT RECOMMENDED**", "**MAY**", and "**OPTIONAL**" in this document are to be interpreted as described in BCP 14 [[RFC2119](#normative-references)] [[RFC8174](#normative-references)] when, and only when, they appear in all capitals, as shown here.
+
+The [Concepts](#concepts) and [Platform Notes](#platform-notes) sections are informative and contain no requirements.
+
+---
+
+## Concepts
+
+### Wall Clock
+
+A clock that reports the current time of day as Unix time (for example `Date.now()`, `System.currentTimeMillis()`, `Date()`). It can jump forward or backward at any time.
+
+### Monotonic Clock
+
+A clock that only moves forward at a steady rate and has no relation to the time of day (for example `performance.now()`, `SystemClock.elapsedRealtimeNanos()`, `clock_gettime_nsec_np(CLOCK_UPTIME_RAW)`). Its readings are only meaningful as differences.
+
+### Anchor
+
+A pair `(anchor_wall, anchor_mono)` captured at the same instant: one wall-clock reading and one monotonic-clock reading. An anchor converts any later monotonic reading into a wall-clock timestamp:
+
+```
+timestamp = anchor_wall + (mono_now − anchor_mono)
+```
+
+---
+
+## Behavior
+
+
+
+### Anchoring
+
+- When a span starts without a local parent (a local root, or segment span), the SDK **MUST** capture an anchor, reading the wall clock and the monotonic clock as close together as possible.
+- The root span's `start_timestamp` **MUST** be `anchor_wall`.
+- Every span in the same local span tree **MUST** use the root's anchor. Child spans **MUST NOT** read the wall clock to compute their timestamps.
+- A span that continues a trace from an incoming request or another process (a remote parent) is a local root and **MUST** capture its own anchor.
+- SDKs **MUST** compute anchored timestamps with a monotonic clock that keeps counting while the device sleeps, where the platform provides one. See [Platform Notes](#platform-notes) for examples.
+
+
+
+
+
+### Timestamps and Durations
+
+- For every span in an anchored tree, the SDK **MUST** compute `start_timestamp` and `end_timestamp` as `anchor_wall + (mono − anchor_mono)` using monotonic readings taken when the span starts and ends.
+- A span's duration (`end_timestamp − start_timestamp`) **MUST** therefore equal the elapsed monotonic time, so it can never be negative.
+
+
+
+
+
+### User-Provided Timestamps
+
+Public APIs such as `startSpan({ startTime })` and `span.end(timestamp)` accept wall-clock timestamps.
+
+- SDKs **MUST** use a user-provided timestamp as given and **MUST NOT** adjust it with the anchor.
+- If a user-provided end timestamp is earlier than the span's start timestamp, the SDK **SHOULD** clamp the end timestamp to the start timestamp. Logging a debug message when this happens helps users find the faulty call.
+- A span started with a user-provided start timestamp and no local parent **SHOULD** still capture an anchor from the current clock readings, and its children **MUST** use that anchor.
+
+
+
+
+
+### Span Trees Across Runtimes
+
+Hybrid SDKs (for example React Native, Flutter, Capacitor, and Unity) run a JavaScript, Dart, or C# layer on top of a native SDK, and each layer has its own clocks.
+
+- When a local span tree crosses from one layer to another, SDKs **SHOULD** pass the root's anchor across the bridge instead of capturing a new anchor in each layer.
+
+
+
+---
+
+## Platform Notes
+
+These notes are informative. They describe platform clocks that satisfy the requirements above and pitfalls known for each platform.
+
+### JavaScript (Browser and Node.js)
+
+- Monotonic clock: `performance.now()`, relative to `performance.timeOrigin`. In Node.js, `process.hrtime.bigint()` is also suitable.
+- `performance.timeOrigin + performance.now()` can drift from `Date.now()`, for example after the tab is backgrounded or the machine sleeps. Comparing the two at anchor time, and using `Date.now()` for `anchor_wall` when they differ significantly, keeps timestamps aligned with wall time. The JavaScript SDK currently corrects the time origin when the two differ by more than one second.
+- How `performance.now()` behaves while the machine sleeps varies by browser and OS.
+
+### Android
+
+- `SystemClock.elapsedRealtimeNanos()` keeps counting during deep sleep.
+- `SystemClock.uptimeMillis()` and `System.nanoTime()` stop counting during deep sleep.
+- App start: `Process.getStartElapsedRealtime()` and `Process.getStartUptimeMillis()` (API 24+) report the process start time in their respective clock domains.
+
+### Apple Platforms (iOS, macOS, tvOS, watchOS, visionOS)
+
+- `clock_gettime_nsec_np(CLOCK_UPTIME_RAW)` and `mach_absolute_time()` stop counting while the device sleeps.
+- `clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)` and `mach_continuous_time()` keep counting while the device sleeps.
+- App start: the process start time is available from `sysctl` (`kinfo_proc.kp_proc.p_starttime`). It's a wall-clock value, so SDKs need to convert it before using it with an anchor.
+
+### Hybrid SDKs
+
+- Layers that run in the same process can often read the same OS clock. For example, on Android the Dart VM's monotonic clock reads `CLOCK_MONOTONIC`, the same clock behind `SystemClock.uptimeMillis()`. Through a synchronous call (JNI or FFI), the Dart layer can read the native SDK's anchor and monotonic clock directly, with no conversion between clock domains.
+- A bridge that only supports asynchronous messages can't capture an anchor pair at a single instant across layers. In that case, the native layer can compute wall-clock timestamps from its own anchor and pass those across the bridge instead.
+
+---
+
+## References
+
+### Normative References
+
+- **[RFC2119]** Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997, [https://www.rfc-editor.org/info/rfc2119](https://www.rfc-editor.org/info/rfc2119).
+- **[RFC8174]** Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, May 2017, [https://www.rfc-editor.org/info/rfc8174](https://www.rfc-editor.org/info/rfc8174).
+- [Spans](/sdk/telemetry/spans/)
+
+### Informative References
+
+- [Envelopes](/sdk/foundations/envelopes/)
From 862c08545d550d3a879ee8f6253f0973a7012151 Mon Sep 17 00:00:00 2001
From: "sentry-junior[bot]"
<264270552+sentry-junior[bot]@users.noreply.github.com>
Date: Tue, 20 Oct 2026 14:10:45 +0000
Subject: [PATCH 2/6] docs(sdk): Remove requirements language section from
timekeeping spec
---
develop-docs/sdk/foundations/timekeeping/index.mdx | 6 ------
1 file changed, 6 deletions(-)
diff --git a/develop-docs/sdk/foundations/timekeeping/index.mdx b/develop-docs/sdk/foundations/timekeeping/index.mdx
index 419a31a62f04c..cf35f02f8a69d 100644
--- a/develop-docs/sdk/foundations/timekeeping/index.mdx
+++ b/develop-docs/sdk/foundations/timekeeping/index.mdx
@@ -29,12 +29,6 @@ Related specs:
- [Spans](/sdk/telemetry/spans/): span payload and timestamp format
- [Envelopes](/sdk/foundations/envelopes/): `sent_at` header used for server-side clock drift correction
-## Requirements Language
-
-The key words "**MUST**", "**MUST NOT**", "**REQUIRED**", "**SHALL**", "**SHALL NOT**", "**SHOULD**", "**SHOULD NOT**", "**RECOMMENDED**", "**NOT RECOMMENDED**", "**MAY**", and "**OPTIONAL**" in this document are to be interpreted as described in BCP 14 [[RFC2119](#normative-references)] [[RFC8174](#normative-references)] when, and only when, they appear in all capitals, as shown here.
-
-The [Concepts](#concepts) and [Platform Notes](#platform-notes) sections are informative and contain no requirements.
-
---
## Concepts
From f8472a99f571756944d44417b7d90e9e9aa02626 Mon Sep 17 00:00:00 2001
From: "sentry-junior[bot]"
<264270552+sentry-junior[bot]@users.noreply.github.com>
Date: Tue, 20 Oct 2026 14:31:54 +0000
Subject: [PATCH 3/6] docs(sdk): Remove references section from timekeeping
spec
---
develop-docs/sdk/foundations/timekeeping/index.mdx | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/develop-docs/sdk/foundations/timekeeping/index.mdx b/develop-docs/sdk/foundations/timekeeping/index.mdx
index cf35f02f8a69d..964c82a0c6634 100644
--- a/develop-docs/sdk/foundations/timekeeping/index.mdx
+++ b/develop-docs/sdk/foundations/timekeeping/index.mdx
@@ -124,17 +124,3 @@ These notes are informative. They describe platform clocks that satisfy the requ
- Layers that run in the same process can often read the same OS clock. For example, on Android the Dart VM's monotonic clock reads `CLOCK_MONOTONIC`, the same clock behind `SystemClock.uptimeMillis()`. Through a synchronous call (JNI or FFI), the Dart layer can read the native SDK's anchor and monotonic clock directly, with no conversion between clock domains.
- A bridge that only supports asynchronous messages can't capture an anchor pair at a single instant across layers. In that case, the native layer can compute wall-clock timestamps from its own anchor and pass those across the bridge instead.
-
----
-
-## References
-
-### Normative References
-
-- **[RFC2119]** Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997, [https://www.rfc-editor.org/info/rfc2119](https://www.rfc-editor.org/info/rfc2119).
-- **[RFC8174]** Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, May 2017, [https://www.rfc-editor.org/info/rfc8174](https://www.rfc-editor.org/info/rfc8174).
-- [Spans](/sdk/telemetry/spans/)
-
-### Informative References
-
-- [Envelopes](/sdk/foundations/envelopes/)
From 257c56dce49baebc1ed5261ef74bba9e7bfea3c1 Mon Sep 17 00:00:00 2001
From: Nelson Osacky
Date: Tue, 20 Oct 2026 16:55:18 +0200
Subject: [PATCH 4/6] docs(sdk): Tighten timekeeping sleep rule and drop
platform notes
Make the sleep-counting clock requirement a biconditional (use such a
clock if and only if the platform provides one; otherwise do not infer
sleep from wall-clock drift) so it no longer reads as an undecided
policy. Fix the Apple clock example in Concepts to one that keeps
counting during sleep, and remove the Platform Notes section, whose
Apple and hybrid examples contradicted the normative rules.
Co-Authored-By: Claude Opus 4.8
---
.../sdk/foundations/timekeeping/index.mdx | 35 ++-----------------
1 file changed, 3 insertions(+), 32 deletions(-)
diff --git a/develop-docs/sdk/foundations/timekeeping/index.mdx b/develop-docs/sdk/foundations/timekeeping/index.mdx
index 964c82a0c6634..ca73664bfd335 100644
--- a/develop-docs/sdk/foundations/timekeeping/index.mdx
+++ b/develop-docs/sdk/foundations/timekeeping/index.mdx
@@ -10,7 +10,7 @@ spec_depends_on:
spec_changelog:
- version: 0.1.0
date: 2026-10-20
- summary: Initial draft — anchor model for span timestamps, duration rules, platform notes
+ summary: Initial draft — anchor model for span timestamps, duration rules
sidebar_order: 30
---
@@ -39,7 +39,7 @@ A clock that reports the current time of day as Unix time (for example `Date.now
### Monotonic Clock
-A clock that only moves forward at a steady rate and has no relation to the time of day (for example `performance.now()`, `SystemClock.elapsedRealtimeNanos()`, `clock_gettime_nsec_np(CLOCK_UPTIME_RAW)`). Its readings are only meaningful as differences.
+A clock that only moves forward at a steady rate and has no relation to the time of day (for example `performance.now()`, `SystemClock.elapsedRealtimeNanos()`, `clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)`). Its readings are only meaningful as differences.
### Anchor
@@ -61,7 +61,7 @@ timestamp = anchor_wall + (mono_now − anchor_mono)
- The root span's `start_timestamp` **MUST** be `anchor_wall`.
- Every span in the same local span tree **MUST** use the root's anchor. Child spans **MUST NOT** read the wall clock to compute their timestamps.
- A span that continues a trace from an incoming request or another process (a remote parent) is a local root and **MUST** capture its own anchor.
-- SDKs **MUST** compute anchored timestamps with a monotonic clock that keeps counting while the device sleeps, where the platform provides one. See [Platform Notes](#platform-notes) for examples.
+- SDKs **MUST** use a monotonic clock that keeps counting while the device sleeps if and only if the platform provides one. Where the platform does not, SDKs **MUST NOT** account for sleep by other means (for example, inferring it from wall-clock drift).
@@ -95,32 +95,3 @@ Hybrid SDKs (for example React Native, Flutter, Capacitor, and Unity) run a Java
- When a local span tree crosses from one layer to another, SDKs **SHOULD** pass the root's anchor across the bridge instead of capturing a new anchor in each layer.
-
----
-
-## Platform Notes
-
-These notes are informative. They describe platform clocks that satisfy the requirements above and pitfalls known for each platform.
-
-### JavaScript (Browser and Node.js)
-
-- Monotonic clock: `performance.now()`, relative to `performance.timeOrigin`. In Node.js, `process.hrtime.bigint()` is also suitable.
-- `performance.timeOrigin + performance.now()` can drift from `Date.now()`, for example after the tab is backgrounded or the machine sleeps. Comparing the two at anchor time, and using `Date.now()` for `anchor_wall` when they differ significantly, keeps timestamps aligned with wall time. The JavaScript SDK currently corrects the time origin when the two differ by more than one second.
-- How `performance.now()` behaves while the machine sleeps varies by browser and OS.
-
-### Android
-
-- `SystemClock.elapsedRealtimeNanos()` keeps counting during deep sleep.
-- `SystemClock.uptimeMillis()` and `System.nanoTime()` stop counting during deep sleep.
-- App start: `Process.getStartElapsedRealtime()` and `Process.getStartUptimeMillis()` (API 24+) report the process start time in their respective clock domains.
-
-### Apple Platforms (iOS, macOS, tvOS, watchOS, visionOS)
-
-- `clock_gettime_nsec_np(CLOCK_UPTIME_RAW)` and `mach_absolute_time()` stop counting while the device sleeps.
-- `clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)` and `mach_continuous_time()` keep counting while the device sleeps.
-- App start: the process start time is available from `sysctl` (`kinfo_proc.kp_proc.p_starttime`). It's a wall-clock value, so SDKs need to convert it before using it with an anchor.
-
-### Hybrid SDKs
-
-- Layers that run in the same process can often read the same OS clock. For example, on Android the Dart VM's monotonic clock reads `CLOCK_MONOTONIC`, the same clock behind `SystemClock.uptimeMillis()`. Through a synchronous call (JNI or FFI), the Dart layer can read the native SDK's anchor and monotonic clock directly, with no conversion between clock domains.
-- A bridge that only supports asynchronous messages can't capture an anchor pair at a single instant across layers. In that case, the native layer can compute wall-clock timestamps from its own anchor and pass those across the bridge instead.
From 4b8695ad48e2c66364e31b0bc0be33dd69d4dd15 Mon Sep 17 00:00:00 2001
From: Nelson Osacky
Date: Tue, 20 Oct 2026 17:07:15 +0200
Subject: [PATCH 5/6] docs(sdk): Carve out user-provided durations and align
span terminology
The "duration always equals elapsed monotonic time, so it can never be
negative" rule applied to every span, which contradicted user-provided
timestamps: those are used as given (and clamped when the end precedes
the start), so their durations carry no such guarantee. Scope the rule
to anchor-computed timestamps and cross-reference the user-provided
section.
Replace "local root", "root span", and "local span tree" with the Spans
spec's "segment span" and "segment". In that spec "root span" means the
trace-wide root, so reusing it for the per-service topmost span was
ambiguous.
Co-Authored-By: Claude Opus 4.8
---
.../sdk/foundations/timekeeping/index.mdx | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/develop-docs/sdk/foundations/timekeeping/index.mdx b/develop-docs/sdk/foundations/timekeeping/index.mdx
index ca73664bfd335..6811258ba364b 100644
--- a/develop-docs/sdk/foundations/timekeeping/index.mdx
+++ b/develop-docs/sdk/foundations/timekeeping/index.mdx
@@ -57,10 +57,10 @@ timestamp = anchor_wall + (mono_now − anchor_mono)
### Anchoring
-- When a span starts without a local parent (a local root, or segment span), the SDK **MUST** capture an anchor, reading the wall clock and the monotonic clock as close together as possible.
-- The root span's `start_timestamp` **MUST** be `anchor_wall`.
-- Every span in the same local span tree **MUST** use the root's anchor. Child spans **MUST NOT** read the wall clock to compute their timestamps.
-- A span that continues a trace from an incoming request or another process (a remote parent) is a local root and **MUST** capture its own anchor.
+- When the SDK starts a [segment span](/sdk/telemetry/spans/#concepts) — the topmost span within a service boundary — it **MUST** capture an anchor, reading the wall clock and the monotonic clock as close together as possible.
+- The segment span's `start_timestamp` **MUST** be `anchor_wall`.
+- Every span in the same segment **MUST** use the segment span's anchor. Child spans **MUST NOT** read the wall clock to compute their timestamps.
+- A span that continues a trace from an incoming request or another process (its parent is a remote span) is itself a segment span and **MUST** capture its own anchor.
- SDKs **MUST** use a monotonic clock that keeps counting while the device sleeps if and only if the platform provides one. Where the platform does not, SDKs **MUST NOT** account for sleep by other means (for example, inferring it from wall-clock drift).
@@ -69,8 +69,8 @@ timestamp = anchor_wall + (mono_now − anchor_mono)
### Timestamps and Durations
-- For every span in an anchored tree, the SDK **MUST** compute `start_timestamp` and `end_timestamp` as `anchor_wall + (mono − anchor_mono)` using monotonic readings taken when the span starts and ends.
-- A span's duration (`end_timestamp − start_timestamp`) **MUST** therefore equal the elapsed monotonic time, so it can never be negative.
+- For every span in the segment, unless it uses a [user-provided timestamp](#user-provided-timestamps), the SDK **MUST** compute its `start_timestamp` and `end_timestamp` as `anchor_wall + (mono − anchor_mono)`, using monotonic readings taken when the span starts and ends.
+- A duration computed this way (`end_timestamp − start_timestamp`) **MUST** equal the elapsed monotonic time, so it can never be negative. Durations built from user-provided timestamps carry no such guarantee; see [User-Provided Timestamps](#user-provided-timestamps).
@@ -82,7 +82,7 @@ Public APIs such as `startSpan({ startTime })` and `span.end(timestamp)` accept
- SDKs **MUST** use a user-provided timestamp as given and **MUST NOT** adjust it with the anchor.
- If a user-provided end timestamp is earlier than the span's start timestamp, the SDK **SHOULD** clamp the end timestamp to the start timestamp. Logging a debug message when this happens helps users find the faulty call.
-- A span started with a user-provided start timestamp and no local parent **SHOULD** still capture an anchor from the current clock readings, and its children **MUST** use that anchor.
+- A segment span started with a user-provided start timestamp **SHOULD** still capture an anchor from the current clock readings, and its children **MUST** use that anchor.
@@ -92,6 +92,6 @@ Public APIs such as `startSpan({ startTime })` and `span.end(timestamp)` accept
Hybrid SDKs (for example React Native, Flutter, Capacitor, and Unity) run a JavaScript, Dart, or C# layer on top of a native SDK, and each layer has its own clocks.
-- When a local span tree crosses from one layer to another, SDKs **SHOULD** pass the root's anchor across the bridge instead of capturing a new anchor in each layer.
+- When a segment's spans cross from one layer to another, SDKs **SHOULD** pass the segment span's anchor across the bridge instead of capturing a new anchor in each layer.
From 00baf9ffa489700b5dcea59bf2c335ff5e7cc987 Mon Sep 17 00:00:00 2001
From: Nelson Osacky
Date: Tue, 20 Oct 2026 17:14:33 +0200
Subject: [PATCH 6/6] docs(sdk): Clarify anchor units and anchor-to-start
relationship
State that the two clocks may report in different units and must be
converted to a common unit, and that computed timestamps are emitted in
Unix seconds. Make explicit that the anchor's monotonic reading is the
segment span's start reading, so the segment span's start_timestamp is
anchor_wall, except when the user provides a start timestamp.
Co-Authored-By: Claude Opus 4.8
---
develop-docs/sdk/foundations/timekeeping/index.mdx | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/develop-docs/sdk/foundations/timekeeping/index.mdx b/develop-docs/sdk/foundations/timekeeping/index.mdx
index 6811258ba364b..ddc8055f84dae 100644
--- a/develop-docs/sdk/foundations/timekeeping/index.mdx
+++ b/develop-docs/sdk/foundations/timekeeping/index.mdx
@@ -49,6 +49,8 @@ A pair `(anchor_wall, anchor_mono)` captured at the same instant: one wall-clock
timestamp = anchor_wall + (mono_now − anchor_mono)
```
+The two clocks can report in different units across platforms (seconds, milliseconds, or nanoseconds); convert both readings to a common unit before combining them.
+
---
## Behavior
@@ -57,8 +59,8 @@ timestamp = anchor_wall + (mono_now − anchor_mono)
### Anchoring
-- When the SDK starts a [segment span](/sdk/telemetry/spans/#concepts) — the topmost span within a service boundary — it **MUST** capture an anchor, reading the wall clock and the monotonic clock as close together as possible.
-- The segment span's `start_timestamp` **MUST** be `anchor_wall`.
+- When the SDK starts a [segment span](/sdk/telemetry/spans/#concepts) — the topmost span within a service boundary — it **MUST** capture an anchor, reading the wall clock and the monotonic clock as close together as possible. This monotonic reading is `anchor_mono`, the segment span's start reading.
+- Unless the user provided a start timestamp (see [User-Provided Timestamps](#user-provided-timestamps)), the segment span's `start_timestamp` **MUST** be `anchor_wall` — the anchor formula at `mono = anchor_mono`.
- Every span in the same segment **MUST** use the segment span's anchor. Child spans **MUST NOT** read the wall clock to compute their timestamps.
- A span that continues a trace from an incoming request or another process (its parent is a remote span) is itself a segment span and **MUST** capture its own anchor.
- SDKs **MUST** use a monotonic clock that keeps counting while the device sleeps if and only if the platform provides one. Where the platform does not, SDKs **MUST NOT** account for sleep by other means (for example, inferring it from wall-clock drift).
@@ -69,7 +71,7 @@ timestamp = anchor_wall + (mono_now − anchor_mono)
### Timestamps and Durations
-- For every span in the segment, unless it uses a [user-provided timestamp](#user-provided-timestamps), the SDK **MUST** compute its `start_timestamp` and `end_timestamp` as `anchor_wall + (mono − anchor_mono)`, using monotonic readings taken when the span starts and ends.
+- For every span in the segment, unless it uses a [user-provided timestamp](#user-provided-timestamps), the SDK **MUST** compute its `start_timestamp` and `end_timestamp` as `anchor_wall + (mono − anchor_mono)`, using monotonic readings taken when the span starts and ends, and convert the result to Unix seconds for the payload.
- A duration computed this way (`end_timestamp − start_timestamp`) **MUST** equal the elapsed monotonic time, so it can never be negative. Durations built from user-provided timestamps carry no such guarantee; see [User-Provided Timestamps](#user-provided-timestamps).