Creating a promotion that starts at 9am for all stores worldwide
Let's say, for example, that a store promotion starts at 9am for all stores worldwide. This means that it starts at 9am CST for stores in Chicago, 9am PST for stores in Seattle, and 9am GMT for stores in the UK.
In our promotions
table on Postgres, we would set the start time for this promotion as 09:00:00.
Each store has a computer with a web browser that looks up available promotions. It needs to pass its local time to the server so that the server can return all promotions for that local time. Thus we need to find a way to capture the local time in JavaScript, encode it, send it to a Java backend, reconstruct it, and then compare that with the start time in the promotions
table.
The local time, of course, depends on the time zone. If it's 9am in Chicago then a store in Chicago should tell the server that it's 9am. It's futile to send the UTC time without some indication of the time zone.
Question: What's a good way to capture the local time (based on time zone) in JavaScript, encode that, send it to a Java backend, reconstruct it as a Java Date
, and then compare that Java Date
with the 9am promotion start time in the Postgres database?
My (unsatisfactory) approach: The best I can think of is to send the UTC time in milliseconds using JavaScript's Date.getTime
method, along with the time zone offset, which can be calculated in minutes using JavaScript's Date.getTimezoneOffset
method and converted to milliseconds. Subtracting the time zone offset from the UTC time in milliseconds, we can then create a Java Date
object from the resulting difference. If it's 9am in Chicago, then, hopefully, the Java Date
will store 9am. What's a little odd about this approach, however, is that the Java Date
will actually be storing 9am UTC, even though it's representing 9am CST. This is just one of the reasons why I am not satisfied with this approach. Can you think of something better?
javascript java date time timezone
|
show 3 more comments
Let's say, for example, that a store promotion starts at 9am for all stores worldwide. This means that it starts at 9am CST for stores in Chicago, 9am PST for stores in Seattle, and 9am GMT for stores in the UK.
In our promotions
table on Postgres, we would set the start time for this promotion as 09:00:00.
Each store has a computer with a web browser that looks up available promotions. It needs to pass its local time to the server so that the server can return all promotions for that local time. Thus we need to find a way to capture the local time in JavaScript, encode it, send it to a Java backend, reconstruct it, and then compare that with the start time in the promotions
table.
The local time, of course, depends on the time zone. If it's 9am in Chicago then a store in Chicago should tell the server that it's 9am. It's futile to send the UTC time without some indication of the time zone.
Question: What's a good way to capture the local time (based on time zone) in JavaScript, encode that, send it to a Java backend, reconstruct it as a Java Date
, and then compare that Java Date
with the 9am promotion start time in the Postgres database?
My (unsatisfactory) approach: The best I can think of is to send the UTC time in milliseconds using JavaScript's Date.getTime
method, along with the time zone offset, which can be calculated in minutes using JavaScript's Date.getTimezoneOffset
method and converted to milliseconds. Subtracting the time zone offset from the UTC time in milliseconds, we can then create a Java Date
object from the resulting difference. If it's 9am in Chicago, then, hopefully, the Java Date
will store 9am. What's a little odd about this approach, however, is that the Java Date
will actually be storing 9am UTC, even though it's representing 9am CST. This is just one of the reasons why I am not satisfied with this approach. Can you think of something better?
javascript java date time timezone
2
Why are you usingj.u.Date
? It's been as-good-as-deprecated for like 4 years. You want LocalDateTime.
– Michael
Nov 21 '18 at 14:10
@Michael Because our software is at least five years old :) I know...java.time
is the new standard... but unfortunately we're not using that in this part of code.
– ktm5124
Nov 21 '18 at 14:12
1
That's not an excuse. Use the ThreeTen-Backport or Joda Time, or upgrade to Java 8.
– Michael
Nov 21 '18 at 14:13
1
@ktm5124 Because LocalDateTime represents a date time without a zone, which is exactly what you want.j.u.Date
is zoned to UTC.
– Michael
Nov 21 '18 at 14:48
2
Moment.js
– Michael
Nov 21 '18 at 15:10
|
show 3 more comments
Let's say, for example, that a store promotion starts at 9am for all stores worldwide. This means that it starts at 9am CST for stores in Chicago, 9am PST for stores in Seattle, and 9am GMT for stores in the UK.
In our promotions
table on Postgres, we would set the start time for this promotion as 09:00:00.
Each store has a computer with a web browser that looks up available promotions. It needs to pass its local time to the server so that the server can return all promotions for that local time. Thus we need to find a way to capture the local time in JavaScript, encode it, send it to a Java backend, reconstruct it, and then compare that with the start time in the promotions
table.
The local time, of course, depends on the time zone. If it's 9am in Chicago then a store in Chicago should tell the server that it's 9am. It's futile to send the UTC time without some indication of the time zone.
Question: What's a good way to capture the local time (based on time zone) in JavaScript, encode that, send it to a Java backend, reconstruct it as a Java Date
, and then compare that Java Date
with the 9am promotion start time in the Postgres database?
My (unsatisfactory) approach: The best I can think of is to send the UTC time in milliseconds using JavaScript's Date.getTime
method, along with the time zone offset, which can be calculated in minutes using JavaScript's Date.getTimezoneOffset
method and converted to milliseconds. Subtracting the time zone offset from the UTC time in milliseconds, we can then create a Java Date
object from the resulting difference. If it's 9am in Chicago, then, hopefully, the Java Date
will store 9am. What's a little odd about this approach, however, is that the Java Date
will actually be storing 9am UTC, even though it's representing 9am CST. This is just one of the reasons why I am not satisfied with this approach. Can you think of something better?
javascript java date time timezone
Let's say, for example, that a store promotion starts at 9am for all stores worldwide. This means that it starts at 9am CST for stores in Chicago, 9am PST for stores in Seattle, and 9am GMT for stores in the UK.
In our promotions
table on Postgres, we would set the start time for this promotion as 09:00:00.
Each store has a computer with a web browser that looks up available promotions. It needs to pass its local time to the server so that the server can return all promotions for that local time. Thus we need to find a way to capture the local time in JavaScript, encode it, send it to a Java backend, reconstruct it, and then compare that with the start time in the promotions
table.
The local time, of course, depends on the time zone. If it's 9am in Chicago then a store in Chicago should tell the server that it's 9am. It's futile to send the UTC time without some indication of the time zone.
Question: What's a good way to capture the local time (based on time zone) in JavaScript, encode that, send it to a Java backend, reconstruct it as a Java Date
, and then compare that Java Date
with the 9am promotion start time in the Postgres database?
My (unsatisfactory) approach: The best I can think of is to send the UTC time in milliseconds using JavaScript's Date.getTime
method, along with the time zone offset, which can be calculated in minutes using JavaScript's Date.getTimezoneOffset
method and converted to milliseconds. Subtracting the time zone offset from the UTC time in milliseconds, we can then create a Java Date
object from the resulting difference. If it's 9am in Chicago, then, hopefully, the Java Date
will store 9am. What's a little odd about this approach, however, is that the Java Date
will actually be storing 9am UTC, even though it's representing 9am CST. This is just one of the reasons why I am not satisfied with this approach. Can you think of something better?
javascript java date time timezone
javascript java date time timezone
asked Nov 21 '18 at 14:06
ktm5124ktm5124
7,926165389
7,926165389
2
Why are you usingj.u.Date
? It's been as-good-as-deprecated for like 4 years. You want LocalDateTime.
– Michael
Nov 21 '18 at 14:10
@Michael Because our software is at least five years old :) I know...java.time
is the new standard... but unfortunately we're not using that in this part of code.
– ktm5124
Nov 21 '18 at 14:12
1
That's not an excuse. Use the ThreeTen-Backport or Joda Time, or upgrade to Java 8.
– Michael
Nov 21 '18 at 14:13
1
@ktm5124 Because LocalDateTime represents a date time without a zone, which is exactly what you want.j.u.Date
is zoned to UTC.
– Michael
Nov 21 '18 at 14:48
2
Moment.js
– Michael
Nov 21 '18 at 15:10
|
show 3 more comments
2
Why are you usingj.u.Date
? It's been as-good-as-deprecated for like 4 years. You want LocalDateTime.
– Michael
Nov 21 '18 at 14:10
@Michael Because our software is at least five years old :) I know...java.time
is the new standard... but unfortunately we're not using that in this part of code.
– ktm5124
Nov 21 '18 at 14:12
1
That's not an excuse. Use the ThreeTen-Backport or Joda Time, or upgrade to Java 8.
– Michael
Nov 21 '18 at 14:13
1
@ktm5124 Because LocalDateTime represents a date time without a zone, which is exactly what you want.j.u.Date
is zoned to UTC.
– Michael
Nov 21 '18 at 14:48
2
Moment.js
– Michael
Nov 21 '18 at 15:10
2
2
Why are you using
j.u.Date
? It's been as-good-as-deprecated for like 4 years. You want LocalDateTime.– Michael
Nov 21 '18 at 14:10
Why are you using
j.u.Date
? It's been as-good-as-deprecated for like 4 years. You want LocalDateTime.– Michael
Nov 21 '18 at 14:10
@Michael Because our software is at least five years old :) I know...
java.time
is the new standard... but unfortunately we're not using that in this part of code.– ktm5124
Nov 21 '18 at 14:12
@Michael Because our software is at least five years old :) I know...
java.time
is the new standard... but unfortunately we're not using that in this part of code.– ktm5124
Nov 21 '18 at 14:12
1
1
That's not an excuse. Use the ThreeTen-Backport or Joda Time, or upgrade to Java 8.
– Michael
Nov 21 '18 at 14:13
That's not an excuse. Use the ThreeTen-Backport or Joda Time, or upgrade to Java 8.
– Michael
Nov 21 '18 at 14:13
1
1
@ktm5124 Because LocalDateTime represents a date time without a zone, which is exactly what you want.
j.u.Date
is zoned to UTC.– Michael
Nov 21 '18 at 14:48
@ktm5124 Because LocalDateTime represents a date time without a zone, which is exactly what you want.
j.u.Date
is zoned to UTC.– Michael
Nov 21 '18 at 14:48
2
2
Moment.js
– Michael
Nov 21 '18 at 15:10
Moment.js
– Michael
Nov 21 '18 at 15:10
|
show 3 more comments
2 Answers
2
active
oldest
votes
Postgres
In Postgres, when you mean 9 AM everywhere, or 9 AM anywhere, on a certain date, use the column data type TIMESTAMP WITHOUT TIME ZONE
. Any time zone or offset-from-UTC included with an input is ignored, with the date and time-of-day taken as-is (no adjustment) and stored. This data type purposely lacks any concept of time zone or offset-from-UTC.
For time-of-day without a date, use TIME WITHOUT TIME ZONE
data type. Postgres also offers a TIME WITH TIME ZONE
only because it is required by the SQL spec; this WITH
type is nonsensical and should never be used.
Postgres is an excellent choice for such a project, as it offers excellent date-time support in both its data types and in its functions. Databases vary widely in their date-time features.
Java
On the Java backend, use only the modern java.time classes. These years ago supplanted the terrible old date-time classes bundled with the earliest versions of Java.
If not yet using Java 8 or later, find nearly all the same functionality in a back-port to Java 6 & 7 in the ThreeTen-Backport project. Well worth the minor effort of adding this library to your project. From the same fine folks who brought you the java.time classes and the Joda-Time project, all led by the same man Stephen Colebourne.
LocalDateTime
In java.time, use LocalDateTime
class for when you mean 9 AM anywhere/everywhere on a certain date. Like TIMESTAMP WITHOUT TIME ZONE
in Postgres, this class purposely lacks any concept of zone or offset.
LocalDateTime ldt = LocalDateTime.of( 2018 , 1 , 23 , 15 , 0 , 0 , 0 ) ; // 3 PM on 23rd of January this year.
LocalTime
If you mean the time-of-day only, without a date, use the class LocalTime
.
LocalTime lt = LocalTime.of( 15 , 0 ) ; // 3 PM.
JDBC
As of JDBC 4.2 and later you can exchange java.time objects with the database via getObject
and setObject
methods.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
If your JDBC drivers are not yet updated to 4.2, then fall back to the awful old legacy classes, but convert immediately to the java.time classes.
Given that the legacy classes lack a class for a date plus time-of-day without time zone, we have to fake it. Use java.sql.Timestamp
which represents a moment in UTC with a resolution of nanoseconds, and just ignore the fact that it is in UTC.
java.sql.Timestamp ts = myResultSet.getTimestamp( … ) ;
For Java 8 and later, convert using new methods added to the old classes. Convert first to java.time.Instant
, which also represents a moment in UTC with a resolution of nanoseconds. Then convert to a LocalDateTime
by effectively removing the concept of UTC.
Instant instant = ts.toInstant() ; // Convert from legacy class to modern one.
LocalDateTime ldt = LocalDateTime.ofInstant( instant , ZoneOffset.UTC ) ; // Remove the concept of UTC (or any other offset or zone) from our data.
For Java 6 & 7 using the ThreeTen-Backport library, use the conversion methods in their utility DateTimeUtils
class.
org.threeten.bp.Instant instant = org.threeten.bp.DateTimeUtils.toInstant( ts ) ; // Convert from legacy class to modern.
org.threeten.bp.LocalDateTime ldt = LocalDateTime.ofInstant( instant , ZoneOffset.UTC ) ; // Remove the concept of UTC (or any other offset or zone) from our data.
ZonedDateTime
The Local…
classes by definition have no real meaning until you place them in the context of a time zone. A LocalDateTime
is not a moment, does not represent a point on the timeline.
Specify a proper time zone name in the format of continent/region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
. Never use the 2-4 letter abbreviation such as PST
or BST
or EST
or IST
as they are not true time zones, not standardized, and not even unique(!).
LocalDateTime ldt =
LocalDateTime.of(
LocalDate.of( 2018 , Month.January , 23 ) ,
LocalTime.of( 9 , 0 )
)
;
ZoneId zLosAngeles = ZoneId.of( "America/Los_Angeles" ) ; // Seattle time zone.
ZonedDateTime zdtSeattle = ldt.atZone( zLosAngeles ) ;
ZoneId zChicago = ZoneId.of( "America/Chicago" ) ;
ZonedDateTime zdtChicago = ldt.atZone( zChicago ) ;
ZoneId zLondon = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdtLondon = ldt.atZone( zLondon ) ;
There we have three ZonedDateTime
objects: zdtSeattle
, zdtChicago
, and zdtLondon
. These are all 9 AM on the 23rd of January earlier this year. Understand that these are three very different moments, each being several hours earlier as you go eastward. They all have the same wall-clock time (9 AM on 23rd) but are three different points on the timeline.
JavaScript
While I do not know JavaScript well enough to say for certain, I doubt you have any library there as rich for date-time handling. The java.time framework is industry-leading.
As for web client user-interface development, I use Vaadin, so it is a non-issue: pure Java on back-end auto-generates the HTML/CSS/DOM/JavaScript needed by the web browser.
find a way to capture the local time in JavaScript
As for detecting the current default time zone in the client machine, I’m no expert, but as I recall the browsers do not return a named time zone, only an offset-from-UTC. See the Answer by Matt Johnson for a possible solution. In any app (desktop or web), ultimately, if the correct time zone is vital, then you must ask or confirm the desired/expected time zone with the user. And it may be wise to always indicate somewhere on your user interface what time zone is being used by your app.
If you need to exchange date-time values between your Java backend and JavaScript code in the front-end, you have two choices primarily:
- ISO 8601
- Count-from-epoch
ISO 8601
The ISO 8601 standard defines a variety of textual formats for exchanging date-time values. These are wisely designed to avoid ambiguity. They are easy to parse by machine, and easy to read by humans across cultures.
The java.time classes use these formats by default when generating/parsing strings.
Count-from-Epoch
I do not recommend this approach, as it is confusing and error-prone, subject to ambiguity and incorrect assumptions between the people and libraries who are sending or receiving.
An epoch reference date is a point in time used as baseline. Then some count forward or backward is made of some granularity.
One big problem is that there are dozens of epoch references used by various systems. The java.time classes by default use the Unix time epoch of first moment of 1970 in UTC, 1970-01-01T00:00Z.
Another problem is that there are many granularities such as whole seconds, milliseconds, microseconds, and nanoseconds. Programmers must document/communicate clearly what granularity is in play.
If you were to be sending your three opening moments for your three stores to JavaScript as a count-from-epoch, you would be sending three different numbers.
long millisecondsSeattle = zdtSeattle.toInstant().toEpochMilli() ;
long millisecondsChicago = zdtChicago.toInstant().toEpochMilli() ;
long millisecondsLondon = zdtLondon.toInstant().toEpochMilli() ;
Results in three different numbers for three different moments.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
Agree with all your points (as usual) except the recommendation for Vaadin to solve the JS side. That is glossing over a key point in the question (IMHO). See my answer about that part, and feel free to copy for your reference and future posts. Thanks.
– Matt Johnson
Nov 22 '18 at 17:26
1
@MattJohnson Thanks for the feedback. I added a bit more of what little I know about JavaScript, and added a link to your Answer.
– Basil Bourque
Nov 22 '18 at 19:17
This is a great answer. Thanks a lot!
– ktm5124
Nov 30 '18 at 16:58
add a comment |
You do not need to capture the user's local time, but merely their IANA time zone identifier, such as "America/Los_Angeles"
. This can then be used in your Java back-end code in APIs that accept a time zone.
In most modern browsers, you can capture the the time zone id like this:
Intl.DateTimeFormat().resolvedOptions().timeZone
If you require supporting older browsers, there are several libraries that will use this Intl API when available, but will fall back to an educated guess when not. More on this here.
Since we're stuck using java.util.Date, it might actually be hard to parse a Date from an IANA time zone identifier. Would you happen to know differently? I wish we could convert to java.time, but this is an old piece of code that still uses java.util.Date.
– ktm5124
Nov 21 '18 at 18:49
You wouldn't parse it to aDate
, you'd usejava.util.TimeZone
, possibly in conjunction withjava.util.Calendar
and/orSimpleDateFormat
. IANA time zone IDs are not unique to the new java.time APIs (though still, you should prefer those when possible).
– Matt Johnson
Nov 21 '18 at 19:39
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53413856%2fcreating-a-promotion-that-starts-at-9am-for-all-stores-worldwide%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Postgres
In Postgres, when you mean 9 AM everywhere, or 9 AM anywhere, on a certain date, use the column data type TIMESTAMP WITHOUT TIME ZONE
. Any time zone or offset-from-UTC included with an input is ignored, with the date and time-of-day taken as-is (no adjustment) and stored. This data type purposely lacks any concept of time zone or offset-from-UTC.
For time-of-day without a date, use TIME WITHOUT TIME ZONE
data type. Postgres also offers a TIME WITH TIME ZONE
only because it is required by the SQL spec; this WITH
type is nonsensical and should never be used.
Postgres is an excellent choice for such a project, as it offers excellent date-time support in both its data types and in its functions. Databases vary widely in their date-time features.
Java
On the Java backend, use only the modern java.time classes. These years ago supplanted the terrible old date-time classes bundled with the earliest versions of Java.
If not yet using Java 8 or later, find nearly all the same functionality in a back-port to Java 6 & 7 in the ThreeTen-Backport project. Well worth the minor effort of adding this library to your project. From the same fine folks who brought you the java.time classes and the Joda-Time project, all led by the same man Stephen Colebourne.
LocalDateTime
In java.time, use LocalDateTime
class for when you mean 9 AM anywhere/everywhere on a certain date. Like TIMESTAMP WITHOUT TIME ZONE
in Postgres, this class purposely lacks any concept of zone or offset.
LocalDateTime ldt = LocalDateTime.of( 2018 , 1 , 23 , 15 , 0 , 0 , 0 ) ; // 3 PM on 23rd of January this year.
LocalTime
If you mean the time-of-day only, without a date, use the class LocalTime
.
LocalTime lt = LocalTime.of( 15 , 0 ) ; // 3 PM.
JDBC
As of JDBC 4.2 and later you can exchange java.time objects with the database via getObject
and setObject
methods.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
If your JDBC drivers are not yet updated to 4.2, then fall back to the awful old legacy classes, but convert immediately to the java.time classes.
Given that the legacy classes lack a class for a date plus time-of-day without time zone, we have to fake it. Use java.sql.Timestamp
which represents a moment in UTC with a resolution of nanoseconds, and just ignore the fact that it is in UTC.
java.sql.Timestamp ts = myResultSet.getTimestamp( … ) ;
For Java 8 and later, convert using new methods added to the old classes. Convert first to java.time.Instant
, which also represents a moment in UTC with a resolution of nanoseconds. Then convert to a LocalDateTime
by effectively removing the concept of UTC.
Instant instant = ts.toInstant() ; // Convert from legacy class to modern one.
LocalDateTime ldt = LocalDateTime.ofInstant( instant , ZoneOffset.UTC ) ; // Remove the concept of UTC (or any other offset or zone) from our data.
For Java 6 & 7 using the ThreeTen-Backport library, use the conversion methods in their utility DateTimeUtils
class.
org.threeten.bp.Instant instant = org.threeten.bp.DateTimeUtils.toInstant( ts ) ; // Convert from legacy class to modern.
org.threeten.bp.LocalDateTime ldt = LocalDateTime.ofInstant( instant , ZoneOffset.UTC ) ; // Remove the concept of UTC (or any other offset or zone) from our data.
ZonedDateTime
The Local…
classes by definition have no real meaning until you place them in the context of a time zone. A LocalDateTime
is not a moment, does not represent a point on the timeline.
Specify a proper time zone name in the format of continent/region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
. Never use the 2-4 letter abbreviation such as PST
or BST
or EST
or IST
as they are not true time zones, not standardized, and not even unique(!).
LocalDateTime ldt =
LocalDateTime.of(
LocalDate.of( 2018 , Month.January , 23 ) ,
LocalTime.of( 9 , 0 )
)
;
ZoneId zLosAngeles = ZoneId.of( "America/Los_Angeles" ) ; // Seattle time zone.
ZonedDateTime zdtSeattle = ldt.atZone( zLosAngeles ) ;
ZoneId zChicago = ZoneId.of( "America/Chicago" ) ;
ZonedDateTime zdtChicago = ldt.atZone( zChicago ) ;
ZoneId zLondon = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdtLondon = ldt.atZone( zLondon ) ;
There we have three ZonedDateTime
objects: zdtSeattle
, zdtChicago
, and zdtLondon
. These are all 9 AM on the 23rd of January earlier this year. Understand that these are three very different moments, each being several hours earlier as you go eastward. They all have the same wall-clock time (9 AM on 23rd) but are three different points on the timeline.
JavaScript
While I do not know JavaScript well enough to say for certain, I doubt you have any library there as rich for date-time handling. The java.time framework is industry-leading.
As for web client user-interface development, I use Vaadin, so it is a non-issue: pure Java on back-end auto-generates the HTML/CSS/DOM/JavaScript needed by the web browser.
find a way to capture the local time in JavaScript
As for detecting the current default time zone in the client machine, I’m no expert, but as I recall the browsers do not return a named time zone, only an offset-from-UTC. See the Answer by Matt Johnson for a possible solution. In any app (desktop or web), ultimately, if the correct time zone is vital, then you must ask or confirm the desired/expected time zone with the user. And it may be wise to always indicate somewhere on your user interface what time zone is being used by your app.
If you need to exchange date-time values between your Java backend and JavaScript code in the front-end, you have two choices primarily:
- ISO 8601
- Count-from-epoch
ISO 8601
The ISO 8601 standard defines a variety of textual formats for exchanging date-time values. These are wisely designed to avoid ambiguity. They are easy to parse by machine, and easy to read by humans across cultures.
The java.time classes use these formats by default when generating/parsing strings.
Count-from-Epoch
I do not recommend this approach, as it is confusing and error-prone, subject to ambiguity and incorrect assumptions between the people and libraries who are sending or receiving.
An epoch reference date is a point in time used as baseline. Then some count forward or backward is made of some granularity.
One big problem is that there are dozens of epoch references used by various systems. The java.time classes by default use the Unix time epoch of first moment of 1970 in UTC, 1970-01-01T00:00Z.
Another problem is that there are many granularities such as whole seconds, milliseconds, microseconds, and nanoseconds. Programmers must document/communicate clearly what granularity is in play.
If you were to be sending your three opening moments for your three stores to JavaScript as a count-from-epoch, you would be sending three different numbers.
long millisecondsSeattle = zdtSeattle.toInstant().toEpochMilli() ;
long millisecondsChicago = zdtChicago.toInstant().toEpochMilli() ;
long millisecondsLondon = zdtLondon.toInstant().toEpochMilli() ;
Results in three different numbers for three different moments.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
Agree with all your points (as usual) except the recommendation for Vaadin to solve the JS side. That is glossing over a key point in the question (IMHO). See my answer about that part, and feel free to copy for your reference and future posts. Thanks.
– Matt Johnson
Nov 22 '18 at 17:26
1
@MattJohnson Thanks for the feedback. I added a bit more of what little I know about JavaScript, and added a link to your Answer.
– Basil Bourque
Nov 22 '18 at 19:17
This is a great answer. Thanks a lot!
– ktm5124
Nov 30 '18 at 16:58
add a comment |
Postgres
In Postgres, when you mean 9 AM everywhere, or 9 AM anywhere, on a certain date, use the column data type TIMESTAMP WITHOUT TIME ZONE
. Any time zone or offset-from-UTC included with an input is ignored, with the date and time-of-day taken as-is (no adjustment) and stored. This data type purposely lacks any concept of time zone or offset-from-UTC.
For time-of-day without a date, use TIME WITHOUT TIME ZONE
data type. Postgres also offers a TIME WITH TIME ZONE
only because it is required by the SQL spec; this WITH
type is nonsensical and should never be used.
Postgres is an excellent choice for such a project, as it offers excellent date-time support in both its data types and in its functions. Databases vary widely in their date-time features.
Java
On the Java backend, use only the modern java.time classes. These years ago supplanted the terrible old date-time classes bundled with the earliest versions of Java.
If not yet using Java 8 or later, find nearly all the same functionality in a back-port to Java 6 & 7 in the ThreeTen-Backport project. Well worth the minor effort of adding this library to your project. From the same fine folks who brought you the java.time classes and the Joda-Time project, all led by the same man Stephen Colebourne.
LocalDateTime
In java.time, use LocalDateTime
class for when you mean 9 AM anywhere/everywhere on a certain date. Like TIMESTAMP WITHOUT TIME ZONE
in Postgres, this class purposely lacks any concept of zone or offset.
LocalDateTime ldt = LocalDateTime.of( 2018 , 1 , 23 , 15 , 0 , 0 , 0 ) ; // 3 PM on 23rd of January this year.
LocalTime
If you mean the time-of-day only, without a date, use the class LocalTime
.
LocalTime lt = LocalTime.of( 15 , 0 ) ; // 3 PM.
JDBC
As of JDBC 4.2 and later you can exchange java.time objects with the database via getObject
and setObject
methods.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
If your JDBC drivers are not yet updated to 4.2, then fall back to the awful old legacy classes, but convert immediately to the java.time classes.
Given that the legacy classes lack a class for a date plus time-of-day without time zone, we have to fake it. Use java.sql.Timestamp
which represents a moment in UTC with a resolution of nanoseconds, and just ignore the fact that it is in UTC.
java.sql.Timestamp ts = myResultSet.getTimestamp( … ) ;
For Java 8 and later, convert using new methods added to the old classes. Convert first to java.time.Instant
, which also represents a moment in UTC with a resolution of nanoseconds. Then convert to a LocalDateTime
by effectively removing the concept of UTC.
Instant instant = ts.toInstant() ; // Convert from legacy class to modern one.
LocalDateTime ldt = LocalDateTime.ofInstant( instant , ZoneOffset.UTC ) ; // Remove the concept of UTC (or any other offset or zone) from our data.
For Java 6 & 7 using the ThreeTen-Backport library, use the conversion methods in their utility DateTimeUtils
class.
org.threeten.bp.Instant instant = org.threeten.bp.DateTimeUtils.toInstant( ts ) ; // Convert from legacy class to modern.
org.threeten.bp.LocalDateTime ldt = LocalDateTime.ofInstant( instant , ZoneOffset.UTC ) ; // Remove the concept of UTC (or any other offset or zone) from our data.
ZonedDateTime
The Local…
classes by definition have no real meaning until you place them in the context of a time zone. A LocalDateTime
is not a moment, does not represent a point on the timeline.
Specify a proper time zone name in the format of continent/region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
. Never use the 2-4 letter abbreviation such as PST
or BST
or EST
or IST
as they are not true time zones, not standardized, and not even unique(!).
LocalDateTime ldt =
LocalDateTime.of(
LocalDate.of( 2018 , Month.January , 23 ) ,
LocalTime.of( 9 , 0 )
)
;
ZoneId zLosAngeles = ZoneId.of( "America/Los_Angeles" ) ; // Seattle time zone.
ZonedDateTime zdtSeattle = ldt.atZone( zLosAngeles ) ;
ZoneId zChicago = ZoneId.of( "America/Chicago" ) ;
ZonedDateTime zdtChicago = ldt.atZone( zChicago ) ;
ZoneId zLondon = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdtLondon = ldt.atZone( zLondon ) ;
There we have three ZonedDateTime
objects: zdtSeattle
, zdtChicago
, and zdtLondon
. These are all 9 AM on the 23rd of January earlier this year. Understand that these are three very different moments, each being several hours earlier as you go eastward. They all have the same wall-clock time (9 AM on 23rd) but are three different points on the timeline.
JavaScript
While I do not know JavaScript well enough to say for certain, I doubt you have any library there as rich for date-time handling. The java.time framework is industry-leading.
As for web client user-interface development, I use Vaadin, so it is a non-issue: pure Java on back-end auto-generates the HTML/CSS/DOM/JavaScript needed by the web browser.
find a way to capture the local time in JavaScript
As for detecting the current default time zone in the client machine, I’m no expert, but as I recall the browsers do not return a named time zone, only an offset-from-UTC. See the Answer by Matt Johnson for a possible solution. In any app (desktop or web), ultimately, if the correct time zone is vital, then you must ask or confirm the desired/expected time zone with the user. And it may be wise to always indicate somewhere on your user interface what time zone is being used by your app.
If you need to exchange date-time values between your Java backend and JavaScript code in the front-end, you have two choices primarily:
- ISO 8601
- Count-from-epoch
ISO 8601
The ISO 8601 standard defines a variety of textual formats for exchanging date-time values. These are wisely designed to avoid ambiguity. They are easy to parse by machine, and easy to read by humans across cultures.
The java.time classes use these formats by default when generating/parsing strings.
Count-from-Epoch
I do not recommend this approach, as it is confusing and error-prone, subject to ambiguity and incorrect assumptions between the people and libraries who are sending or receiving.
An epoch reference date is a point in time used as baseline. Then some count forward or backward is made of some granularity.
One big problem is that there are dozens of epoch references used by various systems. The java.time classes by default use the Unix time epoch of first moment of 1970 in UTC, 1970-01-01T00:00Z.
Another problem is that there are many granularities such as whole seconds, milliseconds, microseconds, and nanoseconds. Programmers must document/communicate clearly what granularity is in play.
If you were to be sending your three opening moments for your three stores to JavaScript as a count-from-epoch, you would be sending three different numbers.
long millisecondsSeattle = zdtSeattle.toInstant().toEpochMilli() ;
long millisecondsChicago = zdtChicago.toInstant().toEpochMilli() ;
long millisecondsLondon = zdtLondon.toInstant().toEpochMilli() ;
Results in three different numbers for three different moments.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
Agree with all your points (as usual) except the recommendation for Vaadin to solve the JS side. That is glossing over a key point in the question (IMHO). See my answer about that part, and feel free to copy for your reference and future posts. Thanks.
– Matt Johnson
Nov 22 '18 at 17:26
1
@MattJohnson Thanks for the feedback. I added a bit more of what little I know about JavaScript, and added a link to your Answer.
– Basil Bourque
Nov 22 '18 at 19:17
This is a great answer. Thanks a lot!
– ktm5124
Nov 30 '18 at 16:58
add a comment |
Postgres
In Postgres, when you mean 9 AM everywhere, or 9 AM anywhere, on a certain date, use the column data type TIMESTAMP WITHOUT TIME ZONE
. Any time zone or offset-from-UTC included with an input is ignored, with the date and time-of-day taken as-is (no adjustment) and stored. This data type purposely lacks any concept of time zone or offset-from-UTC.
For time-of-day without a date, use TIME WITHOUT TIME ZONE
data type. Postgres also offers a TIME WITH TIME ZONE
only because it is required by the SQL spec; this WITH
type is nonsensical and should never be used.
Postgres is an excellent choice for such a project, as it offers excellent date-time support in both its data types and in its functions. Databases vary widely in their date-time features.
Java
On the Java backend, use only the modern java.time classes. These years ago supplanted the terrible old date-time classes bundled with the earliest versions of Java.
If not yet using Java 8 or later, find nearly all the same functionality in a back-port to Java 6 & 7 in the ThreeTen-Backport project. Well worth the minor effort of adding this library to your project. From the same fine folks who brought you the java.time classes and the Joda-Time project, all led by the same man Stephen Colebourne.
LocalDateTime
In java.time, use LocalDateTime
class for when you mean 9 AM anywhere/everywhere on a certain date. Like TIMESTAMP WITHOUT TIME ZONE
in Postgres, this class purposely lacks any concept of zone or offset.
LocalDateTime ldt = LocalDateTime.of( 2018 , 1 , 23 , 15 , 0 , 0 , 0 ) ; // 3 PM on 23rd of January this year.
LocalTime
If you mean the time-of-day only, without a date, use the class LocalTime
.
LocalTime lt = LocalTime.of( 15 , 0 ) ; // 3 PM.
JDBC
As of JDBC 4.2 and later you can exchange java.time objects with the database via getObject
and setObject
methods.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
If your JDBC drivers are not yet updated to 4.2, then fall back to the awful old legacy classes, but convert immediately to the java.time classes.
Given that the legacy classes lack a class for a date plus time-of-day without time zone, we have to fake it. Use java.sql.Timestamp
which represents a moment in UTC with a resolution of nanoseconds, and just ignore the fact that it is in UTC.
java.sql.Timestamp ts = myResultSet.getTimestamp( … ) ;
For Java 8 and later, convert using new methods added to the old classes. Convert first to java.time.Instant
, which also represents a moment in UTC with a resolution of nanoseconds. Then convert to a LocalDateTime
by effectively removing the concept of UTC.
Instant instant = ts.toInstant() ; // Convert from legacy class to modern one.
LocalDateTime ldt = LocalDateTime.ofInstant( instant , ZoneOffset.UTC ) ; // Remove the concept of UTC (or any other offset or zone) from our data.
For Java 6 & 7 using the ThreeTen-Backport library, use the conversion methods in their utility DateTimeUtils
class.
org.threeten.bp.Instant instant = org.threeten.bp.DateTimeUtils.toInstant( ts ) ; // Convert from legacy class to modern.
org.threeten.bp.LocalDateTime ldt = LocalDateTime.ofInstant( instant , ZoneOffset.UTC ) ; // Remove the concept of UTC (or any other offset or zone) from our data.
ZonedDateTime
The Local…
classes by definition have no real meaning until you place them in the context of a time zone. A LocalDateTime
is not a moment, does not represent a point on the timeline.
Specify a proper time zone name in the format of continent/region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
. Never use the 2-4 letter abbreviation such as PST
or BST
or EST
or IST
as they are not true time zones, not standardized, and not even unique(!).
LocalDateTime ldt =
LocalDateTime.of(
LocalDate.of( 2018 , Month.January , 23 ) ,
LocalTime.of( 9 , 0 )
)
;
ZoneId zLosAngeles = ZoneId.of( "America/Los_Angeles" ) ; // Seattle time zone.
ZonedDateTime zdtSeattle = ldt.atZone( zLosAngeles ) ;
ZoneId zChicago = ZoneId.of( "America/Chicago" ) ;
ZonedDateTime zdtChicago = ldt.atZone( zChicago ) ;
ZoneId zLondon = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdtLondon = ldt.atZone( zLondon ) ;
There we have three ZonedDateTime
objects: zdtSeattle
, zdtChicago
, and zdtLondon
. These are all 9 AM on the 23rd of January earlier this year. Understand that these are three very different moments, each being several hours earlier as you go eastward. They all have the same wall-clock time (9 AM on 23rd) but are three different points on the timeline.
JavaScript
While I do not know JavaScript well enough to say for certain, I doubt you have any library there as rich for date-time handling. The java.time framework is industry-leading.
As for web client user-interface development, I use Vaadin, so it is a non-issue: pure Java on back-end auto-generates the HTML/CSS/DOM/JavaScript needed by the web browser.
find a way to capture the local time in JavaScript
As for detecting the current default time zone in the client machine, I’m no expert, but as I recall the browsers do not return a named time zone, only an offset-from-UTC. See the Answer by Matt Johnson for a possible solution. In any app (desktop or web), ultimately, if the correct time zone is vital, then you must ask or confirm the desired/expected time zone with the user. And it may be wise to always indicate somewhere on your user interface what time zone is being used by your app.
If you need to exchange date-time values between your Java backend and JavaScript code in the front-end, you have two choices primarily:
- ISO 8601
- Count-from-epoch
ISO 8601
The ISO 8601 standard defines a variety of textual formats for exchanging date-time values. These are wisely designed to avoid ambiguity. They are easy to parse by machine, and easy to read by humans across cultures.
The java.time classes use these formats by default when generating/parsing strings.
Count-from-Epoch
I do not recommend this approach, as it is confusing and error-prone, subject to ambiguity and incorrect assumptions between the people and libraries who are sending or receiving.
An epoch reference date is a point in time used as baseline. Then some count forward or backward is made of some granularity.
One big problem is that there are dozens of epoch references used by various systems. The java.time classes by default use the Unix time epoch of first moment of 1970 in UTC, 1970-01-01T00:00Z.
Another problem is that there are many granularities such as whole seconds, milliseconds, microseconds, and nanoseconds. Programmers must document/communicate clearly what granularity is in play.
If you were to be sending your three opening moments for your three stores to JavaScript as a count-from-epoch, you would be sending three different numbers.
long millisecondsSeattle = zdtSeattle.toInstant().toEpochMilli() ;
long millisecondsChicago = zdtChicago.toInstant().toEpochMilli() ;
long millisecondsLondon = zdtLondon.toInstant().toEpochMilli() ;
Results in three different numbers for three different moments.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
Postgres
In Postgres, when you mean 9 AM everywhere, or 9 AM anywhere, on a certain date, use the column data type TIMESTAMP WITHOUT TIME ZONE
. Any time zone or offset-from-UTC included with an input is ignored, with the date and time-of-day taken as-is (no adjustment) and stored. This data type purposely lacks any concept of time zone or offset-from-UTC.
For time-of-day without a date, use TIME WITHOUT TIME ZONE
data type. Postgres also offers a TIME WITH TIME ZONE
only because it is required by the SQL spec; this WITH
type is nonsensical and should never be used.
Postgres is an excellent choice for such a project, as it offers excellent date-time support in both its data types and in its functions. Databases vary widely in their date-time features.
Java
On the Java backend, use only the modern java.time classes. These years ago supplanted the terrible old date-time classes bundled with the earliest versions of Java.
If not yet using Java 8 or later, find nearly all the same functionality in a back-port to Java 6 & 7 in the ThreeTen-Backport project. Well worth the minor effort of adding this library to your project. From the same fine folks who brought you the java.time classes and the Joda-Time project, all led by the same man Stephen Colebourne.
LocalDateTime
In java.time, use LocalDateTime
class for when you mean 9 AM anywhere/everywhere on a certain date. Like TIMESTAMP WITHOUT TIME ZONE
in Postgres, this class purposely lacks any concept of zone or offset.
LocalDateTime ldt = LocalDateTime.of( 2018 , 1 , 23 , 15 , 0 , 0 , 0 ) ; // 3 PM on 23rd of January this year.
LocalTime
If you mean the time-of-day only, without a date, use the class LocalTime
.
LocalTime lt = LocalTime.of( 15 , 0 ) ; // 3 PM.
JDBC
As of JDBC 4.2 and later you can exchange java.time objects with the database via getObject
and setObject
methods.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
If your JDBC drivers are not yet updated to 4.2, then fall back to the awful old legacy classes, but convert immediately to the java.time classes.
Given that the legacy classes lack a class for a date plus time-of-day without time zone, we have to fake it. Use java.sql.Timestamp
which represents a moment in UTC with a resolution of nanoseconds, and just ignore the fact that it is in UTC.
java.sql.Timestamp ts = myResultSet.getTimestamp( … ) ;
For Java 8 and later, convert using new methods added to the old classes. Convert first to java.time.Instant
, which also represents a moment in UTC with a resolution of nanoseconds. Then convert to a LocalDateTime
by effectively removing the concept of UTC.
Instant instant = ts.toInstant() ; // Convert from legacy class to modern one.
LocalDateTime ldt = LocalDateTime.ofInstant( instant , ZoneOffset.UTC ) ; // Remove the concept of UTC (or any other offset or zone) from our data.
For Java 6 & 7 using the ThreeTen-Backport library, use the conversion methods in their utility DateTimeUtils
class.
org.threeten.bp.Instant instant = org.threeten.bp.DateTimeUtils.toInstant( ts ) ; // Convert from legacy class to modern.
org.threeten.bp.LocalDateTime ldt = LocalDateTime.ofInstant( instant , ZoneOffset.UTC ) ; // Remove the concept of UTC (or any other offset or zone) from our data.
ZonedDateTime
The Local…
classes by definition have no real meaning until you place them in the context of a time zone. A LocalDateTime
is not a moment, does not represent a point on the timeline.
Specify a proper time zone name in the format of continent/region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
. Never use the 2-4 letter abbreviation such as PST
or BST
or EST
or IST
as they are not true time zones, not standardized, and not even unique(!).
LocalDateTime ldt =
LocalDateTime.of(
LocalDate.of( 2018 , Month.January , 23 ) ,
LocalTime.of( 9 , 0 )
)
;
ZoneId zLosAngeles = ZoneId.of( "America/Los_Angeles" ) ; // Seattle time zone.
ZonedDateTime zdtSeattle = ldt.atZone( zLosAngeles ) ;
ZoneId zChicago = ZoneId.of( "America/Chicago" ) ;
ZonedDateTime zdtChicago = ldt.atZone( zChicago ) ;
ZoneId zLondon = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdtLondon = ldt.atZone( zLondon ) ;
There we have three ZonedDateTime
objects: zdtSeattle
, zdtChicago
, and zdtLondon
. These are all 9 AM on the 23rd of January earlier this year. Understand that these are three very different moments, each being several hours earlier as you go eastward. They all have the same wall-clock time (9 AM on 23rd) but are three different points on the timeline.
JavaScript
While I do not know JavaScript well enough to say for certain, I doubt you have any library there as rich for date-time handling. The java.time framework is industry-leading.
As for web client user-interface development, I use Vaadin, so it is a non-issue: pure Java on back-end auto-generates the HTML/CSS/DOM/JavaScript needed by the web browser.
find a way to capture the local time in JavaScript
As for detecting the current default time zone in the client machine, I’m no expert, but as I recall the browsers do not return a named time zone, only an offset-from-UTC. See the Answer by Matt Johnson for a possible solution. In any app (desktop or web), ultimately, if the correct time zone is vital, then you must ask or confirm the desired/expected time zone with the user. And it may be wise to always indicate somewhere on your user interface what time zone is being used by your app.
If you need to exchange date-time values between your Java backend and JavaScript code in the front-end, you have two choices primarily:
- ISO 8601
- Count-from-epoch
ISO 8601
The ISO 8601 standard defines a variety of textual formats for exchanging date-time values. These are wisely designed to avoid ambiguity. They are easy to parse by machine, and easy to read by humans across cultures.
The java.time classes use these formats by default when generating/parsing strings.
Count-from-Epoch
I do not recommend this approach, as it is confusing and error-prone, subject to ambiguity and incorrect assumptions between the people and libraries who are sending or receiving.
An epoch reference date is a point in time used as baseline. Then some count forward or backward is made of some granularity.
One big problem is that there are dozens of epoch references used by various systems. The java.time classes by default use the Unix time epoch of first moment of 1970 in UTC, 1970-01-01T00:00Z.
Another problem is that there are many granularities such as whole seconds, milliseconds, microseconds, and nanoseconds. Programmers must document/communicate clearly what granularity is in play.
If you were to be sending your three opening moments for your three stores to JavaScript as a count-from-epoch, you would be sending three different numbers.
long millisecondsSeattle = zdtSeattle.toInstant().toEpochMilli() ;
long millisecondsChicago = zdtChicago.toInstant().toEpochMilli() ;
long millisecondsLondon = zdtLondon.toInstant().toEpochMilli() ;
Results in three different numbers for three different moments.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
edited Nov 22 '18 at 19:21
answered Nov 22 '18 at 0:11
Basil BourqueBasil Bourque
109k26375538
109k26375538
Agree with all your points (as usual) except the recommendation for Vaadin to solve the JS side. That is glossing over a key point in the question (IMHO). See my answer about that part, and feel free to copy for your reference and future posts. Thanks.
– Matt Johnson
Nov 22 '18 at 17:26
1
@MattJohnson Thanks for the feedback. I added a bit more of what little I know about JavaScript, and added a link to your Answer.
– Basil Bourque
Nov 22 '18 at 19:17
This is a great answer. Thanks a lot!
– ktm5124
Nov 30 '18 at 16:58
add a comment |
Agree with all your points (as usual) except the recommendation for Vaadin to solve the JS side. That is glossing over a key point in the question (IMHO). See my answer about that part, and feel free to copy for your reference and future posts. Thanks.
– Matt Johnson
Nov 22 '18 at 17:26
1
@MattJohnson Thanks for the feedback. I added a bit more of what little I know about JavaScript, and added a link to your Answer.
– Basil Bourque
Nov 22 '18 at 19:17
This is a great answer. Thanks a lot!
– ktm5124
Nov 30 '18 at 16:58
Agree with all your points (as usual) except the recommendation for Vaadin to solve the JS side. That is glossing over a key point in the question (IMHO). See my answer about that part, and feel free to copy for your reference and future posts. Thanks.
– Matt Johnson
Nov 22 '18 at 17:26
Agree with all your points (as usual) except the recommendation for Vaadin to solve the JS side. That is glossing over a key point in the question (IMHO). See my answer about that part, and feel free to copy for your reference and future posts. Thanks.
– Matt Johnson
Nov 22 '18 at 17:26
1
1
@MattJohnson Thanks for the feedback. I added a bit more of what little I know about JavaScript, and added a link to your Answer.
– Basil Bourque
Nov 22 '18 at 19:17
@MattJohnson Thanks for the feedback. I added a bit more of what little I know about JavaScript, and added a link to your Answer.
– Basil Bourque
Nov 22 '18 at 19:17
This is a great answer. Thanks a lot!
– ktm5124
Nov 30 '18 at 16:58
This is a great answer. Thanks a lot!
– ktm5124
Nov 30 '18 at 16:58
add a comment |
You do not need to capture the user's local time, but merely their IANA time zone identifier, such as "America/Los_Angeles"
. This can then be used in your Java back-end code in APIs that accept a time zone.
In most modern browsers, you can capture the the time zone id like this:
Intl.DateTimeFormat().resolvedOptions().timeZone
If you require supporting older browsers, there are several libraries that will use this Intl API when available, but will fall back to an educated guess when not. More on this here.
Since we're stuck using java.util.Date, it might actually be hard to parse a Date from an IANA time zone identifier. Would you happen to know differently? I wish we could convert to java.time, but this is an old piece of code that still uses java.util.Date.
– ktm5124
Nov 21 '18 at 18:49
You wouldn't parse it to aDate
, you'd usejava.util.TimeZone
, possibly in conjunction withjava.util.Calendar
and/orSimpleDateFormat
. IANA time zone IDs are not unique to the new java.time APIs (though still, you should prefer those when possible).
– Matt Johnson
Nov 21 '18 at 19:39
add a comment |
You do not need to capture the user's local time, but merely their IANA time zone identifier, such as "America/Los_Angeles"
. This can then be used in your Java back-end code in APIs that accept a time zone.
In most modern browsers, you can capture the the time zone id like this:
Intl.DateTimeFormat().resolvedOptions().timeZone
If you require supporting older browsers, there are several libraries that will use this Intl API when available, but will fall back to an educated guess when not. More on this here.
Since we're stuck using java.util.Date, it might actually be hard to parse a Date from an IANA time zone identifier. Would you happen to know differently? I wish we could convert to java.time, but this is an old piece of code that still uses java.util.Date.
– ktm5124
Nov 21 '18 at 18:49
You wouldn't parse it to aDate
, you'd usejava.util.TimeZone
, possibly in conjunction withjava.util.Calendar
and/orSimpleDateFormat
. IANA time zone IDs are not unique to the new java.time APIs (though still, you should prefer those when possible).
– Matt Johnson
Nov 21 '18 at 19:39
add a comment |
You do not need to capture the user's local time, but merely their IANA time zone identifier, such as "America/Los_Angeles"
. This can then be used in your Java back-end code in APIs that accept a time zone.
In most modern browsers, you can capture the the time zone id like this:
Intl.DateTimeFormat().resolvedOptions().timeZone
If you require supporting older browsers, there are several libraries that will use this Intl API when available, but will fall back to an educated guess when not. More on this here.
You do not need to capture the user's local time, but merely their IANA time zone identifier, such as "America/Los_Angeles"
. This can then be used in your Java back-end code in APIs that accept a time zone.
In most modern browsers, you can capture the the time zone id like this:
Intl.DateTimeFormat().resolvedOptions().timeZone
If you require supporting older browsers, there are several libraries that will use this Intl API when available, but will fall back to an educated guess when not. More on this here.
answered Nov 21 '18 at 17:55
Matt JohnsonMatt Johnson
137k41279399
137k41279399
Since we're stuck using java.util.Date, it might actually be hard to parse a Date from an IANA time zone identifier. Would you happen to know differently? I wish we could convert to java.time, but this is an old piece of code that still uses java.util.Date.
– ktm5124
Nov 21 '18 at 18:49
You wouldn't parse it to aDate
, you'd usejava.util.TimeZone
, possibly in conjunction withjava.util.Calendar
and/orSimpleDateFormat
. IANA time zone IDs are not unique to the new java.time APIs (though still, you should prefer those when possible).
– Matt Johnson
Nov 21 '18 at 19:39
add a comment |
Since we're stuck using java.util.Date, it might actually be hard to parse a Date from an IANA time zone identifier. Would you happen to know differently? I wish we could convert to java.time, but this is an old piece of code that still uses java.util.Date.
– ktm5124
Nov 21 '18 at 18:49
You wouldn't parse it to aDate
, you'd usejava.util.TimeZone
, possibly in conjunction withjava.util.Calendar
and/orSimpleDateFormat
. IANA time zone IDs are not unique to the new java.time APIs (though still, you should prefer those when possible).
– Matt Johnson
Nov 21 '18 at 19:39
Since we're stuck using java.util.Date, it might actually be hard to parse a Date from an IANA time zone identifier. Would you happen to know differently? I wish we could convert to java.time, but this is an old piece of code that still uses java.util.Date.
– ktm5124
Nov 21 '18 at 18:49
Since we're stuck using java.util.Date, it might actually be hard to parse a Date from an IANA time zone identifier. Would you happen to know differently? I wish we could convert to java.time, but this is an old piece of code that still uses java.util.Date.
– ktm5124
Nov 21 '18 at 18:49
You wouldn't parse it to a
Date
, you'd use java.util.TimeZone
, possibly in conjunction with java.util.Calendar
and/or SimpleDateFormat
. IANA time zone IDs are not unique to the new java.time APIs (though still, you should prefer those when possible).– Matt Johnson
Nov 21 '18 at 19:39
You wouldn't parse it to a
Date
, you'd use java.util.TimeZone
, possibly in conjunction with java.util.Calendar
and/or SimpleDateFormat
. IANA time zone IDs are not unique to the new java.time APIs (though still, you should prefer those when possible).– Matt Johnson
Nov 21 '18 at 19:39
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53413856%2fcreating-a-promotion-that-starts-at-9am-for-all-stores-worldwide%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Why are you using
j.u.Date
? It's been as-good-as-deprecated for like 4 years. You want LocalDateTime.– Michael
Nov 21 '18 at 14:10
@Michael Because our software is at least five years old :) I know...
java.time
is the new standard... but unfortunately we're not using that in this part of code.– ktm5124
Nov 21 '18 at 14:12
1
That's not an excuse. Use the ThreeTen-Backport or Joda Time, or upgrade to Java 8.
– Michael
Nov 21 '18 at 14:13
1
@ktm5124 Because LocalDateTime represents a date time without a zone, which is exactly what you want.
j.u.Date
is zoned to UTC.– Michael
Nov 21 '18 at 14:48
2
Moment.js
– Michael
Nov 21 '18 at 15:10