diff --git a/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/CountUpTimer.kt b/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/CountUpTimer.kt
index ea1d3d36e2..17af1c3190 100644
--- a/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/CountUpTimer.kt
+++ b/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/CountUpTimer.kt
@@ -33,13 +33,15 @@ class CountUpTimer(
 
     private val lastTime: AtomicLong = AtomicLong(clock.epochMillis())
     private val elapsedTime: AtomicLong = AtomicLong(0)
+    // To ensure that the regular tick value is an exact multiple of `intervalInMs`
+    private val specialRound = SpecialRound(intervalInMs)
 
     private fun startCounter() {
         counterJob?.cancel()
         counterJob = coroutineScope.launch {
             while (true) {
                 delay(intervalInMs - elapsedTime() % intervalInMs)
-                tickListener?.onTick(elapsedTime())
+                tickListener?.onTick(specialRound.round(elapsedTime()))
             }
         }
     }
diff --git a/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/SpecialRound.kt b/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/SpecialRound.kt
new file mode 100644
index 0000000000..82fead13e0
--- /dev/null
+++ b/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/SpecialRound.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2023 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.lib.core.utils.timer
+
+import kotlin.math.round
+
+class SpecialRound(private val step: Long) {
+    /**
+     * Round the provided value to the nearest multiple of `step`.
+     */
+    fun round(value: Long): Long {
+        return round(value.toDouble() / step).toLong() * step
+    }
+}
diff --git a/library/core-utils/src/test/java/im/vector/lib/core/utils/timer/SpecialRoundTest.kt b/library/core-utils/src/test/java/im/vector/lib/core/utils/timer/SpecialRoundTest.kt
new file mode 100644
index 0000000000..73be5aab8b
--- /dev/null
+++ b/library/core-utils/src/test/java/im/vector/lib/core/utils/timer/SpecialRoundTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2023 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.lib.core.utils.timer
+
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.Test
+
+class SpecialRoundTest {
+    @Test
+    fun `test special round 500`() {
+        val sut = SpecialRound(500)
+        sut.round(1) shouldBeEqualTo 0
+        sut.round(499) shouldBeEqualTo 500
+        sut.round(500) shouldBeEqualTo 500
+        sut.round(501) shouldBeEqualTo 500
+        sut.round(999) shouldBeEqualTo 1_000
+        sut.round(1000) shouldBeEqualTo 1_000
+        sut.round(1001) shouldBeEqualTo 1_000
+        sut.round(1499) shouldBeEqualTo 1_500
+        sut.round(1501) shouldBeEqualTo 1_500
+    }
+
+    @Test
+    fun `test special round 1_000`() {
+        val sut = SpecialRound(1_000)
+        sut.round(1) shouldBeEqualTo 0
+        sut.round(499) shouldBeEqualTo 0
+        sut.round(500) shouldBeEqualTo 0
+        sut.round(501) shouldBeEqualTo 1_000
+        sut.round(999) shouldBeEqualTo 1_000
+        sut.round(1000) shouldBeEqualTo 1_000
+        sut.round(1001) shouldBeEqualTo 1_000
+        sut.round(1499) shouldBeEqualTo 1_000
+        sut.round(1501) shouldBeEqualTo 2_000
+    }
+}