com.alibaba.fastjson2.writer.FieldWriterDate Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fastjson2 Show documentation
Show all versions of fastjson2 Show documentation
Fastjson is a JSON processor (JSON parser + JSON generator) written in Java
The newest version!
package com.alibaba.fastjson2.writer;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.util.DateUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.time.*;
import java.time.format.DateTimeFormatter;
abstract class FieldWriterDate
extends FieldWriter {
protected DateTimeFormatter formatter;
final boolean formatMillis;
final boolean formatISO8601;
final boolean formatyyyyMMdd8;
final boolean formatyyyyMMddhhmmss14;
final boolean formatyyyyMMddhhmmss19;
final boolean formatUnixTime;
protected ObjectWriter dateWriter;
protected FieldWriterDate(
String fieldName,
int ordinal,
long features,
String format,
String label,
Type fieldType,
Class fieldClass,
Field field,
Method method
) {
super(fieldName, ordinal, features, format, label, fieldType, fieldClass, field, method);
boolean formatMillis = false, formatISO8601 = false, formatUnixTime = false;
boolean formatyyyyMMdd8 = false, formatyyyyMMddhhmmss14 = false, formatyyyyMMddhhmmss19 = false;
if (format != null) {
switch (format) {
case "millis":
formatMillis = true;
break;
case "iso8601":
formatISO8601 = true;
break;
case "unixtime":
formatUnixTime = true;
break;
case "yyyy-MM-dd HH:mm:ss":
formatyyyyMMddhhmmss19 = true;
break;
case "yyyyMMdd":
formatyyyyMMdd8 = true;
break;
case "yyyyMMddHHmmss":
formatyyyyMMddhhmmss14 = true;
break;
default:
break;
}
}
this.formatMillis = formatMillis;
this.formatISO8601 = formatISO8601;
this.formatUnixTime = formatUnixTime;
this.formatyyyyMMdd8 = formatyyyyMMdd8;
this.formatyyyyMMddhhmmss14 = formatyyyyMMddhhmmss14;
this.formatyyyyMMddhhmmss19 = formatyyyyMMddhhmmss19;
}
@Override
public boolean isDateFormatMillis() {
return formatMillis;
}
@Override
public boolean isDateFormatISO8601() {
return formatISO8601;
}
public DateTimeFormatter getFormatter() {
if (formatter == null
&& format != null
&& !formatMillis
&& !formatISO8601
&& !formatUnixTime
) {
formatter = DateTimeFormatter.ofPattern(format);
}
return formatter;
}
@Override
public ObjectWriter getObjectWriter(JSONWriter jsonWriter, Class valueClass) {
if (valueClass == fieldClass) {
ObjectWriterProvider provider = jsonWriter.context.provider;
if (dateWriter == null) {
if ((provider.userDefineMask & ObjectWriterProvider.TYPE_DATE_MASK) != 0) {
dateWriter = provider.getObjectWriter(valueClass, valueClass, false);
} else {
if (format == null) {
return dateWriter = ObjectWriterImplDate.INSTANCE;
}
return dateWriter = new ObjectWriterImplDate(format, null);
}
}
return dateWriter;
}
return jsonWriter.getObjectWriter(valueClass);
}
@Override
public void writeDate(JSONWriter jsonWriter, long timeMillis) {
if (jsonWriter.jsonb) {
writeFieldName(jsonWriter);
jsonWriter.writeMillis(timeMillis);
return;
}
final int SECONDS_PER_DAY = 60 * 60 * 24;
JSONWriter.Context ctx = jsonWriter.context;
if (formatUnixTime || (format == null && ctx.isDateFormatUnixTime())) {
writeFieldName(jsonWriter);
jsonWriter.writeInt64(timeMillis / 1000);
return;
}
if (formatMillis || (format == null && ctx.isDateFormatMillis())) {
writeFieldName(jsonWriter);
jsonWriter.writeInt64(timeMillis);
return;
}
ZoneId zoneId = ctx.getZoneId();
String dateFormat = this.format != null
? this.format
: ctx.getDateFormat();
boolean formatyyyyMMddhhmmss19 = this.formatyyyyMMddhhmmss19 || (ctx.isFormatyyyyMMddhhmmss19() && this.format == null);
if (dateFormat == null || formatyyyyMMddhhmmss14 || formatyyyyMMddhhmmss19) {
long epochSecond = Math.floorDiv(timeMillis, 1000L);
int offsetTotalSeconds;
if (zoneId == DateUtils.SHANGHAI_ZONE_ID || zoneId.getRules() == DateUtils.SHANGHAI_ZONE_RULES) {
offsetTotalSeconds = DateUtils.getShanghaiZoneOffsetTotalSeconds(epochSecond);
} else {
Instant instant = Instant.ofEpochMilli(timeMillis);
offsetTotalSeconds = zoneId.getRules().getOffset(instant).getTotalSeconds();
}
long localSecond = epochSecond + offsetTotalSeconds;
long localEpochDay = Math.floorDiv(localSecond, (long) SECONDS_PER_DAY);
int secsOfDay = (int) Math.floorMod(localSecond, (long) SECONDS_PER_DAY);
int year, month, dayOfMonth;
{
final int DAYS_PER_CYCLE = 146097;
final long DAYS_0000_TO_1970 = (DAYS_PER_CYCLE * 5L) - (30L * 365L + 7L);
long zeroDay = localEpochDay + DAYS_0000_TO_1970;
// find the march-based year
zeroDay -= 60; // adjust to 0000-03-01 so leap day is at end of four year cycle
long adjust = 0;
if (zeroDay < 0) {
// adjust negative years to positive for calculation
long adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1;
adjust = adjustCycles * 400;
zeroDay += -adjustCycles * DAYS_PER_CYCLE;
}
long yearEst = (400 * zeroDay + 591) / DAYS_PER_CYCLE;
long doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
if (doyEst < 0) {
// fix estimate
yearEst--;
doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
}
yearEst += adjust; // reset any negative year
int marchDoy0 = (int) doyEst;
// convert march-based values back to january-based
int marchMonth0 = (marchDoy0 * 5 + 2) / 153;
month = (marchMonth0 + 2) % 12 + 1;
dayOfMonth = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1;
yearEst += marchMonth0 / 10;
// check year now we are certain it is correct
if (yearEst < Year.MIN_VALUE || yearEst > Year.MAX_VALUE) {
throw new DateTimeException("Invalid year " + yearEst);
}
year = (int) yearEst;
}
int hour, minute, second;
{
final int MINUTES_PER_HOUR = 60;
final int SECONDS_PER_MINUTE = 60;
final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
long secondOfDay = secsOfDay;
if (secondOfDay < 0 || secondOfDay > 86399) {
throw new DateTimeException("Invalid secondOfDay " + secondOfDay);
}
int hours = (int) (secondOfDay / SECONDS_PER_HOUR);
secondOfDay -= hours * SECONDS_PER_HOUR;
int minutes = (int) (secondOfDay / SECONDS_PER_MINUTE);
secondOfDay -= minutes * SECONDS_PER_MINUTE;
hour = hours;
minute = minutes;
second = (int) secondOfDay;
}
if (year >= 0 && year <= 9999) {
if (formatyyyyMMddhhmmss14) {
writeFieldName(jsonWriter);
jsonWriter.writeDateTime14(
year,
month,
dayOfMonth,
hour,
minute,
second
);
return;
}
if (formatyyyyMMddhhmmss19) {
writeFieldName(jsonWriter);
jsonWriter.writeDateTime19(
year,
month,
dayOfMonth,
hour,
minute,
second
);
return;
}
int millis = (int) Math.floorMod(timeMillis, 1000L);
if (millis != 0) {
Instant instant = Instant.ofEpochMilli(timeMillis);
int offsetSeconds = ctx
.getZoneId()
.getRules()
.getOffset(instant)
.getTotalSeconds();
writeFieldName(jsonWriter);
jsonWriter.writeDateTimeISO8601(year, month, dayOfMonth, hour, minute, second, millis, offsetSeconds, false);
return;
}
writeFieldName(jsonWriter);
jsonWriter.writeDateTime19(year, month, dayOfMonth, hour, minute, second);
return;
}
}
writeFieldName(jsonWriter);
ZonedDateTime zdt = ZonedDateTime
.ofInstant(
Instant.ofEpochMilli(timeMillis), zoneId);
if (formatISO8601 || (ctx.isDateFormatISO8601() && this.format == null)) {
int year = zdt.getYear();
if (year >= 0 && year <= 9999) {
int month = zdt.getMonthValue();
int dayOfMonth = zdt.getDayOfMonth();
int hour = zdt.getHour();
int minute = zdt.getMinute();
int second = zdt.getSecond();
int millis = zdt.getNano() / 1000_000;
int offsetSeconds = zdt.getOffset().getTotalSeconds();
jsonWriter.writeDateTimeISO8601(year, month, dayOfMonth, hour, minute, second, millis, offsetSeconds, true);
return;
}
}
if (formatyyyyMMdd8) {
int year = zdt.getYear();
if (year >= 0 && year <= 9999) {
int month = zdt.getMonthValue();
int dayOfMonth = zdt.getDayOfMonth();
jsonWriter.writeDateYYYMMDD8(year, month, dayOfMonth);
return;
}
}
DateTimeFormatter formatter = this.getFormatter();
if (formatter == null) {
formatter = ctx.getDateFormatter();
}
if (formatter != null) {
jsonWriter.writeString(
formatter.format(zdt)
);
} else {
jsonWriter.writeZonedDateTime(zdt);
}
}
}