Reputation: 2372
I have read a lot about time ( incremental time , observed time, offset, timezones...) Now I'm developing a Backend Architecture with Spring and it comes to the point where i have to fit it all together. Clients send and receive JSONs with Timestamps and values and I can decide how the Syntax should be. I'm not shure if the constellation is right the way I planed it so I would be happy if you correct me in necessary points.
First: How I understand the basic concept.
Mantra: Always work with utc time.
Format : iso8601 YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00) or 1997-07-16T20:20:30.45Z
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.
What I planned: In my case it is possible that the data was sampled within diefferent timezones. It's also porrible that a timezone is changed during the sampling process.
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
}
The client can choose an interval from within the data will be returned. The interval has also to be defined as UTC iso format without offset. As far as I know with the UTC format I can do $lte and $gte operations on the date to filter the interval. So the client receives a JSOnArray with mupltiple JSOnObjects. Each Object has a value and a TimeStamp Object. 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 and so one can calculate the local time of the user. But what if the offset changes. I guess it makes sense also to store the offset for that so so one can reconstruct also "old" timezone rules. Do you think this is a good solution or is there something I forgot/misunderstood/can be done more efficient
Upvotes: 0
Views: 657
Reputation: 339422
Your Question is rather confused.
If you have a moment in UTC, you know the offset-from-UTC is zero, so you do not care about further time zone information.
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".
If someone wants to see that moment through the wall-clock time used in Germany, they can apply a ZoneId
to produce a ZonedDateTime
object.
ZoneId zBerlin = ZoneId.of( "Europe/Berlin" ) ;
ZonedDateTime zdtBerlin = instant.atZone( zBerlin ) ;
If someone wants to see that moment through the wall-clock time used in Japan, ditto.
ZoneId zTokyo = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdtTokyo = instant.atZone( zTokyo ) ;
If someone wants to see that moment through the wall-clock time used in Québec, ditto.
ZoneId zMontréal = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdtMontréal = instant.atZone( zMontréal ) ;
All of these (instant
, zdtBerlin
, zdtTokyo
, zdtMontréal
) all represent the very same simultaneous moment, the same point on the timeline. Only the wall-clock time is different. Imagine a conference call with participants in each of these regions. They all experience the same moment, but when they look up at the clock hanging on their respective wall, they each see a different reading.
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.
Be clear on the meaning of zone and offset:
-07:00
.data was sampled within different timezones
You do not care. If you have a moment captured in UTC, that is all you need.
It's also porrible that a timezone is changed during the sampling process.
Again… You do not care. If you have a moment captured in UTC, that is all you need.
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
}
No, much too much. The last four lines are redundant and possibly confusing. All you need is:
"TimeStamp": {
"StartTime": "1997-07-16T20:20:30.45Z",
"EndTime": "1997-07-16T20:20:30.45Z"
}
By the way, the term timestamp
usually means a specific moment, not a span of time. I suggest a better name such as timespan
.
"TimeSpan": {
"StartTime": "1997-07-16T20:20:30.45Z",
"EndTime": "1997-07-16T20:20:30.45Z"
}
By the way, in your examples the start time equals the end time. Perhaps you made a mistake when posting.
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
You do not need additional offset information. The Z
on the end of the first two lines tells you everything you need to know. The Z
, pronounced "Zulu", means UTC, an offset of zero.
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
Apparently the word "user" here is a poor choice of terms. You mean the person collecting the data, not the person receiving the data. So you want to remember the time zone in which the data was collected.
So bundle the name of the time zone in which the data sample or instrument reading was collected.
"TimeSpan": {
"StartTime": "1997-07-16T20:20:30.45Z",
"EndTime": "1997-07-16T20:20:30.45Z"
"SampleTimeZone": "Europe/Berlin"
}
When you want to localize a moment, all you need is a moment (an Instant
) and a time zone (a ZoneId
). From that you can generate a string using the wall-clock time of that zone.
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
No. You were confused about UTC, time zone, and offset-from-UTC somehow being unrelated. But they are all connected. UTC is The One True time. Some places used an offset to adjust for their region’s wall-clock time. A time zone is a history of those changes for that region.
Upvotes: 1
Reputation: 10186
In Java, if you want to talk about a particular point in time, use Instant
. If 2 events happen in different timezones, but at the same actual moment, their Instant
value will be the same.
If you want to know what various clocks in that area said at that time, you need to know which timezone you are in. For example:
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.
The following APIs are part of Java 8 and are fully compatible with JPA and other commonly used libraries/APIs. Equivalent classes exist if you only care about the day that an event took place.
An Instant
can also be converted to a timestamp using instant.toEpochMilli()
, instant.getEpochSecond()
or instant.getNano()
.
Upvotes: 2