This is an automated email from the ASF dual-hosted git repository.
terrymanu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new a2c8572d344 Compute the Snowflake epoch in UTC instead of the system
timezone (#38932)
a2c8572d344 is described below
commit a2c8572d344b3ccd7846e68ded163250d206ed63
Author: Vasiliy Mikhailov <[email protected]>
AuthorDate: Sat Jul 4 08:18:56 2026 +0300
Compute the Snowflake epoch in UTC instead of the system timezone (#38932)
* Compute the Snowflake epoch in UTC instead of the system timezone
The static EPOCH (2016-11-01 00:00:00) was converted to epoch millis using
the JVM default timezone offset, so the generated key timestamps shifted with
the server timezone, risking duplicate or mis-ordered keys across deployments
in different zones. Use ZoneOffset.UTC so the epoch is timezone-independent.
* Force non-UTC timezone in Snowflake epoch test and add 5.5.4 release note
* Apply spotless formatting to snowflake pom
Signed-off-by: vmihaylov <[email protected]>
* Compose test timezone onto inherited Surefire argLine instead of
replacing it
Signed-off-by: Vasiliy Mikhailov <[email protected]>
---------
Signed-off-by: vmihaylov <[email protected]>
Signed-off-by: Vasiliy Mikhailov <[email protected]>
---
RELEASE-NOTES.md | 1 +
infra/algorithm/type/key-generator/type/snowflake/pom.xml | 4 ++++
.../keygen/snowflake/SnowflakeKeyGenerateAlgorithm.java | 5 ++---
.../keygen/snowflake/SnowflakeKeyGenerateAlgorithmTest.java | 11 +++++++++++
4 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index c8723984008..bad29fe27a9 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -33,6 +33,7 @@
1. Sharding: Fix generated actual index names exceeding database identifier
length limits while preserving legacy generated index name compatibility -
[#38449](https://github.com/apache/shardingsphere/pull/38449)
1. Sharding: Fix AUTO_INTERVAL sharding failure under JVM default locales that
use comma decimal separators -
[#38806](https://github.com/apache/shardingsphere/pull/38806)
1. DistSQL: Fix case-sensitive storage unit matching in `SHOW RULES USED
STORAGE UNIT` - [#38848](https://github.com/apache/shardingsphere/pull/38848)
+1. Sharding: Compute the Snowflake key generator epoch in UTC instead of the
JVM default timezone -
[#38932](https://github.com/apache/shardingsphere/pull/38932)
### Enhancements
diff --git a/infra/algorithm/type/key-generator/type/snowflake/pom.xml
b/infra/algorithm/type/key-generator/type/snowflake/pom.xml
index 95b03564f28..6e7adbc71ca 100644
--- a/infra/algorithm/type/key-generator/type/snowflake/pom.xml
+++ b/infra/algorithm/type/key-generator/type/snowflake/pom.xml
@@ -26,6 +26,10 @@
<artifactId>shardingsphere-infra-algorithm-key-generator-snowflake</artifactId>
<name>${project.artifactId}</name>
+ <properties>
+ <argLine>-Duser.timezone=Asia/Shanghai</argLine>
+ </properties>
+
<dependencies>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
diff --git
a/infra/algorithm/type/key-generator/type/snowflake/src/main/java/org/apache/shardingsphere/infra/algorithm/keygen/snowflake/SnowflakeKeyGenerateAlgorithm.java
b/infra/algorithm/type/key-generator/type/snowflake/src/main/java/org/apache/shardingsphere/infra/algorithm/keygen/snowflake/SnowflakeKeyGenerateAlgorithm.java
index 6cfae7a44a5..6c2a17350e7 100644
---
a/infra/algorithm/type/key-generator/type/snowflake/src/main/java/org/apache/shardingsphere/infra/algorithm/keygen/snowflake/SnowflakeKeyGenerateAlgorithm.java
+++
b/infra/algorithm/type/key-generator/type/snowflake/src/main/java/org/apache/shardingsphere/infra/algorithm/keygen/snowflake/SnowflakeKeyGenerateAlgorithm.java
@@ -28,9 +28,8 @@ import
org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
import org.apache.shardingsphere.infra.instance.ComputeNodeInstanceContext;
import
org.apache.shardingsphere.infra.instance.ComputeNodeInstanceContextAware;
-import java.time.Instant;
import java.time.LocalDateTime;
-import java.time.ZoneId;
+import java.time.ZoneOffset;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Properties;
@@ -91,7 +90,7 @@ public final class SnowflakeKeyGenerateAlgorithm implements
KeyGenerateAlgorithm
private int maxTolerateTimeDifferenceMillis;
static {
- EPOCH = LocalDateTime.of(2016, 11, 1, 0, 0,
0).toInstant(ZoneId.systemDefault().getRules().getOffset(Instant.now())).toEpochMilli();
+ EPOCH = LocalDateTime.of(2016, 11, 1, 0, 0,
0).toInstant(ZoneOffset.UTC).toEpochMilli();
}
@Override
diff --git
a/infra/algorithm/type/key-generator/type/snowflake/src/test/java/org/apache/shardingsphere/infra/algorithm/keygen/snowflake/SnowflakeKeyGenerateAlgorithmTest.java
b/infra/algorithm/type/key-generator/type/snowflake/src/test/java/org/apache/shardingsphere/infra/algorithm/keygen/snowflake/SnowflakeKeyGenerateAlgorithmTest.java
index a9c45723901..7e7b6f25902 100644
---
a/infra/algorithm/type/key-generator/type/snowflake/src/test/java/org/apache/shardingsphere/infra/algorithm/keygen/snowflake/SnowflakeKeyGenerateAlgorithmTest.java
+++
b/infra/algorithm/type/key-generator/type/snowflake/src/test/java/org/apache/shardingsphere/infra/algorithm/keygen/snowflake/SnowflakeKeyGenerateAlgorithmTest.java
@@ -52,6 +52,9 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
class SnowflakeKeyGenerateAlgorithmTest {
private static final long DEFAULT_SEQUENCE_BITS = 12L;
@@ -60,6 +63,14 @@ class SnowflakeKeyGenerateAlgorithmTest {
private static final ComputeNodeInstanceContext INSTANCE;
+ @Test
+ void assertEpochShouldBeTimezoneIndependent() {
+ // The EPOCH is supposed to represent 2016-11-01 00:00:00 UTC.
+ // It MUST equal the UTC-based value regardless of system timezone.
+ long expectedUtcEpoch = LocalDateTime.of(2016, 11, 1, 0, 0,
0).toInstant(ZoneOffset.UTC).toEpochMilli();
+ assertThat(SnowflakeKeyGenerateAlgorithm.EPOCH, is(expectedUtcEpoch));
+ }
+
static {
ComputeNodeInstanceContext computeNodeInstanceContext =
mock(ComputeNodeInstanceContext.class);
when(computeNodeInstanceContext.getWorkerId()).thenReturn(0);