/src/main/java/com/alibaba/fastjson/parser/deserializer/Jdk8DateCodec.java
https://github.com/alibaba/fastjson · Java · 636 lines · 569 code · 67 blank · 0 comment · 329 complexity · fb50dcf0e97a28ec1d87a106c1301073 MD5 · raw file
- package com.alibaba.fastjson.parser.deserializer;
- import java.io.IOException;
- import java.lang.reflect.Type;
- import java.time.Duration;
- import java.time.Instant;
- import java.time.LocalDate;
- import java.time.LocalDateTime;
- import java.time.LocalTime;
- import java.time.OffsetDateTime;
- import java.time.OffsetTime;
- import java.time.Period;
- import java.time.ZoneId;
- import java.time.ZonedDateTime;
- import java.time.chrono.ChronoZonedDateTime;
- import java.time.format.DateTimeFormatter;
- import java.time.temporal.TemporalAccessor;
- import java.util.Date;
- import java.util.Locale;
- import java.util.TimeZone;
- import com.alibaba.fastjson.JSON;
- import com.alibaba.fastjson.JSONObject;
- import com.alibaba.fastjson.parser.DefaultJSONParser;
- import com.alibaba.fastjson.parser.JSONLexer;
- import com.alibaba.fastjson.parser.JSONScanner;
- import com.alibaba.fastjson.parser.JSONToken;
- import com.alibaba.fastjson.serializer.*;
- import com.alibaba.fastjson.util.TypeUtils;
- public class Jdk8DateCodec extends ContextObjectDeserializer implements ObjectSerializer, ContextObjectSerializer, ObjectDeserializer {
- public static final Jdk8DateCodec instance = new Jdk8DateCodec();
- private final static String defaultPatttern = "yyyy-MM-dd HH:mm:ss";
- private final static DateTimeFormatter defaultFormatter = DateTimeFormatter.ofPattern(defaultPatttern);
- private final static DateTimeFormatter defaultFormatter_23 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
- private final static DateTimeFormatter formatter_dt19_tw = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
- private final static DateTimeFormatter formatter_dt19_cn = DateTimeFormatter.ofPattern("yyyy年M月d日 HH:mm:ss");
- private final static DateTimeFormatter formatter_dt19_cn_1 = DateTimeFormatter.ofPattern("yyyy年M月d日 H时m分s秒");
- private final static DateTimeFormatter formatter_dt19_kr = DateTimeFormatter.ofPattern("yyyy년M월d일 HH:mm:ss");
- private final static DateTimeFormatter formatter_dt19_us = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss");
- private final static DateTimeFormatter formatter_dt19_eur = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
- private final static DateTimeFormatter formatter_dt19_de = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss");
- private final static DateTimeFormatter formatter_dt19_in = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
- private final static DateTimeFormatter formatter_d8 = DateTimeFormatter.ofPattern("yyyyMMdd");
- private final static DateTimeFormatter formatter_d10_tw = DateTimeFormatter.ofPattern("yyyy/MM/dd");
- private final static DateTimeFormatter formatter_d10_cn = DateTimeFormatter.ofPattern("yyyy年M月d日");
- private final static DateTimeFormatter formatter_d10_kr = DateTimeFormatter.ofPattern("yyyy년M월d일");
- private final static DateTimeFormatter formatter_d10_us = DateTimeFormatter.ofPattern("MM/dd/yyyy");
- private final static DateTimeFormatter formatter_d10_eur = DateTimeFormatter.ofPattern("dd/MM/yyyy");
- private final static DateTimeFormatter formatter_d10_de = DateTimeFormatter.ofPattern("dd.MM.yyyy");
- private final static DateTimeFormatter formatter_d10_in = DateTimeFormatter.ofPattern("dd-MM-yyyy");
- private final static DateTimeFormatter ISO_FIXED_FORMAT =
- DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
- private final static String formatter_iso8601_pattern = "yyyy-MM-dd'T'HH:mm:ss";
- private final static String formatter_iso8601_pattern_23 = "yyyy-MM-dd'T'HH:mm:ss.SSS";
- private final static String formatter_iso8601_pattern_29 = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS";
- private final static DateTimeFormatter formatter_iso8601 = DateTimeFormatter.ofPattern(formatter_iso8601_pattern);
- @SuppressWarnings("unchecked")
- public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName, String format, int feature) {
- JSONLexer lexer = parser.lexer;
- if (lexer.token() == JSONToken.NULL){
- lexer.nextToken();
- return null;
- }
- if (lexer.token() == JSONToken.LITERAL_STRING) {
- String text = lexer.stringVal();
- lexer.nextToken();
- DateTimeFormatter formatter = null;
- if (format != null) {
- if (defaultPatttern.equals(format)) {
- formatter = defaultFormatter;
- } else {
- formatter = DateTimeFormatter.ofPattern(format);
- }
- }
- if ("".equals(text)) {
- return null;
- }
- if (type == LocalDateTime.class) {
- LocalDateTime localDateTime;
- if (text.length() == 10 || text.length() == 8) {
- LocalDate localDate = parseLocalDate(text, format, formatter);
- localDateTime = LocalDateTime.of(localDate, LocalTime.MIN);
- } else {
- localDateTime = parseDateTime(text, formatter);
- }
- return (T) localDateTime;
- } else if (type == LocalDate.class) {
- LocalDate localDate;
- if (text.length() == 23) {
- LocalDateTime localDateTime = LocalDateTime.parse(text);
- localDate = LocalDate.of(localDateTime.getYear(), localDateTime.getMonthValue(),
- localDateTime.getDayOfMonth());
- } else {
- localDate = parseLocalDate(text, format, formatter);
- }
- return (T) localDate;
- } else if (type == LocalTime.class) {
- LocalTime localTime;
- if (text.length() == 23) {
- LocalDateTime localDateTime = LocalDateTime.parse(text);
- localTime = LocalTime.of(localDateTime.getHour(), localDateTime.getMinute(),
- localDateTime.getSecond(), localDateTime.getNano());
- } else {
- boolean digit = true;
- for (int i = 0; i < text.length(); ++i) {
- char ch = text.charAt(i);
- if (ch < '0' || ch > '9') {
- digit = false;
- break;
- }
- }
- if (digit && text.length() > 8 && text.length() < 19) {
- long epochMillis = Long.parseLong(text);
- localTime = LocalDateTime
- .ofInstant(
- Instant.ofEpochMilli(epochMillis),
- JSON.defaultTimeZone.toZoneId())
- .toLocalTime();
- } else {
- localTime = LocalTime.parse(text);
- }
- }
- return (T) localTime;
- } else if (type == ZonedDateTime.class) {
- if (formatter == defaultFormatter) {
- formatter = ISO_FIXED_FORMAT;
- }
- if (formatter == null) {
- if (text.length() <= 19) {
- JSONScanner s = new JSONScanner(text);
- TimeZone timeZone = parser.lexer.getTimeZone();
- s.setTimeZone(timeZone);
- boolean match = s.scanISO8601DateIfMatch(false);
- if (match) {
- Date date = s.getCalendar().getTime();
- return (T) ZonedDateTime.ofInstant(date.toInstant(), timeZone.toZoneId());
- }
- }
- }
- ZonedDateTime zonedDateTime = parseZonedDateTime(text, formatter);
- return (T) zonedDateTime;
- } else if (type == OffsetDateTime.class) {
- OffsetDateTime offsetDateTime = OffsetDateTime.parse(text);
- return (T) offsetDateTime;
- } else if (type == OffsetTime.class) {
- OffsetTime offsetTime = OffsetTime.parse(text);
- return (T) offsetTime;
- } else if (type == ZoneId.class) {
- ZoneId offsetTime = ZoneId.of(text);
- return (T) offsetTime;
- } else if (type == Period.class) {
- Period period = Period.parse(text);
- return (T) period;
- } else if (type == Duration.class) {
- Duration duration = Duration.parse(text);
- return (T) duration;
- } else if (type == Instant.class) {
- boolean digit = true;
- for (int i = 0; i < text.length(); ++i) {
- char ch = text.charAt(i);
- if (ch < '0' || ch > '9') {
- digit = false;
- break;
- }
- }
- if (digit && text.length() > 8 && text.length() < 19) {
- long epochMillis = Long.parseLong(text);
- return (T) Instant.ofEpochMilli(epochMillis);
- }
- Instant instant = Instant.parse(text);
- return (T) instant;
- }
- } else if (lexer.token() == JSONToken.LITERAL_INT) {
- long millis = lexer.longValue();
- lexer.nextToken();
- if ("unixtime".equals(format)) {
- millis *= 1000;
- } else if ("yyyyMMddHHmmss".equals(format)) {
- int yyyy = (int) (millis / 10000000000L);
- int MM = (int) ((millis / 100000000L) % 100);
- int dd = (int) ((millis / 1000000L) % 100);
- int HH = (int) ((millis / 10000L) % 100);
- int mm = (int) ((millis / 100L) % 100);
- int ss = (int) (millis % 100);
- if (type == LocalDateTime.class) {
- return (T) LocalDateTime.of(yyyy, MM, dd, HH, mm, ss);
- }
- }
- if (type == LocalDateTime.class) {
- return (T) LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), JSON.defaultTimeZone.toZoneId());
- }
- if (type == LocalDate.class) {
- return (T) LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), JSON.defaultTimeZone.toZoneId()).toLocalDate();
- }
- if (type == LocalTime.class) {
- return (T) LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), JSON.defaultTimeZone.toZoneId()).toLocalTime();
- }
- if (type == ZonedDateTime.class) {
- return (T) ZonedDateTime.ofInstant(Instant.ofEpochMilli(millis), JSON.defaultTimeZone.toZoneId());
- }
- if (type == Instant.class) {
- return (T) Instant.ofEpochMilli(millis);
- }
- throw new UnsupportedOperationException();
- } else if (lexer.token() == JSONToken.LBRACE) {
- JSONObject object = parser.parseObject();
- if (type == Instant.class) {
- Object epochSecond = object.get("epochSecond");
- Object nano = object.get("nano");
- if (epochSecond instanceof Number && nano instanceof Number) {
- return (T) Instant.ofEpochSecond(
- TypeUtils.longExtractValue((Number) epochSecond)
- , TypeUtils.longExtractValue((Number) nano));
- }
- if (epochSecond instanceof Number) {
- return (T) Instant.ofEpochSecond(
- TypeUtils.longExtractValue((Number) epochSecond));
- }
- } else if (type == Duration.class) {
- Long seconds = object.getLong("seconds");
- if (seconds != null) {
- long nanos = object.getLongValue("nano");
- return (T) Duration.ofSeconds(seconds, nanos);
- }
- }
- } else {
- throw new UnsupportedOperationException();
- }
- return null;
- }
- protected LocalDateTime parseDateTime(String text, DateTimeFormatter formatter) {
- if (formatter == null) {
- if (text.length() == 19) {
- char c4 = text.charAt(4);
- char c7 = text.charAt(7);
- char c10 = text.charAt(10);
- char c13 = text.charAt(13);
- char c16 = text.charAt(16);
- if (c13 == ':' && c16 == ':') {
- if (c4 == '-' && c7 == '-') {
- if (c10 == 'T') {
- formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
- } else if (c10 == ' ') {
- formatter = defaultFormatter;
- }
- } else if (c4 == '/' && c7 == '/') { // tw yyyy/mm/dd
- formatter = formatter_dt19_tw;
- } else {
- char c0 = text.charAt(0);
- char c1 = text.charAt(1);
- char c2 = text.charAt(2);
- char c3 = text.charAt(3);
- char c5 = text.charAt(5);
- if (c2 == '/' && c5 == '/') { // mm/dd/yyyy or mm/dd/yyyy
- int v0 = (c0 - '0') * 10 + (c1 - '0');
- int v1 = (c3 - '0') * 10 + (c4 - '0');
- if (v0 > 12) {
- formatter = formatter_dt19_eur;
- } else if (v1 > 12) {
- formatter = formatter_dt19_us;
- } else {
- String country = Locale.getDefault().getCountry();
- if (country.equals("US")) {
- formatter = formatter_dt19_us;
- } else if (country.equals("BR") //
- || country.equals("AU")) {
- formatter = formatter_dt19_eur;
- }
- }
- } else if (c2 == '.' && c5 == '.') { // dd.mm.yyyy
- formatter = formatter_dt19_de;
- } else if (c2 == '-' && c5 == '-') { // dd-mm-yyyy
- formatter = formatter_dt19_in;
- }
- }
- }
- } else if (text.length() == 23) {
- char c4 = text.charAt(4);
- char c7 = text.charAt(7);
- char c10 = text.charAt(10);
- char c13 = text.charAt(13);
- char c16 = text.charAt(16);
- char c19 = text.charAt(19);
- if (c13 == ':'
- && c16 == ':'
- && c4 == '-'
- && c7 == '-'
- && c10 == ' '
- && c19 == '.'
- ) {
- formatter = defaultFormatter_23;
- }
- }
- if (text.length() >= 17) {
- char c4 = text.charAt(4);
- if (c4 == '年') {
- if (text.charAt(text.length() - 1) == '秒') {
- formatter = formatter_dt19_cn_1;
- } else {
- formatter = formatter_dt19_cn;
- }
- } else if (c4 == '년') {
- formatter = formatter_dt19_kr;
- }
- }
- }
- if (formatter == null) {
- JSONScanner dateScanner = new JSONScanner(text);
- if (dateScanner.scanISO8601DateIfMatch(false)) {
- Instant instant = dateScanner.getCalendar().toInstant();
- return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
- }
- boolean digit = true;
- for (int i = 0; i < text.length(); ++i) {
- char ch = text.charAt(i);
- if (ch < '0' || ch > '9') {
- digit = false;
- break;
- }
- }
- if (digit && text.length() > 8 && text.length() < 19) {
- long epochMillis = Long.parseLong(text);
- return LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), JSON.defaultTimeZone.toZoneId());
- }
- }
- return formatter == null ? //
- LocalDateTime.parse(text) //
- : LocalDateTime.parse(text, formatter);
- }
- protected LocalDate parseLocalDate(String text, String format, DateTimeFormatter formatter) {
- if (formatter == null) {
- if (text.length() == 8) {
- formatter = formatter_d8;
- }
- if (text.length() == 10) {
- char c4 = text.charAt(4);
- char c7 = text.charAt(7);
- if (c4 == '/' && c7 == '/') { // tw yyyy/mm/dd
- formatter = formatter_d10_tw;
- }
- char c0 = text.charAt(0);
- char c1 = text.charAt(1);
- char c2 = text.charAt(2);
- char c3 = text.charAt(3);
- char c5 = text.charAt(5);
- if (c2 == '/' && c5 == '/') { // mm/dd/yyyy or mm/dd/yyyy
- int v0 = (c0 - '0') * 10 + (c1 - '0');
- int v1 = (c3 - '0') * 10 + (c4 - '0');
- if (v0 > 12) {
- formatter = formatter_d10_eur;
- } else if (v1 > 12) {
- formatter = formatter_d10_us;
- } else {
- String country = Locale.getDefault().getCountry();
- if (country.equals("US")) {
- formatter = formatter_d10_us;
- } else if (country.equals("BR") //
- || country.equals("AU")) {
- formatter = formatter_d10_eur;
- }
- }
- } else if (c2 == '.' && c5 == '.') { // dd.mm.yyyy
- formatter = formatter_d10_de;
- } else if (c2 == '-' && c5 == '-') { // dd-mm-yyyy
- formatter = formatter_d10_in;
- }
- }
- if (text.length() >= 9) {
- char c4 = text.charAt(4);
- if (c4 == '年') {
- formatter = formatter_d10_cn;
- } else if (c4 == '년') {
- formatter = formatter_d10_kr;
- }
- }
- boolean digit = true;
- for (int i = 0; i < text.length(); ++i) {
- char ch = text.charAt(i);
- if (ch < '0' || ch > '9') {
- digit = false;
- break;
- }
- }
- if (digit && text.length() > 8 && text.length() < 19) {
- long epochMillis = Long.parseLong(text);
- return LocalDateTime
- .ofInstant(
- Instant.ofEpochMilli(epochMillis),
- JSON.defaultTimeZone.toZoneId())
- .toLocalDate();
- }
- }
- return formatter == null ? //
- LocalDate.parse(text) //
- : LocalDate.parse(text, formatter);
- }
- protected ZonedDateTime parseZonedDateTime(String text, DateTimeFormatter formatter) {
- if (formatter == null) {
- if (text.length() == 19) {
- char c4 = text.charAt(4);
- char c7 = text.charAt(7);
- char c10 = text.charAt(10);
- char c13 = text.charAt(13);
- char c16 = text.charAt(16);
- if (c13 == ':' && c16 == ':') {
- if (c4 == '-' && c7 == '-') {
- if (c10 == 'T') {
- formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
- } else if (c10 == ' ') {
- formatter = defaultFormatter;
- }
- } else if (c4 == '/' && c7 == '/') { // tw yyyy/mm/dd
- formatter = formatter_dt19_tw;
- } else {
- char c0 = text.charAt(0);
- char c1 = text.charAt(1);
- char c2 = text.charAt(2);
- char c3 = text.charAt(3);
- char c5 = text.charAt(5);
- if (c2 == '/' && c5 == '/') { // mm/dd/yyyy or mm/dd/yyyy
- int v0 = (c0 - '0') * 10 + (c1 - '0');
- int v1 = (c3 - '0') * 10 + (c4 - '0');
- if (v0 > 12) {
- formatter = formatter_dt19_eur;
- } else if (v1 > 12) {
- formatter = formatter_dt19_us;
- } else {
- String country = Locale.getDefault().getCountry();
- if (country.equals("US")) {
- formatter = formatter_dt19_us;
- } else if (country.equals("BR") //
- || country.equals("AU")) {
- formatter = formatter_dt19_eur;
- }
- }
- } else if (c2 == '.' && c5 == '.') { // dd.mm.yyyy
- formatter = formatter_dt19_de;
- } else if (c2 == '-' && c5 == '-') { // dd-mm-yyyy
- formatter = formatter_dt19_in;
- }
- }
- }
- }
- if (text.length() >= 17) {
- char c4 = text.charAt(4);
- if (c4 == '年') {
- if (text.charAt(text.length() - 1) == '秒') {
- formatter = formatter_dt19_cn_1;
- } else {
- formatter = formatter_dt19_cn;
- }
- } else if (c4 == '년') {
- formatter = formatter_dt19_kr;
- }
- }
- boolean digit = true;
- for (int i = 0; i < text.length(); ++i) {
- char ch = text.charAt(i);
- if (ch < '0' || ch > '9') {
- digit = false;
- break;
- }
- }
- if (digit && text.length() > 8 && text.length() < 19) {
- long epochMillis = Long.parseLong(text);
- return ZonedDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), JSON.defaultTimeZone.toZoneId());
- }
- }
- return formatter == null ? //
- ZonedDateTime.parse(text) //
- : ZonedDateTime.parse(text, formatter);
- }
- public int getFastMatchToken() {
- return JSONToken.LITERAL_STRING;
- }
- public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
- int features) throws IOException {
- SerializeWriter out = serializer.out;
- if (object == null) {
- out.writeNull();
- } else {
- if (fieldType == null) {
- fieldType = object.getClass();
- }
- if (fieldType == LocalDateTime.class) {
- final int mask = SerializerFeature.UseISO8601DateFormat.getMask();
- LocalDateTime dateTime = (LocalDateTime) object;
- String format = serializer.getDateFormatPattern();
- if (format == null) {
- if ((features & mask) != 0 || serializer.isEnabled(SerializerFeature.UseISO8601DateFormat)) {
- format = formatter_iso8601_pattern;
- } else if (serializer.isEnabled(SerializerFeature.WriteDateUseDateFormat)) {
- if (serializer.getFastJsonConfigDateFormatPattern() != null &&
- serializer.getFastJsonConfigDateFormatPattern().length() > 0){
- format = serializer.getFastJsonConfigDateFormatPattern();
- }else{
- format = JSON.DEFFAULT_DATE_FORMAT;
- }
- } else {
- int nano = dateTime.getNano();
- if (nano == 0) {
- format = formatter_iso8601_pattern;
- } else if (nano % 1000000 == 0) {
- format = formatter_iso8601_pattern_23;
- } else {
- format = formatter_iso8601_pattern_29;
- }
- }
- }
- if (format != null) {
- write(out, dateTime, format);
- } else {
- out.writeLong(dateTime.atZone(JSON.defaultTimeZone.toZoneId()).toInstant().toEpochMilli());
- }
- } else {
- out.writeString(object.toString());
- }
- }
- }
- public void write(JSONSerializer serializer, Object object, BeanContext context) throws IOException {
- SerializeWriter out = serializer.out;
- String format = context.getFormat();
- write(out, (TemporalAccessor) object, format);
- }
- private void write(SerializeWriter out, TemporalAccessor object, String format) {
- DateTimeFormatter formatter;
- if ("unixtime".equals(format)) {
- Instant instant = null;
- if (object instanceof ChronoZonedDateTime) {
- long seconds = ((ChronoZonedDateTime) object).toEpochSecond();
- out.writeInt((int) seconds);
- return;
- }
- if (object instanceof LocalDateTime) {
- long seconds = ((LocalDateTime) object).atZone(JSON.defaultTimeZone.toZoneId()).toEpochSecond();
- out.writeInt((int) seconds);
- return;
- }
- }
- if ("millis".equals(format)) {
- Instant instant = null;
- if (object instanceof ChronoZonedDateTime) {
- instant = ((ChronoZonedDateTime) object).toInstant();
- } else if (object instanceof LocalDateTime) {
- instant = ((LocalDateTime) object).atZone(JSON.defaultTimeZone.toZoneId()).toInstant();
- }
- if (instant != null) {
- long millis = instant.toEpochMilli();
- out.writeLong(millis);
- return;
- }
- }
- if (format == formatter_iso8601_pattern) {
- formatter = formatter_iso8601;
- } else {
- formatter = DateTimeFormatter.ofPattern(format);
- }
- String text = formatter.format((TemporalAccessor) object);
- out.writeString(text);
- }
- public static Object castToLocalDateTime(Object value, String format) {
- if (value == null) {
- return null;
- }
- if (format == null) {
- format = "yyyy-MM-dd HH:mm:ss";
- }
- DateTimeFormatter df = DateTimeFormatter.ofPattern(format);
- return LocalDateTime.parse(value.toString(), df);
- }
- }