package com.vincent.rsf.server.api.controller.erp.params; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; /** * 支持时间戳(秒/毫秒)与多种字符串格式的 Date 反序列化。 * 字符串支持:ISO-8601(如 2024-03-03T08:00:00.000+00:00)、yyyy-MM-dd HH:mm:ss,精确到秒。 */ public class FlexibleDateDeserializer extends JsonDeserializer { private static final long TIMESTAMP_MS_THRESHOLD = 10_000_000_000L; // 约 1970-04-26 起为毫秒 private static final String PATTERN_SECONDS = "yyyy-MM-dd HH:mm:ss"; private static final TimeZone DEFAULT_TZ = TimeZone.getTimeZone("GMT+8"); @Override public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonToken t = p.getCurrentToken(); if (t == JsonToken.VALUE_NUMBER_INT || t == JsonToken.VALUE_NUMBER_FLOAT) { long v = p.getLongValue(); long ms = v < TIMESTAMP_MS_THRESHOLD ? v * 1000 : v; return new Date(ms); } if (t == JsonToken.VALUE_STRING) { String s = p.getText().trim(); if (s.isEmpty()) { return null; } // 1) 尝试纯数字字符串(秒或毫秒) try { long v = Long.parseLong(s); long ms = v < TIMESTAMP_MS_THRESHOLD ? v * 1000 : v; return new Date(ms); } catch (NumberFormatException ignored) { } // 2) ISO-8601(含 T 和时区) if (s.contains("T")) { try { return java.util.Date.from(java.time.Instant.parse(s)); } catch (Exception ignored) { } } // 3) yyyy-MM-dd HH:mm:ss try { SimpleDateFormat sdf = new SimpleDateFormat(PATTERN_SECONDS); sdf.setTimeZone(DEFAULT_TZ); sdf.setLenient(false); return sdf.parse(s); } catch (Exception ignored) { } // 4) 仅日期 yyyy-MM-dd if (s.length() == 10 && s.charAt(4) == '-' && s.charAt(7) == '-') { try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); sdf.setTimeZone(DEFAULT_TZ); sdf.setLenient(false); return sdf.parse(s); } catch (Exception ignored) { } } throw new IOException("Cannot parse date: " + s + ", support: timestamp(seconds/ms), ISO-8601, yyyy-MM-dd HH:mm:ss"); } if (t == JsonToken.VALUE_NULL) { return null; } return (Date) ctxt.handleUnexpectedToken(Date.class, p); } }