Java中Timestamp.valueOf()方法相关代码输出差异的技术咨询
先把你的代码整理得更清晰些,方便分析:
public static void main(String[] args) { Timestamp ts = new Timestamp(116, 02, 12, 20, 45, 0, 0); Date d = new Date(); d.setTime(ts.getTime()); System.out.println(d); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); //System.out.println(ts.getTime()); System.out.println(simpleDateFormat.format(ts)); // 第一行目标输出 System.out.println(Timestamp.valueOf(simpleDateFormat.format(ts))); // 第二行目标输出 }
问题根源:时区处理的不对称性
你看到的两行输出差异,核心是格式化和解析时用了不同的时区:
格式化阶段:你给
SimpleDateFormat指定了UTC时区,所以format(ts)会把原Timestamp对应的时间戳转换成UTC时区的字符串。这里要先确认下原ts的实际时间:Timestamp的旧构造函数里,year参数是年份-1900,month是0-based(0=1月),所以(116,02,12,...)对应的是UTC时间2016年3月12日20:45:00,所以第一行输出的是2016-03-12 20:45:00。解析阶段:
Timestamp.valueOf(String s)这个方法的默认行为是把输入字符串当作本地时区的时间来解析,而不是UTC。举个实际场景:如果你的电脑时区是东八区(GMT+8),那它会把2016-03-12 20:45:00当成东八区的时间,转换成UTC的话就是2016年3月12日12:45:00,对应的时间戳自然和原ts完全不同,输出结果也就有差异了。
怎么解决这个问题?
要让解析后的结果和原ts一致,你得保证解析时也用UTC时区,不能直接用Timestamp.valueOf(),而是用你已经配置好UTC时区的SimpleDateFormat来解析:
// 用同一个带UTC时区的SimpleDateFormat解析 Date parsedDate = simpleDateFormat.parse(simpleDateFormat.format(ts)); Timestamp parsedTs = new Timestamp(parsedDate.getTime()); System.out.println(parsedTs); // 现在输出就和原ts一致了
另外顺便提个小建议:Timestamp的这个旧构造函数已经被标记为过时了,推荐用Java 8及以后的java.time API(比如Instant、ZonedDateTime)来处理时间,这套API的时区逻辑更清晰,能避免很多这类坑。
内容的提问来源于stack exchange,提问作者Sagar Pati

