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..73321ec44 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,9 @@ public Date read(JsonReader in) throws IOException { in.nextNull(); return null; case NUMBER: - return new Date(in.nextInt() * 1000); + // 微信返回的是秒级时间戳,需转为毫秒;此处必须用 long 读取并运算, + // 否则 in.nextInt() * 1000 会发生 int 溢出,导致解析出错误的时间 + return new Date(in.nextLong() * 1000L); 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..4248b1512 --- /dev/null +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/json/WxDateTypeAdapterTest.java @@ -0,0 +1,76 @@ +package me.chanjar.weixin.common.util.json; + +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.Date; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * WxDateTypeAdapter 的单元测试. + * + * @author liyong + */ +public class WxDateTypeAdapterTest { + + private final WxDateTypeAdapter adapter = new WxDateTypeAdapter(); + + private Date read(String json) throws IOException { + JsonReader reader = new JsonReader(new StringReader(json)); + reader.setLenient(true); + return adapter.read(reader); + } + + private String write(Date date) throws IOException { + StringWriter out = new StringWriter(); + JsonWriter writer = new JsonWriter(out); + writer.setLenient(true); + adapter.write(writer, date); + return out.toString(); + } + + /** + * 秒级时间戳转成毫秒时如果按 int 运算会溢出,导致解析出的时间错误(甚至早于 1970 年)。 + */ + @Test + public void testReadCurrentTimestamp() throws IOException { + long seconds = 1481013459L; + Date date = read(String.valueOf(seconds)); + assertThat(date).isNotNull(); + assertThat(date.getTime()).isEqualTo(seconds * 1000L); + } + + @Test + public void testReadTimestampAfterYear2038() throws IOException { + long seconds = 4102444800L; + Date date = read(String.valueOf(seconds)); + assertThat(date).isNotNull(); + assertThat(date.getTime()).isEqualTo(seconds * 1000L); + } + + @Test + public void testReadNull() throws IOException { + assertThat(read("null")).isNull(); + } + + @Test + public void testWrite() throws IOException { + long seconds = 1481013459L; + assertThat(write(new Date(seconds * 1000L))).isEqualTo(String.valueOf(seconds)); + assertThat(write(null)).isEqualTo("null"); + } + + /** + * 序列化与反序列化应当可以互相还原。 + */ + @Test + public void testWriteThenRead() throws IOException { + Date now = new Date(1600000000L * 1000L); + assertThat(read(write(now))).isEqualTo(now); + } +}