fix: normalize SDK timestamps to UTC - #698
Conversation
posthog-android Compliance ReportDate: 2026-08-14 11:15:25 UTC ✅ All Tests Passed!46/46 tests passed Capture Tests✅ 29/29 tests passed View Details
Feature_Flags Tests✅ 17/17 tests passed View Details
|
|
|
Reviews (1): Last reviewed commit: "docs: clarify logcat timestamp fix" | Re-trigger Greptile |
|
(created by claude code) [arno's agent] Real logcat -v epoch lines start with leading spaces because liblog prints the seconds right-aligned via snprintf("%19lld") (verified in AOSP logprint from android-7.0.0_r1 through Android 14), so LOG_LINE_RE with matcher.matches() never matches and every console log line is dropped; the pattern needs a leading \s* (or trim the line before parse) and a test with a padded line. |
|
(created by claude code) [arno's agent] The epoch format modifier only exists from Android 7.0 (absent in android-6.0.1_r81 logprint.c, added in android-7.0.0_r1, same for the -T %s.%q epoch parsing), so on minSdk 23 devices logcat exits with 'Invalid parameter epoch to -v' and console log capture stops working entirely; this needs an SDK_INT gate or a minSdk bump. |
|
@arnohillen Good catch on the padding. Fixed in d7c357b: the epoch parser now accepts logcat’s leading whitespace, with a regression test using a right-aligned epoch line. |
|
@arnohillen Session Replay is only supported on API 26+ ( |
arnohillen
left a comment
There was a problem hiding this comment.
(created by claude code)
[arno's agent] Verified at d7c357b: LOG_LINE_RE now tolerates the right-aligned epoch padding with a regression test on a 19-char padded line, and your API 26 argument for the second point checks out (console lines only emit while isSessionReplayActive() is true, and isSupported() requires SDK_INT >= O in install()).
|
(created by claude code) [arno's agent] isSessionReplayActive() can still return true below API 26 because start() sets the active flag without an isSupported() check, so API 23 devices that previously emitted console-only events now stop silently; those recordings have no snapshots so the loss looks acceptable, noting it only because the API 26+ gate is enforced in install() rather than start(). |
💡 Motivation and Context
SDK dates were formatted with the process default time zone. The JSON represented the correct instant, but it could use a local offset instead of the canonical UTC
Zform. Session replay log capture also used logcat's localthreadtimeoutput, so parsing depended on the device time zone.This change formats SDK dates in UTC while preserving the exact instant. Session replay now requests logcat's epoch format, passes the capture start time as epoch seconds with milliseconds, and converts each epoch timestamp directly into a UTC calendar. Timestamp API documentation now explains that non-UTC inputs keep the same instant and are serialized in UTC.
💚 How did you test it?
GsonDateTypeAdapterTestsets the default time zone toAmerica/Los_Angelesand verifies that2023-07-15T08:30:45.123-07:00serializes as2023-07-15T15:30:45.123Zwithout changing the input instant.PostHogSerializerTestsets the default time zone toAmerica/New_Yorkand verifies the exact UTC values for bothtimestampandsent_atnear a daylight saving transition.LogcatParserTestverifies exact UTC epoch parsing, independence from the process default time zone, conversion of sub-millisecond epoch fractions to milliseconds, log level and payload parsing, and rejection of ambiguousthreadtimelines.PostHogLogCatIntegrationTestverifies the exactlogcat -v epoch -T 1721057445.123 *:Ecommand.make checkFormat,pnpm changeset status --since=origin/main, and committed-HEAD autoreview againstorigin/main.📝 Checklist
If releasing new changes
pnpm changesetto generate a changeset file🤖 Agent context
Autonomy: Human-driven (agent-assisted)
The Pi worker agent prepared the existing implementation for review, added the required changeset, and ran the repository checks and isolated autoreview. The human directed the branch, scope, commit message, PR title, and required validation. This local agent session does not have a shareable session link.