From cdc18713092147c950e69588a7d657b6fc2f1521 Mon Sep 17 00:00:00 2001 From: Ioannis J Date: Mon, 16 Mar 2026 14:34:49 +0200 Subject: [PATCH 1/4] fix: route remaining timestamps through PostHogDateProvider --- posthog/src/main/java/com/posthog/PostHog.kt | 4 ++++ posthog/src/main/java/com/posthog/PostHogStateless.kt | 2 +- .../com/posthog/vendor/uuid/TimeBasedEpochGenerator.kt | 7 ++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/posthog/src/main/java/com/posthog/PostHog.kt b/posthog/src/main/java/com/posthog/PostHog.kt index 690e144fc..32b787418 100644 --- a/posthog/src/main/java/com/posthog/PostHog.kt +++ b/posthog/src/main/java/com/posthog/PostHog.kt @@ -166,6 +166,8 @@ public class PostHog private constructor( this.queue = queue this.replayQueue = replayQueue + TimeBasedEpochGenerator.customTimeProvider = config.dateProvider::currentTimeMillis + if (featureFlags is PostHogRemoteConfig) { config.remoteConfigHolder = featureFlags } @@ -298,6 +300,8 @@ public class PostHog private constructor( featureFlagsCalled.clear() endSession() + + TimeBasedEpochGenerator.customTimeProvider = null } catch (e: Throwable) { config?.logger?.log("Close failed: $e.") } diff --git a/posthog/src/main/java/com/posthog/PostHogStateless.kt b/posthog/src/main/java/com/posthog/PostHogStateless.kt index b17da922b..39e1f4687 100644 --- a/posthog/src/main/java/com/posthog/PostHogStateless.kt +++ b/posthog/src/main/java/com/posthog/PostHogStateless.kt @@ -286,7 +286,7 @@ public open class PostHogStateless protected constructor( event, distinctId, properties = sanitizedProperties, - timestamp = timestamp ?: Date(), + timestamp = timestamp ?: config?.dateProvider?.currentDate() ?: Date(), ) var eventChecked: PostHogEvent? = postHogEvent diff --git a/posthog/src/main/java/com/posthog/vendor/uuid/TimeBasedEpochGenerator.kt b/posthog/src/main/java/com/posthog/vendor/uuid/TimeBasedEpochGenerator.kt index 72054bb02..cf66440a9 100644 --- a/posthog/src/main/java/com/posthog/vendor/uuid/TimeBasedEpochGenerator.kt +++ b/posthog/src/main/java/com/posthog/vendor/uuid/TimeBasedEpochGenerator.kt @@ -24,6 +24,11 @@ internal object TimeBasedEpochGenerator { private val numberGenerator: Random = SecureRandom() private val lock: Lock = ReentrantLock() + private val defaultTimeProvider: () -> Long = { System.currentTimeMillis() } + + @Volatile + var customTimeProvider: (() -> Long)? = null + /* / ********************************************************************** / * UUID generation @@ -34,7 +39,7 @@ internal object TimeBasedEpochGenerator { * @return unix epoch time based UUID */ fun generate(): UUID { - return generate(System.currentTimeMillis()) + return generate((customTimeProvider ?: defaultTimeProvider)()) } /** From 9609340e54300a8202aabbe40225e9c203f9ef06 Mon Sep 17 00:00:00 2001 From: Ioannis J Date: Mon, 16 Mar 2026 14:36:11 +0200 Subject: [PATCH 2/4] chore: add changeset --- .changeset/vast-sheep-vanish.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/vast-sheep-vanish.md diff --git a/.changeset/vast-sheep-vanish.md b/.changeset/vast-sheep-vanish.md new file mode 100644 index 000000000..da94f81ec --- /dev/null +++ b/.changeset/vast-sheep-vanish.md @@ -0,0 +1,5 @@ +--- +"posthog": patch +--- + +fix: route all timestamps through PostHogDateProvider From 0a0df5502fd54d12a917dae1dbe0cc3a5742e53e Mon Sep 17 00:00:00 2001 From: Ioannis J Date: Fri, 20 Mar 2026 10:39:15 +0100 Subject: [PATCH 3/4] fix: refactor --- .../java/com/posthog/android/PostHogAndroid.kt | 7 ++++++- posthog/api/posthog.api | 6 ++++++ posthog/src/main/java/com/posthog/PostHog.kt | 4 ---- .../vendor/uuid/TimeBasedEpochGenerator.kt | 18 +++++++++++------- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/posthog-android/src/main/java/com/posthog/android/PostHogAndroid.kt b/posthog-android/src/main/java/com/posthog/android/PostHogAndroid.kt index 9c5d1f677..2505fb131 100644 --- a/posthog-android/src/main/java/com/posthog/android/PostHogAndroid.kt +++ b/posthog-android/src/main/java/com/posthog/android/PostHogAndroid.kt @@ -24,6 +24,7 @@ import com.posthog.android.surveys.PostHogSurveysIntegration import com.posthog.internal.PostHogDeviceDateProvider import com.posthog.internal.PostHogNoOpLogger import com.posthog.internal.PostHogSessionManager +import com.posthog.vendor.uuid.TimeBasedEpochGenerator import java.io.File /** @@ -103,7 +104,11 @@ public class PostHogAndroid private constructor() { // Defaults to PostHogDeviceDateProvider when api < 33 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (config.dateProvider is PostHogDeviceDateProvider) { - config.dateProvider = PostHogAndroidDateProvider() + val dateProvider = PostHogAndroidDateProvider() + config.dateProvider = dateProvider + TimeBasedEpochGenerator.setDateProvider(dateProvider) + } else { + TimeBasedEpochGenerator.setDateProvider(config.dateProvider) } } config.networkStatus = config.networkStatus ?: PostHogAndroidNetworkStatus(context) diff --git a/posthog/api/posthog.api b/posthog/api/posthog.api index 483150764..33df39eca 100644 --- a/posthog/api/posthog.api +++ b/posthog/api/posthog.api @@ -1910,3 +1910,9 @@ public final class com/posthog/surveys/SurveyType$Companion { public final fun fromValue (Ljava/lang/String;)Lcom/posthog/surveys/SurveyType; } +public final class com/posthog/vendor/uuid/TimeBasedEpochGenerator { + public static final field INSTANCE Lcom/posthog/vendor/uuid/TimeBasedEpochGenerator; + public final fun generate ()Ljava/util/UUID; + public final fun setDateProvider (Lcom/posthog/internal/PostHogDateProvider;)V +} + diff --git a/posthog/src/main/java/com/posthog/PostHog.kt b/posthog/src/main/java/com/posthog/PostHog.kt index 32b787418..690e144fc 100644 --- a/posthog/src/main/java/com/posthog/PostHog.kt +++ b/posthog/src/main/java/com/posthog/PostHog.kt @@ -166,8 +166,6 @@ public class PostHog private constructor( this.queue = queue this.replayQueue = replayQueue - TimeBasedEpochGenerator.customTimeProvider = config.dateProvider::currentTimeMillis - if (featureFlags is PostHogRemoteConfig) { config.remoteConfigHolder = featureFlags } @@ -300,8 +298,6 @@ public class PostHog private constructor( featureFlagsCalled.clear() endSession() - - TimeBasedEpochGenerator.customTimeProvider = null } catch (e: Throwable) { config?.logger?.log("Close failed: $e.") } diff --git a/posthog/src/main/java/com/posthog/vendor/uuid/TimeBasedEpochGenerator.kt b/posthog/src/main/java/com/posthog/vendor/uuid/TimeBasedEpochGenerator.kt index cf66440a9..541b43a4d 100644 --- a/posthog/src/main/java/com/posthog/vendor/uuid/TimeBasedEpochGenerator.kt +++ b/posthog/src/main/java/com/posthog/vendor/uuid/TimeBasedEpochGenerator.kt @@ -2,13 +2,16 @@ package com.posthog.vendor.uuid +import com.posthog.PostHogInternal +import com.posthog.internal.PostHogDateProvider import java.security.SecureRandom import java.util.Random import java.util.UUID import java.util.concurrent.locks.Lock import java.util.concurrent.locks.ReentrantLock -internal object TimeBasedEpochGenerator { +@PostHogInternal +public object TimeBasedEpochGenerator { private const val ENTROPY_BYTE_LENGTH = 10 private const val TIME_BASED_EPOCH_RAW = 7 @@ -24,10 +27,11 @@ internal object TimeBasedEpochGenerator { private val numberGenerator: Random = SecureRandom() private val lock: Lock = ReentrantLock() - private val defaultTimeProvider: () -> Long = { System.currentTimeMillis() } + private var dateProvider: PostHogDateProvider? = null - @Volatile - var customTimeProvider: (() -> Long)? = null + public fun setDateProvider(dateProvider: PostHogDateProvider) { + this.dateProvider = dateProvider + } /* / ********************************************************************** @@ -38,8 +42,8 @@ internal object TimeBasedEpochGenerator { /** * @return unix epoch time based UUID */ - fun generate(): UUID { - return generate((customTimeProvider ?: defaultTimeProvider)()) + public fun generate(): UUID { + return generate(dateProvider?.currentTimeMillis() ?: System.currentTimeMillis()) } /** @@ -47,7 +51,7 @@ internal object TimeBasedEpochGenerator { * @return unix epoch time based UUID */ @Throws(IllegalStateException::class) - fun generate(rawTimestamp: Long): UUID { + private fun generate(rawTimestamp: Long): UUID { return construct(rawTimestamp) } From 88c52dbd4b177a094e888e8093ba145b80b26b6a Mon Sep 17 00:00:00 2001 From: Ioannis J Date: Fri, 20 Mar 2026 10:41:14 +0100 Subject: [PATCH 4/4] chore: add changeset --- .changeset/sunny-pants-kiss.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/sunny-pants-kiss.md diff --git a/.changeset/sunny-pants-kiss.md b/.changeset/sunny-pants-kiss.md new file mode 100644 index 000000000..63ac566c5 --- /dev/null +++ b/.changeset/sunny-pants-kiss.md @@ -0,0 +1,5 @@ +--- +"posthog-android": patch +--- + +fix: route all timestamps through PostHogDateProvider