diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxDateTypeAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxDateTypeAdapter.java
index fd54cf3f4..0dbad926c 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxDateTypeAdapter.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxDateTypeAdapter.java
@@ -35,7 +35,12 @@ public Date read(JsonReader in) throws IOException {
in.nextNull();
return null;
case NUMBER:
- return new Date(in.nextInt() * 1000);
+ long seconds = in.nextLong();
+ try {
+ return new Date(Math.multiplyExact(seconds, 1000L));
+ } catch (ArithmeticException e) {
+ throw new JsonParseException("Timestamp seconds out of range: " + seconds, e);
+ }
default:
throw new JsonParseException("Expected NUMBER but was " + peek);
}
diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/json/WxDateTypeAdapterTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/json/WxDateTypeAdapterTest.java
new file mode 100644
index 000000000..66395b6b5
--- /dev/null
+++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/json/WxDateTypeAdapterTest.java
@@ -0,0 +1,47 @@
+package me.chanjar.weixin.common.util.json;
+
+import com.google.gson.JsonParseException;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.util.Date;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/**
+ * Tests for {@link WxDateTypeAdapter}.
+ */
+public class WxDateTypeAdapterTest {
+ private final WxDateTypeAdapter adapter = new WxDateTypeAdapter();
+
+ @Test
+ public void testReadTimestampAfter2038() throws IOException {
+ Date date = this.adapter.fromJson("4102444800");
+
+ assertThat(date).isEqualTo(new Date(4102444800000L));
+ }
+
+ @Test
+ public void testReadRejectsPositiveMillisecondOverflow() {
+ long overflowingSeconds = Long.MAX_VALUE / 1000 + 1;
+
+ assertThatThrownBy(() -> this.adapter.fromJson(Long.toString(overflowingSeconds)))
+ .isInstanceOf(JsonParseException.class)
+ .hasMessageContaining("out of range");
+ }
+
+ @Test
+ public void testReadRejectsNegativeMillisecondOverflow() {
+ long overflowingSeconds = Long.MIN_VALUE / 1000 - 1;
+
+ assertThatThrownBy(() -> this.adapter.fromJson(Long.toString(overflowingSeconds)))
+ .isInstanceOf(JsonParseException.class)
+ .hasMessageContaining("out of range");
+ }
+
+ @Test
+ public void testWriteUsesSeconds() throws IOException {
+ assertThat(this.adapter.toJson(new Date(4102444800123L))).isEqualTo("4102444800");
+ }
+}
diff --git a/weixin-java-common/src/test/resources/testng.xml b/weixin-java-common/src/test/resources/testng.xml
index a5c082f03..a11351308 100644
--- a/weixin-java-common/src/test/resources/testng.xml
+++ b/weixin-java-common/src/test/resources/testng.xml
@@ -7,6 +7,7 @@
+