如何正确处理服务器端和客户端的时间节省
How to correctly deal with time saving on server and client side
我读了很多关于时间的书(增量时间、观察时间、偏移量、时区...)
现在我正在用 Spring 开发一个后端架构,到了必须将它们组合在一起的地步。客户端发送和接收带有时间戳和值的 JSON,我可以决定语法应该如何。我不确定星座是否按照我计划的方式正确,所以如果你在必要的地方纠正我,我会很高兴。
首先:我是如何理解基本概念的。
口头禅:始终使用 utc 时间。
格式:iso8601
YYYY-MM-DDThh:mm:ss.sTZD(例如 1997-07-16T19:20:30.45+01:00)
要么
1997-07-16T20:20:30.45Z
时区:例如"Europe/Berlin"
这是时区数据库的 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 操作以过滤时间间隔。
因此,客户端会收到一个包含多个 JSOnObject 的 JSOnArray。每个对象都有一个值和一个时间戳对象。通过使用 TimeZone,可以查看数据采样时的偏移量,因此我不必添加偏移量信息,因此可以计算用户的本地时间。但是如果偏移量发生变化怎么办。我想存储偏移量也是有意义的,这样就可以重建 "old" 时区规则。
您认为这是一个好的解决方案,还是我 forgot/misunderstood/can 可以更有效地完成一些事情
在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 是 Java8 的一部分,与 JPA 和其他常用 libraries/APIs 完全兼容。如果您只关心事件发生的日期,则存在等效 类。
也可以使用 instant.toEpochMilli()
、instant.getEpochSecond()
或 instant.getNano()
.
将 Instant
转换为时间戳
你的问题比较混乱。
如果您有 UTC 时间,您知道 offset-from-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".
如果有人想通过在德国使用的 wall-clock 时间看到那一刻,他们可以应用 ZoneId
产生 ZonedDateTime
object.
ZoneId zBerlin = ZoneId.of( "Europe/Berlin" ) ;
ZonedDateTime zdtBerlin = instant.atZone( zBerlin ) ;
如果有人想通过日本使用的 wall-clock 时间看到那一刻,同上。
ZoneId zTokyo = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdtTokyo = instant.atZone( zTokyo ) ;
如果有人想通过魁北克使用的 wall-clock 时间看到那一刻,同上。
ZoneId zMontréal = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdtMontréal = instant.atZone( zMontréal ) ;
所有这些(instant
、zdtBerlin
、zdtTokyo
、zdtMontréal
)都代表了同一时刻,时间轴上的同一点。只有 wall-clock 时间不同。想象一下与每个地区的参与者进行的电话会议。他们都经历了同一时刻,但当他们抬头看着挂在各自墙上的时钟时,他们各自看到了不同的读数。
TimeZone: eg "Europe/Berlin" This is the id for timezone database where the specific rules for the zones are defined ( DST offset .. ).
Offset: Tells you the positive or negative offset to the utc time.
弄清楚zone和offset的含义:
- Offset-from-UTC 只是 hours-minutes-seconds 的数字。而已。例如,
-07:00
.
- 时区多。时区是特定地区的人们使用的偏移量的过去、现在和未来变化的历史。例如,在一个政治家疯狂到采用 Daylight Saving Time (DST), their offset-from-UTC changes twice per year, jumping a head an hour, and then falling back an hour. DST does not bend time in an Einstein/Relativity sense 的地方,DST 只是玩 wall-clock 时间的愚蠢游戏。
data was sampled within different timezones
你不在乎。如果您在 UTC 中捕获了片刻,这就是您所需要的。
It's also porrible that a timezone is changed during the sampling process.
再一次……你不在乎。如果您在 UTC 中捕获了片刻,这就是您所需要的。
So I want to store the data as follows in my 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"
}
顺便说一句,在您的示例中,开始时间等于结束时间。可能是你发错了。
With using the TimeZone one can have a look how the offset was at the time when the data was sampled so I don't have to add offset information
您不需要额外的偏移量信息。前两行末尾的 Z
告诉您需要知道的一切。 Z
,发音为“Zulu”,表示 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.
so one can calculate the local time of the user
显然,这里的“用户”一词用词不当。你指的是收集数据的人,而不是接收数据的人。所以您想记住收集数据的时区。
因此捆绑收集数据样本或仪器读数的时区名称。
"TimeSpan": {
"StartTime": "1997-07-16T20:20:30.45Z",
"EndTime": "1997-07-16T20:20:30.45Z"
"SampleTimeZone": "Europe/Berlin"
}
当您想本地化某个时刻时,您只需要一个时刻 (Instant
) 和一个时区 (ZoneId
)。从那里你可以 生成 使用该区域的 wall-clock 时间的字符串。
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`.
Do you think this is a good solution
没有。您对 UTC、时区和 offset-from-UTC 不知何故无关感到困惑。但它们都是相连的。 UTC 是唯一真实时间。有些地方使用偏移量来调整其所在地区的 wall-clock 时间。时区是该地区这些变化的历史记录。
我读了很多关于时间的书(增量时间、观察时间、偏移量、时区...) 现在我正在用 Spring 开发一个后端架构,到了必须将它们组合在一起的地步。客户端发送和接收带有时间戳和值的 JSON,我可以决定语法应该如何。我不确定星座是否按照我计划的方式正确,所以如果你在必要的地方纠正我,我会很高兴。
首先:我是如何理解基本概念的。
口头禅:始终使用 utc 时间。
格式:iso8601 YYYY-MM-DDThh:mm:ss.sTZD(例如 1997-07-16T19:20:30.45+01:00) 要么 1997-07-16T20:20:30.45Z
时区:例如"Europe/Berlin" 这是时区数据库的 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 操作以过滤时间间隔。 因此,客户端会收到一个包含多个 JSOnObject 的 JSOnArray。每个对象都有一个值和一个时间戳对象。通过使用 TimeZone,可以查看数据采样时的偏移量,因此我不必添加偏移量信息,因此可以计算用户的本地时间。但是如果偏移量发生变化怎么办。我想存储偏移量也是有意义的,这样就可以重建 "old" 时区规则。 您认为这是一个好的解决方案,还是我 forgot/misunderstood/can 可以更有效地完成一些事情
在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 是 Java8 的一部分,与 JPA 和其他常用 libraries/APIs 完全兼容。如果您只关心事件发生的日期,则存在等效 类。
也可以使用 instant.toEpochMilli()
、instant.getEpochSecond()
或 instant.getNano()
.
Instant
转换为时间戳
你的问题比较混乱。
如果您有 UTC 时间,您知道 offset-from-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".
如果有人想通过在德国使用的 wall-clock 时间看到那一刻,他们可以应用 ZoneId
产生 ZonedDateTime
object.
ZoneId zBerlin = ZoneId.of( "Europe/Berlin" ) ;
ZonedDateTime zdtBerlin = instant.atZone( zBerlin ) ;
如果有人想通过日本使用的 wall-clock 时间看到那一刻,同上。
ZoneId zTokyo = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdtTokyo = instant.atZone( zTokyo ) ;
如果有人想通过魁北克使用的 wall-clock 时间看到那一刻,同上。
ZoneId zMontréal = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdtMontréal = instant.atZone( zMontréal ) ;
所有这些(instant
、zdtBerlin
、zdtTokyo
、zdtMontréal
)都代表了同一时刻,时间轴上的同一点。只有 wall-clock 时间不同。想象一下与每个地区的参与者进行的电话会议。他们都经历了同一时刻,但当他们抬头看着挂在各自墙上的时钟时,他们各自看到了不同的读数。
TimeZone: eg "Europe/Berlin" This is the id for timezone database where the specific rules for the zones are defined ( DST offset .. ).
Offset: Tells you the positive or negative offset to the utc time.
弄清楚zone和offset的含义:
- Offset-from-UTC 只是 hours-minutes-seconds 的数字。而已。例如,
-07:00
. - 时区多。时区是特定地区的人们使用的偏移量的过去、现在和未来变化的历史。例如,在一个政治家疯狂到采用 Daylight Saving Time (DST), their offset-from-UTC changes twice per year, jumping a head an hour, and then falling back an hour. DST does not bend time in an Einstein/Relativity sense 的地方,DST 只是玩 wall-clock 时间的愚蠢游戏。
data was sampled within different timezones
你不在乎。如果您在 UTC 中捕获了片刻,这就是您所需要的。
It's also porrible that a timezone is changed during the sampling process.
再一次……你不在乎。如果您在 UTC 中捕获了片刻,这就是您所需要的。
So I want to store the data as follows in my 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"
}
顺便说一句,在您的示例中,开始时间等于结束时间。可能是你发错了。
With using the TimeZone one can have a look how the offset was at the time when the data was sampled so I don't have to add offset information
您不需要额外的偏移量信息。前两行末尾的 Z
告诉您需要知道的一切。 Z
,发音为“Zulu”,表示 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.
so one can calculate the local time of the user
显然,这里的“用户”一词用词不当。你指的是收集数据的人,而不是接收数据的人。所以您想记住收集数据的时区。
因此捆绑收集数据样本或仪器读数的时区名称。
"TimeSpan": {
"StartTime": "1997-07-16T20:20:30.45Z",
"EndTime": "1997-07-16T20:20:30.45Z"
"SampleTimeZone": "Europe/Berlin"
}
当您想本地化某个时刻时,您只需要一个时刻 (Instant
) 和一个时区 (ZoneId
)。从那里你可以 生成 使用该区域的 wall-clock 时间的字符串。
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`.
Do you think this is a good solution
没有。您对 UTC、时区和 offset-from-UTC 不知何故无关感到困惑。但它们都是相连的。 UTC 是唯一真实时间。有些地方使用偏移量来调整其所在地区的 wall-clock 时间。时区是该地区这些变化的历史记录。