diff --git a/backend/Dockerfile b/backend/Dockerfile index 5cbffce..03c20d8 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -22,9 +22,9 @@ FROM eclipse-temurin:17-jre-jammy WORKDIR /app -# 安装必要的工具 +# 安装必要的工具和时区数据 RUN apt-get update && \ - apt-get install -y curl && \ + apt-get install -y curl tzdata && \ rm -rf /var/lib/apt/lists/* # 从构建阶段复制 JAR 文件 @@ -43,6 +43,6 @@ EXPOSE 8000 HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ CMD curl -f http://localhost:8000/api/system/health || exit 1 -# 启动应用 +# 启动应用(自动使用系统时区) ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/accounts/PositionCheckService.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/accounts/PositionCheckService.kt index 95ee012..438b747 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/accounts/PositionCheckService.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/accounts/PositionCheckService.kt @@ -373,22 +373,22 @@ class PositionCheckService( if (position == null) { // 仓位不存在,检查订单创建时间 - // 只有当订单创建时间超过30秒时,才认为仓位被出售了 + // 只有当订单创建时间超过2分钟时,才认为仓位被出售了 // 这样可以避免刚创建的订单因为API延迟而被误判为已卖出 val now = System.currentTimeMillis() val ordersToMarkAsSold = orders.filter { order -> val orderAge = now - order.createdAt - orderAge > 30000 // 30秒 = 30000毫秒 + orderAge > 120000 // 2分钟 = 120000毫秒 } if (ordersToMarkAsSold.isNotEmpty()) { - // 有订单创建时间超过30秒,认为仓位已被出售 + // 有订单创建时间超过2分钟,认为仓位已被出售 val currentPrice = getCurrentMarketPrice(marketId, outcomeIndex) updateOrdersAsSold(ordersToMarkAsSold, currentPrice, copyTrading.id, marketId, outcomeIndex) - logger.debug("仓位不存在且订单创建时间超过30秒,标记为已卖出: marketId=$marketId, outcomeIndex=$outcomeIndex, orderCount=${ordersToMarkAsSold.size}") + logger.debug("仓位不存在且订单创建时间超过2分钟,标记为已卖出: marketId=$marketId, outcomeIndex=$outcomeIndex, orderCount=${ordersToMarkAsSold.size}") } else { - // 订单创建时间不足30秒,可能是刚创建的订单,暂时不处理 - logger.debug("仓位不存在但订单创建时间不足30秒,暂不标记为已卖出: marketId=$marketId, outcomeIndex=$outcomeIndex, orderCount=${orders.size}, oldestOrderAge=${orders.minOfOrNull { now - it.createdAt }?.let { "${it}ms" } ?: "N/A"}") + // 订单创建时间不足2分钟,可能是刚创建的订单,暂时不处理 + logger.debug("仓位不存在但订单创建时间不足2分钟,暂不标记为已卖出: marketId=$marketId, outcomeIndex=$outcomeIndex, orderCount=${orders.size}, oldestOrderAge=${orders.minOfOrNull { now - it.createdAt }?.let { "${it}ms" } ?: "N/A"}") } } else { // 有仓位,按订单下单顺序(FIFO)更新状态 diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/system/TelegramNotificationService.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/system/TelegramNotificationService.kt index 2f45e05..83655c1 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/system/TelegramNotificationService.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/system/TelegramNotificationService.kt @@ -7,6 +7,7 @@ import com.wrbug.polymarketbot.dto.NotificationConfigData import com.wrbug.polymarketbot.dto.TelegramConfigData import com.wrbug.polymarketbot.util.createClient import com.wrbug.polymarketbot.util.toSafeBigDecimal +import com.wrbug.polymarketbot.util.DateUtils import kotlinx.coroutines.* import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient @@ -308,7 +309,7 @@ class TelegramNotificationService( } } - val time = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(java.util.Date()) + val time = DateUtils.formatDateTime() // 转义 HTML 特殊字符 val escapedMarketTitle = marketTitle.replace("<", "<").replace(">", ">") @@ -639,7 +640,7 @@ class TelegramNotificationService( "" } - val time = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(java.util.Date()) + val time = DateUtils.formatDateTime() // 转义 HTML 特殊字符 val escapedMarketTitle = marketTitle.replace("<", "<").replace(">", ">") @@ -760,7 +761,7 @@ class TelegramNotificationService( } } - val time = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(java.util.Date()) + val time = DateUtils.formatDateTime() // 错误信息已经是后端返回的 msg,不需要截断(但为了安全,限制长度) val shortErrorMessage = if (errorMessage.length > 500) { @@ -901,7 +902,7 @@ class TelegramNotificationService( } } - val time = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(java.util.Date()) + val time = DateUtils.formatDateTime() // 转义 HTML 特殊字符 val escapedAccountInfo = accountInfo.replace("<", "<").replace(">", ">") diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/util/DateUtils.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/util/DateUtils.kt index 7861b69..9d5211f 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/util/DateUtils.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/util/DateUtils.kt @@ -1,6 +1,8 @@ package com.wrbug.polymarketbot.util import java.time.Instant +import java.time.ZoneId +import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import java.time.format.DateTimeParseException @@ -15,6 +17,13 @@ object DateUtils { */ private val isoFormatter = DateTimeFormatter.ISO_DATE_TIME + /** + * 使用系统时区的日期时间格式化器(用于显示) + * 格式:yyyy-MM-dd HH:mm:ss + */ + private val displayFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + .withZone(ZoneId.systemDefault()) + /** * 将 ISO 8601 格式的日期字符串转换为时间戳(毫秒) * @param dateString ISO 8601 格式的日期字符串,如 "2020-11-04T00:00:00Z" @@ -61,5 +70,19 @@ object DateUtils { null } } + + /** + * 将时间戳(毫秒)格式化为可读的日期时间字符串(使用系统时区) + * @param timestamp 时间戳(毫秒),如果为 null 则使用当前时间 + * @return 格式化的日期时间字符串,格式:yyyy-MM-dd HH:mm:ss + */ + fun formatDateTime(timestamp: Long? = null): String { + val instant = if (timestamp != null) { + Instant.ofEpochMilli(timestamp) + } else { + Instant.now() + } + return displayFormatter.format(instant) + } } diff --git a/docker/start.sh b/docker/start.sh index b828494..e4567cc 100755 --- a/docker/start.sh +++ b/docker/start.sh @@ -54,6 +54,7 @@ trap cleanup SIGTERM SIGINT # 启动后端服务(以 appuser 用户运行,后台运行) echo "启动后端服务..." +# 自动使用系统时区 java -jar /app/app.jar --spring.profiles.active=${SPRING_PROFILES_ACTIVE:-prod} & BACKEND_PID=$!