Формат времени в UTC

This commit is contained in:
emelianov
2026-06-25 16:21:17 +03:00
parent d0ec0ef754
commit fe54c095ab
164 changed files with 1847 additions and 634 deletions
@@ -1,11 +1,21 @@
package space.nstart.pcp.complan
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes
import java.time.LocalDateTime
@Configuration
class JacksonConfig {
@@ -13,8 +23,26 @@ class JacksonConfig {
fun objectMapper(): ObjectMapper {
val mapper = ObjectMapper()
mapper.registerModule(JavaTimeModule())
.registerModule(utcLocalDateTimeModule())
.registerKotlinModule()
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
return mapper
}
}
private fun utcLocalDateTimeModule(): SimpleModule = SimpleModule("pcp-dynamic-plan-service-jackson2-utc-local-date-time")
.addSerializer(LocalDateTime::class.java, Jackson2UtcLocalDateTimeSerializer())
.addDeserializer(LocalDateTime::class.java, Jackson2UtcLocalDateTimeDeserializer())
private class Jackson2UtcLocalDateTimeSerializer : JsonSerializer<LocalDateTime>() {
override fun serialize(value: LocalDateTime, gen: JsonGenerator, serializers: SerializerProvider) {
gen.writeString(UtcDateTimes.format(value))
}
}
private class Jackson2UtcLocalDateTimeDeserializer : JsonDeserializer<LocalDateTime>() {
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): LocalDateTime {
val value = p.valueAsString ?: throw IllegalArgumentException("Expected ISO-8601 UTC date-time string")
return UtcDateTimes.parse(value)
}
}
@@ -58,6 +58,7 @@ import kotlin.math.abs
import kotlin.math.max
import kotlin.math.roundToLong
import kotlin.math.sin
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes
private const val INTERVAL_COVERAGE_AREA_TOLERANCE = 1.0e-9
private const val INTERVAL_ROUTE_WIDTH_RATIO = 0.9
@@ -841,7 +842,7 @@ class BasicPlanCalculator(
val resultFilePath = if (request.saveResultToFile && status == ComplexPlanCalculationStatus.COMPLETED) {
observationParametersDebugFileWriter.write(
ObservationParametersDebugFileDTO(
createdAt = LocalDateTime.now(),
createdAt = UtcDateTimes.now(),
requestId = request.requestId,
satelliteIds = selectedSatelliteIds,
missingSatelliteIds = missingSatelliteIds,
@@ -0,0 +1,55 @@
package space.nstart.pcp.complan.config
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.convert.converter.Converter
import org.springframework.format.FormatterRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes
import tools.jackson.core.JsonGenerator
import tools.jackson.core.JsonParser
import tools.jackson.databind.DeserializationContext
import tools.jackson.databind.SerializationContext
import tools.jackson.databind.deser.std.StdDeserializer
import tools.jackson.databind.module.SimpleModule
import tools.jackson.databind.ser.std.StdSerializer
import java.time.Clock
import java.time.LocalDateTime
@Configuration
class UtcTimeConfiguration : WebMvcConfigurer {
@Bean
fun clock(): Clock = Clock.systemUTC()
@Bean
fun dynamicPlanUtcLocalDateTimeCustomizer(): JsonMapperBuilderCustomizer = JsonMapperBuilderCustomizer { builder ->
builder.addModule(
SimpleModule("pcp-dynamic-plan-service-utc-local-date-time")
.addSerializer(LocalDateTime::class.java, UtcLocalDateTimeSerializer())
.addDeserializer(LocalDateTime::class.java, UtcLocalDateTimeDeserializer())
)
}
override fun addFormatters(registry: FormatterRegistry) {
registry.addConverter(UtcLocalDateTimeQueryParamConverter())
}
}
private class UtcLocalDateTimeQueryParamConverter : Converter<String, LocalDateTime> {
override fun convert(source: String): LocalDateTime = UtcDateTimes.parse(source)
}
private class UtcLocalDateTimeSerializer : StdSerializer<LocalDateTime>(LocalDateTime::class.java) {
override fun serialize(value: LocalDateTime, gen: JsonGenerator, ctxt: SerializationContext) {
gen.writeString(UtcDateTimes.format(value))
}
}
private class UtcLocalDateTimeDeserializer : StdDeserializer<LocalDateTime>(LocalDateTime::class.java) {
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): LocalDateTime {
val value = p.valueAsString ?: throw IllegalArgumentException("Expected ISO-8601 UTC date-time string")
return UtcDateTimes.parse(value)
}
}
@@ -11,6 +11,7 @@ import jakarta.persistence.ManyToOne
import jakarta.persistence.Table
import java.time.LocalDateTime
import java.util.UUID
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes
@Table(name = "dynamic_plan_route")
@Entity
@@ -31,10 +32,10 @@ class DynamicPlanRouteEntity(
var satelliteId: Long = 0,
@Column(name = "start_time", nullable = false)
var startTime: LocalDateTime = LocalDateTime.now(),
var startTime: LocalDateTime = UtcDateTimes.now(),
@Column(name = "end_time", nullable = false)
var endTime: LocalDateTime = LocalDateTime.now(),
var endTime: LocalDateTime = UtcDateTimes.now(),
@Column(name = "duration", nullable = false)
var duration: Double = 0.0,
@@ -11,6 +11,7 @@ import space.nstart.pcp.complan.types.DynamicPlanRevolutionMode
import space.nstart.pcp.complan.types.DynamicPlanRunStatus
import java.time.LocalDateTime
import java.util.UUID
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes
@Table(name = "dynamic_plan_run")
@Entity
@@ -47,7 +48,7 @@ class DynamicPlanRunEntity(
var filterCoveredRoutes: Boolean = false,
@Column(name = "created_at", nullable = false)
var createdAt: LocalDateTime = LocalDateTime.now(),
var createdAt: LocalDateTime = UtcDateTimes.now(),
@Column(name = "started_at")
var startedAt: LocalDateTime? = null,
@@ -10,10 +10,10 @@ import space.nstart.pcp.complan.types.ObjViewRequestDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.ExactTimePositionRequestDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.FlightLineDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.ObjDTO as BallisticsObjDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.ObjViewRequestDTO as BallisticsObjViewRequestDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.OrbPointDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteOrbitAvailabilityDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SquareViewParamDTO
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes
import java.time.LocalDateTime
/**Получение данных от сервиса баллистики*/
@@ -39,7 +39,7 @@ class BallTaskServce {
UriComponentsBuilder
.fromUriString(ballisticsServiceUrl)
.path("/api/satellites/orbit/availability")
.apply { time?.let { queryParam("time", it) } }
.apply { time?.let { queryParam("time", UtcDateTimes.format(it)) } }
.toUriString()
)
.retrieve()
@@ -53,8 +53,8 @@ class BallTaskServce {
UriComponentsBuilder
.fromUriString(ballisticsServiceUrl)
.path("/api/satellites/$noradId/flight-line")
.queryParam("time_start", timeStart)
.queryParam("time_stop", timeStop)
.queryParam("time_start", UtcDateTimes.format(timeStart))
.queryParam("time_stop", UtcDateTimes.format(timeStop))
.toUriString()
)
.retrieve()
@@ -65,7 +65,13 @@ class BallTaskServce {
RestClient.create()
.post()
.uri(buildBallisticsUri("/api/satellites/$noradId/extract-time"))
.body(request)
.body(
mapOf(
"time" to UtcDateTimes.format(request.time),
"timeStop" to request.timeStop?.let { UtcDateTimes.format(it) },
"stepMs" to request.stepMs
)
)
.retrieve()
.body(ORB_POINT_LIST_TYPE)
.orEmpty()
@@ -80,16 +86,16 @@ class BallTaskServce {
.post()
.uri(buildBallisticsUri("/api/obj-view/mpl-square"))
.body(
BallisticsObjViewRequestDTO(
satellites = satellites,
timeStart = timeStart,
timeStop = timeStop,
obj = BallisticsObjDTO(
mapOf(
"satellites" to satellites,
"timeStart" to UtcDateTimes.format(timeStart),
"timeStop" to UtcDateTimes.format(timeStop),
"obj" to BallisticsObjDTO(
id = obj.id.toString(),
position = obj.position,
contourWKT = obj.contourWKT
),
sunAngleMin = objects.sunAngleMin
"sunAngleMin" to objects.sunAngleMin
)
)
.retrieve()
@@ -28,6 +28,7 @@ import java.time.LocalDateTime
import java.util.UUID
import java.util.concurrent.ExecutorService
import kotlin.math.roundToLong
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes
@Service
class DynamicPlanRunService(
@@ -59,7 +60,7 @@ class DynamicPlanRunService(
calculationMode = request.calculationMode,
revolutionMode = request.revolutionMode,
filterCoveredRoutes = request.filterCoveredRoutes,
createdAt = LocalDateTime.now()
createdAt = UtcDateTimes.now()
)
)
} ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Failed to create calculation run")
@@ -135,7 +136,7 @@ class DynamicPlanRunService(
return@execute 0
}
val finishedAt = LocalDateTime.now()
val finishedAt = UtcDateTimes.now()
runs.forEach { run ->
run.status = DynamicPlanRunStatus.FAILED
run.finishedAt = finishedAt
@@ -171,7 +172,7 @@ class DynamicPlanRunService(
transactionTemplate.execute {
val run = runRepository.findById(runId).orElse(null) ?: return@execute null
run.status = DynamicPlanRunStatus.RUNNING
run.startedAt = LocalDateTime.now()
run.startedAt = UtcDateTimes.now()
run.errorMessage = null
runRepository.save(run)
run.toRequest()
@@ -182,7 +183,7 @@ class DynamicPlanRunService(
val run = runRepository.findById(runId).orElseThrow()
val result = output.result
run.status = DynamicPlanRunStatus.COMPLETED
run.finishedAt = LocalDateTime.now()
run.finishedAt = UtcDateTimes.now()
run.durationMs = result.durationMs
run.resultStatus = result.status.name
run.routesCount = result.routesCount
@@ -200,7 +201,7 @@ class DynamicPlanRunService(
transactionTemplate.execute {
val run = runRepository.findById(runId).orElseThrow()
run.status = DynamicPlanRunStatus.FAILED
run.finishedAt = LocalDateTime.now()
run.finishedAt = UtcDateTimes.now()
run.errorMessage = error.message ?: error::class.java.simpleName
runRepository.save(run)
}
@@ -6,6 +6,7 @@ import org.locationtech.jts.geom.LineString
import space.nstart.pcp.pcp_types_lib.dto.ballistics.FlightLineDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.RevolutionSign
import java.time.LocalDateTime
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes
/**
* Класс космического аппарата**
@@ -17,9 +18,9 @@ class SpaceCraft (
val flightLine : MutableList<FlightLineDTO> = mutableListOf()
/**Время начала планирования аппарата*/
var timeStart: LocalDateTime = LocalDateTime.now()
var timeStart: LocalDateTime = UtcDateTimes.now()
/**Время конца планирования аппарата*/
var timeStop : LocalDateTime = LocalDateTime.now()
var timeStop : LocalDateTime = UtcDateTimes.now()
/**
* Создание линий полета восходящего и нисходящего витка
* @param geomFactory фабрика геометрии