|
|
|
@ -1,6 +1,7 @@ |
|
|
|
package com.gaotao.modules.base.service.Impl; |
|
|
|
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper; |
|
|
|
import com.fasterxml.jackson.databind.SerializationFeature; |
|
|
|
import com.gaotao.modules.api.entity.IfsBoxLabel; |
|
|
|
import com.gaotao.modules.api.service.IfsApiService; |
|
|
|
import com.gaotao.modules.base.entity.LabelSettingData; |
|
|
|
@ -17,6 +18,7 @@ import org.springframework.stereotype.Service; |
|
|
|
import java.math.BigDecimal; |
|
|
|
import java.math.RoundingMode; |
|
|
|
import java.text.DecimalFormat; |
|
|
|
import java.text.SimpleDateFormat; |
|
|
|
import java.time.LocalDate; |
|
|
|
import java.time.ZoneId; |
|
|
|
import java.time.format.DateTimeFormatter; |
|
|
|
@ -787,6 +789,12 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService |
|
|
|
return dateValue; |
|
|
|
} |
|
|
|
|
|
|
|
// 日期偏移处理:正数加天,负数减天 |
|
|
|
Integer dateOffsetDays = element.getDateOffsetDays(); |
|
|
|
if (dateOffsetDays != null && dateOffsetDays != 0) { |
|
|
|
date = date.plusDays(dateOffsetDays.longValue()); |
|
|
|
} |
|
|
|
|
|
|
|
switch (extractType) { |
|
|
|
case "year": |
|
|
|
return String.valueOf(date.getYear()); |
|
|
|
@ -813,6 +821,23 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService |
|
|
|
* 解析日期字符串 |
|
|
|
*/ |
|
|
|
private LocalDate parseDate(String dateValue) { |
|
|
|
String normalizedValue = dateValue != null ? dateValue.trim() : ""; |
|
|
|
if (normalizedValue.isEmpty()) { |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
// 去除字符串两端引号,兼容 "\"2024-09-14T00:00:00\"" 这类数据 |
|
|
|
if ((normalizedValue.startsWith("\"") && normalizedValue.endsWith("\"")) |
|
|
|
|| (normalizedValue.startsWith("'") && normalizedValue.endsWith("'"))) { |
|
|
|
normalizedValue = normalizedValue.substring(1, normalizedValue.length() - 1).trim(); |
|
|
|
} |
|
|
|
|
|
|
|
// 优先使用java.time处理,避免宽松解析导致错误日期(例如 7203-12-23) |
|
|
|
LocalDate javaTimeParsedDate = parseDateByJavaTime(normalizedValue); |
|
|
|
if (javaTimeParsedDate != null) { |
|
|
|
return javaTimeParsedDate; |
|
|
|
} |
|
|
|
|
|
|
|
String[] patterns = { |
|
|
|
// 年月日 |
|
|
|
"yyyy-MM-dd", "yyyy/MM/dd", "yyyy.MM.dd", |
|
|
|
@ -826,6 +851,14 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService |
|
|
|
"MM-dd-yyyy HH:mm:ss", "MM/dd/yyyy HH:mm:ss", "MM.dd.yyyy HH:mm:ss", |
|
|
|
"yyyyMMdd HHmmss", |
|
|
|
|
|
|
|
// ISO时间格式(T分隔) |
|
|
|
"yyyy-MM-dd'T'HH:mm:ss", |
|
|
|
"yyyy-MM-dd'T'HH:mm:ss.SSS", |
|
|
|
"yyyy-MM-dd'T'HH:mm:ssX", |
|
|
|
"yyyy-MM-dd'T'HH:mm:ss.SSSX", |
|
|
|
"yyyy-MM-dd'T'HH:mm:ssXXX", |
|
|
|
"yyyy-MM-dd'T'HH:mm:ss.SSSXXX", |
|
|
|
|
|
|
|
// 年月日 + 时分 |
|
|
|
"yyyy-MM-dd HH:mm", "yyyy/MM/dd HH:mm", "yyyy.MM.dd HH:mm", |
|
|
|
"dd-MM-yyyy HH:mm", "dd/MM/yyyy HH:mm", "dd.MM.yyyy HH:mm", |
|
|
|
@ -833,11 +866,13 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService |
|
|
|
"yyyyMMdd HHmm", |
|
|
|
|
|
|
|
// 带毫秒 |
|
|
|
"yyyy-MM-dd HH:mm:ss.SSS", "yyyy/MM/dd HH:mm:ss.SSS", "yyyy.MM.dd HH:mm:ss.SSS" |
|
|
|
"yyyy-MM-dd HH:mm:ss.S", "yyyy-MM-dd HH:mm:ss.SS", "yyyy-MM-dd HH:mm:ss.SSS", |
|
|
|
"yyyy/MM/dd HH:mm:ss.S", "yyyy/MM/dd HH:mm:ss.SS", "yyyy/MM/dd HH:mm:ss.SSS", |
|
|
|
"yyyy.MM.dd HH:mm:ss.S", "yyyy.MM.dd HH:mm:ss.SS", "yyyy.MM.dd HH:mm:ss.SSS" |
|
|
|
}; |
|
|
|
|
|
|
|
try { |
|
|
|
Date date = DateUtils.parseDate(dateValue.trim(), patterns); |
|
|
|
Date date = DateUtils.parseDateStrictly(normalizedValue, patterns); |
|
|
|
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); |
|
|
|
} catch (Exception e) { |
|
|
|
log.debug("日期解析失败: {}", dateValue); |
|
|
|
@ -845,6 +880,97 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 使用java.time严格解析日期,优先处理ISO格式与数据库常见时间戳字符串 |
|
|
|
*/ |
|
|
|
private LocalDate parseDateByJavaTime(String dateValue) { |
|
|
|
// 兼容纯数字时间戳(秒/毫秒/微秒/纳秒) |
|
|
|
LocalDate epochDate = parseEpochTimestamp(dateValue); |
|
|
|
if (epochDate != null) { |
|
|
|
return epochDate; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
return LocalDate.parse(dateValue, DateTimeFormatter.ISO_LOCAL_DATE); |
|
|
|
} catch (Exception ignored) { |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
return java.time.LocalDateTime.parse(dateValue, DateTimeFormatter.ISO_LOCAL_DATE_TIME).toLocalDate(); |
|
|
|
} catch (Exception ignored) { |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
return java.time.OffsetDateTime.parse(dateValue, DateTimeFormatter.ISO_OFFSET_DATE_TIME).toLocalDate(); |
|
|
|
} catch (Exception ignored) { |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
return java.time.ZonedDateTime.parse(dateValue, DateTimeFormatter.ISO_ZONED_DATE_TIME).toLocalDate(); |
|
|
|
} catch (Exception ignored) { |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
return java.time.Instant.parse(dateValue).atZone(ZoneId.systemDefault()).toLocalDate(); |
|
|
|
} catch (Exception ignored) { |
|
|
|
} |
|
|
|
|
|
|
|
// 兼容数据库常见字符串:2024-09-14 00:00:00.0 |
|
|
|
try { |
|
|
|
java.time.format.DateTimeFormatter formatter = new java.time.format.DateTimeFormatterBuilder() |
|
|
|
.appendPattern("yyyy-MM-dd HH:mm:ss") |
|
|
|
.optionalStart() |
|
|
|
.appendFraction(java.time.temporal.ChronoField.NANO_OF_SECOND, 1, 9, true) |
|
|
|
.optionalEnd() |
|
|
|
.toFormatter(); |
|
|
|
return java.time.LocalDateTime.parse(dateValue, formatter).toLocalDate(); |
|
|
|
} catch (Exception ignored) { |
|
|
|
} |
|
|
|
|
|
|
|
// 兼容数据库常见字符串:2024/09/14 00:00:00.0 |
|
|
|
try { |
|
|
|
java.time.format.DateTimeFormatter formatter = new java.time.format.DateTimeFormatterBuilder() |
|
|
|
.appendPattern("yyyy/MM/dd HH:mm:ss") |
|
|
|
.optionalStart() |
|
|
|
.appendFraction(java.time.temporal.ChronoField.NANO_OF_SECOND, 1, 9, true) |
|
|
|
.optionalEnd() |
|
|
|
.toFormatter(); |
|
|
|
return java.time.LocalDateTime.parse(dateValue, formatter).toLocalDate(); |
|
|
|
} catch (Exception ignored) { |
|
|
|
} |
|
|
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 解析纯数字时间戳字符串 |
|
|
|
*/ |
|
|
|
private LocalDate parseEpochTimestamp(String dateValue) { |
|
|
|
if (dateValue == null || !dateValue.matches("^-?\\d+(\\.\\d+)?$")) { |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
BigDecimal numericValue = new BigDecimal(dateValue); |
|
|
|
long epoch = numericValue.longValue(); |
|
|
|
long absEpoch = Math.abs(epoch); |
|
|
|
|
|
|
|
// 判定时间戳单位并转换为毫秒 |
|
|
|
// 秒:10位左右;毫秒:13位左右;微秒:16位左右;纳秒:19位左右 |
|
|
|
if (absEpoch >= 1_000_000_000_000_000_000L) { |
|
|
|
epoch = epoch / 1_000_000L; // 纳秒 -> 毫秒 |
|
|
|
} else if (absEpoch >= 1_000_000_000_000_000L) { |
|
|
|
epoch = epoch / 1_000L; // 微秒 -> 毫秒 |
|
|
|
} else if (absEpoch < 100_000_000_000L) { |
|
|
|
epoch = epoch * 1_000L; // 秒 -> 毫秒 |
|
|
|
} |
|
|
|
|
|
|
|
return java.time.Instant.ofEpochMilli(epoch).atZone(ZoneId.systemDefault()).toLocalDate(); |
|
|
|
} catch (Exception ignored) { |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 计算周数 |
|
|
|
*/ |
|
|
|
@ -1113,6 +1239,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService |
|
|
|
copy.setDateExtractType(original.getDateExtractType()); |
|
|
|
copy.setFirstWeekDate(original.getFirstWeekDate()); |
|
|
|
copy.setFirstDayOfWeek(original.getFirstDayOfWeek()); |
|
|
|
copy.setDateOffsetDays(original.getDateOffsetDays()); |
|
|
|
copy.setDateFormat(original.getDateFormat()); |
|
|
|
copy.setDateSeparator(original.getDateSeparator()); |
|
|
|
copy.setYearDigits(original.getYearDigits()); |
|
|
|
@ -1598,6 +1725,9 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService |
|
|
|
if (ifsBoxLabels != null && !ifsBoxLabels.isEmpty()) { |
|
|
|
// 将IfsBoxLabel实体类转换为Map |
|
|
|
ObjectMapper objectMapper = new ObjectMapper(); |
|
|
|
// 日期字段转为标准字符串,避免默认序列化为时间戳数字 |
|
|
|
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); |
|
|
|
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); |
|
|
|
for (IfsBoxLabel label : ifsBoxLabels) { |
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
Map<String, Object> dataMap = objectMapper.convertValue(label, Map.class); |
|
|
|
|