Ver código fonte

feat(beisen): add standalone end time normalizer

malk 4 semanas atrás
pai
commit
a9b1091615

+ 8 - 21
mjava-akdsbeisen/src/main/java/com/malk/service/beisen/BSDataSyncService.java

@@ -33,6 +33,9 @@ public class BSDataSyncService {
     @Autowired
     private BSConf bsConf;
 
+    @Autowired
+    private BeisenEndTimeNormalizer beisenEndTimeNormalizer;
+
     private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");
 
     public void syncCurrentMonthData() {
@@ -299,7 +302,7 @@ public class BSDataSyncService {
                 formData.put("textField_mmk1vzvn", toStringValue(data.get("oId")));
                 formData.put("employeeField_mmizoplw", staffId);
                 formData.put("dateField_mmk1vzvt", dateToTimestamp(data.get("startDate")));
-                formData.put("dateField_mmk1vzvu", dateToEndTimestamp(data.get("stopDate")));
+                formData.put("dateField_mmk1vzvu", normalizeEndTime(data.get("stopDate")));
                 formData.put("numberField_mmk1vzvv", toStringValue(data.get("overTimeDuration")));
 
                 break;
@@ -308,7 +311,7 @@ public class BSDataSyncService {
 
                 formData.put("employeeField_mmizoplw", staffId);
                 formData.put("dateField_mmk1vzvt", dateToTimestamp(data.get("startDateTime")));
-                formData.put("dateField_mmk1vzvu", dateToEndTimestamp(data.get("stopDateTime")));
+                formData.put("dateField_mmk1vzvu", normalizeEndTime(data.get("stopDateTime")));
                 formData.put("numberField_mmk1vzvv", toStringValue(data.get("businessDuration")));
                 formData.put("numberField_mmlsurjx", toStringValue(data.get("dayValOfDuration")));
                 break;
@@ -318,7 +321,7 @@ public class BSDataSyncService {
                 formData.put("textField_mmk1vzvo", toStringValue(data.get("vacationType")));
 
                 formData.put("dateField_mmk1vzvt", dateToTimestamp(data.get("vacationStartDateTime")));
-                formData.put("dateField_mmk1vzvu", dateToEndTimestamp(data.get("vacationStopDateTime")));
+                formData.put("dateField_mmk1vzvu", normalizeEndTime(data.get("vacationStopDateTime")));
                 formData.put("numberField_mmk1vzvv", toStringValue(data.get("dayValueOfDuration")));
 
                 break;
@@ -368,24 +371,8 @@ public class BSDataSyncService {
         }
     }
 
-    /**
-     * // prd 北森结束时间为当天 00:00:00 时按当天结束处理,避免日期边界歧义。
-     */
-    Long dateToEndTimestamp(Object dateObj) {
-        Long timestamp = dateToTimestamp(dateObj);
-        if (timestamp == null) {
-            return null;
-        }
-        ZonedDateTime dateTime = Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault());
-        if (dateTime.toLocalTime().equals(java.time.LocalTime.MIDNIGHT)) {
-            return dateTime.withHour(23)
-                    .withMinute(59)
-                    .withSecond(59)
-                    .withNano(0)
-                    .toInstant()
-                    .toEpochMilli();
-        }
-        return timestamp;
+    private Long normalizeEndTime(Object dateObj) {
+        return beisenEndTimeNormalizer.normalize(dateToTimestamp(dateObj));
     }
 
     private String SXW(long  timestamp) {

+ 41 - 0
mjava-akdsbeisen/src/main/java/com/malk/service/beisen/BeisenEndTimeNormalizer.java

@@ -0,0 +1,41 @@
+package com.malk.service.beisen;
+
+import org.springframework.stereotype.Component;
+
+import java.time.Instant;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
+/**
+ * 北森结束时间归一化功能。
+ *
+ * <p>独立承载北森结束时间的业务口径,避免日期边界规则散落在同步流程中。</p>
+ */
+@Component
+public class BeisenEndTimeNormalizer {
+
+    private static final ZoneId BUSINESS_ZONE = ZoneId.of("Asia/Shanghai");
+
+    /**
+     * // prd 北森结束时间为当天 00:00:00 时按当天结束处理,避免日期边界歧义。
+     *
+     * @param timestamp 原始结束时间戳,单位毫秒
+     * @return 归一化后的结束时间戳;输入为空时返回空
+     */
+    public Long normalize(Long timestamp) {
+        if (timestamp == null) {
+            return null;
+        }
+        ZonedDateTime dateTime = Instant.ofEpochMilli(timestamp).atZone(BUSINESS_ZONE);
+        if (dateTime.toLocalTime().equals(LocalTime.MIDNIGHT)) {
+            return dateTime.withHour(23)
+                    .withMinute(59)
+                    .withSecond(59)
+                    .withNano(0)
+                    .toInstant()
+                    .toEpochMilli();
+        }
+        return timestamp;
+    }
+}

+ 0 - 48
mjava-akdsbeisen/src/test/java/com/malk/service/beisen/BSDataSyncServiceTest.java

@@ -1,48 +0,0 @@
-package com.malk.service.beisen;
-
-import org.junit.jupiter.api.Test;
-
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-class BSDataSyncServiceTest {
-
-    private final BSDataSyncService service = new BSDataSyncService();
-
-    @Test
-    void shouldConvertMidnightEndTimeToEndOfSameDay() {
-        long expected = LocalDateTime.of(2026, 8, 24, 23, 59, 59)
-                .atZone(ZoneId.systemDefault())
-                .toInstant()
-                .toEpochMilli();
-
-        assertEquals(expected, service.dateToEndTimestamp("2026-08-24 00:00:00"));
-        assertEquals(expected, service.dateToEndTimestamp("2026-08-24"));
-    }
-
-    @Test
-    void shouldConvertMidnightTimestampToEndOfSameDay() {
-        long midnight = LocalDateTime.of(2026, 8, 24, 0, 0)
-                .atZone(ZoneId.systemDefault())
-                .toInstant()
-                .toEpochMilli();
-        long expected = LocalDateTime.of(2026, 8, 24, 23, 59, 59)
-                .atZone(ZoneId.systemDefault())
-                .toInstant()
-                .toEpochMilli();
-
-        assertEquals(expected, service.dateToEndTimestamp(midnight));
-    }
-
-    @Test
-    void shouldKeepNonMidnightEndTimeUnchanged() {
-        long expected = LocalDateTime.of(2026, 8, 24, 18, 30)
-                .atZone(ZoneId.systemDefault())
-                .toInstant()
-                .toEpochMilli();
-
-        assertEquals(expected, service.dateToEndTimestamp("2026-08-24 18:30:00"));
-    }
-}

+ 53 - 0
mjava-akdsbeisen/src/test/java/com/malk/service/beisen/BeisenEndTimeNormalizerTest.java

@@ -0,0 +1,53 @@
+package com.malk.service.beisen;
+
+import org.junit.jupiter.api.Test;
+
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+class BeisenEndTimeNormalizerTest {
+
+    private static final ZoneId BUSINESS_ZONE = ZoneId.of("Asia/Shanghai");
+
+    private final BeisenEndTimeNormalizer normalizer = new BeisenEndTimeNormalizer();
+
+    @Test
+    void shouldConvertMidnightEndTimeToEndOfSameDay() {
+        long expected = LocalDateTime.of(2026, 8, 24, 23, 59, 59)
+                .atZone(BUSINESS_ZONE)
+                .toInstant()
+                .toEpochMilli();
+        long midnight = LocalDateTime.of(2026, 8, 24, 0, 0)
+                .atZone(BUSINESS_ZONE)
+                .toInstant()
+                .toEpochMilli();
+
+        assertEquals(expected, normalizer.normalize(midnight));
+    }
+
+    @Test
+    void shouldUseShanghaiBusinessTimezone() {
+        long utcMidnight = Instant.parse("2026-08-24T00:00:00Z").toEpochMilli();
+
+        assertEquals(utcMidnight, normalizer.normalize(utcMidnight));
+    }
+
+    @Test
+    void shouldKeepNonMidnightEndTimeUnchanged() {
+        long expected = LocalDateTime.of(2026, 8, 24, 18, 30)
+                .atZone(BUSINESS_ZONE)
+                .toInstant()
+                .toEpochMilli();
+
+        assertEquals(expected, normalizer.normalize(expected));
+    }
+
+    @Test
+    void shouldKeepNullEndTimeAsNull() {
+        assertNull(normalizer.normalize(null));
+    }
+}