我读了很多关于时间的信息(增量时间,观察时间,偏移量,时区... 现在我正在使用Spring开发一个后端架构,到了我必须将它们组合在一起的地步。客户端发送和接收带有时间戳和值的 JSON,我可以决定语法应该如何。如果星座按照我计划的方式正确,我不会担心,所以如果你在必要的点上纠正我,我会很高兴。
第一:我如何理解基本概念。
口头禅:始终使用 UTC 时间。
格式 : ISO8601 YYYY-MM-DDThh:mm:ss.sTZD (例如 1997-07-16T19:20:30.45+01:00) 或 1997-07-16T20:20:30.45Z
时区:例如"欧洲/柏林" 这是时区数据库的 ID,其中 区域已定义( DST 偏移量 .. )。
偏移量:告诉您 UTC 时间的正偏移量或负偏移量。
我的计划:就我而言,数据可能是在不同时区内采样的。在采样过程中时区发生变化也是显而易见的。
所以我想在我的 mongodb 中存储如下数据:
"TimeStamp": {
"StartTime": "1997-07-16T20:20:30.45Z",
"EndTime": "1997-07-16T20:20:30.45Z",
"StartTimeZone":"Europe/Berlin",
"EndTimeZone":"Europe/Berlin",
"StartTimeOffset": +7,
"EndTimeOffset" : +7
}
客户端可以从内部选择一个间隔,将数据返回。间隔还必须定义为没有偏移量的 UTC iso 格式。据我所知,使用 UTC 格式,我可以对日期进行$lte和$gte操作以过滤间隔。 因此,客户端接收一个带有多个 JSOnObjects 的 JSOnArray。每个对象都有一个值和一个时间戳对象。通过使用时区,可以查看数据采样时的偏移量,因此我不必添加偏移量信息,因此可以计算用户的本地时间。但是,如果偏移量发生变化怎么办。我想存储偏移量也是有意义的,这样人们也可以重建"旧"时区规则。 你认为这是一个很好的解决方案,还是我忘记/误解/可以更有效地完成一些事情
在 Java 中,如果你想谈论一个特定的时间点,请使用Instant
。如果 2 个事件发生在不同的时区,但在同一实际时刻,它们的Instant
值将相同。
如果你想知道那个地区的各种时钟当时说了什么,你需要知道你在哪个时区。例如:
Instant now = Instant.now(); // refers to a point in time, independent of location
LocalDateTime nowHere = now.atZone(ZoneId.systemDefault()).toLocalDate(); // refers to "what the clocks say" at your machine's current timezone
LocalDateTime nowSomewhereElse = now.atZone(ZoneId.of("Timezone string")).toLocalDate(); // same as above, but for somewhere else.
以下 API 是 Java 8 的一部分,与 JPA 和其他常用库/API 完全兼容。如果您只关心事件发生的日期,则存在等效类。
Instant
也可以使用instant.toEpochMilli()
、instant.getEpochSecond()
或instant.getNano()
转换为时间戳。
你的问题相当混乱。
如果你有一个 UTC 时刻,你知道 UTC 的偏移量为零,所以你不关心进一步的时区信息。
Instant instant = Instant.now() ; // Capture the current moment as seen in UTC (an offset-from-UTC of zero hours-minutes-seconds).
String output = instant.toString() ; // Generate text representing this moment in UTC in standard ISO 8601 format. The `Z` on end means UTC (an offset of zero), and is pronounced "Zulu".
如果有人想通过德国使用的挂钟时间看到那个时刻,他们可以应用ZoneId
来生成ZonedDateTime
对象。
ZoneId zBerlin = ZoneId.of( "Europe/Berlin" ) ;
ZonedDateTime zdtBerlin = instant.atZone( zBerlin ) ;
如果有人想通过日本使用的挂钟时间看到那一刻,同上。
ZoneId zTokyo = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdtTokyo = instant.atZone( zTokyo ) ;
如果有人想通过魁北克使用的挂钟时间看到那一刻,同上。
ZoneId zMontréal = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdtMontréal = instant.atZone( zMontréal ) ;
所有这些(instant
、zdtBerlin
、zdtTokyo
、zdtMontréal
)都代表了时间轴上的同一同时时刻,同一点。只是挂钟时间不同。想象一下,与每个地区的参与者举行电话会议。他们都经历了同样的时刻,但当他们抬头看挂在各自墙上的时钟时,他们每个人都看到了不同的读数。
时区:例如"欧洲/柏林" 这是时区数据库的 id,其中定义了区域的特定规则(DST 偏移量 .. )。
偏移量:告诉您 UTC 时间的正偏移量或负偏移量。
明确区域和偏移的含义:
- UTC 偏移量只是小时-分钟-秒的数量。而已。例如,
-07:00
. - 时区远不止于此。时区是特定地区人民使用的偏移量过去、现在和未来变化的历史记录。例如,在一个政客们疯狂到采用夏令时 (DST) 的地方,他们的 UTC 偏移量每年更改两次,每小时跳一个头,然后回落一个小时。夏令时不会在爱因斯坦/相对论意义上弯曲时间,夏令时只是用挂钟时间玩愚蠢的游戏。
在不同时区内对数据进行采样
你不在乎。如果您有以 UTC 格式捕获的时刻,这就是您所需要的。
在采样过程中时区发生变化也是显而易见的。
再。。。你不在乎。如果您有以 UTC 格式捕获的时刻,这就是您所需要的。
所以我想在我的 mongodb 中存储如下数据:
"TimeStamp": {
"StartTime": "1997-07-16T20:20:30.45Z",
"EndTime": "1997-07-16T20:20:30.45Z",
"StartTimeZone":"Europe/Berlin",
"EndTimeZone":"Europe/Berlin",
"StartTimeOffset": +7,
"EndTimeOffset" : +7
}
不,太多了。最后四行是多余的,可能令人困惑。您所需要的只是:
"TimeStamp": {
"StartTime": "1997-07-16T20:20:30.45Z",
"EndTime": "1997-07-16T20:20:30.45Z"
}
顺便说一下,术语timestamp
通常意味着一个特定的时刻,而不是一个时间跨度。我建议一个更好的名字,例如timespan
.
"TimeSpan": {
"StartTime": "1997-07-16T20:20:30.45Z",
"EndTime": "1997-07-16T20:20:30.45Z"
}
顺便说一下,在您的示例中,开始时间等于结束时间。也许您在发布时犯了一个错误。
通过使用时区,可以查看数据采样时的偏移量,因此我不必添加偏移量信息
您不需要其他偏移信息。前两行末尾的Z
告诉您需要知道的所有信息。Z
,发音为"祖鲁",意思是UTC,偏移量为零。
String input = "1997-07-16T20:20:30.45Z" ; // The `Z` = UTC, an offset of zero.
Instant instant = Instant.parse( input ) ;
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, different wall-clock time.
因此可以计算用户的本地时间
显然,这里的"用户"一词是一个糟糕的术语选择。你的意思是收集数据的人,而不是接收数据的人。因此,您需要记住收集数据的时区。
因此,请捆绑收集数据样本或仪器读数的时区名称。
"TimeSpan": {
"StartTime": "1997-07-16T20:20:30.45Z",
"EndTime": "1997-07-16T20:20:30.45Z"
"SampleTimeZone": "Europe/Berlin"
}
当您想要本地化某个时刻时,您只需要一个时刻(Instant
)和一个时区(ZoneId
)。由此,您可以使用该区域的挂钟时间生成字符串。
String startInput = … // Pull "StartTime" element from JSON.
String zoneName = … // Pull "SampleTimeZone" from JSON.
Instant instant = Instant.parse( startInput ) ; // "1997-07-16T20:20:30.45Z"
ZoneName zone = ZoneId.of( zoneName ) ; // "Europe/Berlin"
ZonedDateTime zdt = instant.atZone( zone ) ;
String output = zdt.toString() ; // Or use a `DateTimeFormatter`.
你认为这是一个很好的解决方案
不。您对 UTC、时区和 UTC 偏移量不知何故无关感到困惑。但它们都是相互关联的。UTC是唯一真实的时间。一些地方使用偏移量来调整其所在地区的挂钟时间。时区是该区域的这些更改的历史记录。