如何正确处理服务器和客户端的节省时间



我读了很多关于时间的信息(增量时间,观察时间,偏移量,时区... 现在我正在使用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 ) ;

所有这些(instantzdtBerlinzdtTokyozdtMontré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是唯一真实的时间。一些地方使用偏移量来调整其所在地区的挂钟时间。时区是该区域的这些更改的历史记录。

最新更新