java.time
You are using terrible old date-time classes that are troublesome, confusing, and poorly designed. They are now legacy, supplanted by the java.time classes. Avoid Date
, Calendar
, SimpleDateFormat
, and such.
Use real time zones
By CST
did you mean Central Standard Time or China Standard Time?
Specify a proper time zone name in the format of continent/region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
. Never use the 3-4 letter abbreviation such as EST
or IST
as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Chicago" );
Confirm time zone with user
If the time zone is critical for your work, you must confirm which zone was intended by their input. There are ways to guess at the zone or detect a default, but where important, make the zone part of your data-entry along with the date and the time-of-day. You can present a list from which they choose, or let them input a string name.
Ditto for Locale
(discussed below). You can guess, but if critical, ask.
Parse and assemble
Save and retrieve the date in GMT timezone (date should be converted to String). So, if user saves date 10/10/2017 23:05, that will be saved as 10/11/2017 4:05 (5 hours ahead if saved in CST time for e.g.) in DB.
Parse the user input as a LocalDate
and LocalTime
using a DateTimeFormatter
.
In real work you would add try-catch to capture DateTimeParseException
thrown by faulty user input.
DateTimeFormatter fDate = DateTimeFormatter.ofPattern( "MM/dd/uuuu" ) ;
LocalDate ld = LocalDate.parse( inputDate , f ) ;
DateTimeFormatter fTime = DateTimeFormatter.ISO_LOCAL_TIME ;
LocalTime lt = LocalTime.parse( inputTime , f ) ;
Combine, and specify a time zone to get a ZonedDateTime
object.
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
Adjust to UTC by extracting an Instant
which is always in UTC by definition. Same moment, same point on the timeline, but viewed through the lens of a different wall-clock.
Instant instant = zdt.toInstant() ;
Database
Persist to your database, in a column of type TIMESTAMP WITH TIME ZONE
. The other type WITHOUT
ignores any time zone or offset-from-UTC information and is most definitely not what you want to track actual moments in time.
myPreparedStatement.setObject( … , instant ) ;
Retrieve from database.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
While retrieving and presenting the date to UI, it should show as 10/10/2017 23:05 for CST users.
Adjust into whatever time zone the user expects/desires.
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ; // Or "America/Chicago" or "America/Winnipeg" etc.
ZonedDateTime zdt = instant.atZone( z ) ;
Generate textual representation
Also, need to verify a function to know if the date needs to be shown in US/Non-US date format (dd/MM/YYYY vs mm/DD/YYYY).
Likewise, when generating text to represent that moment, automatically localize with whatever Locale
the user expects/desires.
To localize, specify:
FormatStyle
to determine how long or abbreviated should the string be.
Locale
to determine (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, separators, and such.
Example:
Locale l = Locale.FRANCE ; // Or Locale.US etc.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG ).withLocale( l ) ;
String output = zdt.format( f ) ;
Note that Locale
and time zone are orthogonal, unrelated and separate. You can have a French-speaking clerk in Morocco who is tracking a customer's delivery in India. So the moment is stored in UTC in the database running on a server in Canada, exchanged between database and other components in UTC, adjusted into India time zone to address the perspective of customer receiving delivery, and localized to French for reading by the user in Morocco.
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.
Where to obtain the java.time classes?
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.