From 0ff1fd3ceff14d4f44af34a148e6ed6a4015ad63 Mon Sep 17 00:00:00 2001 From: liuzhiming Date: Tue, 17 Mar 2026 09:34:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E6=8F=90=E4=BA=A4=EF=BC=9A?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=88=86=E6=97=B6=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dao/DnerHourlyPowerOutageEventMapper.java | 5 + .../power/grid/entity/HourlyStatisticDTO.java | 18 + .../power/grid/entity/WeatherDataDTO.java | 2 +- .../impl/HourlyOutageExcelProcessService.java | 11 +- .../service/impl/HourlyStatisticService.java | 411 ++++++++++++++++++ .../service/impl/WeatherDataServiceImpl.java | 4 +- .../southern/power/grid/utils/TimeUtil.java | 14 + .../DnerHourlyPowerOutageEventMapper.xml | 8 + 8 files changed, 467 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/southern/power/grid/entity/HourlyStatisticDTO.java create mode 100644 src/main/java/com/southern/power/grid/service/impl/HourlyStatisticService.java diff --git a/src/main/java/com/southern/power/grid/dao/DnerHourlyPowerOutageEventMapper.java b/src/main/java/com/southern/power/grid/dao/DnerHourlyPowerOutageEventMapper.java index 105d8bc..2735af2 100644 --- a/src/main/java/com/southern/power/grid/dao/DnerHourlyPowerOutageEventMapper.java +++ b/src/main/java/com/southern/power/grid/dao/DnerHourlyPowerOutageEventMapper.java @@ -5,6 +5,7 @@ import com.southern.power.grid.entity.DnerHourlyPowerOutageEvent; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.time.LocalDateTime; import java.util.List; /** @@ -25,4 +26,8 @@ public interface DnerHourlyPowerOutageEventMapper extends BaseMapper list); + + List selectByDistrictsAndTime(@Param("districtCodes") List districtCodes, + @Param("startTime") LocalDateTime startTime, + @Param("endTime") LocalDateTime endTime); } diff --git a/src/main/java/com/southern/power/grid/entity/HourlyStatisticDTO.java b/src/main/java/com/southern/power/grid/entity/HourlyStatisticDTO.java new file mode 100644 index 0000000..e4db385 --- /dev/null +++ b/src/main/java/com/southern/power/grid/entity/HourlyStatisticDTO.java @@ -0,0 +1,18 @@ +package com.southern.power.grid.entity; + +import lombok.Data; +import java.util.List; + +/** + * 分时统计结果DTO + */ +@Data +public class HourlyStatisticDTO { + private List timePoints; // 时间点列表,格式:yyyy-MM-dd HH:00:00 + private List userCounts; // 停电影响用户数 + private List precipitations; // 小时降水量 + private List avgTemperatures; // 平均气温 + private List maxTemperatures; // 最高气温 + private List minTemperatures; // 最低气温 + private List maxWindSpeeds; // 极大风速 +} diff --git a/src/main/java/com/southern/power/grid/entity/WeatherDataDTO.java b/src/main/java/com/southern/power/grid/entity/WeatherDataDTO.java index dfc33ce..2fe8aed 100644 --- a/src/main/java/com/southern/power/grid/entity/WeatherDataDTO.java +++ b/src/main/java/com/southern/power/grid/entity/WeatherDataDTO.java @@ -13,7 +13,7 @@ public class WeatherDataDTO { private String temperature; private String hourlyMaxTemperature; private String hourlyMinTemperature; - private String hourlyPrecipitation; + private Double hourlyPrecipitation; private String dailyPrecipitation; private String extremeWindSpeedHourly; } diff --git a/src/main/java/com/southern/power/grid/service/impl/HourlyOutageExcelProcessService.java b/src/main/java/com/southern/power/grid/service/impl/HourlyOutageExcelProcessService.java index 4eb31cd..f9a30ce 100644 --- a/src/main/java/com/southern/power/grid/service/impl/HourlyOutageExcelProcessService.java +++ b/src/main/java/com/southern/power/grid/service/impl/HourlyOutageExcelProcessService.java @@ -10,7 +10,6 @@ import com.southern.power.grid.entity.WeatherDataDTO; import com.southern.power.grid.entity.WeatherSiteAreaConfiguration; import com.southern.power.grid.service.WeatherDataService; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.time.LocalDateTime; @@ -51,7 +50,7 @@ public class HourlyOutageExcelProcessService { * 对外主入口:处理一批 Excel 解析后的数据,按逻辑补齐气象数据并批量入库 */ public void process(List excelRows) { - // 1. 加载南网配置表 + // 1. 加载南网区划配置表 loadNwAreaConfig(); // 2. 加载气象区划配置表 loadWeatherAreaConfig(); @@ -90,6 +89,9 @@ public class HourlyOutageExcelProcessService { } } + /** + * 加载南网区划配置 + * **/ private void loadNwAreaConfig() { nwAreaMap.clear(); List list = nwSiteAreaConfigurationMapper.selectAll(); @@ -103,6 +105,9 @@ public class HourlyOutageExcelProcessService { } } + /** + * 加载气象区划配置表 + * **/ private void loadWeatherAreaConfig() { weatherAreaMap.clear(); List list = weatherSiteAreaConfigurationMapper.selectAll(); @@ -146,7 +151,7 @@ public class HourlyOutageExcelProcessService { e.setTemperature(weatherData.getTemperature()); e.setHourlyMaxTemperature(weatherData.getHourlyMaxTemperature()); e.setHourlyMinTemperature(weatherData.getHourlyMinTemperature()); - e.setHourlyPrecipitation(weatherData.getHourlyPrecipitation()); +// e.setHourlyPrecipitation(weatherData.getHourlyPrecipitation()); e.setDailyPrecipitation(weatherData.getDailyPrecipitation()); e.setExtremeWindSpeedHourly(weatherData.getExtremeWindSpeedHourly()); } diff --git a/src/main/java/com/southern/power/grid/service/impl/HourlyStatisticService.java b/src/main/java/com/southern/power/grid/service/impl/HourlyStatisticService.java new file mode 100644 index 0000000..a577bd7 --- /dev/null +++ b/src/main/java/com/southern/power/grid/service/impl/HourlyStatisticService.java @@ -0,0 +1,411 @@ +package com.southern.power.grid.service.impl; + +import com.southern.power.grid.dao.DnerHourlyPowerOutageEventMapper; +import com.southern.power.grid.dao.NwSiteAreaConfigurationMapper; +import com.southern.power.grid.dao.WeatherSiteAreaConfigurationMapper; +import com.southern.power.grid.entity.DnerHourlyPowerOutageEvent; +import com.southern.power.grid.entity.HourlyStatisticDTO; +import com.southern.power.grid.entity.NwSiteAreaConfiguration; +import com.southern.power.grid.entity.WeatherDataDTO; +import com.southern.power.grid.entity.WeatherSiteAreaConfiguration; +import com.southern.power.grid.service.WeatherDataService; +import com.southern.power.grid.utils.TimeUtil; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Service +public class HourlyStatisticService { + + @Resource + private NwSiteAreaConfigurationMapper nwSiteAreaConfigurationMapper; + + @Resource + private WeatherSiteAreaConfigurationMapper weatherSiteAreaConfigurationMapper; + + @Resource + private WeatherDataService weatherDataService; + + @Resource + private DnerHourlyPowerOutageEventMapper dnerHourlyPowerOutageEventMapper; + + private static final DateTimeFormatter TIME_POINT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00:00"); + + /** + * 获取分时统计全量数据(包含所有指标) + * @param areaType 区域类型:province-省,city-市,county-县 + * @param areaCode 区域编码(省/市/县编码,县为org_code) + * @param startTime 开始时间(包含) + * @param endTime 结束时间(包含) + * @return 分时统计结果 + */ + public HourlyStatisticDTO getHourlyStatistics(String areaType, String areaCode, + LocalDateTime startTime, LocalDateTime endTime) { + // 1. 生成时间点列表(整点) + List timePoints = generateTimePoints(startTime, endTime); + if (timePoints.isEmpty()) { + return new HourlyStatisticDTO(); + } + + // 2. 根据区域类型获取需要统计的区县编码列表 + List districtCodes = getDistrictCodesByArea(areaType, areaCode); + if (districtCodes.isEmpty()) { + return new HourlyStatisticDTO(); + } + + // 3. 分别计算各指标 + HourlyStatisticDTO result = new HourlyStatisticDTO(); + result.setTimePoints(timePoints.stream().map(t -> t.format(TIME_POINT_FORMATTER)).collect(Collectors.toList())); + + // 3.1 停电用户数(直接查分时停电事件表) + Map userCountMap = calculateUserCount(districtCodes, timePoints); + result.setUserCounts(fillList(timePoints, userCountMap, 0L)); + + // 3.2 降水量(需要多站点平均) + Map precipMap = calculatePrecipitation(districtCodes, timePoints); + result.setPrecipitations(fillList(timePoints, precipMap, 0.0)); + + // 3.3 气温(平均/最高/最低) + TemperatureResult tempResult = calculateTemperature(districtCodes, timePoints); + result.setAvgTemperatures(fillList(timePoints, tempResult.getAvgMap(), 0.0)); + result.setMaxTemperatures(fillList(timePoints, tempResult.getMaxMap(), 0.0)); + result.setMinTemperatures(fillList(timePoints, tempResult.getMinMap(), 0.0)); + + // 3.4 风速(极大值) + Map windMap = calculateWindSpeed(districtCodes, timePoints); + result.setMaxWindSpeeds(fillList(timePoints, windMap, 0.0)); + + return result; + } + + /** + * 生成整点时间序列(从startTime的整点开始,到endTime的整点结束,包含首尾) + */ + private List generateTimePoints(LocalDateTime start, LocalDateTime end) { + List points = new ArrayList<>(); + LocalDateTime current = start.withMinute(0).withSecond(0).withNano(0); + LocalDateTime endPoint = end.withMinute(0).withSecond(0).withNano(0); + while (!current.isAfter(endPoint)) { + points.add(current); + current = current.plusHours(1); + } + return points; + } + + /** + * 根据区域类型获取所有需要统计的区县编码列表 + */ + private List getDistrictCodesByArea(String areaType, String areaCode) { + if ("county".equalsIgnoreCase(areaType)) { + return Collections.singletonList(areaCode); + } + + // 查询南网配置表,根据省/市编码获取所有区县编码 + List list; + if ("province".equalsIgnoreCase(areaType)) { + list = new ArrayList<>();// nwSiteAreaConfigurationMapper.selectByProvince(areaCode); + } else if ("city".equalsIgnoreCase(areaType)) { + list = new ArrayList<>(); // nwSiteAreaConfigurationMapper.selectByCity(areaCode); + } else { + return Collections.emptyList(); + } + + if (CollectionUtils.isEmpty(list)) { + return Collections.emptyList(); + } + return list.stream() + .map(NwSiteAreaConfiguration::getDistrictCode) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + } + + // ===================== 停电用户数统计 ===================== + private Map calculateUserCount(List districtCodes, List timePoints) { + // 查询所有区县在时间范围内的停电事件记录 + List events = dnerHourlyPowerOutageEventMapper.selectByDistrictsAndTime( + districtCodes, timePoints.get(0), timePoints.get(timePoints.size() - 1).plusHours(1)); + + // 按区县和整点时刻聚合user_count + Map result = new HashMap<>(); + for (LocalDateTime tp : timePoints) { + result.put(tp, 0L); + } + + if (CollectionUtils.isEmpty(events)) { + return result; + } + + // 注意:data_time是停电开始时间,需按照“停电开始时间 > 整点时刻”的规则计入该整点 + // 但我们表中没有结束时间,无法精确统计“正在停电中”,此处采用简化规则:按开始时间所在小时计入 + // 若未来表添加end_time字段,可修改为更精确的逻辑 + for (DnerHourlyPowerOutageEvent event : events) { + if (event.getDataTime() == null) continue; + LocalDateTime start = TimeUtil.parseToLocalDateTime(event.getDataTime()); // 需要工具类解析字符串 + if (start == null) continue; + + // 找到大于start的最小整点(即start所在的下一个整点) + LocalDateTime targetHour = start.withMinute(0).withSecond(0).withNano(0).plusHours(1); + if (result.containsKey(targetHour)) { + result.merge(targetHour, event.getUserCount() == null ? 0L : event.getUserCount().longValue(), Long::sum); + } + } + + return result; + } + + // ===================== 降水量统计(多站平均) ===================== + private Map calculatePrecipitation(List districtCodes, List timePoints) { + // 1. 获取所有区县关联的气象站ID + List stationIds = getStationIdsByDistricts(districtCodes); + if (stationIds.isEmpty()) { + return emptyMap(timePoints); + } + + // 2. 批量获取所有站点的气象数据(按小时) + Map> stationDataMap = batchFetchWeatherData(stationIds, timePoints); + + // 3. 按小时计算各县平均降水量 + // 由于降水量县级规则是“国家站+区域站平均”,但我们有所有站的数据,需要先计算各县的平均值,再汇总 + // 简化:直接对所有站的数据按小时取平均(因为最终市级还需要再平均,最终结果等价于所有站的平均) + // 但需求要求县级统计时是县级内平均,市级统计时是各县平均再平均,因此必须按县分组先计算平均值 + // 此处我们实现为:先按县分组,每个小时取该县所有站的降水量平均值,得到各县小时降水量;然后所有县的小时降水量再平均(市级)或直接使用(县级) + // 但本方法返回值是总体结果,需要在调用前已经确定是县级还是市级,但调用时districtCodes已经是一个集合,方法需要返回这个集合整体的平均降水量。 + // 因此:对每个小时,计算所有区县在该小时的平均降水量(即先计算每个县内所有站的平均,再对这些县的平均取平均) + return calculateAverageByDistrict(stationDataMap, districtCodes, timePoints, + WeatherDataDTO::getHourlyPrecipitation); + } + + // ===================== 气温统计 ===================== + private TemperatureResult calculateTemperature(List districtCodes, List timePoints) { + // 1. 获取所有区县关联的气象站ID + List stationIds = getStationIdsByDistricts(districtCodes); + if (stationIds.isEmpty()) { + return new TemperatureResult(emptyMap(timePoints), emptyMap(timePoints), emptyMap(timePoints)); + } + + // 2. 获取所有站点的气象数据 + Map> stationDataMap = batchFetchWeatherData(stationIds, timePoints); + + // 3. 分别计算平均、最高、最低 + Map avgMap = calculateAverageByDistrict(stationDataMap, districtCodes, timePoints, + d -> parseDouble(d.getTemperature())); + Map maxMap = calculateExtremeByDistrict(stationDataMap, districtCodes, timePoints, + d -> parseDouble(d.getHourlyMaxTemperature()), true); + Map minMap = calculateExtremeByDistrict(stationDataMap, districtCodes, timePoints, + d -> parseDouble(d.getHourlyMinTemperature()), false); + + return new TemperatureResult(avgMap, maxMap, minMap); + } + + // ===================== 风速统计(极大值) ===================== + private Map calculateWindSpeed(List districtCodes, List timePoints) { + List stationIds = getStationIdsByDistricts(districtCodes); + if (stationIds.isEmpty()) { + return emptyMap(timePoints); + } + + Map> stationDataMap = batchFetchWeatherData(stationIds, timePoints); + + // 风速规则:先取各县内所有站的最大值,再取所有县的最大值(市级) + return calculateExtremeByDistrict(stationDataMap, districtCodes, timePoints, + d -> parseDouble(d.getExtremeWindSpeedHourly()), true); + } + + // ===================== 通用辅助方法 ===================== + + /** + * 根据区县编码列表获取所有气象站ID(去重) + */ + private List getStationIdsByDistricts(List districtCodes) { + if (CollectionUtils.isEmpty(districtCodes)) { + return Collections.emptyList(); + } + List configs = new ArrayList<>(); // new weatherSiteAreaConfigurationMapper.selectByDistrictCodes(districtCodes); + if (CollectionUtils.isEmpty(configs)) { + return Collections.emptyList(); + } + return configs.stream() + .map(WeatherSiteAreaConfiguration::getStationId) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + } + + /** + * 批量获取多个站点在多个时间点的气象数据 + * @return Map> + */ + private Map> batchFetchWeatherData(List stationIds, + List timePoints) { + Map> result = new HashMap<>(); + for (String stationId : stationIds) { + Map stationHourly = new HashMap<>(); + for (LocalDateTime hour : timePoints) { + WeatherDataDTO data = weatherDataService.getWeatherData(stationId, hour); + if (data != null) { + stationHourly.put(hour, data); + } + } + result.put(stationId, stationHourly); + } + return result; + } + + /** + * 计算按县平均后的指标(先求每个县内所有站的平均,再对各县平均取平均) + * @param stationDataMap 站点原始数据 + * @param districtCodes 区县列表 + * @param timePoints 时间点 + * @param valueExtractor 从WeatherDataDTO提取数值的函数 + * @return 每个小时的平均值 + */ + private Map calculateAverageByDistrict(Map> stationDataMap, + List districtCodes, + List timePoints, + Function valueExtractor) { + // 1. 建立区县 -> 站点ID列表的映射 + Map> districtStationMap = getDistrictStationMap(districtCodes); + + Map result = new HashMap<>(); + for (LocalDateTime hour : timePoints) { + List districtAverages = new ArrayList<>(); + for (String districtCode : districtCodes) { + List stations = districtStationMap.getOrDefault(districtCode, Collections.emptyList()); + List values = new ArrayList<>(); + for (String stationId : stations) { + WeatherDataDTO data = stationDataMap.getOrDefault(stationId, Collections.emptyMap()).get(hour); + Double val = valueExtractor.apply(data); + if (val != null) { + values.add(val); + } + } + if (!values.isEmpty()) { + double avg = values.stream().mapToDouble(Double::doubleValue).average().orElse(0.0); + districtAverages.add(avg); + } + } + // 所有县的平均再平均 + if (!districtAverages.isEmpty()) { + double overallAvg = districtAverages.stream().mapToDouble(Double::doubleValue).average().orElse(0.0); + result.put(hour, overallAvg); + } else { + result.put(hour, 0.0); + } + } + return result; + } + + /** + * 计算按县极值后的总体极值(先求每个县内所有站的极值,再取所有县的极值) + * @param isMax true-最大值,false-最小值 + */ + private Map calculateExtremeByDistrict(Map> stationDataMap, + List districtCodes, + List timePoints, + Function valueExtractor, + boolean isMax) { + Map> districtStationMap = getDistrictStationMap(districtCodes); + + Map result = new HashMap<>(); + for (LocalDateTime hour : timePoints) { + List districtExtremes = new ArrayList<>(); + for (String districtCode : districtCodes) { + List stations = districtStationMap.getOrDefault(districtCode, Collections.emptyList()); + Double extreme = null; + for (String stationId : stations) { + WeatherDataDTO data = stationDataMap.getOrDefault(stationId, Collections.emptyMap()).get(hour); + Double val = valueExtractor.apply(data); + if (val != null) { + if (extreme == null) { + extreme = val; + } else if (isMax) { + extreme = Math.max(extreme, val); + } else { + extreme = Math.min(extreme, val); + } + } + } + if (extreme != null) { + districtExtremes.add(extreme); + } + } + // 取所有县极值的极值 + if (!districtExtremes.isEmpty()) { + double overall = isMax ? + districtExtremes.stream().mapToDouble(Double::doubleValue).max().orElse(0.0) : + districtExtremes.stream().mapToDouble(Double::doubleValue).min().orElse(0.0); + result.put(hour, overall); + } else { + result.put(hour, 0.0); + } + } + return result; + } + + /** + * 获取区县到站点ID列表的映射 + */ + private Map> getDistrictStationMap(List districtCodes) { + List configs = new ArrayList<>(); // weatherSiteAreaConfigurationMapper.selectByDistrictCodes(districtCodes); + if (CollectionUtils.isEmpty(configs)) { + return Collections.emptyMap(); + } + return configs.stream() + .filter(c -> c.getStationId() != null) + .collect(Collectors.groupingBy(WeatherSiteAreaConfiguration::getDistrictCode, + Collectors.mapping(WeatherSiteAreaConfiguration::getStationId, Collectors.toList()))); + } + + /** + * 填充列表,确保每个时间点都有值 + */ + private List fillList(List timePoints, Map map, T defaultValue) { + List list = new ArrayList<>(); + for (LocalDateTime tp : timePoints) { + list.add(map.getOrDefault(tp, defaultValue)); + } + return list; + } + + private Map emptyMap(List timePoints) { + Map map = new HashMap<>(); + for (LocalDateTime tp : timePoints) { + map.put(tp, 0.0); + } + return map; + } + + private Double parseDouble(String str) { + try { + return str == null ? null : Double.parseDouble(str); + } catch (NumberFormatException e) { + return null; + } + } + + // 内部类,用于返回气温的三个Map + private static class TemperatureResult { + private final Map avgMap; + private final Map maxMap; + private final Map minMap; + + public TemperatureResult(Map avgMap, + Map maxMap, + Map minMap) { + this.avgMap = avgMap; + this.maxMap = maxMap; + this.minMap = minMap; + } + + public Map getAvgMap() { return avgMap; } + public Map getMaxMap() { return maxMap; } + public Map getMinMap() { return minMap; } + } +} \ No newline at end of file diff --git a/src/main/java/com/southern/power/grid/service/impl/WeatherDataServiceImpl.java b/src/main/java/com/southern/power/grid/service/impl/WeatherDataServiceImpl.java index 83eb010..ea52c13 100644 --- a/src/main/java/com/southern/power/grid/service/impl/WeatherDataServiceImpl.java +++ b/src/main/java/com/southern/power/grid/service/impl/WeatherDataServiceImpl.java @@ -93,7 +93,7 @@ public class WeatherDataServiceImpl implements WeatherDataService { dto.setTemperature(n.getTemperature()); dto.setHourlyMaxTemperature(n.getHourlyMaxTemperature()); dto.setHourlyMinTemperature(n.getHourlyMinTemperature()); - dto.setHourlyPrecipitation(n.getHourlyPrecipitation()); +// dto.setHourlyPrecipitation(n.getHourlyPrecipitation()); dto.setDailyPrecipitation(n.getDailyPrecipitation()); dto.setExtremeWindSpeedHourly(n.getExtremeWindSpeedHourly()); return dto; @@ -107,7 +107,7 @@ public class WeatherDataServiceImpl implements WeatherDataService { dto.setTemperature(r.getTemperature()); dto.setHourlyMaxTemperature(r.getHourlyMaxTemperature()); dto.setHourlyMinTemperature(r.getHourlyMinTemperature()); - dto.setHourlyPrecipitation(r.getHourlyPrecipitation()); +// dto.setHourlyPrecipitation(r.getHourlyPrecipitation()); dto.setDailyPrecipitation(r.getDailyPrecipitation()); dto.setExtremeWindSpeedHourly(r.getExtremeWindSpeedHourly()); return dto; diff --git a/src/main/java/com/southern/power/grid/utils/TimeUtil.java b/src/main/java/com/southern/power/grid/utils/TimeUtil.java index fc39f02..d3a81ab 100644 --- a/src/main/java/com/southern/power/grid/utils/TimeUtil.java +++ b/src/main/java/com/southern/power/grid/utils/TimeUtil.java @@ -3,6 +3,7 @@ package com.southern.power.grid.utils; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.List; @@ -122,4 +123,17 @@ public class TimeUtil { // String strings = getBeforeNumDays("2026-03-15", 5); System.out.println(14/5); } + + private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + public static LocalDateTime parseToLocalDateTime(String dateTimeStr) { + if (dateTimeStr == null || dateTimeStr.isEmpty()) { + return null; + } + try { + return LocalDateTime.parse(dateTimeStr, DEFAULT_FORMATTER); + } catch (DateTimeParseException e) { + return null; + } + } } diff --git a/src/main/resources/mapper/DnerHourlyPowerOutageEventMapper.xml b/src/main/resources/mapper/DnerHourlyPowerOutageEventMapper.xml index 45ffd0a..c82647f 100644 --- a/src/main/resources/mapper/DnerHourlyPowerOutageEventMapper.xml +++ b/src/main/resources/mapper/DnerHourlyPowerOutageEventMapper.xml @@ -42,4 +42,12 @@ ) + + \ No newline at end of file